diff --git a/subsys/nrf_security/cmake/psa_crypto_config.cmake b/subsys/nrf_security/cmake/psa_crypto_config.cmake index 6f48f7125045..1ed522efd4d2 100644 --- a/subsys/nrf_security/cmake/psa_crypto_config.cmake +++ b/subsys/nrf_security/cmake/psa_crypto_config.cmake @@ -60,6 +60,7 @@ kconfig_check_and_set_base_to_one(PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS_255 kconfig_check_and_set_base_to_one(PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS_448) kconfig_check_and_set_base_to_one(PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS) kconfig_check_and_set_base_to_one(PSA_NEED_CRACEN_RSA_PKCS1V15_SIGN) +kconfig_check_and_set_base_to_one(PSA_NEED_CRACEN_ED25519PH) kconfig_check_and_set_base_to_one(PSA_NEED_CRACEN_RSA_PSS) kconfig_check_and_set_base_to_one(PSA_NEED_CRACEN_ASYMMETRIC_SIGNATURE_ANY_ECC) kconfig_check_and_set_base_to_one(PSA_NEED_CRACEN_ASYMMETRIC_SIGNATURE_ANY_RSA) diff --git a/subsys/nrf_security/configs/psa_crypto_config.h.template b/subsys/nrf_security/configs/psa_crypto_config.h.template index 31d39bc82d6a..27ab9473a008 100644 --- a/subsys/nrf_security/configs/psa_crypto_config.h.template +++ b/subsys/nrf_security/configs/psa_crypto_config.h.template @@ -272,6 +272,7 @@ #cmakedefine PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS_255 @PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS_255@ #cmakedefine PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS_448 @PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS_448@ #cmakedefine PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS @PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS@ +#cmakedefine PSA_NEED_CRACEN_ED25519PH @PSA_NEED_CRACEN_ED25519PH@ #cmakedefine PSA_NEED_CRACEN_RSA_PKCS1V15_SIGN @PSA_NEED_CRACEN_RSA_PKCS1V15_SIGN@ #cmakedefine PSA_NEED_CRACEN_RSA_PSS @PSA_NEED_CRACEN_RSA_PSS@ #cmakedefine PSA_NEED_CRACEN_RSA_OAEP @PSA_NEED_CRACEN_RSA_OAEP@ diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c index 340f657f1f83..410f946327d3 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/key_management.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -602,6 +603,7 @@ static psa_status_t export_ecc_public_key_from_keypair(const psa_key_attributes_ psa_status_t psa_status; size_t expected_pub_key_size = 0; int si_status = 0; + psa_algorithm_t key_alg = psa_get_key_algorithm(attributes); const struct sx_pk_ecurve *sx_curve; struct sitask t; @@ -673,9 +675,15 @@ static psa_status_t export_ecc_public_key_from_keypair(const psa_key_attributes_ break; case PSA_ECC_FAMILY_TWISTED_EDWARDS: if (key_bits_attr == 255) { - priv_key.def = si_sig_def_ed25519; - priv_key.key.ed25519 = (struct sx_ed25519_v *)key_buffer; - pub_key.key.ed25519 = (struct sx_ed25519_pt *)data; + if (key_alg == PSA_ALG_ED25519PH) { + priv_key.def = si_sig_def_ed25519ph; + priv_key.key.ed25519 = (struct sx_ed25519_v *)key_buffer; + pub_key.key.ed25519 = (struct sx_ed25519_pt *)data; + } else { + priv_key.def = si_sig_def_ed25519; + priv_key.key.ed25519 = (struct sx_ed25519_v *)key_buffer; + pub_key.key.ed25519 = (struct sx_ed25519_pt *)data; + } } else { priv_key.def = si_sig_def_ed448; priv_key.key.ed448 = (struct sx_ed448_v *)key_buffer; @@ -700,6 +708,7 @@ static psa_status_t export_ecc_public_key_from_keypair(const psa_key_attributes_ *data_length = expected_pub_key_size; return PSA_SUCCESS; } + static psa_status_t export_rsa_public_key_from_keypair(const psa_key_attributes_t *attributes, const uint8_t *key_buffer, size_t key_buffer_size, uint8_t *data, diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/kmu.c b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/kmu.c index d5ba951a4f06..ba3e096615b1 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/kmu.c +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/kmu.c @@ -61,7 +61,7 @@ enum kmu_metadata_algorithm { METADATA_ALG_CMAC = 9, METADATA_ALG_ED25519 = 10, METADATA_ALG_ECDSA = 11, - METADATA_ALG_RESERVED2 = 12, + METADATA_ALG_ED25519PH = 12, METADATA_ALG_RESERVED3 = 13, METADATA_ALG_RESERVED4 = 14, METADATA_ALG_RESERVED5 = 15, @@ -463,6 +463,15 @@ static psa_status_t convert_to_psa_attributes(kmu_metadata *metadata, : PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_TWISTED_EDWARDS)); psa_set_key_algorithm(key_attr, PSA_ALG_PURE_EDDSA); break; + case METADATA_ALG_ED25519PH: + /* If the key can sign it is assumed it is a private key */ + psa_set_key_type( + key_attr, + can_sign(key_attr) + ? PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS) + : PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_TWISTED_EDWARDS)); + psa_set_key_algorithm(key_attr, PSA_ALG_ED25519PH); + break; case METADATA_ALG_ECDSA: psa_set_key_type(key_attr, can_sign(key_attr) @@ -614,6 +623,19 @@ psa_status_t convert_from_psa_attributes(const psa_key_attributes_t *key_attr, metadata->algorithm = METADATA_ALG_ED25519; break; + case PSA_ALG_ED25519PH: + if (PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(key_attr)) != + PSA_ECC_FAMILY_TWISTED_EDWARDS) { + return PSA_ERROR_NOT_SUPPORTED; + } + /* Don't support private keys that are only used for verify */ + if (!can_sign(key_attr) && + PSA_KEY_TYPE_IS_ECC_KEY_PAIR(psa_get_key_type(key_attr))) { + return PSA_ERROR_NOT_SUPPORTED; + } + metadata->algorithm = METADATA_ALG_ED25519PH; + break; + case PSA_ALG_ECDSA(PSA_ALG_ANY_HASH): if (PSA_KEY_TYPE_ECC_GET_FAMILY(psa_get_key_type(key_attr)) != PSA_ECC_FAMILY_SECP_R1) { diff --git a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/sign.c b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/sign.c index 4bf86b2f7e84..2af3cc14baaf 100644 --- a/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/sign.c +++ b/subsys/nrf_security/src/drivers/cracen/cracenpsa/src/sign.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -127,6 +128,19 @@ static int cracen_signature_prepare_ec_prvkey(struct si_sig_privkey *privkey, ch } } + if (IS_ENABLED(PSA_NEED_CRACEN_ED25519PH)) { + if (alg == PSA_ALG_ED25519PH) { + privkey->def = si_sig_def_ed25519ph; + privkey->key.ed25519 = (struct sx_ed25519_v *)key_buffer; + if (message) { + return cracen_signature_set_hashalgo(&privkey->hashalg, alg); + } else { + return cracen_signature_set_hashalgo_from_digestsz( + &privkey->hashalg, alg, digestsz); + } + } + } + if (IS_ENABLED(PSA_NEED_CRACEN_ECDSA_SECP_R1) || IS_ENABLED(PSA_NEED_CRACEN_ECDSA_SECP_K1) || IS_ENABLED(PSA_NEED_CRACEN_ECDSA_BRAINPOOL_P_R1)) { @@ -210,6 +224,25 @@ static int cracen_signature_prepare_ec_pubkey(struct sitask *t, struct si_sig_pu } } + if (IS_ENABLED(PSA_NEED_CRACEN_ED25519PH) && alg == PSA_ALG_ED25519PH) { + pubkey->def = si_sig_def_ed25519ph; + if (PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(psa_get_key_type(attributes))) { + pubkey->key.ed25519 = (struct sx_ed25519_pt *)key_buffer; + if (message) { + cracen_signature_set_hashalgo(&pubkey->hashalg, + alg); + } else { + cracen_signature_set_hashalgo_from_digestsz(&pubkey->hashalg, + alg, digestsz); + } + return SX_OK; + } + if (curvesz != key_buffer_size) { + return SX_ERR_INVALID_KEY_SZ; + } + pubkey->key.ed25519 = (struct sx_ed25519_pt *)pubkey_buffer; + } + if (IS_ENABLED(PSA_NEED_CRACEN_ECDSA_SECP_R1) || IS_ENABLED(PSA_NEED_CRACEN_ECDSA_SECP_K1) || IS_ENABLED(PSA_NEED_CRACEN_ECDSA_BRAINPOOL_P_R1)) { @@ -280,7 +313,7 @@ static psa_status_t cracen_signature_ecc_sign(int message, const psa_key_attribu return silex_statuscodes_to_psa(SX_ERR_INCOMPATIBLE_HW); } - if (!PSA_ALG_IS_ECDSA(alg) && alg != PSA_ALG_PURE_EDDSA) { + if (!PSA_ALG_IS_ECDSA(alg) && alg != PSA_ALG_PURE_EDDSA && alg != PSA_ALG_ED25519PH) { return PSA_ERROR_INVALID_ARGUMENT; } @@ -306,14 +339,34 @@ static psa_status_t cracen_signature_ecc_sign(int message, const psa_key_attribu sign.r = (char *)signature; sign.s = (char *)signature + *signature_length / 2; - if (message) { + /* ED25519PH requires prehashing and supports sign and verify message + * the message is therefore hashed here before si_sig_verify is called + */ + if (alg == PSA_ALG_ED25519PH && message) { + uint8_t status; + uint8_t hash[64]; + size_t output_len; + + status = psa_hash_compute(PSA_ALG_SHA_512, + input, input_length, hash, + sizeof(hash), &output_len); + if (status != PSA_SUCCESS) { + return status; + } + si_sig_create_sign(&t, &privkey, &sign); - si_task_consume(&t, (char *)input, input_length); + si_task_consume(&t, (char *)hash, sizeof(hash)); } else { - si_sig_create_sign_digest(&t, &privkey, &sign); - si_task_consume(&t, (char *)input, sx_hash_get_alg_digestsz(privkey.hashalg)); - } + if (message) { + si_sig_create_sign(&t, &privkey, &sign); + } else { + si_sig_create_sign_digest(&t, &privkey, &sign); + } + si_task_consume(&t, (char *)input, + message ? input_length : sx_hash_get_alg_digestsz(privkey.hashalg)); + + } si_task_run(&t); si_status = si_task_wait(&t); safe_memzero(workmem, sizeof(workmem)); @@ -342,7 +395,7 @@ static psa_status_t cracen_signature_ecc_verify(int message, const psa_key_attri return silex_statuscodes_to_psa(SX_ERR_INCOMPATIBLE_HW); } - if (!PSA_ALG_IS_ECDSA(alg) && alg != PSA_ALG_PURE_EDDSA) { + if (!PSA_ALG_IS_ECDSA(alg) && alg != PSA_ALG_PURE_EDDSA && !PSA_ALG_IS_HASH_EDDSA(alg)) { return PSA_ERROR_NOT_SUPPORTED; } @@ -366,20 +419,37 @@ static psa_status_t cracen_signature_ecc_verify(int message, const psa_key_attri sign.sz = signature_length; sign.r = (char *)signature; sign.s = (char *)signature + signature_length / 2; + /* ED25519PH requires prehashing and supports sign and verify message + * the message is therefore hashed here before si_sig_verify is called + */ + if (alg == PSA_ALG_ED25519PH && message) { + psa_status_t status; + uint8_t hash[64]; + uint32_t output_len; + + status = psa_hash_compute(PSA_ALG_SHA_512, + input, input_length, hash, + sizeof(hash), &output_len); + if (status != PSA_SUCCESS) { + return status; + } - if (message) { si_sig_create_verify(&t, &pubkey, &sign); + si_task_consume(&t, (char *)hash, sizeof(hash)); } else { - if (sx_hash_get_alg_digestsz(pubkey.hashalg) != input_length) { - return PSA_ERROR_INVALID_ARGUMENT; + if (message) { + si_sig_create_verify(&t, &pubkey, &sign); + } else { + if (sx_hash_get_alg_digestsz(pubkey.hashalg) != input_length) { + return PSA_ERROR_INVALID_ARGUMENT; + } + si_sig_create_verify_digest(&t, &pubkey, &sign); } - si_sig_create_verify_digest(&t, &pubkey, &sign); - } - si_task_consume(&t, (char *)input, input_length); + si_task_consume(&t, (char *)input, input_length); + } si_task_run(&t); si_status = si_task_wait(&t); - safe_memzero(workmem, sizeof(workmem)); return silex_statuscodes_to_psa(si_status); } diff --git a/subsys/nrf_security/src/drivers/cracen/psa_driver.Kconfig b/subsys/nrf_security/src/drivers/cracen/psa_driver.Kconfig index bd989b5c4a7e..57b478a9ef92 100644 --- a/subsys/nrf_security/src/drivers/cracen/psa_driver.Kconfig +++ b/subsys/nrf_security/src/drivers/cracen/psa_driver.Kconfig @@ -364,6 +364,14 @@ config PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS_448 depends on PSA_WANT_ECC_TWISTED_EDWARDS_448 depends on PSA_USE_CRACEN_ASYMMETRIC_DRIVER +config PSA_NEED_CRACEN_ED25519PH + bool + default y + select PSA_ACCEL_ED25519PH + depends on PSA_WANT_ALG_ED25519PH + depends on PSA_WANT_ECC_TWISTED_EDWARDS_255 + depends on PSA_USE_CRACEN_ASYMMETRIC_DRIVER + config PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS bool default y @@ -376,6 +384,7 @@ config PSA_NEED_CRACEN_ASYMMETRIC_SIGNATURE_ANY_ECC depends on PSA_NEED_CRACEN_ECDSA_BRAINPOOL_P_R1 || \ PSA_NEED_CRACEN_ECDSA_SECP_R1 || \ PSA_NEED_CRACEN_ECDSA_SECP_K1 || \ + PSA_NEED_CRACEN_ED25519PH || \ PSA_NEED_CRACEN_PURE_EDDSA_TWISTED_EDWARDS config PSA_NEED_CRACEN_RSA_PKCS1V15_SIGN diff --git a/subsys/nrf_security/src/drivers/cracen/sicrypto/include/sicrypto/ed25519ph.h b/subsys/nrf_security/src/drivers/cracen/sicrypto/include/sicrypto/ed25519ph.h new file mode 100644 index 000000000000..26bcfe59cedc --- /dev/null +++ b/subsys/nrf_security/src/drivers/cracen/sicrypto/include/sicrypto/ed25519ph.h @@ -0,0 +1,49 @@ +/** Ed25519 signature-related operations. + * + * @file + * + * @copyright Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef SICRYPTO_ED25519PH_HEADER_FILE +#define SICRYPTO_ED25519PH_HEADER_FILE + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sig.h" + +/** Signature definitions for ED25519PH keys. + * + * The following constraints apply when using Ed25519ph keys: + * + * When generating a signature with si_sig_create_sign(): + * - The task needs a workmem buffer of at least 160 bytes. + * - The message to be signed must be given with a single call to + * si_task_consume(). + * - The buffer for private key material must be in DMA memory. + * - The signature buffer must be in DMA memory. + * + * When verifying a signature with si_sig_create_verify(): + * - The task needs a workmem buffer of at least 64 bytes. + * - The buffer for public key material must be in DMA memory. + * - The signature buffer must be in DMA memory. + * - The task can use partial processing. For the first partial run, the sum of + * the sizes of the provided message chunks plus 64 must be a multiple of + * 128 bytes. For any other partial run, the sum of the sizes of the provided + * message chunks must be a multiple of 128 bytes. + * + * When computing a public key with si_sig_create_pubkey(): + * - The task needs a workmem buffer of at least 64 bytes. + * - The buffer for private key material must be in DMA memory. + */ +extern const struct si_sig_def *const si_sig_def_ed25519ph; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/subsys/nrf_security/src/drivers/cracen/sicrypto/sicrypto.cmake b/subsys/nrf_security/src/drivers/cracen/sicrypto/sicrypto.cmake index 9bb4a88ae970..3b78f2870ac7 100644 --- a/subsys/nrf_security/src/drivers/cracen/sicrypto/sicrypto.cmake +++ b/subsys/nrf_security/src/drivers/cracen/sicrypto/sicrypto.cmake @@ -10,6 +10,7 @@ list(APPEND cracen_driver_sources ${CMAKE_CURRENT_LIST_DIR}/src/ecc.c ${CMAKE_CURRENT_LIST_DIR}/src/ecdsa.c ${CMAKE_CURRENT_LIST_DIR}/src/ed25519.c + ${CMAKE_CURRENT_LIST_DIR}/src/ed25519ph.c ${CMAKE_CURRENT_LIST_DIR}/src/ed448.c ${CMAKE_CURRENT_LIST_DIR}/src/hash.c ${CMAKE_CURRENT_LIST_DIR}/src/hkdf.c diff --git a/subsys/nrf_security/src/drivers/cracen/sicrypto/src/ed25519ph.c b/subsys/nrf_security/src/drivers/cracen/sicrypto/src/ed25519ph.c new file mode 100644 index 000000000000..a670334cdd62 --- /dev/null +++ b/subsys/nrf_security/src/drivers/cracen/sicrypto/src/ed25519ph.c @@ -0,0 +1,410 @@ +/** Ed25519ph signature generation/verification and public key + * computation. Based on RFC 8032. + * + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + * + * The comments in this file use the notations and conventions from RFC 8032. + * + * Workmem layout for an Ed25519ph signature verification task: + * 1. digest (size: 64 bytes). + * + * Workmem layout for an Ed25519ph signature generation task: + * The workmem is made of 5 areas of 32 bytes each (total size 160 bytes). + * In the following we refer to these areas using the numbers 1 to 5. The + * first hash operation computes the private key's digest, which is stored + * in areas 1 and 2. The second hash operation computes r, which is stored + * in areas 4 and 5. The first point multiplication computes R, which is + * written directly to the output buffer. Then the secret scalar s is + * computed in place in area 1. Area 2 is cleared. The second point + * multiplication computes the public key A, which is stored in area 2. The + * third hash operation computes k, which is stored in areas 2 and 3. The + * final operation (r + k * s) mod L computes S, which is written directly + * to the output buffer. + * + * Workmem layout for an Ed25519ph public key generation task: + * 1. digest (size: 64 bytes). The digest of the private key is written in + * this area. Then the secret scalar s is computed in place in the first + * 32 bytes of this area. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "waitqueue.h" +#include "sigdefs.h" +#include "final.h" +#include "util.h" + +/* This is the ASCII string with the + * PHflag 1 and context size 0 appended as defined in: + * https://datatracker.ietf.org/doc/html/rfc8032.html#section-2 + * used for domain seperation between ED25519 and ED25519PH + */ +const char dom2[34] = { + 0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35, + 0x35, 0x31, 0x39, 0x20, 0x6e, 0x6f, 0x20, + 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, + 0x20, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x01, 0x00 +}; + +static int finish_ed25519ph_ver(struct sitask *t, struct siwq *wq) +{ + (void)wq; + sx_pk_release_req(t->pk); + return t->statuscode; +} + +static int continue_ed25519ph_ver(struct sitask *t, struct siwq *wq) +{ + struct sx_pk_acq_req pkreq; + (void)wq; + + if (t->statuscode != SX_OK) { + return t->statuscode; + } + + si_wq_run_after(t, &t->params.ed25519_verif.wq, finish_ed25519ph_ver); + + pkreq = sx_async_ed25519_verify_go( + (struct sx_ed25519_dgst *)t->workmem, t->params.ed25519_verif.pubkey, + (const struct sx_ed25519_v *)(t->params.ed25519_verif.signature->r + + SX_ED25519_PT_SZ), + (const struct sx_ed25519_pt *)t->params.ed25519_verif.signature->r); + if (pkreq.status) { + return si_task_mark_final(t, pkreq.status); + } + + t->pk = pkreq.req; + t->actions.status = si_silexpk_status; + t->actions.wait = si_silexpk_wait; + t->statuscode = SX_ERR_HW_PROCESSING; + + return SX_ERR_HW_PROCESSING; +} + +static void run_ed25519ph_ver(struct sitask *t) +{ + si_wq_run_after(t, &t->params.ed25519_verif.wq, continue_ed25519ph_ver); + + /* Override statuscode to be able to execute si_task_produce() */ + t->statuscode = SX_ERR_READY; + si_task_produce(t, t->workmem, SX_ED25519_DGST_SZ); +} + +static void si_sig_create_ed25519ph_verify(struct sitask *t, const struct si_sig_pubkey *pubkey, + const struct si_sig_signature *signature) +{ + if (t->workmemsz < SX_ED25519_DGST_SZ) { + si_task_mark_final(t, SX_ERR_WORKMEM_BUFFER_TOO_SMALL); + return; + } + + si_hash_create(t, &sxhashalg_sha2_512); + si_task_consume(t, dom2, sizeof(dom2)); + si_task_consume(t, signature->r, SX_ED25519_PT_SZ); + si_task_consume(t, pubkey->key.ed25519->encoded, SX_ED25519_PT_SZ); + t->actions.run = &run_ed25519ph_ver; + t->params.ed25519_verif.pubkey = pubkey->key.ed25519; + t->params.ed25519_verif.signature = signature; +} + +static void si_sig_create_ed25519ph_verify_digest(struct sitask *t, + const struct si_sig_pubkey *pubkey, + const struct si_sig_signature *signature) +{ + si_sig_create_ed25519ph_verify(t, pubkey, signature); +} + +static int ed25519ph_sign_finish(struct sitask *t, struct siwq *wq) +{ + (void)wq; + + if (t->statuscode != SX_OK) { + sx_pk_release_req(t->pk); + return t->statuscode; + } + + /* Get the second part of the signature, the encoded S. */ + sx_async_ed25519_sign_end( + t->pk, + (struct sx_ed25519_v *)(t->params.ed25519_sign.signature->r + SX_ED25519_PT_SZ)); + + return t->statuscode; +} + +static int ed25519ph_sign_continue(struct sitask *t, struct siwq *wq) +{ + struct sx_pk_acq_req pkreq; + (void)wq; + + if (t->statuscode != SX_OK) { + return t->statuscode; + } + + si_wq_run_after(t, &t->params.ed25519_sign.wq, ed25519ph_sign_finish); + + /* Compute (r + k * s) mod L. This gives the second part of the + * signature, which is the encoded S. + */ + pkreq = sx_pk_async_ed25519_sign_go( + (const struct sx_ed25519_dgst *)(t->workmem + SX_ED25519_SZ), + (const struct sx_ed25519_dgst *)(t->workmem + 3 * SX_ED25519_SZ), + (const struct sx_ed25519_v *)t->workmem); + + t->pk = pkreq.req; + t->actions.status = si_silexpk_status; + t->actions.wait = si_silexpk_wait; + t->statuscode = SX_ERR_HW_PROCESSING; + + return SX_ERR_HW_PROCESSING; +} + +static int ed25519ph_sign_k_hash(struct sitask *t, struct siwq *wq) +{ + (void)wq; + + if (t->statuscode != SX_OK) { + sx_pk_release_req(t->pk); + return t->statuscode; + } + + /* Get result of the point multiplication. This is the encoding of the + * [s]B point, which is the public key A. + */ + sx_async_ed25519_ptmult_end(t->pk, (struct sx_ed25519_pt *)(t->workmem + SX_ED25519_SZ)); + + si_wq_run_after(t, &t->params.ed25519_sign.wq, ed25519ph_sign_continue); + + /* Obtain k by hashing (R || A || message). */ + si_hash_create(t, &sxhashalg_sha2_512); + si_task_consume(t, dom2, sizeof(dom2)); + si_task_consume(t, t->params.ed25519_sign.signature->r, SX_ED25519_SZ); + si_task_consume(t, t->workmem + SX_ED25519_SZ, SX_ED25519_SZ); + si_task_consume(t, t->params.ed25519_sign.msg, t->params.ed25519_sign.msgsz); + si_task_produce(t, t->workmem + SX_ED25519_SZ, SX_ED25519_DGST_SZ); + + return SX_ERR_HW_PROCESSING; +} + +static int ed25519ph_compute_pubkey(struct sitask *t) +{ + struct sx_pk_acq_req pkreq; + + /* The secret scalar s is computed in place from the first half of the + * private key digest. + */ + decode_scalar_25519(t->workmem); + + /* Clear second half of private key digest: sx_async_ed25519ph_ptmult_go() + * works on an input of SX_ED25519PH_DGST_SZ bytes. + */ + safe_memset(t->workmem + SX_ED25519_SZ, t->workmemsz - SX_ED25519_SZ, 0, SX_ED25519_SZ); + + /* Perform point multiplication A = [s]B, to obtain the public key A. */ + pkreq = sx_async_ed25519_ptmult_go((const struct sx_ed25519_dgst *)t->workmem); + if (pkreq.status) { + return si_task_mark_final(t, pkreq.status); + } + + t->pk = pkreq.req; + + return (t->statuscode = SX_ERR_HW_PROCESSING); +} + +static int ed25519ph_sign_pubkey_ptmult(struct sitask *t, struct siwq *wq) +{ + (void)wq; + + if (t->statuscode != SX_OK) { + sx_pk_release_req(t->pk); + return t->statuscode; + } + + /* Get result of the point multiplication. This is the encoded point R, + * which is the first part of the signature. + */ + sx_async_ed25519_ptmult_end(t->pk, + (struct sx_ed25519_pt *)t->params.ed25519_sign.signature->r); + + si_wq_run_after(t, &t->params.ed25519_sign.wq, ed25519ph_sign_k_hash); + + return ed25519ph_compute_pubkey(t); +} + +static int ed25519ph_sign_r_ptmult(struct sitask *t, struct siwq *wq) +{ + struct sx_pk_acq_req pkreq; + (void)wq; + + if (t->statuscode != SX_OK) { + return t->statuscode; + } + + si_wq_run_after(t, &t->params.ed25519_sign.wq, ed25519ph_sign_pubkey_ptmult); + + /* Perform point multiplication R = [r]B. */ + pkreq = sx_async_ed25519_ptmult_go( + (const struct sx_ed25519_dgst *)(t->workmem + 3 * SX_ED25519_SZ)); + if (pkreq.status) { + return si_task_mark_final(t, pkreq.status); + } + + t->pk = pkreq.req; + t->actions.status = si_silexpk_status; + t->actions.wait = si_silexpk_wait; + t->statuscode = SX_ERR_HW_PROCESSING; + + return SX_ERR_HW_PROCESSING; +} + +static int ed25519ph_sign_message(struct sitask *t, struct siwq *wq) +{ + (void)wq; + + if (t->statuscode != SX_OK) { + return t->statuscode; + } + + si_wq_run_after(t, &t->params.ed25519_sign.wq, ed25519ph_sign_r_ptmult); + + /* Obtain r by hashing (prefix || message), where prefix is the second + * half of the private key digest. + */ + si_hash_create(t, &sxhashalg_sha2_512); + + si_task_consume(t, dom2, sizeof(dom2)); + si_task_consume(t, t->workmem + SX_ED25519_SZ, SX_ED25519_SZ); + si_task_consume(t, t->params.ed25519_sign.msg, t->params.ed25519_sign.msgsz); + si_task_produce(t, t->workmem + 3 * SX_ED25519_SZ, SX_ED25519_DGST_SZ); + + return SX_ERR_HW_PROCESSING; +} + +static void ed25519ph_sign_hash_privkey(struct sitask *t) +{ + si_wq_run_after(t, &t->params.ed25519_sign.wq, ed25519ph_sign_message); + + /* Hash the private key. */ + si_hash_create(t, &sxhashalg_sha2_512); + si_task_consume(t, t->params.ed25519_sign.privkey->bytes, SX_ED25519_SZ); + si_task_produce(t, t->workmem, SX_ED25519_DGST_SZ); +} + +static void ed25519ph_sign_consume(struct sitask *t, const char *data, size_t sz) +{ + + t->params.ed25519_sign.msg = data; + t->params.ed25519_sign.msgsz = sz; + t->actions.consume = NULL; +} + +static void si_sig_create_ed25519ph_sign_digest(struct sitask *t, + const struct si_sig_privkey *privkey, + struct si_sig_signature *signature) +{ + if (t->workmemsz < 160) { + si_task_mark_final(t, SX_ERR_WORKMEM_BUFFER_TOO_SMALL); + return; + } + + t->params.ed25519_sign.privkey = privkey->key.ed25519; + t->params.ed25519_sign.signature = signature; + t->params.ed25519_sign.msg = NULL; + t->params.ed25519_sign.msgsz = 0; + + t->actions = (struct siactions){0}; + t->statuscode = SX_ERR_READY; + + t->actions.consume = ed25519ph_sign_consume; + t->actions.run = ed25519ph_sign_hash_privkey; +} + +static void si_sig_create_ed25519ph_sign(struct sitask *t, const struct si_sig_privkey *privkey, + struct si_sig_signature *signature) +{ + si_sig_create_ed25519ph_sign_digest(t, privkey, signature); +} + +static int ed25519ph_genpubkey_finish(struct sitask *t, struct siwq *wq) +{ + (void)wq; + + if (t->statuscode != SX_OK) { + sx_pk_release_req(t->pk); + return t->statuscode; + } + + /* Get result of the point multiplication. This is the encoding of the + * [s]B point, which is the public key. + */ + sx_async_ed25519_ptmult_end(t->pk, t->params.ed25519_pubkey.pubkey); + + return t->statuscode; +} + +static int ed25519ph_genpubkey_pointmul(struct sitask *t, struct siwq *wq) +{ + (void)wq; + + if (t->statuscode != SX_OK) { + return t->statuscode; + } + + si_wq_run_after(t, &t->params.ed25519_pubkey.wq, ed25519ph_genpubkey_finish); + + t->actions.status = si_silexpk_status; + t->actions.wait = si_silexpk_wait; + + return ed25519ph_compute_pubkey(t); +} + +static void ed25519ph_genpubkey_hash_privkey(struct sitask *t) +{ + si_wq_run_after(t, &t->params.ed25519_pubkey.wq, ed25519ph_genpubkey_pointmul); + + si_hash_create(t, &sxhashalg_sha2_512); + si_task_consume(t, t->params.ed25519_pubkey.privkey->bytes, SX_ED25519_SZ); + si_task_produce(t, t->workmem, SX_ED25519_DGST_SZ); +} + +static void si_sig_create_ed25519ph_pubkey(struct sitask *t, + const struct si_sig_privkey *privkey, struct si_sig_pubkey *pubkey) +{ + if (t->workmemsz < SX_ED25519_DGST_SZ) { + si_task_mark_final(t, SX_ERR_WORKMEM_BUFFER_TOO_SMALL); + return; + } + + t->actions = (struct siactions){0}; + t->statuscode = SX_ERR_READY; + t->actions.run = ed25519ph_genpubkey_hash_privkey; + t->params.ed25519_pubkey.privkey = privkey->key.ed25519; + t->params.ed25519_pubkey.pubkey = pubkey->key.ed25519; +} + +static unsigned short int get_ed25519ph_key_opsz(const struct si_sig_privkey *privkey) +{ + (void)privkey; + return SX_ED25519_SZ; +} + +const struct si_sig_def *const si_sig_def_ed25519ph = &(const struct si_sig_def){ + .sign = si_sig_create_ed25519ph_sign, + .sign_digest = si_sig_create_ed25519ph_sign_digest, + .verify = si_sig_create_ed25519ph_verify, + .verify_digest = si_sig_create_ed25519ph_verify_digest, + .pubkey = si_sig_create_ed25519ph_pubkey, + .getkeyopsz = get_ed25519ph_key_opsz, + .sigcomponents = 2, +};