From 5b401de7d2f385c1ec356ab41d4b35cb937ed9c2 Mon Sep 17 00:00:00 2001 From: philljj Date: Thu, 5 Oct 2023 08:45:57 -0500 Subject: [PATCH 1/4] Example for xmss hooks support. --- .gitignore | 7 + ...o-support-xmss-reference-integration.patch | 1410 +++++++++++++++++ pq/stateful_hash_sig/Makefile | 24 +- pq/stateful_hash_sig/README.md | 171 +- pq/stateful_hash_sig/lms_example.c | 2 +- pq/stateful_hash_sig/xmss_example.c | 550 +++++++ 6 files changed, 2151 insertions(+), 13 deletions(-) create mode 100644 pq/stateful_hash_sig/0001-Patch-to-support-xmss-reference-integration.patch create mode 100644 pq/stateful_hash_sig/xmss_example.c diff --git a/.gitignore b/.gitignore index 0812e858..a1182ade 100644 --- a/.gitignore +++ b/.gitignore @@ -242,6 +242,13 @@ pk/ed448/*.der pk/curve25519/curve25519_test pk/hpke/hpke_test + +# Post-Quantum Stateful Hash-Based Signatures. +pq/stateful_hash_sig/xmss_example +pq/stateful_hash_sig/xmss_example.key +pq/stateful_hash_sig/lms_example +pq/stateful_hash_sig/lms_example.key + embedded/tls-client-server embedded/tls-server-size embedded/tls-sock-client diff --git a/pq/stateful_hash_sig/0001-Patch-to-support-xmss-reference-integration.patch b/pq/stateful_hash_sig/0001-Patch-to-support-xmss-reference-integration.patch new file mode 100644 index 00000000..3d0dd217 --- /dev/null +++ b/pq/stateful_hash_sig/0001-Patch-to-support-xmss-reference-integration.patch @@ -0,0 +1,1410 @@ +From 14b855cbad45bd19ee3e9e591cc6b426f8b5c9da Mon Sep 17 00:00:00 2001 +From: jordan +Date: Thu, 5 Oct 2023 08:39:19 -0500 +Subject: [PATCH 1/1] Patch to support xmss-reference integration with + wolfCrypt and wolfBoot. + +--- + Makefile | 2 + + fips202.c | 2 +- + hash_address.c | 2 + + params.h | 15 +++ + hash.c => thash.c | 110 ++++++++++++++++++++-- + hash.h => thash.h | 0 + wots.c | 35 ++++++- + xmss.c | 53 ++++++----- + xmss.h | 36 ++++---- + xmss_commons.c | 77 ++++++++++------ + xmss_commons.h | 4 +- + xmss_core.c | 34 ++++--- + xmss_core.h | 26 +++--- + xmss_core_fast.c | 230 ++++++++++++++++++++++++++++++---------------- + 14 files changed, 443 insertions(+), 183 deletions(-) + rename hash.c => thash.c (68%) + rename hash.h => thash.h (100%) + +diff --git a/Makefile b/Makefile +index d1b95d5..435c854 100644 +--- a/Makefile ++++ b/Makefile +@@ -87,3 +87,5 @@ clean: + -$(RM) $(TESTS) + -$(RM) test/vectors + -$(RM) $(UI) ++ -$(RM) *.o ++ -$(RM) *.lo +diff --git a/fips202.c b/fips202.c +index 5e36d66..4565782 100644 +--- a/fips202.c ++++ b/fips202.c +@@ -62,7 +62,7 @@ static const uint64_t KeccakF_RoundConstants[NROUNDS] = + (uint64_t)0x8000000080008008ULL + }; + +-void KeccakF1600_StatePermute(uint64_t * state) ++static void KeccakF1600_StatePermute(uint64_t * state) + { + int round; + +diff --git a/hash_address.c b/hash_address.c +index 3a02473..5396796 100644 +--- a/hash_address.c ++++ b/hash_address.c +@@ -1,5 +1,7 @@ + #include + ++#include "hash_address.h" ++ + void set_layer_addr(uint32_t addr[8], uint32_t layer) + { + addr[0] = layer; +diff --git a/params.h b/params.h +index 58c0619..c55ebaf 100644 +--- a/params.h ++++ b/params.h +@@ -3,6 +3,21 @@ + + #include + ++/* Compile-time constants, assuming SHA256 parameter sets only. ++ * ++ * See params.c for how WOTS_SIG_BYTES and releated were calculated. ++ * ++ * These are to facilitate integration with embedded targets ++ * where variable-length arrays cannot be used (e.g. wolfBoot). ++ * */ ++#define XMSS_SHA256_N 32 ++#define XMSS_SHA256_PADDING_LEN 32 ++#define XMSS_SHA256_MSG_PREFIX_LEN (3 * XMSS_SHA256_N + XMSS_SHA256_PADDING_LEN) ++#define XMSS_SHA256_MAX_MSG_LEN 128 ++#define XMSS_SHA256_MAX_MSG_HASH_LEN (XMSS_SHA256_MSG_PREFIX_LEN + XMSS_SHA256_MAX_MSG_LEN) ++#define XMSS_SHA256_WOTS_SIG_BYTES 2144 ++#define XMSS_SHA256_WOTS_LEN 67 ++ + /* These are merely internal identifiers for the supported hash functions. */ + #define XMSS_SHA2 0 + #define XMSS_SHAKE128 1 +diff --git a/hash.c b/thash.c +similarity index 68% +rename from hash.c +rename to thash.c +index 6724d43..e8af5c4 100644 +--- a/hash.c ++++ b/thash.c +@@ -1,12 +1,14 @@ + #include ++#include + #include +-#include ++ ++#include ++#include + + #include "hash_address.h" + #include "utils.h" + #include "params.h" +-#include "hash.h" +-#include "fips202.h" ++#include "thash.h" + + #define XMSS_HASH_PADDING_F 0 + #define XMSS_HASH_PADDING_H 1 +@@ -14,6 +16,69 @@ + #define XMSS_HASH_PADDING_PRF 3 + #define XMSS_HASH_PADDING_PRF_KEYGEN 4 + ++static int sha256(const unsigned char *in, unsigned long long inlen, ++ unsigned char *out) ++{ ++ wc_Sha256 sha; ++ ++ if (wc_InitSha256_ex(&sha, NULL, INVALID_DEVID) != 0) { ++#if !defined WOLFBOOT_SIGN_XMSS ++ fprintf(stderr, "SHA256 Init failed"); ++#endif ++ return -1; ++ } ++ ++ if (wc_Sha256Update(&sha, in, (word32) inlen) != 0) { ++#if !defined WOLFBOOT_SIGN_XMSS ++ fprintf(stderr, "SHA256 Update failed"); ++#endif ++ return -1; ++ } ++ ++ if (wc_Sha256Final(&sha, out) != 0) { ++#if !defined WOLFBOOT_SIGN_XMSS ++ fprintf(stderr, "SHA256 Final failed"); ++#endif ++ wc_Sha256Free(&sha); ++ return -1; ++ } ++ wc_Sha256Free(&sha); ++ ++ return 0; ++} ++ ++static int sha512(const unsigned char *in, unsigned long long inlen, ++ unsigned char *out) ++{ ++ /* Disabling everything but sha256 for now. */ ++ (void) in; ++ (void) inlen; ++ (void) out; ++ return -1; ++} ++ ++static int shake128(unsigned char *out, unsigned long long outlen, ++ const unsigned char *in, unsigned long long inlen) ++{ ++ /* Disabling everything but sha256 for now. */ ++ (void) in; ++ (void) inlen; ++ (void) out; ++ (void) outlen; ++ return -1; ++} ++ ++static int shake256(unsigned char *out, unsigned long long outlen, ++ const unsigned char *in, unsigned long long inlen) ++{ ++ /* Disabling everything but sha256 for now. */ ++ (void) in; ++ (void) inlen; ++ (void) out; ++ (void) outlen; ++ return -1; ++} ++ + void addr_to_bytes(unsigned char *bytes, const uint32_t addr[8]) + { + int i; +@@ -27,32 +92,39 @@ static int core_hash(const xmss_params *params, + const unsigned char *in, unsigned long long inlen) + { + unsigned char buf[64]; ++ int ret = -1; ++ ++ if (params == NULL || out == NULL || in == NULL) { ++ return -1; ++ } + + if (params->n == 24 && params->func == XMSS_SHA2) { +- SHA256(in, inlen, buf); ++ ret = sha256(in, inlen, buf); + memcpy(out, buf, 24); + } + else if (params->n == 24 && params->func == XMSS_SHAKE256) { +- shake256(out, 24, in, inlen); ++ ret = shake256(out, 24, in, inlen); + } + else if (params->n == 32 && params->func == XMSS_SHA2) { +- SHA256(in, inlen, out); ++ ret = sha256(in, inlen, out); + } + else if (params->n == 32 && params->func == XMSS_SHAKE128) { +- shake128(out, 32, in, inlen); ++ ret = shake128(out, 32, in, inlen); + } + else if (params->n == 32 && params->func == XMSS_SHAKE256) { +- shake256(out, 32, in, inlen); ++ ret = shake256(out, 32, in, inlen); + } + else if (params->n == 64 && params->func == XMSS_SHA2) { +- SHA512(in, inlen, out); ++ ret = sha512(in, inlen, out); + } + else if (params->n == 64 && params->func == XMSS_SHAKE256) { +- shake256(out, 64, in, inlen); ++ ret = shake256(out, 64, in, inlen); + } + else { + return -1; + } ++ ++ if (ret != 0) { return ret; } + return 0; + } + +@@ -63,7 +135,11 @@ int prf(const xmss_params *params, + unsigned char *out, const unsigned char in[32], + const unsigned char *key) + { ++#if defined WOLFBOOT_SIGN_XMSS ++ unsigned char buf[XMSS_SHA256_PADDING_LEN + XMSS_SHA256_N + 32]; ++#else + unsigned char buf[params->padding_len + params->n + 32]; ++#endif + + ull_to_bytes(buf, params->padding_len, XMSS_HASH_PADDING_PRF); + memcpy(buf + params->padding_len, key, params->n); +@@ -80,7 +156,11 @@ int prf_keygen(const xmss_params *params, + unsigned char *out, const unsigned char *in, + const unsigned char *key) + { ++#if defined WOLFBOOT_SIGN_XMSS ++ unsigned char buf[XMSS_SHA256_PADDING_LEN + 2 * XMSS_SHA256_N + 32]; ++#else + unsigned char buf[params->padding_len + 2*params->n + 32]; ++#endif + + ull_to_bytes(buf, params->padding_len, XMSS_HASH_PADDING_PRF_KEYGEN); + memcpy(buf + params->padding_len, key, params->n); +@@ -118,8 +198,13 @@ int thash_h(const xmss_params *params, + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) + { ++#if defined WOLFBOOT_SIGN_XMSS ++ unsigned char buf[XMSS_SHA256_PADDING_LEN + 3 * XMSS_SHA256_N]; ++ unsigned char bitmask[2 * XMSS_SHA256_N]; ++#else + unsigned char buf[params->padding_len + 3 * params->n]; + unsigned char bitmask[2 * params->n]; ++#endif + unsigned char addr_as_bytes[32]; + unsigned int i; + +@@ -150,8 +235,13 @@ int thash_f(const xmss_params *params, + unsigned char *out, const unsigned char *in, + const unsigned char *pub_seed, uint32_t addr[8]) + { ++#if defined WOLFBOOT_SIGN_XMSS ++ unsigned char buf[XMSS_SHA256_PADDING_LEN + 2 * XMSS_SHA256_N]; ++ unsigned char bitmask[XMSS_SHA256_N]; ++#else + unsigned char buf[params->padding_len + 2 * params->n]; + unsigned char bitmask[params->n]; ++#endif + unsigned char addr_as_bytes[32]; + unsigned int i; + +diff --git a/hash.h b/thash.h +similarity index 100% +rename from hash.h +rename to thash.h +diff --git a/wots.c b/wots.c +index d9c8449..8acb313 100644 +--- a/wots.c ++++ b/wots.c +@@ -2,7 +2,7 @@ + #include + + #include "utils.h" +-#include "hash.h" ++#include "thash.h" + #include "wots.h" + #include "hash_address.h" + #include "params.h" +@@ -16,7 +16,11 @@ static void expand_seed(const xmss_params *params, + const unsigned char *pub_seed, uint32_t addr[8]) + { + uint32_t i; ++#if defined WOLFBOOT_SIGN_XMSS ++ unsigned char buf[XMSS_SHA256_N + 32]; ++#else + unsigned char buf[params->n + 32]; ++#endif + + set_hash_addr(addr, 0); + set_key_and_mask(addr, 0); +@@ -83,7 +87,25 @@ static void wots_checksum(const xmss_params *params, + int *csum_base_w, const int *msg_base_w) + { + int csum = 0; ++#if defined WOLFBOOT_SIGN_XMSS ++ /* See params.c ++ * ++ * For NIST SP 800-208 parm sets with SHA256, we have: ++ * ++ * params->wots_w == 16 ++ * params->wots_log_w == 4 ++ * params->wots_len2 == 3 ++ * ++ * Therefore: ++ * ++ * (params->wots_len2 * params->wots_log_w + 7) / 8 = 2 ++ * ++ * (3 * 4 + 7) / 8 = 2 ++ * */ ++ unsigned char csum_bytes[2]; ++#else + unsigned char csum_bytes[(params->wots_len2 * params->wots_log_w + 7) / 8]; ++#endif + unsigned int i; + + /* Compute checksum. */ +@@ -94,7 +116,7 @@ static void wots_checksum(const xmss_params *params, + /* Convert checksum to base_w. */ + /* Make sure expected empty zero bits are the least significant bits. */ + csum = csum << (8 - ((params->wots_len2 * params->wots_log_w) % 8)); +- ull_to_bytes(csum_bytes, sizeof(csum_bytes), csum); ++ ull_to_bytes(csum_bytes, (unsigned int) sizeof(csum_bytes), csum); + base_w(params, csum_base_w, params->wots_len2, csum_bytes); + } + +@@ -139,7 +161,12 @@ void wots_sign(const xmss_params *params, + const unsigned char *seed, const unsigned char *pub_seed, + uint32_t addr[8]) + { ++#if defined WOLFBOOT_SIGN_XMSS ++ int lengths[XMSS_SHA256_WOTS_LEN]; ++#else + int lengths[params->wots_len]; ++#endif ++ + uint32_t i; + + chain_lengths(params, lengths, msg); +@@ -163,7 +190,11 @@ void wots_pk_from_sig(const xmss_params *params, unsigned char *pk, + const unsigned char *sig, const unsigned char *msg, + const unsigned char *pub_seed, uint32_t addr[8]) + { ++#if defined WOLFBOOT_SIGN_XMSS ++ int lengths[XMSS_SHA256_WOTS_LEN]; ++#else + int lengths[params->wots_len]; ++#endif + uint32_t i; + + chain_lengths(params, lengths, msg); +diff --git a/xmss.c b/xmss.c +index 9030f6e..faaa000 100644 +--- a/xmss.c ++++ b/xmss.c +@@ -1,5 +1,6 @@ + #include + ++#include "xmss.h" + #include "params.h" + #include "xmss_core.h" + +@@ -7,7 +8,9 @@ + identify the parameter set to be used. After setting the parameters accordingly + it falls back to the regular XMSS core functions. */ + +-int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) ++#ifndef XMSS_VERIFY_ONLY ++int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid, ++ void * rng) + { + xmss_params params; + unsigned int i; +@@ -22,7 +25,8 @@ int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) + i.e. not just for interoperability, but also for internal use. */ + sk[XMSS_OID_LEN - i - 1] = (oid >> (8 * i)) & 0xFF; + } +- return xmss_core_keypair(¶ms, pk + XMSS_OID_LEN, sk + XMSS_OID_LEN); ++ return xmss_core_keypair(¶ms, pk + XMSS_OID_LEN, sk + XMSS_OID_LEN, ++ rng); + } + + int xmss_sign(unsigned char *sk, +@@ -42,24 +46,8 @@ int xmss_sign(unsigned char *sk, + return xmss_core_sign(¶ms, sk + XMSS_OID_LEN, sm, smlen, m, mlen); + } + +-int xmss_sign_open(unsigned char *m, unsigned long long *mlen, +- const unsigned char *sm, unsigned long long smlen, +- const unsigned char *pk) +-{ +- xmss_params params; +- uint32_t oid = 0; +- unsigned int i; +- +- for (i = 0; i < XMSS_OID_LEN; i++) { +- oid |= pk[XMSS_OID_LEN - i - 1] << (i * 8); +- } +- if (xmss_parse_oid(¶ms, oid)) { +- return -1; +- } +- return xmss_core_sign_open(¶ms, m, mlen, sm, smlen, pk + XMSS_OID_LEN); +-} +- +-int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) ++int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid, ++ void * rng) + { + xmss_params params; + unsigned int i; +@@ -71,7 +59,8 @@ int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) + pk[XMSS_OID_LEN - i - 1] = (oid >> (8 * i)) & 0xFF; + sk[XMSS_OID_LEN - i - 1] = (oid >> (8 * i)) & 0xFF; + } +- return xmssmt_core_keypair(¶ms, pk + XMSS_OID_LEN, sk + XMSS_OID_LEN); ++ return xmssmt_core_keypair(¶ms, pk + XMSS_OID_LEN, sk + XMSS_OID_LEN, ++ rng); + } + + int xmssmt_sign(unsigned char *sk, +@@ -90,8 +79,26 @@ int xmssmt_sign(unsigned char *sk, + } + return xmssmt_core_sign(¶ms, sk + XMSS_OID_LEN, sm, smlen, m, mlen); + } ++#endif /* ifndef XMSS_VERIFY_ONLY */ ++ ++int xmss_sign_open(const unsigned char *msg, unsigned long long *msglen, ++ const unsigned char *sm, unsigned long long smlen, ++ const unsigned char *pk) ++{ ++ xmss_params params; ++ uint32_t oid = 0; ++ unsigned int i; ++ ++ for (i = 0; i < XMSS_OID_LEN; i++) { ++ oid |= pk[XMSS_OID_LEN - i - 1] << (i * 8); ++ } ++ if (xmss_parse_oid(¶ms, oid)) { ++ return -1; ++ } ++ return xmss_core_sign_open(¶ms, msg, msglen, sm, smlen, pk + XMSS_OID_LEN); ++} + +-int xmssmt_sign_open(unsigned char *m, unsigned long long *mlen, ++int xmssmt_sign_open(const unsigned char *msg, unsigned long long *msglen, + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk) + { +@@ -105,5 +112,5 @@ int xmssmt_sign_open(unsigned char *m, unsigned long long *mlen, + if (xmssmt_parse_oid(¶ms, oid)) { + return -1; + } +- return xmssmt_core_sign_open(¶ms, m, mlen, sm, smlen, pk + XMSS_OID_LEN); ++ return xmssmt_core_sign_open(¶ms, msg, msglen, sm, smlen, pk + XMSS_OID_LEN); + } +diff --git a/xmss.h b/xmss.h +index c7b4b69..8f4bab4 100644 +--- a/xmss.h ++++ b/xmss.h +@@ -3,50 +3,54 @@ + + #include + ++#ifndef XMSS_VERIFY_ONLY + /** + * Generates a XMSS key pair for a given parameter set. + * Format sk: [OID || (32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] + * Format pk: [OID || root || PUB_SEED] + */ +-int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid); ++int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid, ++ void * rng); + + /** + * Signs a message using an XMSS secret key. + * Returns +- * 1. an array containing the signature followed by the message AND ++ * 1. an array containing the signature AND + * 2. an updated secret key! + */ + int xmss_sign(unsigned char *sk, + unsigned char *sm, unsigned long long *smlen, + const unsigned char *m, unsigned long long mlen); + +-/** +- * Verifies a given message signature pair using a given public key. +- * +- * Note: m and mlen are pure outputs which carry the message in case +- * verification succeeds. The (input) message is assumed to be contained in sm +- * which has the form [signature || message]. +- */ +-int xmss_sign_open(unsigned char *m, unsigned long long *mlen, +- const unsigned char *sm, unsigned long long smlen, +- const unsigned char *pk); +- + /* + * Generates a XMSSMT key pair for a given parameter set. + * Format sk: [OID || (ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] + * Format pk: [OID || root || PUB_SEED] + */ +-int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid); ++int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid, ++ void * rng); + + /** + * Signs a message using an XMSSMT secret key. + * Returns +- * 1. an array containing the signature followed by the message AND ++ * 1. an array containing the signature AND + * 2. an updated secret key! + */ + int xmssmt_sign(unsigned char *sk, + unsigned char *sm, unsigned long long *smlen, + const unsigned char *m, unsigned long long mlen); ++#endif /* ifndef XMSS_VERIFY_ONLY */ ++ ++/** ++ * Verifies a given message signature pair using a given public key. ++ * ++ * Note: m and mlen are pure outputs which carry the message in case ++ * verification succeeds. The (input) message is assumed to be contained in sm ++ * which has the form [signature || message]. ++ */ ++int xmss_sign_open(const unsigned char *msg, unsigned long long *msglen, ++ const unsigned char *sm, unsigned long long smlen, ++ const unsigned char *pk); + + /** + * Verifies a given message signature pair using a given public key. +@@ -55,7 +59,7 @@ int xmssmt_sign(unsigned char *sk, + * verification succeeds. The (input) message is assumed to be contained in sm + * which has the form [signature || message]. + */ +-int xmssmt_sign_open(unsigned char *m, unsigned long long *mlen, ++int xmssmt_sign_open(const unsigned char *msg, unsigned long long *msglen, + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk); + #endif +diff --git a/xmss_commons.c b/xmss_commons.c +index 2b76b94..0599a76 100644 +--- a/xmss_commons.c ++++ b/xmss_commons.c +@@ -2,7 +2,7 @@ + #include + #include + +-#include "hash.h" ++#include "thash.h" + #include "hash_address.h" + #include "params.h" + #include "wots.h" +@@ -57,7 +57,11 @@ static void compute_root(const xmss_params *params, unsigned char *root, + const unsigned char *pub_seed, uint32_t addr[8]) + { + uint32_t i; ++#if defined WOLFBOOT_SIGN_XMSS ++ unsigned char buffer[2 * XMSS_SHA256_N]; ++#else + unsigned char buffer[2*params->n]; ++#endif + + /* If leafidx is odd (last bit = 1), current path element is a right child + and auth_path has to go left. Otherwise it is the other way around. */ +@@ -74,7 +78,7 @@ static void compute_root(const xmss_params *params, unsigned char *root, + for (i = 0; i < params->tree_height - 1; i++) { + set_tree_height(addr, i); + leafidx >>= 1; +- set_tree_index(addr, leafidx); ++ set_tree_index(addr, (uint32_t) leafidx); + + /* Pick the right or left neighbor, depending on parity of the node. */ + if (leafidx & 1) { +@@ -91,7 +95,7 @@ static void compute_root(const xmss_params *params, unsigned char *root, + /* The last iteration is exceptional; we do not copy an auth_path node. */ + set_tree_height(addr, params->tree_height - 1); + leafidx >>= 1; +- set_tree_index(addr, leafidx); ++ set_tree_index(addr, (uint32_t) leafidx); + thash_h(params, root, buffer, pub_seed, addr); + } + +@@ -105,7 +109,11 @@ void gen_leaf_wots(const xmss_params *params, unsigned char *leaf, + const unsigned char *sk_seed, const unsigned char *pub_seed, + uint32_t ltree_addr[8], uint32_t ots_addr[8]) + { ++#if defined WOLFBOOT_SIGN_XMSS ++ unsigned char pk[XMSS_SHA256_WOTS_SIG_BYTES]; ++#else + unsigned char pk[params->wots_sig_bytes]; ++#endif + + wots_pkgen(params, pk, sk_seed, pub_seed, ots_addr); + +@@ -118,31 +126,43 @@ void gen_leaf_wots(const xmss_params *params, unsigned char *leaf, + * Note that this assumes a pk without an OID, i.e. [root || PUB_SEED] + */ + int xmss_core_sign_open(const xmss_params *params, +- unsigned char *m, unsigned long long *mlen, +- const unsigned char *sm, unsigned long long smlen, ++ const unsigned char *msg, unsigned long long *msglen, ++ const unsigned char *sig, unsigned long long siglen, + const unsigned char *pk) + { + /* XMSS signatures are fundamentally an instance of XMSSMT signatures. + For d=1, as is the case with XMSS, some of the calls in the XMSSMT + routine become vacuous (i.e. the loop only iterates once, and address + management can be simplified a bit).*/ +- return xmssmt_core_sign_open(params, m, mlen, sm, smlen, pk); ++ return xmssmt_core_sign_open(params, msg, msglen, sig, siglen, pk); + } + + /** + * Verifies a given message signature pair under a given public key. + * Note that this assumes a pk without an OID, i.e. [root || PUB_SEED] ++ * ++ * Note: in WOLFBOOT_SIGN_XMSS build, the max allowed message length (msglen) ++ * is XMSS_SHA256_MAX_MSG_LEN. This is to facilitate having a manageable small ++ * static array, rather than a variable length array, for the message hash. + */ + int xmssmt_core_sign_open(const xmss_params *params, +- unsigned char *m, unsigned long long *mlen, +- const unsigned char *sm, unsigned long long smlen, ++ const unsigned char *msg, unsigned long long *msglen, ++ const unsigned char *sig, unsigned long long siglen, + const unsigned char *pk) + { + const unsigned char *pub_root = pk; + const unsigned char *pub_seed = pk + params->n; ++#if defined WOLFBOOT_SIGN_XMSS ++ unsigned char m_with_prefix[XMSS_SHA256_MAX_MSG_HASH_LEN]; ++ unsigned char wots_pk[XMSS_SHA256_WOTS_SIG_BYTES]; ++ unsigned char leaf[XMSS_SHA256_N]; ++ unsigned char root[XMSS_SHA256_N]; ++#else ++ unsigned char m_with_prefix[*msglen + params->padding_len + 3*params->n]; + unsigned char wots_pk[params->wots_sig_bytes]; + unsigned char leaf[params->n]; + unsigned char root[params->n]; ++#endif + unsigned char *mhash = root; + unsigned long long idx = 0; + unsigned int i; +@@ -152,24 +172,33 @@ int xmssmt_core_sign_open(const xmss_params *params, + uint32_t ltree_addr[8] = {0}; + uint32_t node_addr[8] = {0}; + ++#if defined WOLFBOOT_SIGN_XMSS ++ if (*msglen > XMSS_SHA256_MAX_MSG_LEN) { ++ return -1; ++ } ++#endif ++ ++ if (siglen != params->sig_bytes) { ++ /* Some inconsistency has happened. */ ++ return -1; ++ } ++ + set_type(ots_addr, XMSS_ADDR_TYPE_OTS); + set_type(ltree_addr, XMSS_ADDR_TYPE_LTREE); + set_type(node_addr, XMSS_ADDR_TYPE_HASHTREE); + +- *mlen = smlen - params->sig_bytes; +- + /* Convert the index bytes from the signature to an integer. */ +- idx = bytes_to_ull(sm, params->index_bytes); ++ idx = bytes_to_ull(sig, params->index_bytes); + + /* Put the message all the way at the end of the m buffer, so that we can + * prepend the required other inputs for the hash function. */ +- memcpy(m + params->sig_bytes, sm + params->sig_bytes, *mlen); ++ memset(m_with_prefix, 0, sizeof(m_with_prefix)); ++ memcpy(m_with_prefix + params->padding_len + 3*params->n, msg, *msglen); + + /* Compute the message hash. */ +- hash_message(params, mhash, sm + params->index_bytes, pk, idx, +- m + params->sig_bytes - params->padding_len - 3*params->n, +- *mlen); +- sm += params->index_bytes + params->n; ++ hash_message(params, mhash, sig + params->index_bytes, pk, idx, ++ m_with_prefix, *msglen); ++ sig += params->index_bytes + params->n; + + /* For each subtree.. */ + for (i = 0; i < params->d; i++) { +@@ -188,28 +217,24 @@ int xmssmt_core_sign_open(const xmss_params *params, + set_ots_addr(ots_addr, idx_leaf); + /* Initially, root = mhash, but on subsequent iterations it is the root + of the subtree below the currently processed subtree. */ +- wots_pk_from_sig(params, wots_pk, sm, root, pub_seed, ots_addr); +- sm += params->wots_sig_bytes; ++ wots_pk_from_sig(params, wots_pk, sig, root, pub_seed, ots_addr); ++ sig += params->wots_sig_bytes; + + /* Compute the leaf node using the WOTS public key. */ + set_ltree_addr(ltree_addr, idx_leaf); + l_tree(params, leaf, wots_pk, pub_seed, ltree_addr); + + /* Compute the root node of this subtree. */ +- compute_root(params, root, leaf, idx_leaf, sm, pub_seed, node_addr); +- sm += params->tree_height*params->n; ++ compute_root(params, root, leaf, idx_leaf, sig, pub_seed, node_addr); ++ sig += params->tree_height*params->n; + } + + /* Check if the root node equals the root node in the public key. */ + if (memcmp(root, pub_root, params->n)) { +- /* If not, zero the message */ +- memset(m, 0, *mlen); +- *mlen = 0; ++ /* If not, set message length to zero */ ++ *msglen = 0; + return -1; + } + +- /* If verification was successful, copy the message from the signature. */ +- memcpy(m, sm, *mlen); +- + return 0; + } +diff --git a/xmss_commons.h b/xmss_commons.h +index 9d9f077..33dbffe 100644 +--- a/xmss_commons.h ++++ b/xmss_commons.h +@@ -18,7 +18,7 @@ void gen_leaf_wots(const xmss_params *params, unsigned char *leaf, + * Note that this assumes a pk without an OID, i.e. [root || PUB_SEED] + */ + int xmss_core_sign_open(const xmss_params *params, +- unsigned char *m, unsigned long long *mlen, ++ const unsigned char *msg, unsigned long long *msglen, + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk); + +@@ -27,7 +27,7 @@ int xmss_core_sign_open(const xmss_params *params, + * Note that this assumes a pk without an OID, i.e. [root || PUB_SEED] + */ + int xmssmt_core_sign_open(const xmss_params *params, +- unsigned char *m, unsigned long long *mlen, ++ const unsigned char *msg, unsigned long long *msglen, + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk); + #endif +diff --git a/xmss_core.c b/xmss_core.c +index af9f8d1..6d3b2f1 100644 +--- a/xmss_core.c ++++ b/xmss_core.c +@@ -2,15 +2,19 @@ + #include + #include + +-#include "hash.h" ++#include "thash.h" + #include "hash_address.h" + #include "params.h" +-#include "randombytes.h" + #include "wots.h" + #include "utils.h" + #include "xmss_commons.h" + #include "xmss_core.h" + ++#include ++#include ++#include ++#include ++ + /** + * For a given leaf index, computes the authentication path and the resulting + * root node using Merkle's TreeHash algorithm. +@@ -101,28 +105,28 @@ unsigned long long xmss_xmssmt_core_sk_bytes(const xmss_params *params) + * Format pk: [root || PUB_SEED], omitting algorithm OID. + */ + int xmss_core_keypair(const xmss_params *params, +- unsigned char *pk, unsigned char *sk) ++ unsigned char *pk, unsigned char *sk, void * rng) + { + /* The key generation procedure of XMSS and XMSSMT is exactly the same. + The only important detail is that the right subtree must be selected; + this requires us to correctly set the d=1 parameter for XMSS. */ +- return xmssmt_core_keypair(params, pk, sk); ++ return xmssmt_core_keypair(params, pk, sk, rng); + } + + /** +- * Signs a message. Returns an array containing the signature followed by the +- * message and an updated secret key. ++ * Signs a message. Returns an array containing the signature, ++ * and an updated secret key. + */ + int xmss_core_sign(const xmss_params *params, + unsigned char *sk, +- unsigned char *sm, unsigned long long *smlen, +- const unsigned char *m, unsigned long long mlen) ++ unsigned char *sig, unsigned long long *siglen, ++ const unsigned char *msg, unsigned long long msglen) + { + /* XMSS signatures are fundamentally an instance of XMSSMT signatures. + For d=1, as is the case with XMSS, some of the calls in the XMSSMT + routine become vacuous (i.e. the loop only iterates once, and address + management can be simplified a bit).*/ +- return xmssmt_core_sign(params, sk, sm, smlen, m, mlen); ++ return xmssmt_core_sign(params, sk, sig, siglen, msg, msglen); + } + + /* +@@ -166,11 +170,19 @@ int xmssmt_core_seed_keypair(const xmss_params *params, + * Format pk: [root || PUB_SEED] omitting algorithm OID. + */ + int xmssmt_core_keypair(const xmss_params *params, +- unsigned char *pk, unsigned char *sk) ++ unsigned char *pk, unsigned char *sk, ++ void * rng) + { + unsigned char seed[3 * params->n]; ++ int ret = 0; ++ ++ ret = wc_RNG_GenerateBlock(rng, seed, (word32) sizeof(seed)); ++ ++ if (ret != 0) { ++ fprintf(stderr, "error: wc_RNG_GenerateBlock failed: %d\n", ret); ++ return -1; ++ } + +- randombytes(seed, 3 * params->n); + xmssmt_core_seed_keypair(params, pk, sk, seed); + + return 0; +diff --git a/xmss_core.h b/xmss_core.h +index e83bc7d..bc1d0c2 100644 +--- a/xmss_core.h ++++ b/xmss_core.h +@@ -12,13 +12,14 @@ + */ + unsigned long long xmss_xmssmt_core_sk_bytes(const xmss_params *params); + ++#ifndef XMSS_VERIFY_ONLY + /* + * Generates a XMSS key pair for a given parameter set. + * Format sk: [(32bit) index || SK_SEED || SK_PRF || PUB_SEED || root] + * Format pk: [root || PUB_SEED], omitting algorithm OID. + */ + int xmss_core_keypair(const xmss_params *params, +- unsigned char *pk, unsigned char *sk); ++ unsigned char *pk, unsigned char *sk, void * rng); + + /** + * Signs a message. Returns an array containing the signature followed by the +@@ -29,22 +30,13 @@ int xmss_core_sign(const xmss_params *params, + unsigned char *sm, unsigned long long *smlen, + const unsigned char *m, unsigned long long mlen); + +-/** +- * Verifies a given message signature pair under a given public key. +- * Note that this assumes a pk without an OID, i.e. [root || PUB_SEED] +- */ +-int xmss_core_sign_open(const xmss_params *params, +- unsigned char *m, unsigned long long *mlen, +- const unsigned char *sm, unsigned long long smlen, +- const unsigned char *pk); +- + /* + * Generates a XMSSMT key pair for a given parameter set. + * Format sk: [(ceil(h/8) bit) index || SK_SEED || SK_PRF || PUB_SEED || root] + * Format pk: [root || PUB_SEED] omitting algorithm OID. + */ + int xmssmt_core_keypair(const xmss_params *params, +- unsigned char *pk, unsigned char *sk); ++ unsigned char *pk, unsigned char *sk, void * rng); + + /* + * Derives a XMSSMT key pair for a given parameter set. +@@ -64,13 +56,23 @@ int xmssmt_core_sign(const xmss_params *params, + unsigned char *sk, + unsigned char *sm, unsigned long long *smlen, + const unsigned char *m, unsigned long long mlen); ++#endif /* ifndef XMSS_VERIFY_ONLY */ ++ ++/** ++ * Verifies a given message signature pair under a given public key. ++ * Note that this assumes a pk without an OID, i.e. [root || PUB_SEED] ++ */ ++int xmss_core_sign_open(const xmss_params *params, ++ const unsigned char *msg, unsigned long long *msglen, ++ const unsigned char *sm, unsigned long long smlen, ++ const unsigned char *pk); + + /** + * Verifies a given message signature pair under a given public key. + * Note that this assumes a pk without an OID, i.e. [root || PUB_SEED] + */ + int xmssmt_core_sign_open(const xmss_params *params, +- unsigned char *m, unsigned long long *mlen, ++ const unsigned char *msg, unsigned long long *msglen, + const unsigned char *sm, unsigned long long smlen, + const unsigned char *pk); + +diff --git a/xmss_core_fast.c b/xmss_core_fast.c +index cbf87ec..7d75a22 100644 +--- a/xmss_core_fast.c ++++ b/xmss_core_fast.c +@@ -2,15 +2,21 @@ + #include + #include + +-#include "hash.h" ++#include "thash.h" + #include "hash_address.h" + #include "params.h" +-#include "randombytes.h" + #include "wots.h" + #include "utils.h" + #include "xmss_commons.h" + #include "xmss_core.h" + ++#include ++#include ++#include ++#include ++ ++#ifndef XMSS_VERIFY_ONLY ++ + typedef struct{ + unsigned char h; + unsigned long next_idx; +@@ -94,7 +100,7 @@ static void xmssmt_deserialize_state(const xmss_params *params, + states[i].stack = sk; + sk += (params->tree_height + 1) * params->n; + +- states[i].stackoffset = bytes_to_ull(sk, 4); ++ states[i].stackoffset = (unsigned int) bytes_to_ull(sk, 4); + sk += 4; + + states[i].stacklevels = sk; +@@ -126,7 +132,7 @@ static void xmssmt_deserialize_state(const xmss_params *params, + states[i].retain = sk; + sk += ((1 << params->bds_k) - params->bds_k - 1) * params->n; + +- states[i].next_leaf = bytes_to_ull(sk, 4); ++ states[i].next_leaf = (unsigned int) bytes_to_ull(sk, 4); + sk += 4; + } + +@@ -299,8 +305,8 @@ static void treehash_update(const xmss_params *params, + copy_subtree_addr(node_addr, addr); + set_type(node_addr, 2); + +- set_ltree_addr(ltree_addr, treehash->next_idx); +- set_ots_addr(ots_addr, treehash->next_idx); ++ set_ltree_addr(ltree_addr, (uint32_t) treehash->next_idx); ++ set_ots_addr(ots_addr, (uint32_t) treehash->next_idx); + + unsigned char nodebuffer[2 * params->n]; + unsigned int nodeheight = 0; +@@ -309,7 +315,7 @@ static void treehash_update(const xmss_params *params, + memcpy(nodebuffer + params->n, nodebuffer, params->n); + memcpy(nodebuffer, state->stack + (state->stackoffset-1)*params->n, params->n); + set_tree_height(node_addr, nodeheight); +- set_tree_index(node_addr, (treehash->next_idx >> (nodeheight+1))); ++ set_tree_index(node_addr, (uint32_t) (treehash->next_idx >> (nodeheight+1))); + thash_h(params, nodebuffer, nodebuffer, pub_seed, node_addr); + nodeheight++; + treehash->stackusage--; +@@ -476,13 +482,13 @@ static void bds_round(const xmss_params *params, + memcpy(state->keep + (tau >> 1)*params->n, state->auth + tau*params->n, params->n); + } + if (tau == 0) { +- set_ltree_addr(ltree_addr, leaf_idx); +- set_ots_addr(ots_addr, leaf_idx); ++ set_ltree_addr(ltree_addr, (uint32_t) leaf_idx); ++ set_ots_addr(ots_addr, (uint32_t) leaf_idx); + gen_leaf_wots(params, state->auth, sk_seed, pub_seed, ltree_addr, ots_addr); + } + else { + set_tree_height(node_addr, (tau-1)); +- set_tree_index(node_addr, leaf_idx >> tau); ++ set_tree_index(node_addr, (uint32_t) leaf_idx >> tau); + thash_h(params, state->auth + tau * params->n, buf, pub_seed, node_addr); + for (i = 0; i < tau; i++) { + if (i < params->tree_height - params->bds_k) { +@@ -490,13 +496,13 @@ static void bds_round(const xmss_params *params, + } + else { + offset = (1 << (params->tree_height - 1 - i)) + i - params->tree_height; +- rowidx = ((leaf_idx >> i) - 1) >> 1; ++ rowidx = (unsigned int) ((leaf_idx >> i) - 1) >> 1; + memcpy(state->auth + i * params->n, state->retain + (offset + rowidx) * params->n, params->n); + } + } + + for (i = 0; i < ((tau < params->tree_height - params->bds_k) ? tau : (params->tree_height - params->bds_k)); i++) { +- startidx = leaf_idx + 1 + 3 * (1 << i); ++ startidx = (unsigned int) leaf_idx + 1 + 3 * (1 << i); + if (startidx < 1U << params->tree_height) { + state->treehash[i].h = i; + state->treehash[i].next_idx = startidx; +@@ -507,6 +513,8 @@ static void bds_round(const xmss_params *params, + } + } + ++#endif /* ifndef XMSS_VERIFY_ONLY */ ++ + /** + * Given a set of parameters, this function returns the size of the secret key. + * This is implementation specific, as varying choices in tree traversal will +@@ -530,15 +538,18 @@ unsigned long long xmss_xmssmt_core_sk_bytes(const xmss_params *params) + + (params->d - 1) * params->wots_sig_bytes; + } + ++#ifndef XMSS_VERIFY_ONLY + /* + * Generates a XMSS key pair for a given parameter set. + * Format sk: [(32bit) idx || SK_SEED || SK_PRF || root || PUB_SEED] + * Format pk: [root || PUB_SEED] omitting algo oid. + */ + int xmss_core_keypair(const xmss_params *params, +- unsigned char *pk, unsigned char *sk) ++ unsigned char *pk, unsigned char *sk, ++ void * rng) + { + uint32_t addr[8] = {0}; ++ int ret = 0; + + // TODO refactor BDS state not to need separate treehash instances + bds_state state; +@@ -555,16 +566,27 @@ int xmss_core_keypair(const xmss_params *params, + sk[1] = 0; + sk[2] = 0; + sk[3] = 0; ++ + // Init SK_SEED (n byte) and SK_PRF (n byte) +- randombytes(sk + params->index_bytes, 2*params->n); ++ ret = wc_RNG_GenerateBlock(rng, sk + params->index_bytes, ++ (word32) 2*params->n); ++ ++ if (ret != 0) { return -1; } + + // Init PUB_SEED (n byte) +- randombytes(sk + params->index_bytes + 3*params->n, params->n); ++ ret = wc_RNG_GenerateBlock(rng, sk + params->index_bytes + 3*params->n, ++ (word32) params->n); ++ ++ if (ret != 0) { return -1; } ++ + // Copy PUB_SEED to public key + memcpy(pk + params->n, sk + params->index_bytes + 3*params->n, params->n); + + // Compute root +- treehash_init(params, pk, params->tree_height, 0, &state, sk + params->index_bytes, sk + params->index_bytes + 3*params->n, addr); ++ treehash_init(params, pk, params->tree_height, 0, &state, ++ sk + params->index_bytes, ++ sk + params->index_bytes + 3*params->n, addr); ++ + // copy root to sk + memcpy(sk + params->index_bytes + 2*params->n, pk, params->n); + +@@ -577,19 +599,39 @@ int xmss_core_keypair(const xmss_params *params, + /** + * Signs a message. + * Returns +- * 1. an array containing the signature followed by the message AND ++ * 1. an array containing the signature AND + * 2. an updated secret key! + * ++ * Note: in WOLFBOOT_SIGN_XMSS build, the max allowed message length (msglen) ++ * is XMSS_SHA256_MAX_MSG_LEN. This is to facilitate having a manageable small ++ * static array, rather than a variable length array, for the message hash. + */ + int xmss_core_sign(const xmss_params *params, + unsigned char *sk, +- unsigned char *sm, unsigned long long *smlen, +- const unsigned char *m, unsigned long long mlen) ++ unsigned char *sig, unsigned long long *siglen, ++ const unsigned char *msg, unsigned long long msglen) + { + const unsigned char *pub_root = sk + params->index_bytes + 2*params->n; + ++#if defined WOLFBOOT_SIGN_XMSS ++ unsigned char m_with_prefix[XMSS_SHA256_MAX_MSG_HASH_LEN]; ++#else ++ unsigned char m_with_prefix[msglen + params->padding_len + 3*params->n]; ++#endif ++ + uint16_t i = 0; + ++#if defined WOLFBOOT_SIGN_XMSS ++ if (msglen > XMSS_SHA256_MAX_MSG_LEN) { ++ return -1; ++ } ++#endif ++ ++ if (*siglen != params->sig_bytes) { ++ /* Some inconsistency has happened. */ ++ return -1; ++ } ++ + // TODO refactor BDS state not to need separate treehash instances + bds_state state; + treehash_inst treehash[params->tree_height - params->bds_k]; +@@ -599,7 +641,9 @@ int xmss_core_sign(const xmss_params *params, + xmss_deserialize_state(params, &state, sk); + + // Extract SK +- unsigned long idx = ((unsigned long)sk[0] << 24) | ((unsigned long)sk[1] << 16) | ((unsigned long)sk[2] << 8) | sk[3]; ++ unsigned long idx = ((unsigned long)sk[0] << 24) | ++ ((unsigned long)sk[1] << 16) | ++ ((unsigned long)sk[2] << 8) | sk[3]; + + /* Check if we can still sign with this sk. + * If not, return -2 +@@ -658,32 +702,32 @@ int xmss_core_sign(const xmss_params *params, + + /* Already put the message in the right place, to make it easier to prepend + * things when computing the hash over the message. */ +- memcpy(sm + params->sig_bytes, m, mlen); ++ memset(m_with_prefix, 0, sizeof(m_with_prefix)); ++ memcpy(m_with_prefix + params->padding_len + 3*params->n, msg, msglen); + + /* Compute the message hash. */ + hash_message(params, msg_h, R, pub_root, idx, +- sm + params->sig_bytes - params->padding_len - 3*params->n, +- mlen); ++ m_with_prefix, msglen); + + // Start collecting signature +- *smlen = 0; ++ *siglen = 0; + + // Copy index to signature +- sm[0] = (idx >> 24) & 255; +- sm[1] = (idx >> 16) & 255; +- sm[2] = (idx >> 8) & 255; +- sm[3] = idx & 255; ++ sig[0] = (idx >> 24) & 255; ++ sig[1] = (idx >> 16) & 255; ++ sig[2] = (idx >> 8) & 255; ++ sig[3] = idx & 255; + +- sm += 4; +- *smlen += 4; ++ sig += 4; ++ *siglen += 4; + + // Copy R to signature + for (i = 0; i < params->n; i++) { +- sm[i] = R[i]; ++ sig[i] = R[i]; + } + +- sm += params->n; +- *smlen += params->n; ++ sig += params->n; ++ *siglen += params->n; + + // ---------------------------------- + // Now we start to "really sign" +@@ -691,27 +735,24 @@ int xmss_core_sign(const xmss_params *params, + + // Prepare Address + set_type(ots_addr, 0); +- set_ots_addr(ots_addr, idx); ++ set_ots_addr(ots_addr, (uint32_t) idx); + + // Compute WOTS signature +- wots_sign(params, sm, msg_h, sk_seed, pub_seed, ots_addr); ++ wots_sign(params, sig, msg_h, sk_seed, pub_seed, ots_addr); + +- sm += params->wots_sig_bytes; +- *smlen += params->wots_sig_bytes; ++ sig += params->wots_sig_bytes; ++ *siglen += params->wots_sig_bytes; + + // the auth path was already computed during the previous round +- memcpy(sm, state.auth, params->tree_height*params->n); ++ memcpy(sig, state.auth, params->tree_height*params->n); + + if (idx < (1U << params->tree_height) - 1) { + bds_round(params, &state, idx, sk_seed, pub_seed, ots_addr); + bds_treehash_update(params, &state, (params->tree_height - params->bds_k) >> 1, sk_seed, pub_seed, ots_addr); + } + +- sm += params->tree_height*params->n; +- *smlen += params->tree_height*params->n; +- +- memcpy(sm, m, mlen); +- *smlen += mlen; ++ sig += params->tree_height*params->n; ++ *siglen += params->tree_height*params->n; + + /* Write the updated BDS state back into sk. */ + xmss_serialize_state(params, sk, &state); +@@ -725,11 +766,12 @@ int xmss_core_sign(const xmss_params *params, + * Format pk: [root || PUB_SEED] omitting algo oid. + */ + int xmssmt_core_keypair(const xmss_params *params, +- unsigned char *pk, unsigned char *sk) ++ unsigned char *pk, unsigned char *sk, void * rng) + { +- uint32_t addr[8] = {0}; +- unsigned int i; +- unsigned char *wots_sigs; ++ uint32_t addr[8] = {0}; ++ unsigned int i; ++ unsigned char * wots_sigs; ++ int ret = 0; + + // TODO refactor BDS state not to need separate treehash instances + bds_state states[2*params->d - 1]; +@@ -750,10 +792,17 @@ int xmssmt_core_keypair(const xmss_params *params, + sk[i] = 0; + } + // Init SK_SEED (params->n byte) and SK_PRF (params->n byte) +- randombytes(sk+params->index_bytes, 2*params->n); ++ ret = wc_RNG_GenerateBlock(rng, sk+params->index_bytes, ++ (word32) 2*params->n); ++ ++ if (ret != 0) { return -1; } + + // Init PUB_SEED (params->n byte) +- randombytes(sk+params->index_bytes + 3*params->n, params->n); ++ ret = wc_RNG_GenerateBlock(rng, sk+params->index_bytes + 3*params->n, ++ (word32) params->n); ++ ++ if (ret != 0) { return -1; } ++ + // Copy PUB_SEED to public key + memcpy(pk+params->n, sk+params->index_bytes+3*params->n, params->n); + +@@ -778,17 +827,37 @@ int xmssmt_core_keypair(const xmss_params *params, + /** + * Signs a message. + * Returns +- * 1. an array containing the signature followed by the message AND ++ * 1. an array containing the signature AND + * 2. an updated secret key! + * ++ * Note: in WOLFBOOT_SIGN_XMSS build, the max allowed message length (msglen) ++ * is XMSS_SHA256_MAX_MSG_LEN. This is to facilitate having a manageable small ++ * static array, rather than a variable length array, for the message hash. + */ + int xmssmt_core_sign(const xmss_params *params, + unsigned char *sk, +- unsigned char *sm, unsigned long long *smlen, +- const unsigned char *m, unsigned long long mlen) ++ unsigned char *sig, unsigned long long *siglen, ++ const unsigned char *msg, unsigned long long msglen) + { + const unsigned char *pub_root = sk + params->index_bytes + 2*params->n; + ++#if defined WOLFBOOT_SIGN_XMSS ++ unsigned char m_with_prefix[XMSS_SHA256_MAX_MSG_HASH_LEN]; ++#else ++ unsigned char m_with_prefix[msglen + params->padding_len + 3*params->n]; ++#endif ++ ++#if defined WOLFBOOT_SIGN_XMSS ++ if (msglen > XMSS_SHA256_MAX_MSG_LEN) { ++ return -1; ++ } ++#endif ++ ++ if (*siglen != params->sig_bytes) { ++ /* Some inconsistency has happened. */ ++ return -1; ++ } ++ + uint64_t idx_tree; + uint32_t idx_leaf; + uint64_t i, j; +@@ -867,31 +936,34 @@ int xmssmt_core_sign(const xmss_params *params, + + /* Already put the message in the right place, to make it easier to prepend + * things when computing the hash over the message. */ +- memcpy(sm + params->sig_bytes, m, mlen); ++ memset(m_with_prefix, 0, sizeof(m_with_prefix)); ++ memcpy(m_with_prefix + params->padding_len + 3*params->n, msg, msglen); ++ + + /* Compute the message hash. */ + hash_message(params, msg_h, R, pub_root, idx, +- sm + params->sig_bytes - params->padding_len - 3*params->n, +- mlen); ++ m_with_prefix, ++ /* sig + params->sig_bytes - params->padding_len - 3*params->n, */ ++ msglen); + + // Start collecting signature +- *smlen = 0; ++ *siglen = 0; + + // Copy index to signature + for (i = 0; i < params->index_bytes; i++) { +- sm[i] = (idx >> 8*(params->index_bytes - 1 - i)) & 255; ++ sig[i] = (idx >> 8*(params->index_bytes - 1 - i)) & 255; + } + +- sm += params->index_bytes; +- *smlen += params->index_bytes; ++ sig += params->index_bytes; ++ *siglen += params->index_bytes; + + // Copy R to signature + for (i = 0; i < params->n; i++) { +- sm[i] = R[i]; ++ sig[i] = R[i]; + } + +- sm += params->n; +- *smlen += params->n; ++ sig += params->n; ++ *siglen += params->n; + + // ---------------------------------- + // Now we start to "really sign" +@@ -908,27 +980,27 @@ int xmssmt_core_sign(const xmss_params *params, + set_ots_addr(ots_addr, idx_leaf); + + // Compute WOTS signature +- wots_sign(params, sm, msg_h, sk_seed, pub_seed, ots_addr); ++ wots_sign(params, sig, msg_h, sk_seed, pub_seed, ots_addr); + +- sm += params->wots_sig_bytes; +- *smlen += params->wots_sig_bytes; ++ sig += params->wots_sig_bytes; ++ *siglen += params->wots_sig_bytes; + +- memcpy(sm, states[0].auth, params->tree_height*params->n); +- sm += params->tree_height*params->n; +- *smlen += params->tree_height*params->n; ++ memcpy(sig, states[0].auth, params->tree_height*params->n); ++ sig += params->tree_height*params->n; ++ *siglen += params->tree_height*params->n; + + // prepare signature of remaining layers + for (i = 1; i < params->d; i++) { + // put WOTS signature in place +- memcpy(sm, wots_sigs + (i-1)*params->wots_sig_bytes, params->wots_sig_bytes); ++ memcpy(sig, wots_sigs + (i-1)*params->wots_sig_bytes, params->wots_sig_bytes); + +- sm += params->wots_sig_bytes; +- *smlen += params->wots_sig_bytes; ++ sig += params->wots_sig_bytes; ++ *siglen += params->wots_sig_bytes; + + // put AUTH nodes in place +- memcpy(sm, states[i].auth, params->tree_height*params->n); +- sm += params->tree_height*params->n; +- *smlen += params->tree_height*params->n; ++ memcpy(sig, states[i].auth, params->tree_height*params->n); ++ sig += params->tree_height*params->n; ++ *siglen += params->tree_height*params->n; + } + + updates = (params->tree_height - params->bds_k) >> 1; +@@ -944,7 +1016,7 @@ int xmssmt_core_sign(const xmss_params *params, + if (! (((idx + 1) & ((1ULL << ((i+1)*params->tree_height)) - 1)) == 0)) { + idx_leaf = (idx >> (params->tree_height * i)) & ((1 << params->tree_height)-1); + idx_tree = (idx >> (params->tree_height * (i+1))); +- set_layer_addr(addr, i); ++ set_layer_addr(addr, (uint32_t) i); + set_tree_addr(addr, idx_tree); + if (i == (unsigned int) (needswap_upto + 1)) { + bds_round(params, &states[i], idx_leaf, sk_seed, pub_seed, addr); +@@ -962,7 +1034,7 @@ int xmssmt_core_sign(const xmss_params *params, + else if (idx < (1ULL << params->full_height) - 1) { + deep_state_swap(params, states+params->d + i, states + i); + +- set_layer_addr(ots_addr, (i+1)); ++ set_layer_addr(ots_addr, (uint32_t) (i+1)); + set_tree_addr(ots_addr, ((idx + 1) >> ((i+2) * params->tree_height))); + set_ots_addr(ots_addr, (((idx >> ((i+1) * params->tree_height)) + 1) & ((1 << params->tree_height)-1))); + +@@ -972,17 +1044,15 @@ int xmssmt_core_sign(const xmss_params *params, + states[params->d + i].next_leaf = 0; + + updates--; // WOTS-signing counts as one update +- needswap_upto = i; ++ needswap_upto = (int) i; + for (j = 0; j < params->tree_height-params->bds_k; j++) { + states[i].treehash[j].completed = 1; + } + } + } + +- memcpy(sm, m, mlen); +- *smlen += mlen; +- + xmssmt_serialize_state(params, sk, states); + + return 0; + } ++#endif /* ifndef XMSS_VERIFY_ONLY */ +-- +2.40.0 + diff --git a/pq/stateful_hash_sig/Makefile b/pq/stateful_hash_sig/Makefile index e208ae9c..8924b11b 100644 --- a/pq/stateful_hash_sig/Makefile +++ b/pq/stateful_hash_sig/Makefile @@ -1,14 +1,15 @@ # PQ Stateful Hash-Based Signature Examples Makefile CC = gcc LIB_PATH = /usr/local -HSS_INC = -CFLAGS = -Wall -I$(LIB_PATH)/include -I$(HSS_INC) +HSS_INC = +XMSS_INC = +CFLAGS = -Wall -I$(LIB_PATH)/include LIBS = -L$(LIB_PATH)/lib -lm # option variables -DYN_LIB = -lwolfssl -STATIC_LIB = $(LIB_PATH)/lib/libwolfssl.a -HSS_LIB = +WOLF_DYN_LIB = -lwolfssl +WOLF_STATIC_LIB = $(LIB_PATH)/lib/libwolfssl.a +HSS_LIB = DEBUG_FLAGS = -g -DDEBUG DEBUG_INC_PATHS = -MD OPTIMIZE = -Os @@ -16,9 +17,6 @@ OPTIMIZE = -Os # Options #CFLAGS+=$(DEBUG_FLAGS) #CFLAGS+=$(OPTIMIZE) -LIBS+=$(STATIC_LIB) -#LIBS+=$(DYN_LIB) -LIBS+=$(HSS_LIB) # build targets SRC=$(wildcard *.c) @@ -33,8 +31,16 @@ debug: all # build template lms_example: lms_example.c - $(CC) -o $@ $< $(CFLAGS) $(LIBS) + $(CC) -o $@ $< $(CFLAGS) -I$(HSS_INC) $(LIBS) $(WOLF_STATIC_LIB) $(HSS_LIB) + +xmss_example: xmss_example.c + $(CC) -o $@ $< $(CFLAGS) -I$(XMSS_INC) $(LIBS) $(WOLF_DYN_LIB) + +xmss_example_verifyonly: xmss_example.c + $(CC) -o $@ $< $(CFLAGS) -I$(XMSS_INC) -DWOLFSSL_XMSS_VERIFY_ONLY $(LIBS) $(WOLF_DYN_LIB) clean: rm -f $(TARGETS) + rm -f xmss_example_verifyonly rm -f lms_example.key + rm -f xmss_example.key diff --git a/pq/stateful_hash_sig/README.md b/pq/stateful_hash_sig/README.md index d6a6453c..0a1a3d01 100644 --- a/pq/stateful_hash_sig/README.md +++ b/pq/stateful_hash_sig/README.md @@ -6,15 +6,24 @@ This directory contains: with configurable LMS/HSS parameters. Requires wolfssl with `--enable-lms=yes` and `--with-liblms=`. +- An example that uses wolfCrypt XMSS/XMSS^MT hooks to sign and verify a message + with a configurable XMSS/XMSS^MT parameter string. Requires wolfssl with `--enable-xmss=yes` + and `--with-libxmss=`. + # Prerequisites -The LMS sign verify example requires that hash-sigs has been built, and +The LMS/HSS sign verify example requires that hash-sigs has been built, and wolfSSL has been built with LMS/HSS support enabled. Please see Item 17 in the wolfSSL repo's INSTALL file. https://github.com/wolfSSL/wolfssl/blob/master/INSTALL -## Building the Applications +The XMSS/XMSS^MT example requires that the xmss-reference repository has been +cloned and patched. Please see item 20 in the wolfSSL repo's INSTALL file. + +The patch to use is `0001-Patch-to-support-xmss-reference-integration.patch` from this XMSS/XMSS^MT example. + +# Building the LMS/HSS example Configure the Makefile to point to your hash-sigs install: @@ -29,7 +38,7 @@ HSS_LIB = Then build: ``` -$ make +$ make lms_example ``` ## Signing and Verifying a Message with LMS/HSS @@ -66,3 +75,159 @@ examples: description: ... ``` + +# Building the XMSS/XMSS^MT example + +Configure the Makefile to point to your xmss install: + +``` +XMSS_INC = +``` + +Nothing more is needed after patching, as wolfSSL will automatically +build and link the xmss-reference objects it needs. + +Build wolfSSL XMSS/XMSS^MT hooks support with: + +``` +$ ./configure \ + --enable-xmss \ + --with-libxmss= +$ make +``` + +Note that depending on your architecture you may add `--enable-intelasm` +or `--enable-armasm` to speedup the XMSS/XMSS^MT hash operations. + +Asumming wolfSSL has been built, you may finally build the xmss example with: + +``` +$ make xmss_example +``` + +Build the verify-only example with +``` +$ make xmss_example_verifyonly +``` + + +## Signing and Verifying a Message with XMSS/XMSS^MT + +To see the help and usage, run the program without options: +```sh +$ ./xmss_example +usage: + ./xmss_example [num signatures] + +examples: + ./xmss_example XMSSMT-SHA2_20/4_256 5 + ./xmss_example XMSSMT-SHA2_60/6_256 100 + ./xmss_example XMSS-SHA2_10_256 1023 +``` + +The param string may be any name from this table: + +``` + ---------------------------------------------------------- + | Name Oid n w len h d | + XMSS: | "XMSS-SHA2_10_256" 0x00000001 32 16 67 10 1 | + | "XMSS-SHA2_16_256" 0x00000002 32 16 67 16 1 | + | "XMSS-SHA2_20_256" 0x00000003 32 16 67 20 1 | + | | + XMSSMT: | "XMSSMT-SHA2_20/2_256" 0x00000001 32 16 67 20 2 | + | "XMSSMT-SHA2_20/4_256" 0x00000002 32 16 67 20 4 | + | "XMSSMT-SHA2_40/2_256" 0x00000003 32 16 67 40 2 | + | "XMSSMT-SHA2_40/4_256" 0x00000004 32 16 67 40 4 | + | "XMSSMT-SHA2_40/8_256" 0x00000005 32 16 67 40 8 | + | "XMSSMT-SHA2_60/3_256" 0x00000006 32 16 67 60 3 | + | "XMSSMT-SHA2_60/6_256" 0x00000007 32 16 67 60 6 | + | "XMSSMT-SHA2_60/12_256" 0x00000008 32 16 67 60 12 | + ---------------------------------------------------------- +``` + +Here `n=32` is the number of bytes in the SHA256 has function, `w=16` +is the Winternitz parameter, `len=67` is the length of Winternitz chains, +`h` is the is the total height of the tree or hyper-tree, and `d` is the +number of levels in the hyper-tree. The number of signatures available +is `N = 2 ** (h)`. + +The main contributor to key generation time is the ratio `h/d`. +Not surprisingly, be aware that `XMSS-SHA2_20_256`, and `XMSSMT-SHA2_60/3_256`, are particularly +CPU intensive because of the large number of hash operations involved, and +may take a long time. E.g. on an Intel i7 linux system these examples took +approximately 24 min, and 1 hour, respectively. + +The other examples will be much faster. + +An interesting facet of XMSS/XMSS^MT is that the private key format +and size is implementation specific. The wolfSSL XMSS/XMSS^MT hooks +feature uses the "fast" implementation from xmss-reference, which +has larger private key sizes. + +For example: + +``` +$ ./xmss_example "XMSSMT-SHA2_20/2_256" 200 +using parameters: XMSSMT-SHA2_20/2_256 +signature length: 4963 +priv key length: 6002 +pub key length: 68 +...done! +signing and verifying 200 signatures... +...done! +finished + +``` + +``` +$ ./xmss_example "XMSSMT-SHA2_40/4_256" 200 +using parameters: XMSSMT-SHA2_40/4_256 +signature length: 9893 +priv key length: 15256 +pub key length: 68 +...done! +signing and verifying 200 signatures... +...done! +finished +``` + +## Using the verify-only XMSS/XMSS^MT example + +The usage for the verify-only example is: +``` +$ ./xmss_example_verifyonly +usage: + ./xmss_example_verifyonly + +For simplicity message is assumed to be 32 bytes in size. + +examples: + ./xmss_example_verifyonly XMSSMT-SHA2_20/4_256 xmss_pub.key xmss_sig.bin msg.bin + ./xmss_example_verifyonly XMSSMT-SHA2_60/6_256 xmss_pub.key xmss_sig.bin msg.bin + ./xmss_example_verifyonly XMSS-SHA2_10_256 xmss_pub.key xmss_sig.bin msg.bin +``` + +An example: +``` +$./xmss_example_verifyonly XMSSMT-SHA2_20/2_256 pk.bin sig.bin msg.bin +using parameters: XMSSMT-SHA2_20/2_256 +pub: +0x00 0x00 0x00 0x01 0x2B 0xC1 0xA4 0x8D +0x32 0x4B 0x15 0xA8 0xF6 0xEA 0x04 0xC0 +0x96 0x52 0x70 0x4D 0x4C 0x19 0x94 0xA4 +0x2D 0x2E 0xDA 0x52 0xA4 0x5F 0xF7 0xA8 +0x50 0x0A 0xE1 0xB3 0x77 0xD6 0x85 0x33 +0xB0 0x8A 0x4F 0x9D 0x54 0x6B 0xE9 0xFE +0x4B 0x3B 0xCB 0x5A 0x7A 0x92 0x86 0x0C +0x4B 0x7F 0xBF 0x2E 0xA0 0x1F 0x47 0x6F +0xDB 0x35 0x1C 0x61 +msg: +0xF1 0x91 0x9C 0xC0 0xA7 0xDC 0xEB 0xCE +0x38 0x96 0xEC 0x28 0x3A 0x9E 0xE1 0xA0 +0xA3 0x2F 0x94 0x1E 0xE7 0xB0 0x56 0x15 +0x54 0x8C 0x17 0xF4 0x65 0xFF 0xCB 0x08 +signature length: 4963 +pub key length: 68 +Verify good! +finished +``` diff --git a/pq/stateful_hash_sig/lms_example.c b/pq/stateful_hash_sig/lms_example.c index a7dea03c..69429310 100644 --- a/pq/stateful_hash_sig/lms_example.c +++ b/pq/stateful_hash_sig/lms_example.c @@ -1,6 +1,6 @@ /* lms_example.c * - * Copyright (C) 2022 wolfSSL Inc. + * Copyright (C) 2023 wolfSSL Inc. * * This file is part of wolfSSL. * diff --git a/pq/stateful_hash_sig/xmss_example.c b/pq/stateful_hash_sig/xmss_example.c new file mode 100644 index 00000000..2707b9f1 --- /dev/null +++ b/pq/stateful_hash_sig/xmss_example.c @@ -0,0 +1,550 @@ +/* xmss_example.c + * + * Copyright (C) 2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#include +#include + +#include +#include + +#ifdef HAVE_LIBXMSS + +#include +#include + +static void dump_hex(const char * what, const uint8_t * buf, size_t len); +static void print_usage(void); +#if !defined WOLFSSL_XMSS_VERIFY_ONLY +static int write_key_file(const byte * priv, word32 privSz, void * context); +static int read_key_file(byte * priv, word32 privSz, void * context); +static int do_xmss_example(const char * params, size_t sigs_to_do); + +static WC_RNG rng; +static byte * read_buf = NULL; + +int +main(int argc, + char * argv[]) +{ + const char * params = NULL; + size_t sigs_to_do = 1; + int ret = 0; + + if (argc < 2 || argc > 3) { + print_usage(); + return EXIT_FAILURE; + } + + params = argv[1]; + + if (argc == 3) { + sigs_to_do = atoll(argv[2]); + } + + ret = wc_InitRng(&rng); + if (ret) { + fprintf(stderr, "error: wc_InitRng returned %d\n", ret); + return EXIT_FAILURE; + } + + ret = do_xmss_example(params, sigs_to_do); + + wc_FreeRng(&rng); + + return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +static void +print_usage(void) +{ + fprintf(stderr, "usage:\n"); + fprintf(stderr, " ./xmss_example [num signatures]\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "examples:\n"); + fprintf(stderr, " ./xmss_example XMSSMT-SHA2_20/4_256 5\n"); + fprintf(stderr, " ./xmss_example XMSSMT-SHA2_60/6_256 100\n"); + fprintf(stderr, " ./xmss_example XMSS-SHA2_10_256 1023\n"); + + exit(EXIT_FAILURE); +} + +static int +write_key_file(const byte * priv, + word32 privSz, + void * context) +{ + FILE * file = NULL; + const char * filename = NULL; + int n_cmp = 0; + size_t n_read = 0; + size_t n_write = 0; + int err = 0; + + if (priv == NULL || context == NULL || privSz == 0) { + fprintf(stderr, "error: invalid write args\n"); + return WC_XMSS_RC_BAD_ARG; + } + + filename = context; + + /* Open file for read and write. */ + file = fopen(filename, "r+"); + if (!file) { + /* Create the file if it didn't exist. */ + file = fopen(filename, "w+"); + if (!file) { + fprintf(stderr, "error: fopen(%s, \"w+\") failed: %d\n", filename, + ferror(file)); + return WC_XMSS_RC_WRITE_FAIL; + } + } + + n_write = fwrite(priv, 1, privSz, file); + + if (n_write != privSz) { + fprintf(stderr, "error: wrote %zu, expected %d: %d\n", n_write, privSz, + ferror(file)); + return WC_XMSS_RC_WRITE_FAIL; + } + + /* Verify data has actually been written to disk correctly. */ + rewind(file); + + XMEMSET(read_buf, 0, n_write); + + n_read = fread(read_buf, 1, n_write, file); + + if (n_read != n_write) { + fprintf(stderr, "error: read %zu, expected %zu: %d\n", n_read, n_write, + ferror(file)); + return WC_XMSS_RC_WRITE_FAIL; + } + + n_cmp = XMEMCMP(read_buf, priv, n_write); + if (n_cmp != 0) { + fprintf(stderr, "error: write data was corrupted: %d\n", n_cmp); + return WC_XMSS_RC_WRITE_FAIL; + } + + err = fclose(file); + if (err) { + fprintf(stderr, "error: fclose returned %d\n", err); + return WC_XMSS_RC_WRITE_FAIL; + } + + return WC_XMSS_RC_SAVED_TO_NV_MEMORY; +} + +static int +read_key_file(byte * priv, + word32 privSz, + void * context) +{ + FILE * file = NULL; + const char * filename = NULL; + size_t n_read = 0; + + if (priv == NULL || context == NULL || privSz == 0) { + fprintf(stderr, "error: invalid read args\n"); + return WC_XMSS_RC_BAD_ARG; + } + + filename = context; + + file = fopen(filename, "rb"); + if (!file) { + fprintf(stderr, "error: fopen(%s, \"rb\") failed\n", filename); + return WC_XMSS_RC_READ_FAIL; + } + + n_read = fread(priv, 1, privSz, file); + + if (n_read != privSz) { + fprintf(stderr, "error: read %zu, expected %d: %d\n", n_read, privSz, + ferror(file)); + return WC_XMSS_RC_READ_FAIL; + } + + fclose(file); + + return WC_XMSS_RC_READ_TO_MEMORY; +} + +static int +do_xmss_example(const char * params, + size_t sigs_to_do) +{ + XmssKey signingKey; + XmssKey verifyKey; + const char * msg = "wolfSSL XMSS example message!"; + const char * filename = "xmss_example.key"; + int ret = 0; + byte * sig = NULL; + word32 sigSz = 0; + word32 privSz = 0; + word32 pubSz = 0; + + printf("using parameters: %s\n", params); + + ret = wc_XmssKey_Init(&signingKey, NULL, 0); + if (ret) { + fprintf(stderr, "error: wc_XmssKey_Init returned %d\n", ret); + goto exit_xmss_example; + } + + ret = wc_XmssKey_Init(&verifyKey, NULL, 0); + if (ret) { + fprintf(stderr, "error: wc_XmssKey_Init returned %d\n", ret); + goto exit_xmss_example; + } + + ret = wc_XmssKey_SetParamStr(&signingKey, params); + if (ret) { + fprintf(stderr, "error: wc_XmssKey_SetParameters(%s) returned %d\n", + params, ret); + goto exit_xmss_example; + } + + ret = wc_XmssKey_SetWriteCb(&signingKey, write_key_file); + if (ret) { + fprintf(stderr, "error: wc_XmssKey_SetWriteCb failed: %d\n", ret); + goto exit_xmss_example; + } + + ret = wc_XmssKey_SetReadCb(&signingKey, read_key_file); + if (ret) { + fprintf(stderr, "error: wc_XmssKey_SetReadCb failed: %d\n", ret); + goto exit_xmss_example; + } + + ret = wc_XmssKey_SetContext(&signingKey, (void *) filename); + if (ret) { + fprintf(stderr, "error: wc_XmssKey_SetContext failed: %d\n", ret); + goto exit_xmss_example; + } + + ret = wc_XmssKey_GetSigLen(&signingKey, &sigSz); + if (ret || sigSz == 0) { + fprintf(stderr, "error: wc_XmssKey_GetSigLen returned: %d, %d\n", + ret, sigSz); + goto exit_xmss_example; + } + + ret = wc_XmssKey_GetPubLen(&signingKey, &pubSz); + if (ret || pubSz == 0) { + fprintf(stderr, "error: wc_XmssKey_GetPubLen returned: %d, %d\n", + ret, pubSz); + goto exit_xmss_example; + } + + ret = wc_XmssKey_GetPrivLen(&signingKey, &privSz); + if (ret || pubSz == 0) { + fprintf(stderr, "error: wc_XmssKey_GetPrivLen returned: %d, %d\n", + ret, privSz); + goto exit_xmss_example; + } + + printf("signature length: %d\n", sigSz); + printf("priv key length: %d\n", privSz); + printf("pub key length: %d\n", pubSz); + + read_buf = malloc(privSz); + if (read_buf == NULL) { + fprintf(stderr, "error: malloc read_buf failed\n"); + goto exit_xmss_example; + } + + ret = wc_XmssKey_MakeKey(&signingKey, &rng); + if (ret) { + fprintf(stderr, "error: wc_XmssKey_MakeKey returned %d\n", ret); + goto exit_xmss_example; + } + + printf("...done!\n"); + + if (sigs_to_do == 0) { + read_key_file(read_buf, privSz, (void *) filename); + dump_hex("priv", read_buf, privSz); + dump_hex("pub", signingKey.pk, pubSz); + goto exit_xmss_example; + } + + sig = malloc(sigSz); + if (sig == NULL) { + fprintf(stderr, "error: malloc(%d) failed\n", sigSz); + goto exit_xmss_example; + } + + ret = wc_XmssKey_ExportPub(&verifyKey, &signingKey); + if (ret) { + fprintf(stderr, "error: wc_XmssKey_ExportPub returned %d\n", ret); + goto exit_xmss_example; + } + + printf("signing and verifying %zu signatures...\n", sigs_to_do); + for (size_t i = 0; i < sigs_to_do; ++i) { + ret = wc_XmssKey_Sign(&signingKey, sig, &sigSz,(byte *) msg, + strlen(msg)); + if (ret) { + fprintf(stderr, "error: %zu: wc_XmssKey_Sign returned %d\n", i, ret); + goto exit_xmss_example; + } + + ret = wc_XmssKey_Verify(&verifyKey, sig, sigSz, (const byte *) msg, + strlen(msg)); + if (ret) { + fprintf(stderr, "error: %zu: wc_XmssKey_Verify returned %d\n", i, ret); + goto exit_xmss_example; + } + } + + printf("...done!\n"); + printf("finished\n"); + +exit_xmss_example: + + if (sig != NULL) { + free(sig); + sig = NULL; + } + + if (read_buf != NULL) { + free(read_buf); + read_buf = NULL; + } + + wc_XmssKey_Free(&signingKey); + wc_XmssKey_Free(&verifyKey); + + return ret; +} + + +#else /* if !defined WOLFSSL_XMSS_VERIFY_ONLY */ +static int read_file(byte * data, word32 len, const char * filename); +static int do_xmss_example(const char * params, const char * pubfile, + const char * sigfile, const char * msgfile); + +int +main(int argc, + char * argv[]) +{ + const char * params = NULL; + const char * pubfile = NULL; + const char * sigfile = NULL; + const char * msgfile = NULL; + int ret = 0; + + if (argc != 5) { + print_usage(); + } + + params = argv[1]; + pubfile = argv[2]; + sigfile = argv[3]; + msgfile = argv[4]; + + ret = do_xmss_example(params, pubfile, sigfile, msgfile); + + return ret; +} + +static void +print_usage(void) +{ + fprintf(stderr, "usage:\n"); + fprintf(stderr, " ./xmss_example_verifyonly \n"); + fprintf(stderr, "\n"); + fprintf(stderr, "For simplicity message is assumed to be 32 bytes in size.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "examples:\n"); + fprintf(stderr, " ./xmss_example_verifyonly XMSSMT-SHA2_20/4_256 xmss_pub.key xmss_sig.bin msg.bin\n"); + fprintf(stderr, " ./xmss_example_verifyonly XMSSMT-SHA2_60/6_256 xmss_pub.key xmss_sig.bin msg.bin\n"); + fprintf(stderr, " ./xmss_example_verifyonly XMSS-SHA2_10_256 xmss_pub.key xmss_sig.bin msg.bin\n"); + + exit(EXIT_FAILURE); +} + + +static int +do_xmss_example(const char * params, + const char * pubfile, + const char * sigfile, + const char * msgfile) +{ + int ret = 0; + XmssKey verifyKey; + byte * sig = NULL; + word32 sigSz = 0; + word32 pubSz = 0; + byte pub[XMSS_SHA256_PUBLEN]; + byte msg[32]; + + printf("using parameters: %s\n", params); + + ret = wc_XmssKey_Init(&verifyKey, NULL, 0); + if (ret) { + fprintf(stderr, "error: wc_XmssKey_Init returned %d\n", ret); + goto exit_xmss_example; + } + + ret = wc_XmssKey_SetParamStr(&verifyKey, params); + if (ret) { + fprintf(stderr, "error: wc_XmssKey_SetParameters(%s) returned %d\n", + params, ret); + goto exit_xmss_example; + } + + ret = wc_XmssKey_GetSigLen(&verifyKey, &sigSz); + if (ret || sigSz == 0) { + fprintf(stderr, "error: wc_XmssKey_GetSigLen returned: %d, %d\n", + ret, sigSz); + goto exit_xmss_example; + } + + ret = wc_XmssKey_GetPubLen(&verifyKey, &pubSz); + if (ret || pubSz == 0) { + fprintf(stderr, "error: wc_XmssKey_GetPubLen returned: %d, %d\n", + ret, pubSz); + goto exit_xmss_example; + } + + ret = read_file(msg, sizeof(msg), msgfile); + if (ret) { + fprintf(stderr, "error: read_file(%s) failed\n", msgfile); + goto exit_xmss_example; + } + + sig = malloc(sigSz); + if (sig == NULL) { + fprintf(stderr, "error: malloc(%d) failed\n", sigSz); + goto exit_xmss_example; + } + + ret = read_file(sig, sigSz, sigfile) ; + if (ret) { + fprintf(stderr, "error: read_file(%s) failed\n", sigfile); + goto exit_xmss_example; + } + + ret = read_file(pub, XMSS_SHA256_PUBLEN, pubfile); + if (ret) { + fprintf(stderr, "error: read_file(%s) failed\n", pubfile); + goto exit_xmss_example; + } + + ret = wc_XmssKey_ImportPubRaw(&verifyKey, pub, sizeof(pub)); + if (ret != 0) { + /* Something is wrong with the pub key or LMS parameters. */ + fprintf(stderr, "error: wc_XmssKey_ImportPubRaw" \ + " returned %d\n", ret); + goto exit_xmss_example; + } + + dump_hex("pub: ", pub, sizeof(pub)); + dump_hex("msg: ", msg, sizeof(msg)); + printf("signature length: %d\n", sigSz); + printf("pub key length: %d\n", pubSz); + + ret = wc_XmssKey_Verify(&verifyKey, sig, sigSz, (const byte *) msg, + sizeof(msg)); + if (ret) { + fprintf(stderr, "error: wc_XmssKey_Verify returned %d\n", ret); + goto exit_xmss_example; + } + + printf("Verify good!\n"); + printf("finished\n"); + +exit_xmss_example: + + if (sig != NULL) { + free(sig); + sig = NULL; + } + + wc_XmssKey_Free(&verifyKey); + + return ret; +} + +static int +read_file(byte * data, + word32 len, + const char * filename) +{ + FILE * file = NULL; + size_t n_read = 0; + + if (data == NULL || filename == NULL || len == 0) { + fprintf(stderr, "error: invalid read_file args\n"); + return -1; + } + + file = fopen(filename, "rb"); + if (!file) { + fprintf(stderr, "error: fopen(%s, \"rb\") failed\n", filename); + return -1; + } + + n_read = fread(data, 1, len, file); + + if (n_read != len) { + fprintf(stderr, "error: read %zu, expected %d: %d\n", n_read, len, + ferror(file)); + return -1; + } + + fclose(file); + + return 0; +} + +#endif /* if !defined WOLFSSL_XMSS_VERIFY_ONLY */ + +static void +dump_hex(const char * what, + const uint8_t * buf, + size_t len) +{ + printf("%s\n", what); + for (size_t i = 0; i < len; ++i) { + printf("0x%02X ", buf[i]); + + if ((i + 1) % 8 == 0) { + printf("\n"); + } + } + + if (len % 8) { + printf("\n"); + } + + return; +} + +#else + +int main(int argc, char** argv) { + printf("This requires the --with-libxmss flag.\n"); + return 0; +} +#endif /* WITH_LIBXMSS */ + From 87df7747dace488b62dd5d28f13697bdb33e756e Mon Sep 17 00:00:00 2001 From: philljj Date: Mon, 9 Oct 2023 11:45:34 -0500 Subject: [PATCH 2/4] Example for xmss hooks support: update patch and build. --- ...-wolfSSL-xmss-reference-integration.patch} | 1353 +++++++++++++---- pq/stateful_hash_sig/Makefile | 5 +- pq/stateful_hash_sig/README.md | 20 +- pq/stateful_hash_sig/xmss_example.c | 2 + 4 files changed, 1107 insertions(+), 273 deletions(-) rename pq/stateful_hash_sig/{0001-Patch-to-support-xmss-reference-integration.patch => 0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch} (58%) diff --git a/pq/stateful_hash_sig/0001-Patch-to-support-xmss-reference-integration.patch b/pq/stateful_hash_sig/0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch similarity index 58% rename from pq/stateful_hash_sig/0001-Patch-to-support-xmss-reference-integration.patch rename to pq/stateful_hash_sig/0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch index 3d0dd217..975561d9 100644 --- a/pq/stateful_hash_sig/0001-Patch-to-support-xmss-reference-integration.patch +++ b/pq/stateful_hash_sig/0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch @@ -1,38 +1,90 @@ -From 14b855cbad45bd19ee3e9e591cc6b426f8b5c9da Mon Sep 17 00:00:00 2001 +From 605ac49e4c4bcb65191c1c9bb821cbc31354e1e3 Mon Sep 17 00:00:00 2001 From: jordan -Date: Thu, 5 Oct 2023 08:39:19 -0500 -Subject: [PATCH 1/1] Patch to support xmss-reference integration with - wolfCrypt and wolfBoot. +Date: Mon, 9 Oct 2023 11:31:08 -0500 +Subject: [PATCH 1/1] Patch to support wolfSSL xmss-reference integration. --- - Makefile | 2 + - fips202.c | 2 +- - hash_address.c | 2 + - params.h | 15 +++ - hash.c => thash.c | 110 ++++++++++++++++++++-- - hash.h => thash.h | 0 - wots.c | 35 ++++++- - xmss.c | 53 ++++++----- - xmss.h | 36 ++++---- - xmss_commons.c | 77 ++++++++++------ - xmss_commons.h | 4 +- - xmss_core.c | 34 ++++--- - xmss_core.h | 26 +++--- - xmss_core_fast.c | 230 ++++++++++++++++++++++++++++++---------------- - 14 files changed, 443 insertions(+), 183 deletions(-) - rename hash.c => thash.c (68%) - rename hash.h => thash.h (100%) + Makefile | 36 +++++- + fips202.c | 2 +- + hash_address.c | 2 + + params.h | 15 +++ + randombytes.c | 2 + + test/speed.c | 98 +++++++++++++-- + test/wots.c | 77 ++++++++++++ + test/xmss.c | 135 +++++++++++++++------ + test/xmss_determinism.c | 77 ++++++++++++ + test/xmss_max_signatures.c | 72 +++++++++++ + hash.c => thash.c | 72 +++++++++-- + hash.h => thash.h | 5 +- + ui/keypair.c | 73 ++++++++++++ + wots.c | 31 ++++- + xmss.c | 41 ++++--- + xmss.h | 30 ++--- + xmss_callbacks.h | 12 ++ + xmss_commons.c | 77 ++++++++---- + xmss_commons.h | 4 +- + xmss_core.c | 60 ++++++++-- + xmss_core.h | 22 ++-- + xmss_core_fast.c | 238 +++++++++++++++++++++++++------------ + 22 files changed, 957 insertions(+), 224 deletions(-) + rename hash.c => thash.c (79%) + rename hash.h => thash.h (96%) + create mode 100644 xmss_callbacks.h diff --git a/Makefile b/Makefile -index d1b95d5..435c854 100644 +index d1b95d5..599df68 100644 --- a/Makefile +++ b/Makefile -@@ -87,3 +87,5 @@ clean: +@@ -1,9 +1,10 @@ + CC = /usr/bin/gcc +-CFLAGS = -Wall -g -O3 -Wextra -Wpedantic +-LDLIBS = -lcrypto ++CFLAGS = -Wall -O2 -Wextra -Wpedantic ++VERIFY_CFLAGS = -DXMSS_VERIFY_ONLY -Wall -O2 -Wextra -Wpedantic ++LDLIBS = -lwolfssl + +-SOURCES = params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss.c xmss_core.c xmss_commons.c utils.c +-HEADERS = params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss.h xmss_core.h xmss_commons.h utils.h ++SOURCES = params.c thash.c fips202.c hash_address.c randombytes.c wots.c xmss.c xmss_core.c xmss_commons.c utils.c ++HEADERS = params.h thash.h fips202.h hash_address.h randombytes.h wots.h xmss.h xmss_core.h xmss_commons.h utils.h + + SOURCES_FAST = $(subst xmss_core.c,xmss_core_fast.c,$(SOURCES)) + HEADERS_FAST = $(subst xmss_core.c,xmss_core_fast.c,$(HEADERS)) +@@ -83,7 +84,34 @@ ui/xmss_%: ui/%.c $(SOURCES) $(OBJS) $(HEADERS) + ui/xmssmt_%: ui/%.c $(SOURCES) $(OBJS) $(HEADERS) + $(CC) -DXMSSMT $(CFLAGS) -o $@ $(SOURCES) $< $(LDLIBS) + ++# Only the test xmss executables link with wolfssl. ++# xmss_lib.a does not link with wolfssl, as this would create circular ++# dependencies. ++xmss_lib.a: params.o thash.o hash_address.o wots.o xmss.o xmss_core_fast.o \ ++ xmss_commons.o utils.o ++ $(AR) rcs $@ $^ ++ ++xmss_verify_lib.a: CFLAGS += -DXMSS_VERIFY_ONLY ++ ++xmss_verify_lib.a: params.o thash.o hash_address.o wots.o xmss.o xmss_core_fast.o \ ++ xmss_commons.o utils.o ++ $(AR) rcs $@ $^ ++ + clean: -$(RM) $(TESTS) -$(RM) test/vectors -$(RM) $(UI) + -$(RM) *.o + -$(RM) *.lo ++ -$(RM) xmss_lib.a ++ ++#%.o:%.c ++# @echo "[$(CC)] $@" ++# $(CC) -DXMSSMT -fPIC $(CFLAGS) -c -o $@ $< ++ ++#wolfcrypt_integration: params.lo thash.lo hash_address.lo wots.lo xmss.lo xmss_core_fast.lo xmss_commons.lo utils.lo ++# ++#%.lo:%.c ++# @echo "[$(CC)] $@" ++## $(CC) -fPIC $(CFLAGS) -c -o $@ $< ++# libtool --tag=CC --mode=compile $(CC) $(CFLAGS) -c $< diff --git a/fips202.c b/fips202.c index 5e36d66..4565782 100644 --- a/fips202.c @@ -84,58 +136,89 @@ index 58c0619..c55ebaf 100644 /* These are merely internal identifiers for the supported hash functions. */ #define XMSS_SHA2 0 #define XMSS_SHAKE128 1 -diff --git a/hash.c b/thash.c -similarity index 68% -rename from hash.c -rename to thash.c -index 6724d43..e8af5c4 100644 ---- a/hash.c -+++ b/thash.c -@@ -1,12 +1,14 @@ - #include -+#include - #include --#include +diff --git a/randombytes.c b/randombytes.c +index bfc8d93..ba4d7ac 100644 +--- a/randombytes.c ++++ b/randombytes.c +@@ -5,6 +5,8 @@ This code was taken from the SPHINCS reference implementation and is public doma + #include + #include + ++#include "randombytes.h" + + static int fd = -1; + + void randombytes(unsigned char *x, unsigned long long xlen) +diff --git a/test/speed.c b/test/speed.c +index 6ae58b0..93d7d3c 100644 +--- a/test/speed.c ++++ b/test/speed.c +@@ -4,8 +4,13 @@ + + #include "../xmss.h" + #include "../params.h" ++#include "../xmss_callbacks.h" + #include "../randombytes.h" + ++#include +#include -+#include ++#include ++ + #define XMSS_MLEN 32 - #include "hash_address.h" - #include "utils.h" - #include "params.h" --#include "hash.h" --#include "fips202.h" -+#include "thash.h" + #ifndef XMSS_SIGNATURES +@@ -34,6 +39,8 @@ + #endif + #endif - #define XMSS_HASH_PADDING_F 0 - #define XMSS_HASH_PADDING_H 1 -@@ -14,6 +16,69 @@ - #define XMSS_HASH_PADDING_PRF 3 - #define XMSS_HASH_PADDING_PRF_KEYGEN 4 ++static WC_RNG rng; ++ + static unsigned long long cpucycles(void) + { + unsigned long long result; +@@ -78,6 +85,53 @@ static void print_results(unsigned long long *t, size_t tlen) + printf("\n"); + } -+static int sha256(const unsigned char *in, unsigned long long inlen, -+ unsigned char *out) ++static int rng_cb(void * output, size_t length) ++{ ++ int ret = 0; ++ ++ if (output == NULL) { ++ return -1; ++ } ++ ++ if (length == 0) { ++ return 0; ++ } ++ ++ ret = wc_RNG_GenerateBlock(&rng, output, (word32) length); ++ ++ if (ret) { ++ printf("error: xmss rng_cb failed"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int sha256_cb(const unsigned char *in, unsigned long long inlen, ++ unsigned char *out) +{ + wc_Sha256 sha; + + if (wc_InitSha256_ex(&sha, NULL, INVALID_DEVID) != 0) { -+#if !defined WOLFBOOT_SIGN_XMSS -+ fprintf(stderr, "SHA256 Init failed"); -+#endif ++ printf("SHA256 Init failed"); + return -1; + } + + if (wc_Sha256Update(&sha, in, (word32) inlen) != 0) { -+#if !defined WOLFBOOT_SIGN_XMSS -+ fprintf(stderr, "SHA256 Update failed"); -+#endif ++ printf("SHA256 Update failed"); + return -1; + } + + if (wc_Sha256Final(&sha, out) != 0) { -+#if !defined WOLFBOOT_SIGN_XMSS -+ fprintf(stderr, "SHA256 Final failed"); -+#endif ++ printf("SHA256 Final failed"); + wc_Sha256Free(&sha); + return -1; + } @@ -144,54 +227,685 @@ index 6724d43..e8af5c4 100644 + return 0; +} + -+static int sha512(const unsigned char *in, unsigned long long inlen, -+ unsigned char *out) -+{ -+ /* Disabling everything but sha256 for now. */ -+ (void) in; -+ (void) inlen; -+ (void) out; -+ return -1; -+} -+ -+static int shake128(unsigned char *out, unsigned long long outlen, -+ const unsigned char *in, unsigned long long inlen) -+{ -+ /* Disabling everything but sha256 for now. */ -+ (void) in; -+ (void) inlen; -+ (void) out; -+ (void) outlen; -+ return -1; -+} -+ -+static int shake256(unsigned char *out, unsigned long long outlen, -+ const unsigned char *in, unsigned long long inlen) -+{ -+ /* Disabling everything but sha256 for now. */ -+ (void) in; -+ (void) inlen; -+ (void) out; -+ (void) outlen; -+ return -1; -+} -+ - void addr_to_bytes(unsigned char *bytes, const uint32_t addr[8]) + int main() { + /* Make stdout buffer more responsive. */ +@@ -88,6 +142,24 @@ int main() + int ret = 0; int i; -@@ -27,32 +92,39 @@ static int core_hash(const xmss_params *params, + ++ ret = wc_InitRng(&rng); ++ if (ret != 0) { ++ printf("error: init rng failed: %d\n", ret); ++ return -1; ++ } ++ ++ ret = xmss_set_sha_cb(sha256_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_sha_cb failed"); ++ return -1; ++ } ++ ++ ret = xmss_set_rng_cb(rng_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_rng_cb failed"); ++ return -1; ++ } ++ + // TODO test more different variants + if (XMSS_STR_TO_OID(&oid, XMSS_VARIANT)) { + #ifdef XMSSMT +@@ -101,18 +173,18 @@ int main() + + unsigned char pk[XMSS_OID_LEN + params.pk_bytes]; + unsigned char sk[XMSS_OID_LEN + params.sk_bytes]; +- unsigned char *m = malloc(XMSS_MLEN); +- unsigned char *sm = malloc(params.sig_bytes + XMSS_MLEN); +- unsigned char *mout = malloc(params.sig_bytes + XMSS_MLEN); +- unsigned long long smlen; +- unsigned long long mlen; ++ unsigned char *msg = malloc(XMSS_MLEN); ++ unsigned char *sig = malloc(params.sig_bytes); ++ unsigned char *msgout = malloc(XMSS_MLEN); ++ unsigned long long siglen; ++ unsigned long long msglen; + + unsigned long long t0, t1; + unsigned long long *t = malloc(sizeof(unsigned long long) * XMSS_SIGNATURES); + struct timespec start, stop; + double result; + +- randombytes(m, XMSS_MLEN); ++ randombytes(msg, XMSS_MLEN); + + printf("Benchmarking variant %s\n", XMSS_VARIANT); + +@@ -130,7 +202,7 @@ int main() + + for (i = 0; i < XMSS_SIGNATURES; i++) { + t[i] = cpucycles(); +- XMSS_SIGN(sk, sm, &smlen, m, XMSS_MLEN); ++ XMSS_SIGN(sk, sig, &siglen, msg, XMSS_MLEN); + } + print_results(t, XMSS_SIGNATURES); + +@@ -138,7 +210,7 @@ int main() + + for (i = 0; i < XMSS_SIGNATURES; i++) { + t[i] = cpucycles(); +- ret |= XMSS_SIGN_OPEN(mout, &mlen, sm, smlen, pk); ++ ret |= XMSS_SIGN_OPEN(msgout, &msglen, sig, siglen, pk); + } + print_results(t, XMSS_SIGNATURES); + +@@ -150,10 +222,12 @@ int main() + printf("Public key size: %d (%.2f KiB)\n", params.pk_bytes, params.pk_bytes / 1024.0); + printf("Secret key size: %llu (%.2f KiB)\n", params.sk_bytes, params.sk_bytes / 1024.0); + +- free(m); +- free(sm); +- free(mout); ++ wc_FreeRng(&rng); ++ ++ free(msg); ++ free(sig); ++ free(msgout); + free(t); + + return ret; +-} +\ No newline at end of file ++} +diff --git a/test/wots.c b/test/wots.c +index 8b2b6de..6192527 100644 +--- a/test/wots.c ++++ b/test/wots.c +@@ -3,14 +3,26 @@ + #include + + #include "../wots.h" ++#include "../xmss_callbacks.h" + #include "../randombytes.h" + #include "../params.h" + ++#include ++#include ++#include ++ ++static int rng_cb(void * output, size_t length); ++static int sha256_cb(const unsigned char *in, unsigned long long inlen, ++ unsigned char *out); ++ ++static WC_RNG rng; ++ + int main() + { + xmss_params params; + // TODO test more different OIDs + uint32_t oid = 0x00000001; ++ int ret = -1; + + /* For WOTS it doesn't matter if we use XMSS or XMSSMT. */ + xmss_parse_oid(¶ms, oid); +@@ -23,6 +35,24 @@ int main() + unsigned char m[params.n]; + uint32_t addr[8] = {0}; + ++ ret = wc_InitRng(&rng); ++ if (ret != 0) { ++ printf("error: init rng failed: %d\n", ret); ++ return -1; ++ } ++ ++ ret = xmss_set_sha_cb(sha256_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_sha_cb failed"); ++ return -1; ++ } ++ ++ ret = xmss_set_rng_cb(rng_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_rng_cb failed"); ++ return -1; ++ } ++ + randombytes(seed, params.n); + randombytes(pub_seed, params.n); + randombytes(m, params.n); +@@ -41,3 +71,50 @@ int main() + printf("successful.\n"); + return 0; + } ++ ++static int rng_cb(void * output, size_t length) ++{ ++ int ret = 0; ++ ++ if (output == NULL) { ++ return -1; ++ } ++ ++ if (length == 0) { ++ return 0; ++ } ++ ++ ret = wc_RNG_GenerateBlock(&rng, output, (word32) length); ++ ++ if (ret) { ++ printf("error: xmss rng_cb failed"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int sha256_cb(const unsigned char *in, unsigned long long inlen, ++ unsigned char *out) ++{ ++ wc_Sha256 sha; ++ ++ if (wc_InitSha256_ex(&sha, NULL, INVALID_DEVID) != 0) { ++ printf("SHA256 Init failed"); ++ return -1; ++ } ++ ++ if (wc_Sha256Update(&sha, in, (word32) inlen) != 0) { ++ printf("SHA256 Update failed"); ++ return -1; ++ } ++ ++ if (wc_Sha256Final(&sha, out) != 0) { ++ printf("SHA256 Final failed"); ++ wc_Sha256Free(&sha); ++ return -1; ++ } ++ wc_Sha256Free(&sha); ++ ++ return 0; ++} +diff --git a/test/xmss.c b/test/xmss.c +index 3703759..675e4a5 100644 +--- a/test/xmss.c ++++ b/test/xmss.c +@@ -4,9 +4,14 @@ + #include + + #include "../xmss.h" ++#include "../xmss_callbacks.h" + #include "../params.h" + #include "../randombytes.h" + ++#include ++#include ++#include ++ + #define XMSS_MLEN 32 + + #ifndef XMSS_SIGNATURES +@@ -29,6 +34,12 @@ + #define XMSS_VARIANT "XMSS-SHA2_10_256" + #endif + ++static int rng_cb(void * output, size_t length); ++static int sha256_cb(const unsigned char *in, unsigned long long inlen, ++ unsigned char *out); ++ ++static WC_RNG rng; ++ + int main() + { + xmss_params params; +@@ -42,13 +53,30 @@ int main() + + unsigned char pk[XMSS_OID_LEN + params.pk_bytes]; + unsigned char sk[XMSS_OID_LEN + params.sk_bytes]; +- unsigned char *m = malloc(XMSS_MLEN); +- unsigned char *sm = malloc(params.sig_bytes + XMSS_MLEN); +- unsigned char *mout = malloc(params.sig_bytes + XMSS_MLEN); +- unsigned long long smlen; +- unsigned long long mlen; ++ unsigned char *msg = malloc(XMSS_MLEN); ++ unsigned char *sig = malloc(params.sig_bytes); ++ unsigned long long siglen = params.sig_bytes; ++ unsigned long long msglen = XMSS_MLEN; ++ ++ ret = wc_InitRng(&rng); ++ if (ret != 0) { ++ printf("error: init rng failed: %d\n", ret); ++ return -1; ++ } + +- randombytes(m, XMSS_MLEN); ++ ret = xmss_set_sha_cb(sha256_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_sha_cb failed"); ++ return -1; ++ } ++ ++ ret = xmss_set_rng_cb(rng_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_rng_cb failed"); ++ return -1; ++ } ++ ++ randombytes(msg, XMSS_MLEN); + + XMSS_KEYPAIR(pk, sk, oid); + +@@ -57,19 +85,19 @@ int main() + for (i = 0; i < XMSS_SIGNATURES; i++) { + printf(" - iteration #%d:\n", i); + +- XMSS_SIGN(sk, sm, &smlen, m, XMSS_MLEN); ++ XMSS_SIGN(sk, sig, &siglen, msg, XMSS_MLEN); + +- if (smlen != params.sig_bytes + XMSS_MLEN) { +- printf(" X smlen incorrect [%llu != %u]!\n", +- smlen, params.sig_bytes); ++ if (siglen != params.sig_bytes) { ++ printf(" X siglen incorrect [%llu != %u]!\n", ++ siglen, params.sig_bytes); + ret = -1; + } + else { +- printf(" smlen as expected [%llu].\n", smlen); ++ printf(" siglen as expected [%llu].\n", siglen); + } + + /* Test if signature is valid. */ +- if (XMSS_SIGN_OPEN(mout, &mlen, sm, smlen, pk)) { ++ if (XMSS_SIGN_OPEN(msg, &msglen, sig, siglen, pk)) { + printf(" X verification failed!\n"); + ret = -1; + } +@@ -78,57 +106,96 @@ int main() + } + + /* Test if the correct message was recovered. */ +- if (mlen != XMSS_MLEN) { +- printf(" X mlen incorrect [%llu != %u]!\n", mlen, XMSS_MLEN); ++ if (msglen != XMSS_MLEN) { ++ printf(" X msglen incorrect [%llu != %u]!\n", msglen, XMSS_MLEN); + ret = -1; + } + else { +- printf(" mlen as expected [%llu].\n", mlen); +- } +- if (memcmp(m, mout, XMSS_MLEN)) { +- printf(" X output message incorrect!\n"); +- ret = -1; +- } +- else { +- printf(" output message as expected.\n"); ++ printf(" msglen as expected [%llu].\n", msglen); + } + + /* Test if flipping bits invalidates the signature (it should). */ + + /* Flip the first bit of the message. Should invalidate. */ +- sm[smlen - 1] ^= 1; +- if (!XMSS_SIGN_OPEN(mout, &mlen, sm, smlen, pk)) { ++ sig[siglen - 1] ^= 1; ++ if (!XMSS_SIGN_OPEN(msg, &msglen, sig, siglen, pk)) { + printf(" X flipping a bit of m DID NOT invalidate signature!\n"); + ret = -1; + } + else { + printf(" flipping a bit of m invalidates signature.\n"); + } +- sm[smlen - 1] ^= 1; ++ sig[siglen - 1] ^= 1; + + #ifdef XMSS_TEST_INVALIDSIG + int j; + /* Flip one bit per hash; the signature is almost entirely hashes. + This also flips a bit in the index, which is also a useful test. */ +- for (j = 0; j < (int)(smlen - XMSS_MLEN); j += params.n) { +- sm[j] ^= 1; +- if (!XMSS_SIGN_OPEN(mout, &mlen, sm, smlen, pk)) { ++ for (j = 0; j < (int)(siglen - XMSS_MLEN); j += params.n) { ++ sig[j] ^= 1; ++ if (!XMSS_SIGN_OPEN(msg, &msglen, sig, siglen, pk)) { + printf(" X flipping bit %d DID NOT invalidate sig + m!\n", j); +- sm[j] ^= 1; ++ sig[j] ^= 1; + ret = -1; + break; + } +- sm[j] ^= 1; ++ sig[j] ^= 1; + } +- if (j >= (int)(smlen - XMSS_MLEN)) { ++ if (j >= (int)(siglen - XMSS_MLEN)) { + printf(" changing any signature hash invalidates signature.\n"); + } + #endif + } + +- free(m); +- free(sm); +- free(mout); ++ free(msg); ++ free(sig); + + return ret; + } ++ ++static int rng_cb(void * output, size_t length) ++{ ++ int ret = 0; ++ ++ if (output == NULL) { ++ return -1; ++ } ++ ++ if (length == 0) { ++ return 0; ++ } ++ ++ ret = wc_RNG_GenerateBlock(&rng, output, (word32) length); ++ ++ if (ret) { ++ printf("error: xmss rng_cb failed"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int sha256_cb(const unsigned char *in, unsigned long long inlen, ++ unsigned char *out) ++{ ++ wc_Sha256 sha; ++ ++ if (wc_InitSha256_ex(&sha, NULL, INVALID_DEVID) != 0) { ++ printf("SHA256 Init failed"); ++ return -1; ++ } ++ ++ if (wc_Sha256Update(&sha, in, (word32) inlen) != 0) { ++ printf("SHA256 Update failed"); ++ return -1; ++ } ++ ++ if (wc_Sha256Final(&sha, out) != 0) { ++ printf("SHA256 Final failed"); ++ wc_Sha256Free(&sha); ++ return -1; ++ } ++ wc_Sha256Free(&sha); ++ ++ return 0; ++} +diff --git a/test/xmss_determinism.c b/test/xmss_determinism.c +index 49629f8..a309157 100644 +--- a/test/xmss_determinism.c ++++ b/test/xmss_determinism.c +@@ -3,17 +3,47 @@ + #include + + #include "../params.h" ++#include "../xmss_callbacks.h" + #include "../xmss.h" + #include "../randombytes.h" + ++#include ++#include ++#include ++ + #define MLEN 32 + ++static int rng_cb(void * output, size_t length); ++static int sha256_cb(const unsigned char *in, unsigned long long inlen, ++ unsigned char *out); ++ ++static WC_RNG rng; ++ + int main() + { + xmss_params params; + char *oidstr = "XMSS-SHA2_10_256"; + uint32_t oid; + unsigned int i; ++ int ret = -1; ++ ++ ret = wc_InitRng(&rng); ++ if (ret != 0) { ++ printf("error: init rng failed: %d\n", ret); ++ return -1; ++ } ++ ++ ret = xmss_set_sha_cb(sha256_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_sha_cb failed"); ++ return -1; ++ } ++ ++ ret = xmss_set_rng_cb(rng_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_rng_cb failed"); ++ return -1; ++ } + + fprintf(stderr, "Testing if XMSS-SHA2_10_256 signing is deterministic.. "); + +@@ -55,3 +85,50 @@ int main() + + return 0; + } ++ ++static int rng_cb(void * output, size_t length) ++{ ++ int ret = 0; ++ ++ if (output == NULL) { ++ return -1; ++ } ++ ++ if (length == 0) { ++ return 0; ++ } ++ ++ ret = wc_RNG_GenerateBlock(&rng, output, (word32) length); ++ ++ if (ret) { ++ printf("error: xmss rng_cb failed"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int sha256_cb(const unsigned char *in, unsigned long long inlen, ++ unsigned char *out) ++{ ++ wc_Sha256 sha; ++ ++ if (wc_InitSha256_ex(&sha, NULL, INVALID_DEVID) != 0) { ++ printf("SHA256 Init failed"); ++ return -1; ++ } ++ ++ if (wc_Sha256Update(&sha, in, (word32) inlen) != 0) { ++ printf("SHA256 Update failed"); ++ return -1; ++ } ++ ++ if (wc_Sha256Final(&sha, out) != 0) { ++ printf("SHA256 Final failed"); ++ wc_Sha256Free(&sha); ++ return -1; ++ } ++ wc_Sha256Free(&sha); ++ ++ return 0; ++} +diff --git a/test/xmss_max_signatures.c b/test/xmss_max_signatures.c +index d4a45a4..b1432da 100644 +--- a/test/xmss_max_signatures.c ++++ b/test/xmss_max_signatures.c +@@ -5,9 +5,14 @@ + + #include "../xmss.h" + #include "../params.h" ++#include "../xmss_callbacks.h" + #include "../randombytes.h" + #include "../utils.h" + ++#include ++#include ++#include ++ + #define XMSS_MLEN 32 + + // #ifndef XMSS_SIGNATURES +@@ -32,6 +37,55 @@ + #define XMSS_SIGNATURES (1 << 10) + #endif + ++static WC_RNG rng; ++ ++static int rng_cb(void * output, size_t length) ++{ ++ int ret = 0; ++ ++ if (output == NULL) { ++ return -1; ++ } ++ ++ if (length == 0) { ++ return 0; ++ } ++ ++ ret = wc_RNG_GenerateBlock(&rng, output, (word32) length); ++ ++ if (ret) { ++ printf("error: xmss rng_cb failed"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int sha256_cb(const unsigned char *in, unsigned long long inlen, ++ unsigned char *out) ++{ ++ wc_Sha256 sha; ++ ++ if (wc_InitSha256_ex(&sha, NULL, INVALID_DEVID) != 0) { ++ printf("SHA256 Init failed"); ++ return -1; ++ } ++ ++ if (wc_Sha256Update(&sha, in, (word32) inlen) != 0) { ++ printf("SHA256 Update failed"); ++ return -1; ++ } ++ ++ if (wc_Sha256Final(&sha, out) != 0) { ++ printf("SHA256 Final failed"); ++ wc_Sha256Free(&sha); ++ return -1; ++ } ++ wc_Sha256Free(&sha); ++ ++ return 0; ++} ++ + int main() + { + xmss_params params; +@@ -53,6 +107,24 @@ int main() + unsigned long long idx; + unsigned long long j; + ++ ret = wc_InitRng(&rng); ++ if (ret != 0) { ++ printf("error: init rng failed: %d\n", ret); ++ return -1; ++ } ++ ++ ret = xmss_set_sha_cb(sha256_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_sha_cb failed"); ++ return -1; ++ } ++ ++ ret = xmss_set_rng_cb(rng_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_rng_cb failed"); ++ return -1; ++ } ++ + randombytes(m, XMSS_MLEN); + + XMSS_KEYPAIR(pk, sk, oid); +diff --git a/hash.c b/thash.c +similarity index 79% +rename from hash.c +rename to thash.c +index 6724d43..54e8954 100644 +--- a/hash.c ++++ b/thash.c +@@ -1,12 +1,14 @@ + #include ++#include + #include +-#include + ++#include "xmss_callbacks.h" + #include "hash_address.h" + #include "utils.h" + #include "params.h" +-#include "hash.h" +-#include "fips202.h" ++#include "thash.h" ++ ++static sha_cb_t sha_cb = NULL; + + #define XMSS_HASH_PADDING_F 0 + #define XMSS_HASH_PADDING_H 1 +@@ -22,37 +24,67 @@ void addr_to_bytes(unsigned char *bytes, const uint32_t addr[8]) + } + } + ++int xmss_set_sha_cb(sha_cb_t cb) ++{ ++ if (cb == NULL) { ++ return -1; ++ } ++ ++ sha_cb = cb; ++ ++ return 0; ++} ++ + static int core_hash(const xmss_params *params, + unsigned char *out, const unsigned char *in, unsigned long long inlen) { - unsigned char buf[64]; -+ int ret = -1; +- unsigned char buf[64]; ++ int ret = -1; + ++ if (sha_cb == NULL) { ++ return -1; ++ } + + if (params == NULL || out == NULL || in == NULL) { + return -1; + } - ++ ++ /* The choice of SHA256 and n=32 is set at compile time. */ ++ if (params->n != XMSS_SHA256_N || params->func != XMSS_SHA2) { ++ return -1; ++ } ++ ++ ret = sha_cb(in, inlen, out); ++ ++/* if (params->n == 24 && params->func == XMSS_SHA2) { - SHA256(in, inlen, buf); -+ ret = sha256(in, inlen, buf); ++ ret = sha_cb(in, inlen, out); memcpy(out, buf, 24); } else if (params->n == 24 && params->func == XMSS_SHAKE256) { @@ -200,7 +914,7 @@ index 6724d43..e8af5c4 100644 } else if (params->n == 32 && params->func == XMSS_SHA2) { - SHA256(in, inlen, out); -+ ret = sha256(in, inlen, out); ++ ret = sha_cb(in, inlen, out); } else if (params->n == 32 && params->func == XMSS_SHAKE128) { - shake128(out, 32, in, inlen); @@ -221,12 +935,13 @@ index 6724d43..e8af5c4 100644 else { return -1; } ++*/ + + if (ret != 0) { return ret; } return 0; } -@@ -63,7 +135,11 @@ int prf(const xmss_params *params, +@@ -63,7 +95,11 @@ int prf(const xmss_params *params, unsigned char *out, const unsigned char in[32], const unsigned char *key) { @@ -238,7 +953,7 @@ index 6724d43..e8af5c4 100644 ull_to_bytes(buf, params->padding_len, XMSS_HASH_PADDING_PRF); memcpy(buf + params->padding_len, key, params->n); -@@ -80,7 +156,11 @@ int prf_keygen(const xmss_params *params, +@@ -80,7 +116,11 @@ int prf_keygen(const xmss_params *params, unsigned char *out, const unsigned char *in, const unsigned char *key) { @@ -250,7 +965,7 @@ index 6724d43..e8af5c4 100644 ull_to_bytes(buf, params->padding_len, XMSS_HASH_PADDING_PRF_KEYGEN); memcpy(buf + params->padding_len, key, params->n); -@@ -118,8 +198,13 @@ int thash_h(const xmss_params *params, +@@ -118,8 +158,13 @@ int thash_h(const xmss_params *params, unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { @@ -264,7 +979,7 @@ index 6724d43..e8af5c4 100644 unsigned char addr_as_bytes[32]; unsigned int i; -@@ -150,8 +235,13 @@ int thash_f(const xmss_params *params, +@@ -150,8 +195,13 @@ int thash_f(const xmss_params *params, unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { @@ -279,11 +994,130 @@ index 6724d43..e8af5c4 100644 unsigned int i; diff --git a/hash.h b/thash.h -similarity index 100% +similarity index 96% rename from hash.h rename to thash.h +index 6e13d12..dcfb781 100644 +--- a/hash.h ++++ b/thash.h +@@ -1,9 +1,10 @@ +-#ifndef XMSS_HASH_H +-#define XMSS_HASH_H ++#ifndef XMSS_THASH_H ++#define XMSS_THASH_H + + #include + #include "params.h" + ++ + void addr_to_bytes(unsigned char *bytes, const uint32_t addr[8]); + + int prf(const xmss_params *params, +diff --git a/ui/keypair.c b/ui/keypair.c +index 612c448..64dc067 100644 +--- a/ui/keypair.c ++++ b/ui/keypair.c +@@ -3,6 +3,11 @@ + + #include "../params.h" + #include "../xmss.h" ++#include "../xmss_callbacks.h" ++ ++#include ++#include ++#include + + #ifdef XMSSMT + #define XMSS_STR_TO_OID xmssmt_str_to_oid +@@ -14,11 +19,61 @@ + #define XMSS_KEYPAIR xmss_keypair + #endif + ++static WC_RNG rng; ++ ++static int rng_cb(void * output, size_t length) ++{ ++ int ret = 0; ++ ++ if (output == NULL) { ++ return -1; ++ } ++ ++ if (length == 0) { ++ return 0; ++ } ++ ++ ret = wc_RNG_GenerateBlock(&rng, output, (word32) length); ++ ++ if (ret) { ++ printf("error: xmss rng_cb failed"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int sha256_cb(const unsigned char *in, unsigned long long inlen, ++ unsigned char *out) ++{ ++ wc_Sha256 sha; ++ ++ if (wc_InitSha256_ex(&sha, NULL, INVALID_DEVID) != 0) { ++ printf("SHA256 Init failed"); ++ return -1; ++ } ++ ++ if (wc_Sha256Update(&sha, in, (word32) inlen) != 0) { ++ printf("SHA256 Update failed"); ++ return -1; ++ } ++ ++ if (wc_Sha256Final(&sha, out) != 0) { ++ printf("SHA256 Final failed"); ++ wc_Sha256Free(&sha); ++ return -1; ++ } ++ wc_Sha256Free(&sha); ++ ++ return 0; ++} ++ + int main(int argc, char **argv) + { + xmss_params params; + uint32_t oid = 0; + int parse_oid_result = 0; ++ int ret = -1; + + if (argc != 2) { + fprintf(stderr, "Expected parameter string (e.g. 'XMSS-SHA2_10_256')" +@@ -27,6 +82,24 @@ int main(int argc, char **argv) + return -1; + } + ++ ret = wc_InitRng(&rng); ++ if (ret != 0) { ++ printf("error: init rng failed: %d\n", ret); ++ return -1; ++ } ++ ++ ret = xmss_set_sha_cb(sha256_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_sha_cb failed"); ++ return -1; ++ } ++ ++ ret = xmss_set_rng_cb(rng_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_rng_cb failed"); ++ return -1; ++ } ++ + XMSS_STR_TO_OID(&oid, argv[1]); + parse_oid_result = XMSS_PARSE_OID(¶ms, oid); + if (parse_oid_result != 0) { diff --git a/wots.c b/wots.c -index d9c8449..8acb313 100644 +index d9c8449..825c2dc 100644 --- a/wots.c +++ b/wots.c @@ -2,7 +2,7 @@ @@ -307,7 +1141,7 @@ index d9c8449..8acb313 100644 set_hash_addr(addr, 0); set_key_and_mask(addr, 0); -@@ -83,7 +87,25 @@ static void wots_checksum(const xmss_params *params, +@@ -83,7 +87,23 @@ static void wots_checksum(const xmss_params *params, int *csum_base_w, const int *msg_base_w) { int csum = 0; @@ -322,8 +1156,6 @@ index d9c8449..8acb313 100644 + * + * Therefore: + * -+ * (params->wots_len2 * params->wots_log_w + 7) / 8 = 2 -+ * + * (3 * 4 + 7) / 8 = 2 + * */ + unsigned char csum_bytes[2]; @@ -333,7 +1165,7 @@ index d9c8449..8acb313 100644 unsigned int i; /* Compute checksum. */ -@@ -94,7 +116,7 @@ static void wots_checksum(const xmss_params *params, +@@ -94,7 +114,7 @@ static void wots_checksum(const xmss_params *params, /* Convert checksum to base_w. */ /* Make sure expected empty zero bits are the least significant bits. */ csum = csum << (8 - ((params->wots_len2 * params->wots_log_w) % 8)); @@ -342,20 +1174,17 @@ index d9c8449..8acb313 100644 base_w(params, csum_base_w, params->wots_len2, csum_bytes); } -@@ -139,7 +161,12 @@ void wots_sign(const xmss_params *params, +@@ -139,7 +159,8 @@ void wots_sign(const xmss_params *params, const unsigned char *seed, const unsigned char *pub_seed, uint32_t addr[8]) { -+#if defined WOLFBOOT_SIGN_XMSS -+ int lengths[XMSS_SHA256_WOTS_LEN]; -+#else - int lengths[params->wots_len]; -+#endif -+ +- int lengths[params->wots_len]; ++ /* int lengths[params->wots_len]; */ ++ int lengths[67]; uint32_t i; chain_lengths(params, lengths, msg); -@@ -163,7 +190,11 @@ void wots_pk_from_sig(const xmss_params *params, unsigned char *pk, +@@ -163,7 +184,11 @@ void wots_pk_from_sig(const xmss_params *params, unsigned char *pk, const unsigned char *sig, const unsigned char *msg, const unsigned char *pub_seed, uint32_t addr[8]) { @@ -368,7 +1197,7 @@ index d9c8449..8acb313 100644 chain_lengths(params, lengths, msg); diff --git a/xmss.c b/xmss.c -index 9030f6e..faaa000 100644 +index 9030f6e..dbae7e5 100644 --- a/xmss.c +++ b/xmss.c @@ -1,5 +1,6 @@ @@ -378,28 +1207,15 @@ index 9030f6e..faaa000 100644 #include "params.h" #include "xmss_core.h" -@@ -7,7 +8,9 @@ +@@ -7,6 +8,7 @@ identify the parameter set to be used. After setting the parameters accordingly it falls back to the regular XMSS core functions. */ --int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) +#ifndef XMSS_VERIFY_ONLY -+int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid, -+ void * rng) + int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) { xmss_params params; - unsigned int i; -@@ -22,7 +25,8 @@ int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) - i.e. not just for interoperability, but also for internal use. */ - sk[XMSS_OID_LEN - i - 1] = (oid >> (8 * i)) & 0xFF; - } -- return xmss_core_keypair(¶ms, pk + XMSS_OID_LEN, sk + XMSS_OID_LEN); -+ return xmss_core_keypair(¶ms, pk + XMSS_OID_LEN, sk + XMSS_OID_LEN, -+ rng); - } - - int xmss_sign(unsigned char *sk, -@@ -42,24 +46,8 @@ int xmss_sign(unsigned char *sk, +@@ -42,23 +44,6 @@ int xmss_sign(unsigned char *sk, return xmss_core_sign(¶ms, sk + XMSS_OID_LEN, sm, smlen, m, mlen); } @@ -420,23 +1236,10 @@ index 9030f6e..faaa000 100644 - return xmss_core_sign_open(¶ms, m, mlen, sm, smlen, pk + XMSS_OID_LEN); -} - --int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) -+int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid, -+ void * rng) + int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) { xmss_params params; - unsigned int i; -@@ -71,7 +59,8 @@ int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) - pk[XMSS_OID_LEN - i - 1] = (oid >> (8 * i)) & 0xFF; - sk[XMSS_OID_LEN - i - 1] = (oid >> (8 * i)) & 0xFF; - } -- return xmssmt_core_keypair(¶ms, pk + XMSS_OID_LEN, sk + XMSS_OID_LEN); -+ return xmssmt_core_keypair(¶ms, pk + XMSS_OID_LEN, sk + XMSS_OID_LEN, -+ rng); - } - - int xmssmt_sign(unsigned char *sk, -@@ -90,8 +79,26 @@ int xmssmt_sign(unsigned char *sk, +@@ -90,8 +75,26 @@ int xmssmt_sign(unsigned char *sk, } return xmssmt_core_sign(¶ms, sk + XMSS_OID_LEN, sm, smlen, m, mlen); } @@ -464,7 +1267,7 @@ index 9030f6e..faaa000 100644 const unsigned char *sm, unsigned long long smlen, const unsigned char *pk) { -@@ -105,5 +112,5 @@ int xmssmt_sign_open(unsigned char *m, unsigned long long *mlen, +@@ -105,5 +108,5 @@ int xmssmt_sign_open(unsigned char *m, unsigned long long *mlen, if (xmssmt_parse_oid(¶ms, oid)) { return -1; } @@ -472,10 +1275,10 @@ index 9030f6e..faaa000 100644 + return xmssmt_core_sign_open(¶ms, msg, msglen, sm, smlen, pk + XMSS_OID_LEN); } diff --git a/xmss.h b/xmss.h -index c7b4b69..8f4bab4 100644 +index c7b4b69..199ce88 100644 --- a/xmss.h +++ b/xmss.h -@@ -3,50 +3,54 @@ +@@ -3,6 +3,7 @@ #include @@ -483,12 +1286,7 @@ index c7b4b69..8f4bab4 100644 /** * Generates a XMSS key pair for a given parameter set. * Format sk: [OID || (32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] - * Format pk: [OID || root || PUB_SEED] - */ --int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid); -+int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid, -+ void * rng); - +@@ -13,24 +14,13 @@ int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid); /** * Signs a message using an XMSS secret key. * Returns @@ -514,12 +1312,7 @@ index c7b4b69..8f4bab4 100644 /* * Generates a XMSSMT key pair for a given parameter set. * Format sk: [OID || (ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] - * Format pk: [OID || root || PUB_SEED] - */ --int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid); -+int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid, -+ void * rng); - +@@ -41,12 +31,24 @@ int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid); /** * Signs a message using an XMSSMT secret key. * Returns @@ -545,7 +1338,7 @@ index c7b4b69..8f4bab4 100644 /** * Verifies a given message signature pair using a given public key. -@@ -55,7 +59,7 @@ int xmssmt_sign(unsigned char *sk, +@@ -55,7 +57,7 @@ int xmssmt_sign(unsigned char *sk, * verification succeeds. The (input) message is assumed to be contained in sm * which has the form [signature || message]. */ @@ -554,6 +1347,24 @@ index c7b4b69..8f4bab4 100644 const unsigned char *sm, unsigned long long smlen, const unsigned char *pk); #endif +diff --git a/xmss_callbacks.h b/xmss_callbacks.h +new file mode 100644 +index 0000000..31bd300 +--- /dev/null ++++ b/xmss_callbacks.h +@@ -0,0 +1,12 @@ ++#ifndef XMSS_CALLBACKS_H ++#define XMSS_CALLBACKS_H ++ ++/* Callback used for SHA and RNG operations. */ ++typedef int (*sha_cb_t)(const unsigned char *in, unsigned long long inlen, ++ unsigned char *out); ++typedef int (*rng_cb_t)(void * output, size_t length); ++ ++int xmss_set_sha_cb(sha_cb_t cb); ++int xmss_set_rng_cb(rng_cb_t cb); ++ ++#endif diff --git a/xmss_commons.c b/xmss_commons.c index 2b76b94..0599a76 100644 --- a/xmss_commons.c @@ -758,10 +1569,10 @@ index 9d9f077..33dbffe 100644 const unsigned char *pk); #endif diff --git a/xmss_core.c b/xmss_core.c -index af9f8d1..6d3b2f1 100644 +index af9f8d1..e80175b 100644 --- a/xmss_core.c +++ b/xmss_core.c -@@ -2,15 +2,19 @@ +@@ -2,15 +2,47 @@ #include #include @@ -775,26 +1586,61 @@ index af9f8d1..6d3b2f1 100644 #include "xmss_commons.h" #include "xmss_core.h" -+#include -+#include -+#include -+#include ++#ifndef XMSS_VERIFY_ONLY ++#include "xmss_callbacks.h" ++ ++static rng_cb_t rng_cb = NULL; ++ ++typedef struct{ ++ unsigned char h; ++ unsigned long next_idx; ++ unsigned char stackusage; ++ unsigned char completed; ++ unsigned char *node; ++} treehash_inst; ++ ++typedef struct { ++ unsigned char *stack; ++ unsigned int stackoffset; ++ unsigned char *stacklevels; ++ unsigned char *auth; ++ unsigned char *keep; ++ treehash_inst *treehash; ++ unsigned char *retain; ++ unsigned int next_leaf; ++} bds_state; ++ ++int xmss_set_rng_cb(rng_cb_t cb) ++{ ++ if (cb == NULL) { ++ return -1; ++ } ++ rng_cb = cb; ++ return 0; ++} + /** * For a given leaf index, computes the authentication path and the resulting * root node using Merkle's TreeHash algorithm. -@@ -101,28 +105,28 @@ unsigned long long xmss_xmssmt_core_sk_bytes(const xmss_params *params) - * Format pk: [root || PUB_SEED], omitting algorithm OID. - */ - int xmss_core_keypair(const xmss_params *params, -- unsigned char *pk, unsigned char *sk) -+ unsigned char *pk, unsigned char *sk, void * rng) - { - /* The key generation procedure of XMSS and XMSSMT is exactly the same. - The only important detail is that the right subtree must be selected; - this requires us to correctly set the d=1 parameter for XMSS. */ -- return xmssmt_core_keypair(params, pk, sk); -+ return xmssmt_core_keypair(params, pk, sk, rng); +@@ -85,6 +117,8 @@ static void treehash(const xmss_params *params, + memcpy(root, stack, params->n); + } + ++#endif /* ifndef XMSS_VERIFY_ONLY */ ++ + /** + * Given a set of parameters, this function returns the size of the secret key. + * This is implementation specific, as varying choices in tree traversal will +@@ -95,6 +129,8 @@ unsigned long long xmss_xmssmt_core_sk_bytes(const xmss_params *params) + return params->index_bytes + 4 * params->n; + } + ++#ifndef XMSS_VERIFY_ONLY ++ + /* + * Generates a XMSS key pair for a given parameter set. + * Format sk: [(32bit) index || SK_SEED || SK_PRF || root || PUB_SEED] +@@ -110,19 +146,19 @@ int xmss_core_keypair(const xmss_params *params, } /** @@ -819,21 +1665,16 @@ index af9f8d1..6d3b2f1 100644 } /* -@@ -166,11 +170,19 @@ int xmssmt_core_seed_keypair(const xmss_params *params, - * Format pk: [root || PUB_SEED] omitting algorithm OID. - */ - int xmssmt_core_keypair(const xmss_params *params, -- unsigned char *pk, unsigned char *sk) -+ unsigned char *pk, unsigned char *sk, -+ void * rng) +@@ -169,8 +205,15 @@ int xmssmt_core_keypair(const xmss_params *params, + unsigned char *pk, unsigned char *sk) { unsigned char seed[3 * params->n]; + int ret = 0; + -+ ret = wc_RNG_GenerateBlock(rng, seed, (word32) sizeof(seed)); ++ //ret = wc_RNG_GenerateBlock(rng, seed, (word32) sizeof(seed)); ++ ret = rng_cb(seed, sizeof(seed)); + + if (ret != 0) { -+ fprintf(stderr, "error: wc_RNG_GenerateBlock failed: %d\n", ret); + return -1; + } @@ -841,11 +1682,16 @@ index af9f8d1..6d3b2f1 100644 xmssmt_core_seed_keypair(params, pk, sk, seed); return 0; +@@ -271,3 +314,4 @@ int xmssmt_core_sign(const xmss_params *params, + + return 0; + } ++#endif /* ifndef XMSS_VERIFY_ONLY */ diff --git a/xmss_core.h b/xmss_core.h -index e83bc7d..bc1d0c2 100644 +index e83bc7d..21d72ef 100644 --- a/xmss_core.h +++ b/xmss_core.h -@@ -12,13 +12,14 @@ +@@ -12,6 +12,7 @@ */ unsigned long long xmss_xmssmt_core_sk_bytes(const xmss_params *params); @@ -853,15 +1699,7 @@ index e83bc7d..bc1d0c2 100644 /* * Generates a XMSS key pair for a given parameter set. * Format sk: [(32bit) index || SK_SEED || SK_PRF || PUB_SEED || root] - * Format pk: [root || PUB_SEED], omitting algorithm OID. - */ - int xmss_core_keypair(const xmss_params *params, -- unsigned char *pk, unsigned char *sk); -+ unsigned char *pk, unsigned char *sk, void * rng); - - /** - * Signs a message. Returns an array containing the signature followed by the -@@ -29,22 +30,13 @@ int xmss_core_sign(const xmss_params *params, +@@ -29,15 +30,6 @@ int xmss_core_sign(const xmss_params *params, unsigned char *sm, unsigned long long *smlen, const unsigned char *m, unsigned long long mlen); @@ -877,14 +1715,6 @@ index e83bc7d..bc1d0c2 100644 /* * Generates a XMSSMT key pair for a given parameter set. * Format sk: [(ceil(h/8) bit) index || SK_SEED || SK_PRF || PUB_SEED || root] - * Format pk: [root || PUB_SEED] omitting algorithm OID. - */ - int xmssmt_core_keypair(const xmss_params *params, -- unsigned char *pk, unsigned char *sk); -+ unsigned char *pk, unsigned char *sk, void * rng); - - /* - * Derives a XMSSMT key pair for a given parameter set. @@ -64,13 +56,23 @@ int xmssmt_core_sign(const xmss_params *params, unsigned char *sk, unsigned char *sm, unsigned long long *smlen, @@ -911,10 +1741,10 @@ index e83bc7d..bc1d0c2 100644 const unsigned char *pk); diff --git a/xmss_core_fast.c b/xmss_core_fast.c -index cbf87ec..7d75a22 100644 +index cbf87ec..1a71c07 100644 --- a/xmss_core_fast.c +++ b/xmss_core_fast.c -@@ -2,15 +2,21 @@ +@@ -2,15 +2,19 @@ #include #include @@ -928,17 +1758,31 @@ index cbf87ec..7d75a22 100644 #include "xmss_commons.h" #include "xmss_core.h" -+#include -+#include -+#include -+#include -+ +#ifndef XMSS_VERIFY_ONLY ++#include "xmss_callbacks.h" ++ ++static rng_cb_t rng_cb = NULL; + typedef struct{ unsigned char h; unsigned long next_idx; -@@ -94,7 +100,7 @@ static void xmssmt_deserialize_state(const xmss_params *params, +@@ -30,6 +34,15 @@ typedef struct { + unsigned int next_leaf; + } bds_state; + ++int xmss_set_rng_cb(rng_cb_t cb) ++{ ++ if (cb == NULL) { ++ return -1; ++ } ++ rng_cb = cb; ++ return 0; ++} ++ + /* These serialization functions provide a transition between the current + way of storing the state in an exposed struct, and storing it as part of the + byte array that is the secret key. +@@ -94,7 +107,7 @@ static void xmssmt_deserialize_state(const xmss_params *params, states[i].stack = sk; sk += (params->tree_height + 1) * params->n; @@ -947,7 +1791,7 @@ index cbf87ec..7d75a22 100644 sk += 4; states[i].stacklevels = sk; -@@ -126,7 +132,7 @@ static void xmssmt_deserialize_state(const xmss_params *params, +@@ -126,7 +139,7 @@ static void xmssmt_deserialize_state(const xmss_params *params, states[i].retain = sk; sk += ((1 << params->bds_k) - params->bds_k - 1) * params->n; @@ -956,7 +1800,7 @@ index cbf87ec..7d75a22 100644 sk += 4; } -@@ -299,8 +305,8 @@ static void treehash_update(const xmss_params *params, +@@ -299,8 +312,8 @@ static void treehash_update(const xmss_params *params, copy_subtree_addr(node_addr, addr); set_type(node_addr, 2); @@ -967,7 +1811,7 @@ index cbf87ec..7d75a22 100644 unsigned char nodebuffer[2 * params->n]; unsigned int nodeheight = 0; -@@ -309,7 +315,7 @@ static void treehash_update(const xmss_params *params, +@@ -309,7 +322,7 @@ static void treehash_update(const xmss_params *params, memcpy(nodebuffer + params->n, nodebuffer, params->n); memcpy(nodebuffer, state->stack + (state->stackoffset-1)*params->n, params->n); set_tree_height(node_addr, nodeheight); @@ -976,7 +1820,7 @@ index cbf87ec..7d75a22 100644 thash_h(params, nodebuffer, nodebuffer, pub_seed, node_addr); nodeheight++; treehash->stackusage--; -@@ -476,13 +482,13 @@ static void bds_round(const xmss_params *params, +@@ -476,13 +489,13 @@ static void bds_round(const xmss_params *params, memcpy(state->keep + (tau >> 1)*params->n, state->auth + tau*params->n, params->n); } if (tau == 0) { @@ -993,7 +1837,7 @@ index cbf87ec..7d75a22 100644 thash_h(params, state->auth + tau * params->n, buf, pub_seed, node_addr); for (i = 0; i < tau; i++) { if (i < params->tree_height - params->bds_k) { -@@ -490,13 +496,13 @@ static void bds_round(const xmss_params *params, +@@ -490,13 +503,13 @@ static void bds_round(const xmss_params *params, } else { offset = (1 << (params->tree_height - 1 - i)) + i - params->tree_height; @@ -1009,7 +1853,7 @@ index cbf87ec..7d75a22 100644 if (startidx < 1U << params->tree_height) { state->treehash[i].h = i; state->treehash[i].next_idx = startidx; -@@ -507,6 +513,8 @@ static void bds_round(const xmss_params *params, +@@ -507,6 +520,8 @@ static void bds_round(const xmss_params *params, } } @@ -1018,7 +1862,7 @@ index cbf87ec..7d75a22 100644 /** * Given a set of parameters, this function returns the size of the secret key. * This is implementation specific, as varying choices in tree traversal will -@@ -530,15 +538,18 @@ unsigned long long xmss_xmssmt_core_sk_bytes(const xmss_params *params) +@@ -530,6 +545,7 @@ unsigned long long xmss_xmssmt_core_sk_bytes(const xmss_params *params) + (params->d - 1) * params->wots_sig_bytes; } @@ -1026,34 +1870,34 @@ index cbf87ec..7d75a22 100644 /* * Generates a XMSS key pair for a given parameter set. * Format sk: [(32bit) idx || SK_SEED || SK_PRF || root || PUB_SEED] - * Format pk: [root || PUB_SEED] omitting algo oid. - */ - int xmss_core_keypair(const xmss_params *params, -- unsigned char *pk, unsigned char *sk) -+ unsigned char *pk, unsigned char *sk, -+ void * rng) +@@ -539,6 +555,7 @@ int xmss_core_keypair(const xmss_params *params, + unsigned char *pk, unsigned char *sk) { uint32_t addr[8] = {0}; + int ret = 0; // TODO refactor BDS state not to need separate treehash instances bds_state state; -@@ -555,16 +566,27 @@ int xmss_core_keypair(const xmss_params *params, +@@ -555,16 +572,31 @@ int xmss_core_keypair(const xmss_params *params, sk[1] = 0; sk[2] = 0; sk[3] = 0; + // Init SK_SEED (n byte) and SK_PRF (n byte) - randombytes(sk + params->index_bytes, 2*params->n); -+ ret = wc_RNG_GenerateBlock(rng, sk + params->index_bytes, -+ (word32) 2*params->n); ++ //ret = wc_RNG_GenerateBlock(rng, sk + params->index_bytes, ++ // (word32) 2*params->n); ++ ++ ret = rng_cb(sk + params->index_bytes, 2*params->n); + + if (ret != 0) { return -1; } // Init PUB_SEED (n byte) - randombytes(sk + params->index_bytes + 3*params->n, params->n); -+ ret = wc_RNG_GenerateBlock(rng, sk + params->index_bytes + 3*params->n, -+ (word32) params->n); ++ //ret = wc_RNG_GenerateBlock(rng, sk + params->index_bytes + 3*params->n, ++ // (word32) params->n); ++ ++ ret = rng_cb(sk + params->index_bytes + 3*params->n, params->n); + + if (ret != 0) { return -1; } + @@ -1069,7 +1913,7 @@ index cbf87ec..7d75a22 100644 // copy root to sk memcpy(sk + params->index_bytes + 2*params->n, pk, params->n); -@@ -577,19 +599,39 @@ int xmss_core_keypair(const xmss_params *params, +@@ -577,19 +609,39 @@ int xmss_core_keypair(const xmss_params *params, /** * Signs a message. * Returns @@ -1112,7 +1956,7 @@ index cbf87ec..7d75a22 100644 // TODO refactor BDS state not to need separate treehash instances bds_state state; treehash_inst treehash[params->tree_height - params->bds_k]; -@@ -599,7 +641,9 @@ int xmss_core_sign(const xmss_params *params, +@@ -599,7 +651,9 @@ int xmss_core_sign(const xmss_params *params, xmss_deserialize_state(params, &state, sk); // Extract SK @@ -1123,7 +1967,7 @@ index cbf87ec..7d75a22 100644 /* Check if we can still sign with this sk. * If not, return -2 -@@ -658,32 +702,32 @@ int xmss_core_sign(const xmss_params *params, +@@ -658,32 +712,32 @@ int xmss_core_sign(const xmss_params *params, /* Already put the message in the right place, to make it easier to prepend * things when computing the hash over the message. */ @@ -1169,7 +2013,7 @@ index cbf87ec..7d75a22 100644 // ---------------------------------- // Now we start to "really sign" -@@ -691,27 +735,24 @@ int xmss_core_sign(const xmss_params *params, +@@ -691,27 +745,24 @@ int xmss_core_sign(const xmss_params *params, // Prepare Address set_type(ots_addr, 0); @@ -1204,12 +2048,9 @@ index cbf87ec..7d75a22 100644 /* Write the updated BDS state back into sk. */ xmss_serialize_state(params, sk, &state); -@@ -725,11 +766,12 @@ int xmss_core_sign(const xmss_params *params, - * Format pk: [root || PUB_SEED] omitting algo oid. - */ +@@ -727,9 +778,10 @@ int xmss_core_sign(const xmss_params *params, int xmssmt_core_keypair(const xmss_params *params, -- unsigned char *pk, unsigned char *sk) -+ unsigned char *pk, unsigned char *sk, void * rng) + unsigned char *pk, unsigned char *sk) { - uint32_t addr[8] = {0}; - unsigned int i; @@ -1221,27 +2062,29 @@ index cbf87ec..7d75a22 100644 // TODO refactor BDS state not to need separate treehash instances bds_state states[2*params->d - 1]; -@@ -750,10 +792,17 @@ int xmssmt_core_keypair(const xmss_params *params, +@@ -750,10 +802,19 @@ int xmssmt_core_keypair(const xmss_params *params, sk[i] = 0; } // Init SK_SEED (params->n byte) and SK_PRF (params->n byte) - randombytes(sk+params->index_bytes, 2*params->n); -+ ret = wc_RNG_GenerateBlock(rng, sk+params->index_bytes, -+ (word32) 2*params->n); ++ //ret = wc_RNG_GenerateBlock(rng, sk+params->index_bytes, ++ // (word32) 2*params->n); ++ ret = rng_cb(sk+params->index_bytes, 2*params->n); + + if (ret != 0) { return -1; } // Init PUB_SEED (params->n byte) - randombytes(sk+params->index_bytes + 3*params->n, params->n); -+ ret = wc_RNG_GenerateBlock(rng, sk+params->index_bytes + 3*params->n, -+ (word32) params->n); ++ //ret = wc_RNG_GenerateBlock(rng, sk+params->index_bytes + 3*params->n, ++ // (word32) params->n); ++ ret = rng_cb(sk+params->index_bytes + 3*params->n, params->n); + + if (ret != 0) { return -1; } + // Copy PUB_SEED to public key memcpy(pk+params->n, sk+params->index_bytes+3*params->n, params->n); -@@ -778,17 +827,37 @@ int xmssmt_core_keypair(const xmss_params *params, +@@ -778,17 +839,37 @@ int xmssmt_core_keypair(const xmss_params *params, /** * Signs a message. * Returns @@ -1282,7 +2125,7 @@ index cbf87ec..7d75a22 100644 uint64_t idx_tree; uint32_t idx_leaf; uint64_t i, j; -@@ -867,31 +936,34 @@ int xmssmt_core_sign(const xmss_params *params, +@@ -867,31 +948,34 @@ int xmssmt_core_sign(const xmss_params *params, /* Already put the message in the right place, to make it easier to prepend * things when computing the hash over the message. */ @@ -1327,7 +2170,7 @@ index cbf87ec..7d75a22 100644 // ---------------------------------- // Now we start to "really sign" -@@ -908,27 +980,27 @@ int xmssmt_core_sign(const xmss_params *params, +@@ -908,27 +992,27 @@ int xmssmt_core_sign(const xmss_params *params, set_ots_addr(ots_addr, idx_leaf); // Compute WOTS signature @@ -1367,7 +2210,7 @@ index cbf87ec..7d75a22 100644 } updates = (params->tree_height - params->bds_k) >> 1; -@@ -944,7 +1016,7 @@ int xmssmt_core_sign(const xmss_params *params, +@@ -944,7 +1028,7 @@ int xmssmt_core_sign(const xmss_params *params, if (! (((idx + 1) & ((1ULL << ((i+1)*params->tree_height)) - 1)) == 0)) { idx_leaf = (idx >> (params->tree_height * i)) & ((1 << params->tree_height)-1); idx_tree = (idx >> (params->tree_height * (i+1))); @@ -1376,7 +2219,7 @@ index cbf87ec..7d75a22 100644 set_tree_addr(addr, idx_tree); if (i == (unsigned int) (needswap_upto + 1)) { bds_round(params, &states[i], idx_leaf, sk_seed, pub_seed, addr); -@@ -962,7 +1034,7 @@ int xmssmt_core_sign(const xmss_params *params, +@@ -962,7 +1046,7 @@ int xmssmt_core_sign(const xmss_params *params, else if (idx < (1ULL << params->full_height) - 1) { deep_state_swap(params, states+params->d + i, states + i); @@ -1385,7 +2228,7 @@ index cbf87ec..7d75a22 100644 set_tree_addr(ots_addr, ((idx + 1) >> ((i+2) * params->tree_height))); set_ots_addr(ots_addr, (((idx >> ((i+1) * params->tree_height)) + 1) & ((1 << params->tree_height)-1))); -@@ -972,17 +1044,15 @@ int xmssmt_core_sign(const xmss_params *params, +@@ -972,17 +1056,15 @@ int xmssmt_core_sign(const xmss_params *params, states[params->d + i].next_leaf = 0; updates--; // WOTS-signing counts as one update diff --git a/pq/stateful_hash_sig/Makefile b/pq/stateful_hash_sig/Makefile index 8924b11b..52c34244 100644 --- a/pq/stateful_hash_sig/Makefile +++ b/pq/stateful_hash_sig/Makefile @@ -10,6 +10,7 @@ LIBS = -L$(LIB_PATH)/lib -lm WOLF_DYN_LIB = -lwolfssl WOLF_STATIC_LIB = $(LIB_PATH)/lib/libwolfssl.a HSS_LIB = +XMSS_LIB = DEBUG_FLAGS = -g -DDEBUG DEBUG_INC_PATHS = -MD OPTIMIZE = -Os @@ -34,10 +35,10 @@ lms_example: lms_example.c $(CC) -o $@ $< $(CFLAGS) -I$(HSS_INC) $(LIBS) $(WOLF_STATIC_LIB) $(HSS_LIB) xmss_example: xmss_example.c - $(CC) -o $@ $< $(CFLAGS) -I$(XMSS_INC) $(LIBS) $(WOLF_DYN_LIB) + $(CC) -o $@ $< $(CFLAGS) -I$(XMSS_INC) $(LIBS) $(WOLF_STATIC_LIB) $(XMSS_LIB) xmss_example_verifyonly: xmss_example.c - $(CC) -o $@ $< $(CFLAGS) -I$(XMSS_INC) -DWOLFSSL_XMSS_VERIFY_ONLY $(LIBS) $(WOLF_DYN_LIB) + $(CC) -o $@ $< $(CFLAGS) -I$(XMSS_INC) -DWOLFSSL_XMSS_VERIFY_ONLY $(LIBS) $(WOLF_STATIC_LIB) $(XMSS_LIB) clean: rm -f $(TARGETS) diff --git a/pq/stateful_hash_sig/README.md b/pq/stateful_hash_sig/README.md index 0a1a3d01..a0d0031c 100644 --- a/pq/stateful_hash_sig/README.md +++ b/pq/stateful_hash_sig/README.md @@ -19,9 +19,9 @@ in the wolfSSL repo's INSTALL file. https://github.com/wolfSSL/wolfssl/blob/master/INSTALL The XMSS/XMSS^MT example requires that the xmss-reference repository has been -cloned and patched. Please see item 20 in the wolfSSL repo's INSTALL file. +cloned, patched, and built. Please see item 20 in the wolfSSL repo's INSTALL file. -The patch to use is `0001-Patch-to-support-xmss-reference-integration.patch` from this XMSS/XMSS^MT example. +The patch to use is `0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch` from this XMSS/XMSS^MT example. # Building the LMS/HSS example @@ -84,22 +84,11 @@ Configure the Makefile to point to your xmss install: XMSS_INC = ``` -Nothing more is needed after patching, as wolfSSL will automatically -build and link the xmss-reference objects it needs. - -Build wolfSSL XMSS/XMSS^MT hooks support with: - ``` -$ ./configure \ - --enable-xmss \ - --with-libxmss= -$ make +XMSS_LIB = ``` -Note that depending on your architecture you may add `--enable-intelasm` -or `--enable-armasm` to speedup the XMSS/XMSS^MT hash operations. - -Asumming wolfSSL has been built, you may finally build the xmss example with: +Then build: ``` $ make xmss_example @@ -110,7 +99,6 @@ Build the verify-only example with $ make xmss_example_verifyonly ``` - ## Signing and Verifying a Message with XMSS/XMSS^MT To see the help and usage, run the program without options: diff --git a/pq/stateful_hash_sig/xmss_example.c b/pq/stateful_hash_sig/xmss_example.c index 2707b9f1..0913d135 100644 --- a/pq/stateful_hash_sig/xmss_example.c +++ b/pq/stateful_hash_sig/xmss_example.c @@ -271,6 +271,8 @@ do_xmss_example(const char * params, goto exit_xmss_example; } + printf("making key with %s parameters...\n", params); + ret = wc_XmssKey_MakeKey(&signingKey, &rng); if (ret) { fprintf(stderr, "error: wc_XmssKey_MakeKey returned %d\n", ret); From 61571b3c80e1357fc419af9c7751f21268df361a Mon Sep 17 00:00:00 2001 From: philljj Date: Wed, 11 Oct 2023 15:07:08 -0500 Subject: [PATCH 3/4] Example for xmss hooks support: little more patch cleanup. --- ...t-wolfSSL-xmss-reference-integration.patch | 319 ++++++++++++++---- 1 file changed, 249 insertions(+), 70 deletions(-) diff --git a/pq/stateful_hash_sig/0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch b/pq/stateful_hash_sig/0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch index 975561d9..1f817510 100644 --- a/pq/stateful_hash_sig/0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch +++ b/pq/stateful_hash_sig/0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch @@ -1,19 +1,19 @@ -From 605ac49e4c4bcb65191c1c9bb821cbc31354e1e3 Mon Sep 17 00:00:00 2001 +From 12dd009393d254202d0dc26763c95e2a731d5e7e Mon Sep 17 00:00:00 2001 From: jordan -Date: Mon, 9 Oct 2023 11:31:08 -0500 +Date: Wed, 11 Oct 2023 14:59:47 -0500 Subject: [PATCH 1/1] Patch to support wolfSSL xmss-reference integration. --- - Makefile | 36 +++++- + Makefile | 29 ++++- fips202.c | 2 +- hash_address.c | 2 + params.h | 15 +++ randombytes.c | 2 + test/speed.c | 98 +++++++++++++-- test/wots.c | 77 ++++++++++++ - test/xmss.c | 135 +++++++++++++++------ - test/xmss_determinism.c | 77 ++++++++++++ - test/xmss_max_signatures.c | 72 +++++++++++ + test/xmss.c | 139 ++++++++++++++++------ + test/xmss_determinism.c | 95 +++++++++++++-- + test/xmss_max_signatures.c | 94 +++++++++++++-- hash.c => thash.c | 72 +++++++++-- hash.h => thash.h | 5 +- ui/keypair.c | 73 ++++++++++++ @@ -23,34 +23,37 @@ Subject: [PATCH 1/1] Patch to support wolfSSL xmss-reference integration. xmss_callbacks.h | 12 ++ xmss_commons.c | 77 ++++++++---- xmss_commons.h | 4 +- - xmss_core.c | 60 ++++++++-- + xmss_core.c | 115 ++++++++++++++---- xmss_core.h | 22 ++-- xmss_core_fast.c | 238 +++++++++++++++++++++++++------------ - 22 files changed, 957 insertions(+), 224 deletions(-) + 22 files changed, 1014 insertions(+), 259 deletions(-) rename hash.c => thash.c (79%) rename hash.h => thash.h (96%) create mode 100644 xmss_callbacks.h diff --git a/Makefile b/Makefile -index d1b95d5..599df68 100644 +index d1b95d5..9f72e6d 100644 --- a/Makefile +++ b/Makefile -@@ -1,9 +1,10 @@ +@@ -1,9 +1,13 @@ CC = /usr/bin/gcc -CFLAGS = -Wall -g -O3 -Wextra -Wpedantic -LDLIBS = -lcrypto +CFLAGS = -Wall -O2 -Wextra -Wpedantic +VERIFY_CFLAGS = -DXMSS_VERIFY_ONLY -Wall -O2 -Wextra -Wpedantic +LDLIBS = -lwolfssl ++# Alternate build settings to check for memory issues. ++#CC = clang ++#CFLAGS = -g -fsanitize=memory -Wall -Wextra -Wpedantic -SOURCES = params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss.c xmss_core.c xmss_commons.c utils.c -HEADERS = params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss.h xmss_core.h xmss_commons.h utils.h -+SOURCES = params.c thash.c fips202.c hash_address.c randombytes.c wots.c xmss.c xmss_core.c xmss_commons.c utils.c -+HEADERS = params.h thash.h fips202.h hash_address.h randombytes.h wots.h xmss.h xmss_core.h xmss_commons.h utils.h ++SOURCES = params.c thash.c hash_address.c randombytes.c wots.c xmss.c xmss_core.c xmss_commons.c utils.c ++HEADERS = params.h thash.h hash_address.h randombytes.h wots.h xmss.h xmss_core.h xmss_commons.h utils.h SOURCES_FAST = $(subst xmss_core.c,xmss_core_fast.c,$(SOURCES)) HEADERS_FAST = $(subst xmss_core.c,xmss_core_fast.c,$(HEADERS)) -@@ -83,7 +84,34 @@ ui/xmss_%: ui/%.c $(SOURCES) $(OBJS) $(HEADERS) +@@ -83,7 +87,24 @@ ui/xmss_%: ui/%.c $(SOURCES) $(OBJS) $(HEADERS) ui/xmssmt_%: ui/%.c $(SOURCES) $(OBJS) $(HEADERS) $(CC) -DXMSSMT $(CFLAGS) -o $@ $(SOURCES) $< $(LDLIBS) @@ -74,17 +77,7 @@ index d1b95d5..599df68 100644 + -$(RM) *.o + -$(RM) *.lo + -$(RM) xmss_lib.a -+ -+#%.o:%.c -+# @echo "[$(CC)] $@" -+# $(CC) -DXMSSMT -fPIC $(CFLAGS) -c -o $@ $< -+ -+#wolfcrypt_integration: params.lo thash.lo hash_address.lo wots.lo xmss.lo xmss_core_fast.lo xmss_commons.lo utils.lo -+# -+#%.lo:%.c -+# @echo "[$(CC)] $@" -+## $(CC) -fPIC $(CFLAGS) -c -o $@ $< -+# libtool --tag=CC --mode=compile $(CC) $(CFLAGS) -c $< ++ -$(RM) xmss_verify_lib.a diff --git a/fips202.c b/fips202.c index 5e36d66..4565782 100644 --- a/fips202.c @@ -424,7 +417,7 @@ index 8b2b6de..6192527 100644 + return 0; +} diff --git a/test/xmss.c b/test/xmss.c -index 3703759..675e4a5 100644 +index 3703759..f921920 100644 --- a/test/xmss.c +++ b/test/xmss.c @@ -4,9 +4,14 @@ @@ -455,7 +448,7 @@ index 3703759..675e4a5 100644 int main() { xmss_params params; -@@ -42,13 +53,30 @@ int main() +@@ -42,34 +53,55 @@ int main() unsigned char pk[XMSS_OID_LEN + params.pk_bytes]; unsigned char sk[XMSS_OID_LEN + params.sk_bytes]; @@ -466,8 +459,6 @@ index 3703759..675e4a5 100644 - unsigned long long mlen; + unsigned char *msg = malloc(XMSS_MLEN); + unsigned char *sig = malloc(params.sig_bytes); -+ unsigned long long siglen = params.sig_bytes; -+ unsigned long long msglen = XMSS_MLEN; + + ret = wc_InitRng(&rng); + if (ret != 0) { @@ -492,12 +483,19 @@ index 3703759..675e4a5 100644 XMSS_KEYPAIR(pk, sk, oid); -@@ -57,19 +85,19 @@ int main() + printf("Testing %d %s signatures.. \n", XMSS_SIGNATURES, XMSS_VARIANT); + for (i = 0; i < XMSS_SIGNATURES; i++) { ++ unsigned long long siglen = params.sig_bytes; ++ unsigned long long msglen = XMSS_MLEN; ++ printf(" - iteration #%d:\n", i); - XMSS_SIGN(sk, sm, &smlen, m, XMSS_MLEN); -+ XMSS_SIGN(sk, sig, &siglen, msg, XMSS_MLEN); ++ if (XMSS_SIGN(sk, sig, &siglen, msg, XMSS_MLEN)) { ++ printf(" sign failed!\n"); ++ ret = -1; ++ } - if (smlen != params.sig_bytes + XMSS_MLEN) { - printf(" X smlen incorrect [%llu != %u]!\n", @@ -518,7 +516,7 @@ index 3703759..675e4a5 100644 printf(" X verification failed!\n"); ret = -1; } -@@ -78,57 +106,96 @@ int main() +@@ -78,57 +110,96 @@ int main() } /* Test if the correct message was recovered. */ @@ -545,7 +543,7 @@ index 3703759..675e4a5 100644 /* Flip the first bit of the message. Should invalidate. */ - sm[smlen - 1] ^= 1; - if (!XMSS_SIGN_OPEN(mout, &mlen, sm, smlen, pk)) { -+ sig[siglen - 1] ^= 1; ++ msg[0] ^= 1; + if (!XMSS_SIGN_OPEN(msg, &msglen, sig, siglen, pk)) { printf(" X flipping a bit of m DID NOT invalidate signature!\n"); ret = -1; @@ -554,7 +552,7 @@ index 3703759..675e4a5 100644 printf(" flipping a bit of m invalidates signature.\n"); } - sm[smlen - 1] ^= 1; -+ sig[siglen - 1] ^= 1; ++ msg[0] ^= 1; #ifdef XMSS_TEST_INVALIDSIG int j; @@ -563,7 +561,7 @@ index 3703759..675e4a5 100644 - for (j = 0; j < (int)(smlen - XMSS_MLEN); j += params.n) { - sm[j] ^= 1; - if (!XMSS_SIGN_OPEN(mout, &mlen, sm, smlen, pk)) { -+ for (j = 0; j < (int)(siglen - XMSS_MLEN); j += params.n) { ++ for (j = 0; j < (int)(siglen); j += params.n) { + sig[j] ^= 1; + if (!XMSS_SIGN_OPEN(msg, &msglen, sig, siglen, pk)) { printf(" X flipping bit %d DID NOT invalidate sig + m!\n", j); @@ -576,7 +574,7 @@ index 3703759..675e4a5 100644 + sig[j] ^= 1; } - if (j >= (int)(smlen - XMSS_MLEN)) { -+ if (j >= (int)(siglen - XMSS_MLEN)) { ++ if (j >= (int)(siglen)) { printf(" changing any signature hash invalidates signature.\n"); } #endif @@ -638,7 +636,7 @@ index 3703759..675e4a5 100644 + return 0; +} diff --git a/test/xmss_determinism.c b/test/xmss_determinism.c -index 49629f8..a309157 100644 +index 49629f8..b985e5c 100644 --- a/test/xmss_determinism.c +++ b/test/xmss_determinism.c @@ -3,17 +3,47 @@ @@ -689,6 +687,43 @@ index 49629f8..a309157 100644 fprintf(stderr, "Testing if XMSS-SHA2_10_256 signing is deterministic.. "); +@@ -24,10 +54,10 @@ int main() + unsigned char sk[XMSS_OID_LEN + params.sk_bytes]; + unsigned char sk2[XMSS_OID_LEN + params.sk_bytes]; + +- unsigned char m[MLEN]; +- unsigned char sm[params.sig_bytes + MLEN]; +- unsigned char sm2[params.sig_bytes + MLEN]; +- unsigned long long smlen; ++ unsigned char msg[MLEN]; ++ unsigned char sig[params.sig_bytes]; ++ unsigned char sig2[params.sig_bytes]; ++ unsigned long long siglen = params.sig_bytes; + + xmss_keypair(pk, sk, oid); + +@@ -35,16 +65,16 @@ int main() + memcpy(sk2, sk, XMSS_OID_LEN + params.sk_bytes); + + /* Sign a random message (but twice the same one). */ +- randombytes(m, MLEN); ++ randombytes(msg, MLEN); + +- xmss_sign(sk, sm, &smlen, m, MLEN); +- xmss_sign(sk2, sm2, &smlen, m, MLEN); ++ xmss_sign(sk, sig, &siglen, msg, MLEN); ++ xmss_sign(sk2, sig2, &siglen, msg, MLEN); + + /* Compare signature, and, if applicable, print the differences. */ +- if (memcmp(sm, sm2, params.sig_bytes + MLEN)) { ++ if (memcmp(sig, sig2, params.sig_bytes)) { + fprintf(stderr, "signatures differ!\n"); + for (i = 0; i < params.sig_bytes + MLEN; i++) { +- fprintf(stderr, (sm[i] != sm2[i] ? "x" : ".")); ++ fprintf(stderr, (sig[i] != sig2[i] ? "x" : ".")); + } + fprintf(stderr, "\n"); + return -1; @@ -55,3 +85,50 @@ int main() return 0; @@ -741,7 +776,7 @@ index 49629f8..a309157 100644 + return 0; +} diff --git a/test/xmss_max_signatures.c b/test/xmss_max_signatures.c -index d4a45a4..b1432da 100644 +index d4a45a4..2442ec0 100644 --- a/test/xmss_max_signatures.c +++ b/test/xmss_max_signatures.c @@ -5,9 +5,14 @@ @@ -759,11 +794,86 @@ index d4a45a4..b1432da 100644 #define XMSS_MLEN 32 // #ifndef XMSS_SIGNATURES -@@ -32,6 +37,55 @@ +@@ -32,6 +37,12 @@ #define XMSS_SIGNATURES (1 << 10) #endif ++static int rng_cb(void * output, size_t length); ++static int sha256_cb(const unsigned char *in, unsigned long long inlen, ++ unsigned char *out); ++ +static WC_RNG rng; ++ + int main() + { + xmss_params params; +@@ -46,14 +57,31 @@ int main() + + unsigned char pk[XMSS_OID_LEN + params.pk_bytes]; + unsigned char sk[XMSS_OID_LEN + params.sk_bytes]; +- unsigned char *m = malloc(XMSS_MLEN); +- unsigned char *sm = malloc(params.sig_bytes + XMSS_MLEN); +- unsigned char *mout = malloc(params.sig_bytes + XMSS_MLEN); +- unsigned long long smlen; ++ unsigned char *msg = malloc(XMSS_MLEN); ++ unsigned char *sig = malloc(params.sig_bytes); ++ unsigned long long siglen = params.sig_bytes; + unsigned long long idx; + unsigned long long j; + +- randombytes(m, XMSS_MLEN); ++ ret = wc_InitRng(&rng); ++ if (ret != 0) { ++ printf("error: init rng failed: %d\n", ret); ++ return -1; ++ } ++ ++ ret = xmss_set_sha_cb(sha256_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_sha_cb failed"); ++ return -1; ++ } ++ ++ ret = xmss_set_rng_cb(rng_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_rng_cb failed"); ++ return -1; ++ } ++ ++ randombytes(msg, XMSS_MLEN); + + XMSS_KEYPAIR(pk, sk, oid); + +@@ -63,7 +91,7 @@ int main() + if( (i & 1023) == 0) + printf(" - iteration #%d:\n", i); + +- return_code = XMSS_SIGN(sk, sm, &smlen, m, XMSS_MLEN); ++ return_code = XMSS_SIGN(sk, sig, &siglen, msg, XMSS_MLEN); + + if (return_code != 0) { + printf(" Error! Return code was %d\n",return_code); +@@ -75,7 +103,7 @@ int main() + for (; i < (XMSS_SIGNATURES) + 2; i++) { + printf(" - iteration #%d:\n", i); + +- return_code = XMSS_SIGN(sk, sm, &smlen, m, XMSS_MLEN); ++ return_code = XMSS_SIGN(sk, sig, &siglen, msg, XMSS_MLEN); + + if (return_code == 0) { + printf(" Error! Return code was %d\n",return_code); +@@ -94,9 +122,55 @@ int main() + printf("\n"); + } + +- free(m); +- free(sm); +- free(mout); ++ free(msg); ++ free(sig); + + return ret; + } + +static int rng_cb(void * output, size_t length) +{ @@ -811,35 +921,6 @@ index d4a45a4..b1432da 100644 + + return 0; +} -+ - int main() - { - xmss_params params; -@@ -53,6 +107,24 @@ int main() - unsigned long long idx; - unsigned long long j; - -+ ret = wc_InitRng(&rng); -+ if (ret != 0) { -+ printf("error: init rng failed: %d\n", ret); -+ return -1; -+ } -+ -+ ret = xmss_set_sha_cb(sha256_cb); -+ if (ret != 0) { -+ printf("error: xmss_set_sha_cb failed"); -+ return -1; -+ } -+ -+ ret = xmss_set_rng_cb(rng_cb); -+ if (ret != 0) { -+ printf("error: xmss_set_rng_cb failed"); -+ return -1; -+ } -+ - randombytes(m, XMSS_MLEN); - - XMSS_KEYPAIR(pk, sk, oid); diff --git a/hash.c b/thash.c similarity index 79% rename from hash.c @@ -1569,7 +1650,7 @@ index 9d9f077..33dbffe 100644 const unsigned char *pk); #endif diff --git a/xmss_core.c b/xmss_core.c -index af9f8d1..e80175b 100644 +index af9f8d1..70fe403 100644 --- a/xmss_core.c +++ b/xmss_core.c @@ -2,15 +2,47 @@ @@ -1665,7 +1746,7 @@ index af9f8d1..e80175b 100644 } /* -@@ -169,8 +205,15 @@ int xmssmt_core_keypair(const xmss_params *params, +@@ -169,21 +205,35 @@ int xmssmt_core_keypair(const xmss_params *params, unsigned char *pk, unsigned char *sk) { unsigned char seed[3 * params->n]; @@ -1682,7 +1763,105 @@ index af9f8d1..e80175b 100644 xmssmt_core_seed_keypair(params, pk, sk, seed); return 0; -@@ -271,3 +314,4 @@ int xmssmt_core_sign(const xmss_params *params, + } + ++ + /** +- * Signs a message. Returns an array containing the signature followed by the +- * message and an updated secret key. ++ * Signs a message. ++ * Returns ++ * 1. an array containing the signature AND ++ * 2. an updated secret key! ++ * ++ * Note: in WOLFBOOT_SIGN_XMSS build, the max allowed message length (msglen) ++ * is XMSS_SHA256_MAX_MSG_LEN. This is to facilitate having a manageable small ++ * static array, rather than a variable length array, for the message hash. + */ + int xmssmt_core_sign(const xmss_params *params, + unsigned char *sk, +- unsigned char *sm, unsigned long long *smlen, +- const unsigned char *m, unsigned long long mlen) ++ unsigned char *sig, unsigned long long *siglen, ++ const unsigned char *msg, unsigned long long msglen) + { + const unsigned char *sk_seed = sk + params->index_bytes; + const unsigned char *sk_prf = sk + params->index_bytes + params->n; +@@ -197,13 +247,30 @@ int xmssmt_core_sign(const xmss_params *params, + unsigned int i; + uint32_t idx_leaf; + ++#if defined WOLFBOOT_SIGN_XMSS ++ unsigned char m_with_prefix[XMSS_SHA256_MAX_MSG_HASH_LEN]; ++#else ++ unsigned char m_with_prefix[msglen + params->padding_len + 3*params->n]; ++#endif ++ ++#if defined WOLFBOOT_SIGN_XMSS ++ if (msglen > XMSS_SHA256_MAX_MSG_LEN) { ++ return -1; ++ } ++#endif ++ ++ if (*siglen != params->sig_bytes) { ++ /* Some inconsistency has happened. */ ++ return -1; ++ } ++ + uint32_t ots_addr[8] = {0}; + set_type(ots_addr, XMSS_ADDR_TYPE_OTS); + + /* Already put the message in the right place, to make it easier to prepend + * things when computing the hash over the message. */ +- memcpy(sm + params->sig_bytes, m, mlen); +- *smlen = params->sig_bytes + mlen; ++ memset(m_with_prefix, 0, sizeof(m_with_prefix)); ++ memcpy(m_with_prefix + params->padding_len + 3*params->n, msg, msglen); + + /* Read and use the current index from the secret key. */ + idx = (unsigned long)bytes_to_ull(sk, params->index_bytes); +@@ -230,7 +297,7 @@ int xmssmt_core_sign(const xmss_params *params, + return -2; // We already used all one-time keys + } + +- memcpy(sm, sk, params->index_bytes); ++ memcpy(sig, sk, params->index_bytes); + + /************************************************************************* + * THIS IS WHERE PRODUCTION IMPLEMENTATIONS WOULD UPDATE THE SECRET KEY. * +@@ -240,13 +307,12 @@ int xmssmt_core_sign(const xmss_params *params, + + /* Compute the digest randomization value. */ + ull_to_bytes(idx_bytes_32, 32, idx); +- prf(params, sm + params->index_bytes, idx_bytes_32, sk_prf); ++ prf(params, sig + params->index_bytes, idx_bytes_32, sk_prf); + + /* Compute the message hash. */ +- hash_message(params, mhash, sm + params->index_bytes, pub_root, idx, +- sm + params->sig_bytes - params->padding_len - 3*params->n, +- mlen); +- sm += params->index_bytes + params->n; ++ hash_message(params, mhash, sig + params->index_bytes, pub_root, idx, ++ m_with_prefix, msglen); ++ sig += params->index_bytes + params->n; + + set_type(ots_addr, XMSS_ADDR_TYPE_OTS); + +@@ -261,13 +327,14 @@ int xmssmt_core_sign(const xmss_params *params, + /* Compute a WOTS signature. */ + /* Initially, root = mhash, but on subsequent iterations it is the root + of the subtree below the currently processed subtree. */ +- wots_sign(params, sm, root, sk_seed, pub_seed, ots_addr); +- sm += params->wots_sig_bytes; ++ wots_sign(params, sig, root, sk_seed, pub_seed, ots_addr); ++ sig += params->wots_sig_bytes; + + /* Compute the authentication path for the used WOTS leaf. */ +- treehash(params, root, sm, sk_seed, pub_seed, idx_leaf, ots_addr); +- sm += params->tree_height*params->n; ++ treehash(params, root, sig, sk_seed, pub_seed, idx_leaf, ots_addr); ++ sig += params->tree_height*params->n; + } return 0; } From 37aad60e2563a72f104b4ad554e0b63480a72cc8 Mon Sep 17 00:00:00 2001 From: philljj Date: Fri, 13 Oct 2023 13:41:02 -0500 Subject: [PATCH 4/4] Example for xmss hooks support: include an addendum patch readme. --- ...t-wolfSSL-xmss-reference-integration.patch | 639 ++++++++++++------ pq/stateful_hash_sig/README.md | 1 + 2 files changed, 431 insertions(+), 209 deletions(-) diff --git a/pq/stateful_hash_sig/0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch b/pq/stateful_hash_sig/0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch index 1f817510..054d62f1 100644 --- a/pq/stateful_hash_sig/0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch +++ b/pq/stateful_hash_sig/0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch @@ -1,33 +1,37 @@ -From 12dd009393d254202d0dc26763c95e2a731d5e7e Mon Sep 17 00:00:00 2001 +From 99503968a914ed74693eb0e10199fe3cfa83d652 Mon Sep 17 00:00:00 2001 From: jordan -Date: Wed, 11 Oct 2023 14:59:47 -0500 +Date: Fri, 13 Oct 2023 13:29:46 -0500 Subject: [PATCH 1/1] Patch to support wolfSSL xmss-reference integration. --- - Makefile | 29 ++++- + Makefile | 29 +++- fips202.c | 2 +- hash_address.c | 2 + - params.h | 15 +++ + params.h | 15 ++ + patch_readme.md | 42 ++++++ randombytes.c | 2 + - test/speed.c | 98 +++++++++++++-- - test/wots.c | 77 ++++++++++++ - test/xmss.c | 139 ++++++++++++++++------ - test/xmss_determinism.c | 95 +++++++++++++-- - test/xmss_max_signatures.c | 94 +++++++++++++-- - hash.c => thash.c | 72 +++++++++-- + test/oid.c | 2 +- + test/speed.c | 103 ++++++++++++-- + test/vectors.c | 4 +- + test/wots.c | 79 ++++++++++- + test/xmss.c | 141 ++++++++++++++----- + test/xmss_determinism.c | 97 +++++++++++-- + test/xmss_max_signatures.c | 102 ++++++++++++-- + hash.c => thash.c | 72 ++++++---- hash.h => thash.h | 5 +- - ui/keypair.c | 73 ++++++++++++ - wots.c | 31 ++++- - xmss.c | 41 ++++--- - xmss.h | 30 ++--- + ui/keypair.c | 73 ++++++++++ + wots.c | 33 ++++- + xmss.c | 49 +++---- + xmss.h | 48 +++---- xmss_callbacks.h | 12 ++ - xmss_commons.c | 77 ++++++++---- + xmss_commons.c | 77 +++++++---- xmss_commons.h | 4 +- - xmss_core.c | 115 ++++++++++++++---- - xmss_core.h | 22 ++-- - xmss_core_fast.c | 238 +++++++++++++++++++++++++------------ - 22 files changed, 1014 insertions(+), 259 deletions(-) - rename hash.c => thash.c (79%) + xmss_core.c | 135 +++++++++++++----- + xmss_core.h | 22 +-- + xmss_core_fast.c | 276 ++++++++++++++++++++++++------------- + 25 files changed, 1099 insertions(+), 327 deletions(-) + create mode 100644 patch_readme.md + rename hash.c => thash.c (82%) rename hash.h => thash.h (96%) create mode 100644 xmss_callbacks.h @@ -129,6 +133,54 @@ index 58c0619..c55ebaf 100644 /* These are merely internal identifiers for the supported hash functions. */ #define XMSS_SHA2 0 #define XMSS_SHAKE128 1 +diff --git a/patch_readme.md b/patch_readme.md +new file mode 100644 +index 0000000..a870353 +--- /dev/null ++++ b/patch_readme.md +@@ -0,0 +1,42 @@ ++# Addendum readme for the wolfssl xmss-reference integration patch ++ ++This patch contains a number of changes that were primarily motivated to ++facilitate wolfBoot XMSS support for embedded-targets. Specifically, the ++following changes have been made: ++ ++- All variable-length arrays (VLAs) necessary have been guarded with the define ++ `WOLFBOOT_SIGN_XMSS`, and replaced with static compile-time constant arrays, ++ with constants such as `XMSS_SHA256_WOTS_LEN` that have been defined in `params.h`. ++ They assume that the choice of SHA256 as the hashing function is a compile ++ time constant, and the function `core_hash()` has been updated to reflect this. ++ The param parsing logic in `params.c` has not been touched though, to allow for ++ in the future changing the underlying hash function at compile time if desired. ++- The signing and verifying APIs (`xmss_sign()`, `xmssmt_sign()`,`xmss_sign_open()`, ++ `xmssmt_sign_open()`) have been updated so that the message and signature are ++ passed as separate args, rather than a concatenated array. Additionally, for ++ wolfBoot builds the message length has been restricted to the compile time ++ constant of `XMSS_SHA256_MAX_MSG_LEN`. The appropriate APIs have had their ++ comments updates, and include an additional comment explaining this: ++``` ++ * Note: in WOLFBOOT_SIGN_XMSS build, the max allowed message length (msglen) ++ * is XMSS_SHA256_MAX_MSG_LEN. This is to facilitate having a manageable small ++ * static array, rather than a variable length array, for the message hash. ++``` ++- SHA256 and RNG operations are handled by registered callback functions. See ++ the header `xmss_callbacks.h` for the callback setter functions. This allows ++ offloading of SHA and RNG operations to wolfCrypt. ++- The tree-hash sources `hash.c` and `hash.h` were renamed to `thash.[c,h]`, to ++ avoid potential confusion with similarly named targets in wolfBoot. ++- The `Makefile` has been updated to build static libraries `xmss_lib.a`, ++ and `xmss_verify_lib.a`. The `xmss_verify_lib.a` is a verify-only build, ++ with an additional define `XMSS_VERIFY_ONLY` that guards out keygen ++ and signing functions. ++- The `Makefile` has been updated to link against wolfSSL `LDLIBS = -lwolfssl` ++ for the building of the tests in `test/`. The linking is *not* done for ++ building the static libs though, to avoid a circular dependency. Linking with ++ wolfssl to build the static libs is not necessary because the RNG and SHA ++ operations are provided by setting callbacks. ++- The tests in `test/` have been updated to reflect these changes. ++- Some minor changes were made to fix warnings from clang `-fsanitize=memory`. ++- Some minor cosmetic changes were made (cleanup trailing space, wrap long lines, ++ etc). diff --git a/randombytes.c b/randombytes.c index bfc8d93..ba4d7ac 100644 --- a/randombytes.c @@ -142,8 +194,21 @@ index bfc8d93..ba4d7ac 100644 static int fd = -1; void randombytes(unsigned char *x, unsigned long long xlen) +diff --git a/test/oid.c b/test/oid.c +index 6c51032..5daf5d1 100644 +--- a/test/oid.c ++++ b/test/oid.c +@@ -22,7 +22,7 @@ + return -1;\ + } + +-int main() ++int main(void) + { + uint32_t oid; + xmss_params params; diff --git a/test/speed.c b/test/speed.c -index 6ae58b0..93d7d3c 100644 +index 6ae58b0..80758ec 100644 --- a/test/speed.c +++ b/test/speed.c @@ -4,8 +4,13 @@ @@ -160,19 +225,114 @@ index 6ae58b0..93d7d3c 100644 #define XMSS_MLEN 32 #ifndef XMSS_SIGNATURES -@@ -34,6 +39,8 @@ +@@ -34,6 +39,12 @@ #endif #endif ++static int rng_cb(void * output, size_t length); ++static int sha256_cb(const unsigned char *in, unsigned long long inlen, ++ unsigned char *out); ++ +static WC_RNG rng; + static unsigned long long cpucycles(void) { unsigned long long result; -@@ -78,6 +85,53 @@ static void print_results(unsigned long long *t, size_t tlen) +@@ -78,7 +89,7 @@ static void print_results(unsigned long long *t, size_t tlen) printf("\n"); } +-int main() ++int main(void) + { + /* Make stdout buffer more responsive. */ + setbuf(stdout, NULL); +@@ -88,6 +99,24 @@ int main() + int ret = 0; + int i; + ++ ret = wc_InitRng(&rng); ++ if (ret != 0) { ++ printf("error: init rng failed: %d\n", ret); ++ return -1; ++ } ++ ++ ret = xmss_set_sha_cb(sha256_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_sha_cb failed"); ++ return -1; ++ } ++ ++ ret = xmss_set_rng_cb(rng_cb); ++ if (ret != 0) { ++ printf("error: xmss_set_rng_cb failed"); ++ return -1; ++ } ++ + // TODO test more different variants + if (XMSS_STR_TO_OID(&oid, XMSS_VARIANT)) { + #ifdef XMSSMT +@@ -101,18 +130,16 @@ int main() + + unsigned char pk[XMSS_OID_LEN + params.pk_bytes]; + unsigned char sk[XMSS_OID_LEN + params.sk_bytes]; +- unsigned char *m = malloc(XMSS_MLEN); +- unsigned char *sm = malloc(params.sig_bytes + XMSS_MLEN); +- unsigned char *mout = malloc(params.sig_bytes + XMSS_MLEN); +- unsigned long long smlen; +- unsigned long long mlen; ++ unsigned char *msg = malloc(XMSS_MLEN); ++ unsigned char *sig = malloc(params.sig_bytes); ++ unsigned long long siglen = params.sig_bytes; + + unsigned long long t0, t1; + unsigned long long *t = malloc(sizeof(unsigned long long) * XMSS_SIGNATURES); + struct timespec start, stop; + double result; + +- randombytes(m, XMSS_MLEN); ++ randombytes(msg, XMSS_MLEN); + + printf("Benchmarking variant %s\n", XMSS_VARIANT); + +@@ -130,15 +157,17 @@ int main() + + for (i = 0; i < XMSS_SIGNATURES; i++) { + t[i] = cpucycles(); +- XMSS_SIGN(sk, sm, &smlen, m, XMSS_MLEN); ++ XMSS_SIGN(sk, sig, &siglen, msg, XMSS_MLEN); + } + print_results(t, XMSS_SIGNATURES); + + printf("Verifying %d signatures..\n", XMSS_SIGNATURES); + + for (i = 0; i < XMSS_SIGNATURES; i++) { ++ unsigned long long msglen = XMSS_MLEN; ++ + t[i] = cpucycles(); +- ret |= XMSS_SIGN_OPEN(mout, &mlen, sm, smlen, pk); ++ ret |= XMSS_SIGN_OPEN(msg, &msglen, sig, siglen, pk); + } + print_results(t, XMSS_SIGNATURES); + +@@ -150,10 +179,58 @@ int main() + printf("Public key size: %d (%.2f KiB)\n", params.pk_bytes, params.pk_bytes / 1024.0); + printf("Secret key size: %llu (%.2f KiB)\n", params.sk_bytes, params.sk_bytes / 1024.0); + +- free(m); +- free(sm); +- free(mout); ++ wc_FreeRng(&rng); ++ ++ free(msg); ++ free(sig); + free(t); + + return ret; +-} +\ No newline at end of file ++} ++ +static int rng_cb(void * output, size_t length) +{ + int ret = 0; @@ -219,98 +379,27 @@ index 6ae58b0..93d7d3c 100644 + + return 0; +} -+ - int main() - { - /* Make stdout buffer more responsive. */ -@@ -88,6 +142,24 @@ int main() - int ret = 0; - int i; +diff --git a/test/vectors.c b/test/vectors.c +index f21ed6a..f5f5547 100644 +--- a/test/vectors.c ++++ b/test/vectors.c +@@ -1,4 +1,4 @@ +-/* ++/* + * Generate intermediate test vectors useful to test implementations. + */ -+ ret = wc_InitRng(&rng); -+ if (ret != 0) { -+ printf("error: init rng failed: %d\n", ret); -+ return -1; -+ } -+ -+ ret = xmss_set_sha_cb(sha256_cb); -+ if (ret != 0) { -+ printf("error: xmss_set_sha_cb failed"); -+ return -1; -+ } -+ -+ ret = xmss_set_rng_cb(rng_cb); -+ if (ret != 0) { -+ printf("error: xmss_set_rng_cb failed"); -+ return -1; -+ } -+ - // TODO test more different variants - if (XMSS_STR_TO_OID(&oid, XMSS_VARIANT)) { - #ifdef XMSSMT -@@ -101,18 +173,18 @@ int main() +@@ -111,7 +111,7 @@ void vectors_wots(uint32_t oid) { + printf("\n"); + } - unsigned char pk[XMSS_OID_LEN + params.pk_bytes]; - unsigned char sk[XMSS_OID_LEN + params.sk_bytes]; -- unsigned char *m = malloc(XMSS_MLEN); -- unsigned char *sm = malloc(params.sig_bytes + XMSS_MLEN); -- unsigned char *mout = malloc(params.sig_bytes + XMSS_MLEN); -- unsigned long long smlen; -- unsigned long long mlen; -+ unsigned char *msg = malloc(XMSS_MLEN); -+ unsigned char *sig = malloc(params.sig_bytes); -+ unsigned char *msgout = malloc(XMSS_MLEN); -+ unsigned long long siglen; -+ unsigned long long msglen; - - unsigned long long t0, t1; - unsigned long long *t = malloc(sizeof(unsigned long long) * XMSS_SIGNATURES); - struct timespec start, stop; - double result; - -- randombytes(m, XMSS_MLEN); -+ randombytes(msg, XMSS_MLEN); - - printf("Benchmarking variant %s\n", XMSS_VARIANT); - -@@ -130,7 +202,7 @@ int main() - - for (i = 0; i < XMSS_SIGNATURES; i++) { - t[i] = cpucycles(); -- XMSS_SIGN(sk, sm, &smlen, m, XMSS_MLEN); -+ XMSS_SIGN(sk, sig, &siglen, msg, XMSS_MLEN); +-int main() { ++int main(void) { + for (uint32_t oid = 1; oid <= 0x15; oid += 3) { + vectors_wots(oid); } - print_results(t, XMSS_SIGNATURES); - -@@ -138,7 +210,7 @@ int main() - - for (i = 0; i < XMSS_SIGNATURES; i++) { - t[i] = cpucycles(); -- ret |= XMSS_SIGN_OPEN(mout, &mlen, sm, smlen, pk); -+ ret |= XMSS_SIGN_OPEN(msgout, &msglen, sig, siglen, pk); - } - print_results(t, XMSS_SIGNATURES); - -@@ -150,10 +222,12 @@ int main() - printf("Public key size: %d (%.2f KiB)\n", params.pk_bytes, params.pk_bytes / 1024.0); - printf("Secret key size: %llu (%.2f KiB)\n", params.sk_bytes, params.sk_bytes / 1024.0); - -- free(m); -- free(sm); -- free(mout); -+ wc_FreeRng(&rng); -+ -+ free(msg); -+ free(sig); -+ free(msgout); - free(t); - - return ret; --} -\ No newline at end of file -+} diff --git a/test/wots.c b/test/wots.c -index 8b2b6de..6192527 100644 +index 8b2b6de..fdaf369 100644 --- a/test/wots.c +++ b/test/wots.c @@ -3,14 +3,26 @@ @@ -321,6 +410,7 @@ index 8b2b6de..6192527 100644 #include "../randombytes.h" #include "../params.h" +-int main() +#include +#include +#include @@ -331,7 +421,7 @@ index 8b2b6de..6192527 100644 + +static WC_RNG rng; + - int main() ++int main(void) { xmss_params params; // TODO test more different OIDs @@ -417,7 +507,7 @@ index 8b2b6de..6192527 100644 + return 0; +} diff --git a/test/xmss.c b/test/xmss.c -index 3703759..f921920 100644 +index 3703759..a71a46a 100644 --- a/test/xmss.c +++ b/test/xmss.c @@ -4,9 +4,14 @@ @@ -435,19 +525,21 @@ index 3703759..f921920 100644 #define XMSS_MLEN 32 #ifndef XMSS_SIGNATURES -@@ -29,6 +34,12 @@ +@@ -29,7 +34,13 @@ #define XMSS_VARIANT "XMSS-SHA2_10_256" #endif +-int main() +static int rng_cb(void * output, size_t length); +static int sha256_cb(const unsigned char *in, unsigned long long inlen, + unsigned char *out); + +static WC_RNG rng; + - int main() ++int main(void) { xmss_params params; + uint32_t oid; @@ -42,34 +53,55 @@ int main() unsigned char pk[XMSS_OID_LEN + params.pk_bytes]; @@ -636,7 +728,7 @@ index 3703759..f921920 100644 + return 0; +} diff --git a/test/xmss_determinism.c b/test/xmss_determinism.c -index 49629f8..b985e5c 100644 +index 49629f8..1984f1e 100644 --- a/test/xmss_determinism.c +++ b/test/xmss_determinism.c @@ -3,17 +3,47 @@ @@ -653,13 +745,14 @@ index 49629f8..b985e5c 100644 + #define MLEN 32 +-int main() +static int rng_cb(void * output, size_t length); +static int sha256_cb(const unsigned char *in, unsigned long long inlen, + unsigned char *out); + +static WC_RNG rng; + - int main() ++int main(void) { xmss_params params; char *oidstr = "XMSS-SHA2_10_256"; @@ -776,7 +869,7 @@ index 49629f8..b985e5c 100644 + return 0; +} diff --git a/test/xmss_max_signatures.c b/test/xmss_max_signatures.c -index d4a45a4..2442ec0 100644 +index d4a45a4..be145b5 100644 --- a/test/xmss_max_signatures.c +++ b/test/xmss_max_signatures.c @@ -5,9 +5,14 @@ @@ -794,19 +887,21 @@ index d4a45a4..2442ec0 100644 #define XMSS_MLEN 32 // #ifndef XMSS_SIGNATURES -@@ -32,6 +37,12 @@ +@@ -32,7 +37,13 @@ #define XMSS_SIGNATURES (1 << 10) #endif +-int main() +static int rng_cb(void * output, size_t length); +static int sha256_cb(const unsigned char *in, unsigned long long inlen, + unsigned char *out); + +static WC_RNG rng; + - int main() ++int main(void) { xmss_params params; + uint32_t oid; @@ -46,14 +57,31 @@ int main() unsigned char pk[XMSS_OID_LEN + params.pk_bytes]; @@ -862,13 +957,26 @@ index d4a45a4..2442ec0 100644 if (return_code == 0) { printf(" Error! Return code was %d\n",return_code); -@@ -94,9 +122,55 @@ int main() +@@ -84,19 +112,65 @@ int main() + else { + printf("Return code as expected [%d].\n", return_code); + } +- ++ + idx = (unsigned long)bytes_to_ull(sk, params.index_bytes); + printf("Index: %llu\n", idx); + printf("Secret key: %llu\n", idx); + for (j = 0; j < XMSS_OID_LEN + params.sk_bytes;j++) + printf("%d ", sk[j]); +- ++ printf("\n"); } - +- - free(m); - free(sm); - free(mout); ++ + free(msg); + free(sig); @@ -922,10 +1030,10 @@ index d4a45a4..2442ec0 100644 + return 0; +} diff --git a/hash.c b/thash.c -similarity index 79% +similarity index 82% rename from hash.c rename to thash.c -index 6724d43..54e8954 100644 +index 6724d43..eb01946 100644 --- a/hash.c +++ b/thash.c @@ -1,12 +1,14 @@ @@ -946,7 +1054,7 @@ index 6724d43..54e8954 100644 #define XMSS_HASH_PADDING_F 0 #define XMSS_HASH_PADDING_H 1 -@@ -22,37 +24,67 @@ void addr_to_bytes(unsigned char *bytes, const uint32_t addr[8]) +@@ -22,37 +24,39 @@ void addr_to_bytes(unsigned char *bytes, const uint32_t addr[8]) } } @@ -968,61 +1076,47 @@ index 6724d43..54e8954 100644 - unsigned char buf[64]; + int ret = -1; +- if (params->n == 24 && params->func == XMSS_SHA2) { +- SHA256(in, inlen, buf); +- memcpy(out, buf, 24); +- } +- else if (params->n == 24 && params->func == XMSS_SHAKE256) { +- shake256(out, 24, in, inlen); +- } +- else if (params->n == 32 && params->func == XMSS_SHA2) { +- SHA256(in, inlen, out); +- } +- else if (params->n == 32 && params->func == XMSS_SHAKE128) { +- shake128(out, 32, in, inlen); +- } +- else if (params->n == 32 && params->func == XMSS_SHAKE256) { +- shake256(out, 32, in, inlen); +- } +- else if (params->n == 64 && params->func == XMSS_SHA2) { +- SHA512(in, inlen, out); + if (sha_cb == NULL) { + return -1; -+ } + } +- else if (params->n == 64 && params->func == XMSS_SHAKE256) { +- shake256(out, 64, in, inlen); + + if (params == NULL || out == NULL || in == NULL) { + return -1; -+ } + } +- else { + + /* The choice of SHA256 and n=32 is set at compile time. */ + if (params->n != XMSS_SHA256_N || params->func != XMSS_SHA2) { -+ return -1; -+ } -+ -+ ret = sha_cb(in, inlen, out); -+ -+/* - if (params->n == 24 && params->func == XMSS_SHA2) { -- SHA256(in, inlen, buf); -+ ret = sha_cb(in, inlen, out); - memcpy(out, buf, 24); - } - else if (params->n == 24 && params->func == XMSS_SHAKE256) { -- shake256(out, 24, in, inlen); -+ ret = shake256(out, 24, in, inlen); - } - else if (params->n == 32 && params->func == XMSS_SHA2) { -- SHA256(in, inlen, out); -+ ret = sha_cb(in, inlen, out); - } - else if (params->n == 32 && params->func == XMSS_SHAKE128) { -- shake128(out, 32, in, inlen); -+ ret = shake128(out, 32, in, inlen); - } - else if (params->n == 32 && params->func == XMSS_SHAKE256) { -- shake256(out, 32, in, inlen); -+ ret = shake256(out, 32, in, inlen); - } - else if (params->n == 64 && params->func == XMSS_SHA2) { -- SHA512(in, inlen, out); -+ ret = sha512(in, inlen, out); - } - else if (params->n == 64 && params->func == XMSS_SHAKE256) { -- shake256(out, 64, in, inlen); -+ ret = shake256(out, 64, in, inlen); - } - else { return -1; } -+*/ ++ ++ ret = sha_cb(in, inlen, out); + + if (ret != 0) { return ret; } return 0; } -@@ -63,7 +95,11 @@ int prf(const xmss_params *params, +@@ -63,7 +67,11 @@ int prf(const xmss_params *params, unsigned char *out, const unsigned char in[32], const unsigned char *key) { @@ -1034,7 +1128,7 @@ index 6724d43..54e8954 100644 ull_to_bytes(buf, params->padding_len, XMSS_HASH_PADDING_PRF); memcpy(buf + params->padding_len, key, params->n); -@@ -80,7 +116,11 @@ int prf_keygen(const xmss_params *params, +@@ -80,7 +88,11 @@ int prf_keygen(const xmss_params *params, unsigned char *out, const unsigned char *in, const unsigned char *key) { @@ -1046,7 +1140,7 @@ index 6724d43..54e8954 100644 ull_to_bytes(buf, params->padding_len, XMSS_HASH_PADDING_PRF_KEYGEN); memcpy(buf + params->padding_len, key, params->n); -@@ -118,8 +158,13 @@ int thash_h(const xmss_params *params, +@@ -118,8 +130,13 @@ int thash_h(const xmss_params *params, unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { @@ -1060,7 +1154,7 @@ index 6724d43..54e8954 100644 unsigned char addr_as_bytes[32]; unsigned int i; -@@ -150,8 +195,13 @@ int thash_f(const xmss_params *params, +@@ -150,8 +167,13 @@ int thash_f(const xmss_params *params, unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8]) { @@ -1198,7 +1292,7 @@ index 612c448..64dc067 100644 parse_oid_result = XMSS_PARSE_OID(¶ms, oid); if (parse_oid_result != 0) { diff --git a/wots.c b/wots.c -index d9c8449..825c2dc 100644 +index d9c8449..844940c 100644 --- a/wots.c +++ b/wots.c @@ -2,7 +2,7 @@ @@ -1210,7 +1304,12 @@ index d9c8449..825c2dc 100644 #include "wots.h" #include "hash_address.h" #include "params.h" -@@ -16,7 +16,11 @@ static void expand_seed(const xmss_params *params, +@@ -12,11 +12,15 @@ + * Expands an n-byte array into a len*n byte array using the `prf_keygen` function. + */ + static void expand_seed(const xmss_params *params, +- unsigned char *outseeds, const unsigned char *inseed, ++ unsigned char *outseeds, const unsigned char *inseed, const unsigned char *pub_seed, uint32_t addr[8]) { uint32_t i; @@ -1278,7 +1377,7 @@ index d9c8449..825c2dc 100644 chain_lengths(params, lengths, msg); diff --git a/xmss.c b/xmss.c -index 9030f6e..dbae7e5 100644 +index 9030f6e..b5f5168 100644 --- a/xmss.c +++ b/xmss.c @@ -1,5 +1,6 @@ @@ -1296,10 +1395,24 @@ index 9030f6e..dbae7e5 100644 int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) { xmss_params params; -@@ -42,23 +44,6 @@ int xmss_sign(unsigned char *sk, - return xmss_core_sign(¶ms, sk + XMSS_OID_LEN, sm, smlen, m, mlen); +@@ -26,8 +28,8 @@ int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) } + int xmss_sign(unsigned char *sk, +- unsigned char *sm, unsigned long long *smlen, +- const unsigned char *m, unsigned long long mlen) ++ unsigned char *sig, unsigned long long *siglen, ++ const unsigned char *msg, unsigned long long msglen) + { + xmss_params params; + uint32_t oid = 0; +@@ -39,24 +41,7 @@ int xmss_sign(unsigned char *sk, + if (xmss_parse_oid(¶ms, oid)) { + return -1; + } +- return xmss_core_sign(¶ms, sk + XMSS_OID_LEN, sm, smlen, m, mlen); +-} +- -int xmss_sign_open(unsigned char *m, unsigned long long *mlen, - const unsigned char *sm, unsigned long long smlen, - const unsigned char *pk) @@ -1315,19 +1428,18 @@ index 9030f6e..dbae7e5 100644 - return -1; - } - return xmss_core_sign_open(¶ms, m, mlen, sm, smlen, pk + XMSS_OID_LEN); --} -- ++ return xmss_core_sign(¶ms, sk + XMSS_OID_LEN, sig, siglen, msg, msglen); + } + int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) - { - xmss_params params; -@@ -90,8 +75,26 @@ int xmssmt_sign(unsigned char *sk, +@@ -90,9 +75,27 @@ int xmssmt_sign(unsigned char *sk, } return xmssmt_core_sign(¶ms, sk + XMSS_OID_LEN, sm, smlen, m, mlen); } +#endif /* ifndef XMSS_VERIFY_ONLY */ + +int xmss_sign_open(const unsigned char *msg, unsigned long long *msglen, -+ const unsigned char *sm, unsigned long long smlen, ++ const unsigned char *sig, unsigned long long siglen, + const unsigned char *pk) +{ + xmss_params params; @@ -1340,23 +1452,25 @@ index 9030f6e..dbae7e5 100644 + if (xmss_parse_oid(¶ms, oid)) { + return -1; + } -+ return xmss_core_sign_open(¶ms, msg, msglen, sm, smlen, pk + XMSS_OID_LEN); ++ return xmss_core_sign_open(¶ms, msg, msglen, sig, siglen, pk + XMSS_OID_LEN); +} -int xmssmt_sign_open(unsigned char *m, unsigned long long *mlen, +- const unsigned char *sm, unsigned long long smlen, +int xmssmt_sign_open(const unsigned char *msg, unsigned long long *msglen, - const unsigned char *sm, unsigned long long smlen, ++ const unsigned char *sig, unsigned long long siglen, const unsigned char *pk) { + xmss_params params; @@ -105,5 +108,5 @@ int xmssmt_sign_open(unsigned char *m, unsigned long long *mlen, if (xmssmt_parse_oid(¶ms, oid)) { return -1; } - return xmssmt_core_sign_open(¶ms, m, mlen, sm, smlen, pk + XMSS_OID_LEN); -+ return xmssmt_core_sign_open(¶ms, msg, msglen, sm, smlen, pk + XMSS_OID_LEN); ++ return xmssmt_core_sign_open(¶ms, msg, msglen, sig, siglen, pk + XMSS_OID_LEN); } diff --git a/xmss.h b/xmss.h -index c7b4b69..199ce88 100644 +index c7b4b69..b2b3980 100644 --- a/xmss.h +++ b/xmss.h @@ -3,6 +3,7 @@ @@ -1367,7 +1481,7 @@ index c7b4b69..199ce88 100644 /** * Generates a XMSS key pair for a given parameter set. * Format sk: [OID || (32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] -@@ -13,24 +14,13 @@ int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid); +@@ -13,23 +14,12 @@ int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid); /** * Signs a message using an XMSS secret key. * Returns @@ -1376,9 +1490,9 @@ index c7b4b69..199ce88 100644 * 2. an updated secret key! */ int xmss_sign(unsigned char *sk, - unsigned char *sm, unsigned long long *smlen, - const unsigned char *m, unsigned long long mlen); - +- unsigned char *sm, unsigned long long *smlen, +- const unsigned char *m, unsigned long long mlen); +- -/** - * Verifies a given message signature pair using a given public key. - * @@ -1389,11 +1503,12 @@ index c7b4b69..199ce88 100644 -int xmss_sign_open(unsigned char *m, unsigned long long *mlen, - const unsigned char *sm, unsigned long long smlen, - const unsigned char *pk); -- ++ unsigned char *sig, unsigned long long *siglen, ++ const unsigned char *msg, unsigned long long msglen); + /* * Generates a XMSSMT key pair for a given parameter set. - * Format sk: [OID || (ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] -@@ -41,12 +31,24 @@ int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid); +@@ -41,21 +31,33 @@ int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid); /** * Signs a message using an XMSSMT secret key. * Returns @@ -1402,30 +1517,38 @@ index c7b4b69..199ce88 100644 * 2. an updated secret key! */ int xmssmt_sign(unsigned char *sk, - unsigned char *sm, unsigned long long *smlen, - const unsigned char *m, unsigned long long mlen); +- unsigned char *sm, unsigned long long *smlen, +- const unsigned char *m, unsigned long long mlen); ++ unsigned char *sig, unsigned long long *siglen, ++ const unsigned char *msg, unsigned long long msglen); +#endif /* ifndef XMSS_VERIFY_ONLY */ + +/** -+ * Verifies a given message signature pair using a given public key. ++ * Verifies a given signature using a given public key. + * -+ * Note: m and mlen are pure outputs which carry the message in case -+ * verification succeeds. The (input) message is assumed to be contained in sm -+ * which has the form [signature || message]. ++ * - msg is the input message of length msglen. ++ * - sig is the signature to verify, of length siglen. ++ * - pk is the public key without an OID. + */ +int xmss_sign_open(const unsigned char *msg, unsigned long long *msglen, -+ const unsigned char *sm, unsigned long long smlen, ++ const unsigned char *sig, unsigned long long siglen, + const unsigned char *pk); /** - * Verifies a given message signature pair using a given public key. -@@ -55,7 +57,7 @@ int xmssmt_sign(unsigned char *sk, - * verification succeeds. The (input) message is assumed to be contained in sm - * which has the form [signature || message]. +- * Verifies a given message signature pair using a given public key. ++ * Verifies a given signature using a given public key. + * +- * Note: m and mlen are pure outputs which carry the message in case +- * verification succeeds. The (input) message is assumed to be contained in sm +- * which has the form [signature || message]. ++ * - msg is the input message of length msglen. ++ * - sig is the signature to verify, of length siglen. ++ * - pk is the public key without an OID. */ -int xmssmt_sign_open(unsigned char *m, unsigned long long *mlen, +- const unsigned char *sm, unsigned long long smlen, +int xmssmt_sign_open(const unsigned char *msg, unsigned long long *msglen, - const unsigned char *sm, unsigned long long smlen, ++ const unsigned char *sig, unsigned long long siglen, const unsigned char *pk); #endif diff --git a/xmss_callbacks.h b/xmss_callbacks.h @@ -1650,7 +1773,7 @@ index 9d9f077..33dbffe 100644 const unsigned char *pk); #endif diff --git a/xmss_core.c b/xmss_core.c -index af9f8d1..70fe403 100644 +index af9f8d1..7e76564 100644 --- a/xmss_core.c +++ b/xmss_core.c @@ -2,15 +2,47 @@ @@ -1787,7 +1910,7 @@ index af9f8d1..70fe403 100644 { const unsigned char *sk_seed = sk + params->index_bytes; const unsigned char *sk_prf = sk + params->index_bytes + params->n; -@@ -197,13 +247,30 @@ int xmssmt_core_sign(const xmss_params *params, +@@ -197,28 +247,45 @@ int xmssmt_core_sign(const xmss_params *params, unsigned int i; uint32_t idx_leaf; @@ -1820,11 +1943,40 @@ index af9f8d1..70fe403 100644 /* Read and use the current index from the secret key. */ idx = (unsigned long)bytes_to_ull(sk, params->index_bytes); -@@ -230,7 +297,7 @@ int xmssmt_core_sign(const xmss_params *params, +- ++ + /* Check if we can still sign with this sk. + * If not, return -2 +- * +- * If this is the last possible signature (because the max index value +- * is reached), production implementations should delete the secret key ++ * ++ * If this is the last possible signature (because the max index value ++ * is reached), production implementations should delete the secret key + * to prevent accidental further use. +- * +- * For the case of total tree height of 64 we do not use the last signature +- * to be on the safe side (there is no index value left to indicate that the ++ * ++ * For the case of total tree height of 64 we do not use the last signature ++ * to be on the safe side (there is no index value left to indicate that the + * key is finished, hence external handling would be necessary) +- */ ++ */ + if (idx >= ((1ULL << params->full_height) - 1)) { + // Delete secret key here. We only do this in memory, production code + // has to make sure that this happens on disk. +@@ -226,11 +293,11 @@ int xmssmt_core_sign(const xmss_params *params, + memset(sk + params->index_bytes, 0, (params->sk_bytes - params->index_bytes)); + if (idx > ((1ULL << params->full_height) - 1)) + return -2; // We already used all one-time keys +- if ((params->full_height == 64) && (idx == ((1ULL << params->full_height) - 1))) ++ if ((params->full_height == 64) && (idx == ((1ULL << params->full_height) - 1))) return -2; // We already used all one-time keys } - +- - memcpy(sm, sk, params->index_bytes); ++ + memcpy(sig, sk, params->index_bytes); /************************************************************************* @@ -1920,7 +2072,7 @@ index e83bc7d..21d72ef 100644 const unsigned char *pk); diff --git a/xmss_core_fast.c b/xmss_core_fast.c -index cbf87ec..1a71c07 100644 +index cbf87ec..0a31323 100644 --- a/xmss_core_fast.c +++ b/xmss_core_fast.c @@ -2,15 +2,19 @@ @@ -2135,17 +2287,50 @@ index cbf87ec..1a71c07 100644 // TODO refactor BDS state not to need separate treehash instances bds_state state; treehash_inst treehash[params->tree_height - params->bds_k]; -@@ -599,7 +651,9 @@ int xmss_core_sign(const xmss_params *params, +@@ -599,19 +651,21 @@ int xmss_core_sign(const xmss_params *params, xmss_deserialize_state(params, &state, sk); // Extract SK - unsigned long idx = ((unsigned long)sk[0] << 24) | ((unsigned long)sk[1] << 16) | ((unsigned long)sk[2] << 8) | sk[3]; +- + unsigned long idx = ((unsigned long)sk[0] << 24) | + ((unsigned long)sk[1] << 16) | + ((unsigned long)sk[2] << 8) | sk[3]; - ++ /* Check if we can still sign with this sk. * If not, return -2 +- * +- * If this is the last possible signature (because the max index value +- * is reached), production implementations should delete the secret key ++ * ++ * If this is the last possible signature (because the max index value ++ * is reached), production implementations should delete the secret key + * to prevent accidental further use. +- * +- * For the case of total tree height of 64 we do not use the last signature +- * to be on the safe side (there is no index value left to indicate that the ++ * ++ * For the case of total tree height of 64 we do not use the last signature ++ * to be on the safe side (there is no index value left to indicate that the + * key is finished, hence external handling would be necessary) +- */ ++ */ + if (idx >= ((1ULL << params->full_height) - 1)) { + // Delete secret key here. We only do this in memory, production code + // has to make sure that this happens on disk. +@@ -619,10 +673,10 @@ int xmss_core_sign(const xmss_params *params, + memset(sk + params->index_bytes, 0, (params->sk_bytes - params->index_bytes)); + if (idx > ((1ULL << params->full_height) - 1)) + return -2; // We already used all one-time keys +- if ((params->full_height == 64) && (idx == ((1ULL << params->full_height) - 1))) ++ if ((params->full_height == 64) && (idx == ((1ULL << params->full_height) - 1))) + return -2; // We already used all one-time keys + } +- ++ + unsigned char sk_seed[params->n]; + memcpy(sk_seed, sk + params->index_bytes, params->n); + unsigned char sk_prf[params->n]; @@ -658,32 +712,32 @@ int xmss_core_sign(const xmss_params *params, /* Already put the message in the right place, to make it easier to prepend @@ -2304,6 +2489,42 @@ index cbf87ec..1a71c07 100644 uint64_t idx_tree; uint32_t idx_leaf; uint64_t i, j; +@@ -824,15 +905,15 @@ int xmssmt_core_sign(const xmss_params *params, + + /* Check if we can still sign with this sk. + * If not, return -2 +- * +- * If this is the last possible signature (because the max index value +- * is reached), production implementations should delete the secret key ++ * ++ * If this is the last possible signature (because the max index value ++ * is reached), production implementations should delete the secret key + * to prevent accidental further use. +- * +- * For the case of total tree height of 64 we do not use the last signature +- * to be on the safe side (there is no index value left to indicate that the ++ * ++ * For the case of total tree height of 64 we do not use the last signature ++ * to be on the safe side (there is no index value left to indicate that the + * key is finished, hence external handling would be necessary) +- */ ++ */ + if (idx >= ((1ULL << params->full_height) - 1)) { + // Delete secret key here. We only do this in memory, production code + // has to make sure that this happens on disk. +@@ -840,10 +921,10 @@ int xmssmt_core_sign(const xmss_params *params, + memset(sk + params->index_bytes, 0, (params->sk_bytes - params->index_bytes)); + if (idx > ((1ULL << params->full_height) - 1)) + return -2; // We already used all one-time keys +- if ((params->full_height == 64) && (idx == ((1ULL << params->full_height) - 1))) ++ if ((params->full_height == 64) && (idx == ((1ULL << params->full_height) - 1))) + return -2; // We already used all one-time keys + } +- ++ + memcpy(sk_seed, sk+params->index_bytes, params->n); + memcpy(sk_prf, sk+params->index_bytes+params->n, params->n); + memcpy(pub_seed, sk+params->index_bytes+3*params->n, params->n); @@ -867,31 +948,34 @@ int xmssmt_core_sign(const xmss_params *params, /* Already put the message in the right place, to make it easier to prepend diff --git a/pq/stateful_hash_sig/README.md b/pq/stateful_hash_sig/README.md index a0d0031c..354da9fb 100644 --- a/pq/stateful_hash_sig/README.md +++ b/pq/stateful_hash_sig/README.md @@ -22,6 +22,7 @@ The XMSS/XMSS^MT example requires that the xmss-reference repository has been cloned, patched, and built. Please see item 20 in the wolfSSL repo's INSTALL file. The patch to use is `0001-Patch-to-support-wolfSSL-xmss-reference-integration.patch` from this XMSS/XMSS^MT example. +This patch includes an addendum readme, `patch_readme.md`, that lists all changes made and explains their rationale. # Building the LMS/HSS example