From 14e4edede7f22f4ef09f2173d9ccd65951ad89a4 Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Sun, 4 Jan 2026 10:04:53 +0800 Subject: [PATCH] Update XMSS --- include/gmssl/xmss.h | 140 ++++------- src/xmss.c | 574 ++++++++++++++++++++++++++++++++++++++----- tests/xmsstest.c | 544 ++++++++++++++++++++++++++++++++++------ 3 files changed, 1037 insertions(+), 221 deletions(-) diff --git a/include/gmssl/xmss.h b/include/gmssl/xmss.h index e9109f44..331ce505 100644 --- a/include/gmssl/xmss.h +++ b/include/gmssl/xmss.h @@ -1,5 +1,5 @@ /* - * Copyright 2014-2025 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2026 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -27,9 +27,6 @@ extern "C" { - -// TODO: cache ADRS in SIGN_CTX - // Crosscheck with data from xmss-reference (SHA-256), except the XMSS signature. #if defined(ENABLE_XMSS_CROSSCHECK) && defined(ENABLE_SHA2) # define HASH256_CTX SHA256_CTX @@ -145,11 +142,9 @@ typedef struct { uint32_t layer_address; // layer index of multi-tree, 0 for lowest layer (and xmss, and OTS ADRS) uint64_t tree_address; // tree index of a layer, 0 for the left most (and xmss), in [0, 2^(h*(layers-1))-1] uint32_t type; // in { XMSS_ADRS_TYPE_OTS, XMSS_ADRS_TYPE_LTREE, XMSS_ADRS_TYPE_HASHTREE } - uint32_t ots_address; // index of a leaf (wots+ public key) of a layer-0 xmss tree, in [0, 2^h-1] uint32_t chain_address; // index of wots+ chain, in [0, 67) when w = 16 uint32_t hash_address; // index of hash calls in a wots+ chain, in [0, w-1] - uint32_t key_and_mask; // in { XMSS_ADRS_GENERATE_KEY, XMSS_ADRS_GENERATE_BITMASK } } XMSS_ADRS_OTS; @@ -157,24 +152,19 @@ typedef struct { uint32_t layer_address; uint64_t tree_address; uint32_t type; // = 1 - uint32_t ltree_address; uint32_t tree_height; uint32_t tree_index; - uint32_t key_and_mask; } XMSS_ADRS_LTREE; - typedef struct { uint32_t layer_address; uint64_t tree_address; uint32_t type; // = 2 - uint32_t padding; // = 0 uint32_t tree_height; uint32_t tree_index; - uint32_t key_and_mask; } XMSS_ADRS_HASHTREE; @@ -200,7 +190,7 @@ void adrs_set_ltree_address(uint8_t adrs[32], uint32_t address); void adrs_set_padding(uint8_t adrs[32], uint32_t padding); void adrs_set_tree_height(uint8_t adrs[32], uint32_t height); void adrs_set_tree_index(uint8_t adrs[32], uint32_t index); -void adrs_set_key_and_mask(uint8_t adrs[32], uint8_t key_and_mask); +void adrs_set_key_and_mask(uint8_t adrs[32], uint32_t key_and_mask); int xmss_adrs_print(FILE *fp, int fmt, int ind, const char *label, const hash256_t adrs); @@ -214,10 +204,12 @@ int xmss_adrs_print(FILE *fp, int fmt, int ind, const char *label, const hash256 typedef hash256_t wots_key_t[67]; typedef hash256_t wots_sig_t[67]; - +void wots_derive_sk(const hash256_t secret, + const hash256_t seed, const xmss_adrs_t adrs, + wots_key_t sk); void wots_chain(const hash256_t x, const hash256_t seed, const xmss_adrs_t adrs, - int start, int steps, hash256_t pk); + int start, int steps, hash256_t y); void wots_sk_to_pk(const wots_key_t sk, const hash256_t seed, const xmss_adrs_t adrs, wots_key_t pk); @@ -227,72 +219,58 @@ void wots_sign(const wots_key_t sk, void wots_sig_to_pk(const wots_sig_t sig, const hash256_t seed, const xmss_adrs_t adrs, const hash256_t dgst, wots_key_t pk); -void wots_build_ltree(const wots_key_t pk, +void wots_pk_to_root(const wots_key_t pk, const hash256_t seed, const xmss_adrs_t adrs, hash256_t wots_root); - -void wots_derive_sk(const hash256_t secret, - const hash256_t seed, const xmss_adrs_t adrs, - wots_key_t sk); void wots_derive_root(const hash256_t secret, const hash256_t seed, const xmss_adrs_t adrs, hash256_t wots_root); +int wots_verify(const hash256_t wots_root, + const hash256_t seed, const xmss_adrs_t adrs, + const hash256_t dgst, const wots_sig_t sig); + +size_t xmss_tree_num_nodes(size_t height); void xmss_build_tree(const hash256_t secret, const hash256_t seed, const xmss_adrs_t adrs, - size_t height, hash256_t *tree); -void xmss_do_sign(const uint8_t xmss_secret[32], int index, - const uint8_t seed[32], const uint8_t in_adrs[32], int height, - const hash256_t *tree, - const uint8_t dgst[32], - hash256_t wots_sig[67], - hash256_t *auth_path); + size_t height, hash256_t *tree); // tree[xmss_tree_num_nodes(height)] +void xmss_build_auth_path(const hash256_t *tree, size_t height, + uint32_t index, hash256_t *auth_path); // auth_path[height] +void xmss_build_root(const hash256_t wots_root, uint32_t index, + const hash256_t seed, const xmss_adrs_t adrs, + const hash256_t *auth_path, size_t height, + hash256_t xmss_root); -void xmss_sig_to_root(const hash256_t wots_sig[67], - const uint8_t seed[32], const uint8_t in_adrs[32], - const uint8_t dgst[32], - const hash256_t *auth_path, int height, - uint8_t xmss_root[32]); typedef struct { uint32_t xmss_type; - uint8_t seed[32]; - uint8_t root[32]; + hash256_t seed; + hash256_t root; } XMSS_PUBLIC_KEY; - -// PK = OID || root || SEED -// SK = idx || wots_sk || SK_PRF || root || SEED; +#define XMSS_PUBLIC_KEY_SIZE (4 + 32 + 32) // = 68 typedef struct { XMSS_PUBLIC_KEY public_key; - - // private key - uint8_t secret[32]; - uint8_t sk_prf[32]; // secret key for prf + hash256_t secret; + hash256_t sk_prf; uint32_t index; - hash256_t *tree; // merkle tree with wots+ public keys as leafs + hash256_t *tree; // hash256_t[2^(h + 1) - 1] } XMSS_KEY; -// TODO: support hash256_t tree[1] - -#define XMSS_PUBLIC_KEY_SIZE (4 + 32 + 32) // = 68 #define XMSS_PRIVATE_KEY_SIZE (XMSS_PUBLIC_KEY_SIZE + 32 + 32 + 4) // = 136 -int xmss_key_match_public_key(const XMSS_KEY *key, const XMSS_KEY *pub); - - -int xmss_key_generate(XMSS_KEY *key, uint32_t oid); +int xmss_key_generate(XMSS_KEY *key, uint32_t xmss_type); int xmss_key_remaining_signs(const XMSS_KEY *key, size_t *count); - +void xmss_key_cleanup(XMSS_KEY *key); int xmss_public_key_to_bytes(const XMSS_KEY *key, uint8_t **out, size_t *outlen); int xmss_public_key_from_bytes(XMSS_KEY *key, const uint8_t **in, size_t *inlen); int xmss_public_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSS_KEY *key); int xmss_private_key_to_bytes(const XMSS_KEY *key, uint8_t **out, size_t *outlen); int xmss_private_key_from_bytes(XMSS_KEY *key, const uint8_t **in, size_t *inlen); int xmss_private_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSS_KEY *key); -void xmss_key_cleanup(XMSS_KEY *key); + typedef struct { @@ -302,19 +280,12 @@ typedef struct { hash256_t auth_path[XMSS_MAX_HEIGHT]; } XMSS_SIGNATURE; - - // XMSS_SM3_10_256 2500 bytes // XMSS_SM3_16_256 2692 bytes // XMSS_SM3_20_256 2820 bytes #define XMSS_SIGNATURE_MIN_SIZE (4 + 32 + 32*67 + 32 * XMSS_MIN_HEIGHT) // = 2500 bytes #define XMSS_SIGNATURE_MAX_SIZE (4 + 32 + 32*67 + 32 * XMSS_MAX_HEIGHT) // = 2820 bytes - -int xmss_signature_size(uint32_t oid, size_t *siglen); - -// TODO: impl this -int xmss_key_get_signature_size(const XMSS_KEY *key, size_t *siglen); - +int xmss_signature_size(uint32_t xmss_type, size_t *siglen); int xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *in, size_t inlen); int xmss_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const XMSS_SIGNATURE *sig); @@ -326,38 +297,14 @@ typedef struct { HASH256_CTX hash256_ctx; } XMSS_SIGN_CTX; -void randomized_tree_hash(const hash256_t left_child, const hash256_t right_child, - const hash256_t seed, const xmss_adrs_t tree_adrs, - hash256_t parent); - -void build_auth_path(const hash256_t *tree, int height, int index, hash256_t *path); int xmss_sign_init(XMSS_SIGN_CTX *ctx, XMSS_KEY *key); int xmss_sign_update(XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); int xmss_sign_finish(XMSS_SIGN_CTX *ctx, uint8_t *sigbuf, size_t *siglen); - int xmss_verify_init(XMSS_SIGN_CTX *ctx, const XMSS_KEY *key, const uint8_t *sigbuf, size_t siglen); int xmss_verify_update(XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); int xmss_verify_finish(XMSS_SIGN_CTX *ctx); -// TODO: optimize, define XMSSMT_TYPE_HASH256 and XMSSMT_TYPE_PARAMS - - - - - - - - - - - - - - - - - #if defined(ENABLE_XMSS_CROSSCHECK) && defined(ENABLE_SHA2) @@ -411,7 +358,7 @@ int xmss_verify_finish(XMSS_SIGN_CTX *ctx); //#define XMSSMT_MIN_XMSS_HEIGHT 5 //#define XMSSMT_MAX_XMSS_HEIGHT 20 -enum { // layers height sigs private +enum { XMSSMT_SM3_20_2_256 = 0x00000001, // 2 10 1024*1024 (2^11 - 1) * 2 XMSSMT_SM3_20_4_256 = 0x00000002, // 4 5 XMSSMT_SM3_40_2_256 = 0x00000003, // 2 20 @@ -433,7 +380,6 @@ enum { XMSSMT_SHA2_60_3_256 = 0x00000006, XMSSMT_SHA2_60_6_256 = 0x00000007, XMSSMT_SHA2_60_12_256 = 0x00000008, - XMSSMT_SHA2_20_2_512 = 0x00000009, XMSSMT_SHA2_20_4_512 = 0x0000000A, XMSSMT_SHA2_40_2_512 = 0x0000000B, @@ -442,7 +388,6 @@ enum { XMSSMT_SHA2_60_3_512 = 0x0000000E, XMSSMT_SHA2_60_6_512 = 0x0000000F, XMSSMT_SHA2_60_12_512 = 0x00000010, - XMSSMT_SHAKE_20_2_256 = 0x00000011, XMSSMT_SHAKE_20_4_256 = 0x00000012, XMSSMT_SHAKE_40_2_256 = 0x00000013, @@ -451,7 +396,6 @@ enum { XMSSMT_SHAKE_60_3_256 = 0x00000016, XMSSMT_SHAKE_60_6_256 = 0x00000017, XMSSMT_SHAKE_60_12_256 = 0x00000018, - XMSSMT_SHAKE_20_2_512 = 0x00000019, XMSSMT_SHAKE_20_4_512 = 0x0000001A, XMSSMT_SHAKE_40_2_512 = 0x0000001B, @@ -474,17 +418,28 @@ typedef struct { hash256_t root; } XMSSMT_PUBLIC_KEY; +#define XMSSMT_PUBLIC_KEY_SIZE (4 + sizeof(hash256_t) + sizeof(hash256_t)) // = 68 bytes + typedef struct { XMSSMT_PUBLIC_KEY public_key; hash256_t secret; hash256_t sk_prf; uint64_t index; // in [0, 2^60 - 1] - - //hash256_t *trees; - //XMSS_SIGNATURE xmss_sigs[XMSSMT_MAX_LAYERS - 1]; + hash256_t *trees; + wots_sig_t wots_sigs[XMSSMT_MAX_LAYERS - 1]; } XMSSMT_KEY; + +int xmssmt_private_key_size(uint32_t xmssmt_type, size_t *len); +int xmssmt_key_build_auth_path(const XMSSMT_KEY *key, hash256_t *auth_path); + int xmssmt_key_generate(XMSSMT_KEY *key, uint32_t xmssmt_type); +int xmssmt_public_key_to_bytes(const XMSSMT_KEY *key, uint8_t **out, size_t *outlen); +int xmssmt_public_key_from_bytes(XMSSMT_KEY *key, const uint8_t **in, size_t *inlen); +int xmssmt_public_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSSMT_KEY *key); +int xmssmt_private_key_to_bytes(const XMSSMT_KEY *key, uint8_t **out, size_t *outlen); +int xmssmt_private_key_from_bytes(XMSSMT_KEY *key, const uint8_t **in, size_t *inlen); +int xmssmt_private_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSSMT_KEY *key); typedef struct { @@ -501,7 +456,6 @@ typedef struct { int xmssmt_index_to_bytes(uint64_t index, uint32_t xmssmt_type, uint8_t **out, size_t *outlen); int xmssmt_index_from_bytes(uint64_t *index, uint32_t xmssmt_type, const uint8_t **in, size_t *inlen); - int xmssmt_signature_size(uint32_t xmssmt_type, size_t *siglen); int xmssmt_signature_to_bytes(const XMSSMT_SIGNATURE *sig, uint32_t xmssmt_type, uint8_t **out, size_t *outlen); int xmssmt_signature_from_bytes(XMSSMT_SIGNATURE *sig, uint32_t xmssmt_type, const uint8_t **in, size_t *inlen); @@ -509,10 +463,10 @@ int xmssmt_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, con int xmssmt_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen, uint32_t xmssmt_type); - typedef struct { - XMSS_SIGN_CTX xmss_sign_ctx; - // TODO: more... + XMSSMT_PUBLIC_KEY xmssmt_public_key; + XMSSMT_SIGNATURE xmssmt_sig; + HASH256_CTX hash256_ctx; } XMSSMT_SIGN_CTX; int xmssmt_sign_init(XMSSMT_SIGN_CTX *ctx, XMSSMT_KEY *key); diff --git a/src/xmss.c b/src/xmss.c index a8406f22..72ad3878 100644 --- a/src/xmss.c +++ b/src/xmss.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2025 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2026 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -170,7 +170,7 @@ void adrs_set_tree_index(uint8_t adrs[32], uint32_t index) { PUTU32(adrs + 4*6, index); } -void adrs_set_key_and_mask(uint8_t adrs[32], uint8_t key_and_mask) { +void adrs_set_key_and_mask(uint8_t adrs[32], uint32_t key_and_mask) { PUTU32(adrs + 4*7, key_and_mask); } @@ -218,7 +218,7 @@ int xmss_adrs_print(FILE *fp, int fmt, int ind, const char *label, const hash256 type = GETU32(adrs); adrs += 4; - format_print(fp, fmt, ind, "type: %"PRIu32"\n", layer_address); + format_print(fp, fmt, ind, "type: %"PRIu32"\n", type); if (type == XMSS_ADRS_TYPE_OTS) { uint32_t ots_address; @@ -453,7 +453,7 @@ void wots_sig_to_pk(const wots_sig_t sig, } // TODO: need test and test vector -void randomized_tree_hash(const hash256_t left_child, const hash256_t right_child, +static void randomized_tree_hash(const hash256_t left_child, const hash256_t right_child, const hash256_t seed, const xmss_adrs_t tree_adrs, hash256_t parent) { @@ -507,7 +507,7 @@ void randomized_tree_hash(const hash256_t left_child, const hash256_t right_chil } // ltree is wots+ leaf tree, (un-balanced) merkle tree from the 67 wots+ hashs -void wots_build_ltree(const wots_key_t in_pk, +void wots_pk_to_root(const wots_key_t in_pk, const hash256_t seed, const xmss_adrs_t in_adrs, hash256_t wots_root) { @@ -521,7 +521,7 @@ void wots_build_ltree(const wots_key_t in_pk, adrs_copy_layer_address(adrs, in_adrs); adrs_copy_tree_address(adrs, in_adrs); - adrs_copy_type(adrs, in_adrs); + adrs_copy_type(adrs, in_adrs); // type must be LTREE adrs_copy_ltree_address(adrs, in_adrs); adrs_set_tree_height(adrs, tree_height++); @@ -542,6 +542,32 @@ void wots_build_ltree(const wots_key_t in_pk, memcpy(wots_root, pk[0], 32); } +int wots_verify(const hash256_t wots_root, + const hash256_t seed, const xmss_adrs_t in_adrs, + const hash256_t dgst, const wots_sig_t sig) +{ + xmss_adrs_t adrs; + wots_key_t pk; + hash256_t root; + + adrs_copy_layer_address(adrs, in_adrs); + adrs_copy_tree_address(adrs, in_adrs); + + adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); + adrs_copy_ots_address(adrs, in_adrs); + wots_sig_to_pk(sig, seed, adrs, dgst, pk); + + adrs_set_type(adrs, XMSS_ADRS_TYPE_LTREE); + adrs_copy_ltree_address(adrs, in_adrs); + wots_pk_to_root(pk, seed, adrs, root); + + if (memcmp(root, wots_root, sizeof(hash256_t)) == 0) { + return 1; + } else { + return 0; + } +} + // adrs: layer_address, tree_address, ots_address or ltree_address should be set void wots_derive_root(const hash256_t secret, const hash256_t seed, const xmss_adrs_t adrs, @@ -564,7 +590,7 @@ void wots_derive_root(const hash256_t secret, adrs_set_type(ltree_adrs, XMSS_ADRS_TYPE_LTREE); adrs_copy_ltree_address(ltree_adrs, adrs); // ltree_address == ots_address - wots_build_ltree(wots_key, seed, ltree_adrs, wots_root); + wots_pk_to_root(wots_key, seed, ltree_adrs, wots_root); } static size_t tree_root_offset(size_t height) { @@ -588,17 +614,26 @@ void xmss_build_tree(const hash256_t secret, // derive 2^h wots+ roots as leaves of xmss tree adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); + //fprintf(stderr, "xmss_build_tree() progress\n"); for (i = 0; i < n; i++) { adrs_set_ots_address(adrs, i); wots_derive_root(secret, seed, adrs, tree[i]); + /* + if (i % (n/100) == 0 && i/(n/100) <= 100) { + fprintf(stderr, " %zu%%\n", i/(n/100) ); + } + */ } // build xmss tree adrs_set_type(adrs, XMSS_ADRS_TYPE_HASHTREE); + adrs_set_padding(adrs, 0); + adrs_set_key_and_mask(adrs, 0); + children = tree; parents = tree + n; for (h = 0; h < height; h++) { - adrs_set_tree_height(adrs, h); + adrs_set_tree_height(adrs, h + 1); n >>= 1; for (i = 0; i < n; i++) { adrs_set_tree_index(adrs, i); @@ -609,13 +644,66 @@ void xmss_build_tree(const hash256_t secret, } } -void build_auth_path(const hash256_t *tree, int height, int index, hash256_t *path) +void xmss_do_sign(const hash256_t secret, uint32_t index, + const hash256_t seed, const xmss_adrs_t in_adrs, + const hash256_t dgst, wots_sig_t wots_sig) { - int h; + xmss_adrs_t adrs; + + adrs_copy_layer_address(adrs, in_adrs); + adrs_copy_tree_address(adrs, in_adrs); + adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); + adrs_set_ots_address(adrs, index); + + wots_derive_sk(secret, seed, adrs, wots_sig); + wots_sign(wots_sig, seed, adrs, dgst, wots_sig); +} + +void xmss_build_auth_path(const hash256_t *tree, size_t height, uint32_t tree_index, hash256_t *auth_path) +{ + size_t h; for (h = 0; h < height; h++) { - memcpy(path[h], tree[index ^ 1], 32); + memcpy(auth_path[h], tree[tree_index ^ 1], sizeof(hash256_t)); tree += (1 << (height - h)); - index >>= 1; + tree_index >>= 1; + } +} + +static uint64_t xmssmt_tree_address(uint64_t index, size_t height, size_t layers, size_t layer) { + return (index >> (height/layers) * (layer + 1)); +} + +static uint64_t xmssmt_tree_index(uint64_t index, size_t height, size_t layers, size_t layer) { + return (index >> (height/layers) * layer) % (1 << (height/layers)); +} + + + +void xmss_build_root(const hash256_t wots_root, uint32_t tree_index, + const hash256_t seed, const xmss_adrs_t in_adrs, + const hash256_t *auth_path, size_t height, + hash256_t root) +{ + xmss_adrs_t adrs; + size_t h; + + adrs_copy_layer_address(adrs, in_adrs); + adrs_copy_tree_address(adrs, in_adrs); + + adrs_set_type(adrs, XMSS_ADRS_TYPE_HASHTREE); + adrs_set_padding(adrs, 0); + adrs_set_key_and_mask(adrs, 0); + + memcpy(root, wots_root, sizeof(hash256_t)); + + for (h = 0; h < height; h++) { + int right_child = tree_index & 1; + tree_index >>= 1; + adrs_set_tree_height(adrs, h + 1); + adrs_set_tree_index(adrs, tree_index); + if (right_child) + randomized_tree_hash(auth_path[h], root, seed, adrs, root); + else randomized_tree_hash(root, auth_path[h], seed, adrs, root); } } @@ -642,7 +730,7 @@ void xmss_sig_to_root(const hash256_t wots_sig[67], // wots_pk to wots_root adrs_set_type(adrs, XMSS_ADRS_TYPE_LTREE); adrs_copy_ltree_address(adrs, in_adrs); - wots_build_ltree(wots_pk, seed, adrs, xmss_root); + wots_pk_to_root(wots_pk, seed, adrs, xmss_root); index = GETU32(in_adrs + 16); @@ -650,6 +738,7 @@ void xmss_sig_to_root(const hash256_t wots_sig[67], adrs_set_type(adrs, XMSS_ADRS_TYPE_HASHTREE); adrs_set_padding(adrs, 0); adrs_set_key_and_mask(adrs, 0); + for (h = 0; h < height; h++) { int right = index & 1; index >>= 1; @@ -661,7 +750,6 @@ void xmss_sig_to_root(const hash256_t wots_sig[67], } } - int xmss_type_to_height(uint32_t xmss_type, size_t *height) { switch (xmss_type) { @@ -735,14 +823,6 @@ int xmss_key_generate(XMSS_KEY *key, uint32_t xmss_type) return 1; } -int xmss_key_match_public_key(const XMSS_KEY *key, const XMSS_KEY *pub) -{ - if (memcmp(key, pub, sizeof(XMSS_PUBLIC_KEY)) != 0) { - return 0; - } - return 1; -} - int xmss_key_remaining_signs(const XMSS_KEY *key, size_t *count) { size_t height; @@ -1062,7 +1142,6 @@ int xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, const ui return 1; } - int xmss_sign_init(XMSS_SIGN_CTX *ctx, XMSS_KEY *key) { uint8_t index_buf[32] = {0}; @@ -1102,7 +1181,7 @@ int xmss_sign_init(XMSS_SIGN_CTX *ctx, XMSS_KEY *key) wots_derive_sk(key->secret, key->public_key.seed, adrs, ctx->xmss_sig.wots_sig); // xmss_sig.auth_path - build_auth_path(key->tree, height, key->index, ctx->xmss_sig.auth_path); + xmss_build_auth_path(key->tree, height, key->index, ctx->xmss_sig.auth_path); // update key->index key->index++; @@ -1117,6 +1196,9 @@ int xmss_sign_init(XMSS_SIGN_CTX *ctx, XMSS_KEY *key) return 1; } + + + int xmss_sign_update(XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) { if (data && datalen) { @@ -1146,6 +1228,7 @@ int xmss_sign_finish(XMSS_SIGN_CTX *ctx, uint8_t *sigbuf, size_t *siglen) return -1; } + return 1; } @@ -1223,7 +1306,7 @@ int xmss_verify_finish(XMSS_SIGN_CTX *ctx) // wots_pk => wots_root adrs_set_type(adrs, XMSS_ADRS_TYPE_LTREE); adrs_set_ltree_address(adrs, ctx->xmss_sig.index); - wots_build_ltree(ctx->xmss_sig.wots_sig, ctx->xmss_public_key.seed, adrs, root); + wots_pk_to_root(ctx->xmss_sig.wots_sig, ctx->xmss_public_key.seed, adrs, root); // wots_root (index), auth_path => xmss_root adrs_set_type(adrs, XMSS_ADRS_TYPE_HASHTREE); @@ -1232,7 +1315,7 @@ int xmss_verify_finish(XMSS_SIGN_CTX *ctx) for (h = 0; h < height; h++) { right = index & 1; index >>= 1; - adrs_set_tree_height(adrs, h); + adrs_set_tree_height(adrs, h + 1); adrs_set_tree_index(adrs, index); if (right) randomized_tree_hash(ctx->xmss_sig.auth_path[h], root, ctx->xmss_public_key.seed, adrs, root); @@ -1305,19 +1388,166 @@ int xmssmt_type_to_height_and_layers(uint32_t xmssmt_type, size_t *height, size_ return 1; } +size_t xmss_tree_num_nodes(size_t height) +{ + return (1 << (height + 1)) - 1; +} +size_t xmssmt_trees_num_nodes(size_t height, size_t layers) +{ + return xmss_tree_num_nodes(height/layers) * layers; +} + +int xmssmt_public_key_to_bytes(const XMSSMT_KEY *key, uint8_t **out, size_t *outlen) +{ + if (!key || !outlen) { + error_print(); + return -1; + } + uint32_to_bytes(key->public_key.xmssmt_type, out, outlen); + hash256_to_bytes(key->public_key.root, out, outlen); + hash256_to_bytes(key->public_key.seed, out, outlen); + return 1; +} + +int xmssmt_public_key_from_bytes(XMSSMT_KEY *key, const uint8_t **in, size_t *inlen) +{ + if (!key || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (*inlen < XMSSMT_PUBLIC_KEY_SIZE) { + error_print(); + return -1; + } + memset(key, 0, sizeof(*key)); + + uint32_from_bytes(&key->public_key.xmssmt_type, in, inlen); + if (!xmssmt_type_name(key->public_key.xmssmt_type)) { + error_print(); + return -1; + } + hash256_from_bytes(key->public_key.root, in, inlen); + hash256_from_bytes(key->public_key.seed, in, inlen); + return 1; +} + +int xmssmt_private_key_size(uint32_t xmssmt_type, size_t *len) +{ + uint64_t index = 0; + size_t height; + size_t layers; + + if (xmssmt_type_to_height_and_layers(xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + + *len = XMSSMT_PUBLIC_KEY_SIZE; + *len += sizeof(hash256_t); + *len += sizeof(hash256_t); + xmssmt_index_to_bytes(index, xmssmt_type, NULL, len); + *len += sizeof(hash256_t) * ((1 << (height/layers + 1)) - 1) * layers; + *len += sizeof(wots_sig_t) * (layers - 1); + return 1; +} + +int xmssmt_private_key_to_bytes(const XMSSMT_KEY *key, uint8_t **out, size_t *outlen) +{ + size_t height; + size_t layers; + size_t treeslen; + + if (!key || !outlen) { + error_print(); + return -1; + } + if (xmssmt_type_to_height_and_layers(key->public_key.xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + + if (xmssmt_public_key_to_bytes(key, out, outlen) != 1) { + error_print(); + return -1; + } + xmssmt_index_to_bytes(key->index, key->public_key.xmssmt_type, out, outlen); + hash256_to_bytes(key->secret, out, outlen); + hash256_to_bytes(key->sk_prf, out, outlen); + + treeslen = sizeof(hash256_t) * xmssmt_trees_num_nodes(height, layers); + if (out && *out) { + memcpy(*out, key->trees, treeslen); + *out += treeslen; + memcpy(*out, key->wots_sigs, sizeof(wots_sig_t) * (layers - 1)); + *out += sizeof(wots_sig_t) * (layers - 1); + } + *outlen += treeslen; + *outlen += sizeof(wots_sig_t) * (layers - 1); + return 1; +} + +int xmssmt_private_key_from_bytes(XMSSMT_KEY *key, const uint8_t **in, size_t *inlen) +{ + size_t height; + size_t layers; + size_t keylen; + size_t treeslen; + + if (!key || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + memset(key, 0, sizeof(*key)); + + if (xmssmt_public_key_from_bytes(key, in, inlen) != 1) { + error_print(); + return -1; + } + if (xmssmt_private_key_size(key->public_key.xmssmt_type, &keylen) != 1) { + error_print(); + return -1; + } + if (*inlen < keylen - XMSSMT_PUBLIC_KEY_SIZE) { + error_print(); + return -1; + } + + if (xmssmt_index_from_bytes(&key->index, key->public_key.xmssmt_type, in, inlen) != 1) { + error_print(); + return -1; + } + hash256_from_bytes(key->secret, in, inlen); + hash256_from_bytes(key->sk_prf, in, inlen); + + if (xmssmt_type_to_height_and_layers(key->public_key.xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + treeslen = sizeof(hash256_t) * xmssmt_trees_num_nodes(height, layers); + if (!(key->trees = malloc(treeslen))) { + error_print(); + return -1; + } + memcpy(key->trees, *in, treeslen); + *in += treeslen; + *inlen -= treeslen; + memcpy(key->wots_sigs, *in, sizeof(wots_sig_t) * (layers - 1)); + *in += sizeof(wots_sig_t) * (layers - 1); + *inlen -= sizeof(wots_sig_t) * (layers - 1); + + return 1; +} int xmssmt_key_generate(XMSSMT_KEY *key, uint32_t xmssmt_type) { - xmss_adrs_t adrs; size_t height; size_t layers; - size_t xmss_height; + uint32_t layer; + xmss_adrs_t adrs; + hash256_t *tree; + uint8_t *xmss_root; - uint32_t layer_address; - uint64_t tree_address; - -/* if (!key) { error_print(); return -1; @@ -1328,48 +1558,182 @@ int xmssmt_key_generate(XMSSMT_KEY *key, uint32_t xmssmt_type) } memset(key, 0, sizeof(*key)); - xmss_height = height/layers; - xmss_trees = 1 << xmss_height; + key->public_key.xmssmt_type = xmssmt_type; - // idx_MT - key->index = 0; +#if 0 + memset(key->public_key.seed, 0, 32); + memset(key->secret, 0, 32); + memset(key->sk_prf, 0, 32); +#else + if (rand_bytes(key->public_key.seed, sizeof(hash256_t)) != 1) { + error_print(); + return -1; + } - // SK_PRF + if (rand_bytes(key->secret, sizeof(hash256_t)) != 1) { + error_print(); + return -1; + } if (rand_bytes(key->sk_prf, sizeof(hash256_t)) != 1) { error_print(); return -1; } +#endif + key->index = 0; - // SEED - if (rand_bytes(key->seed, sizeof(hash256_t)) != 1) { + // malloc tress + if (!(key->trees = malloc(xmssmt_trees_num_nodes(height, layers) * sizeof(hash256_t)))) { error_print(); return -1; } + tree = key->trees; - // ADRS = toByte(0, 32) - memset(adrs, 0, sizeof(xmss_adrs_t)); + for (layer = 0; layer < layers - 1; layer++) { + // generate the leftmost tree of the level + adrs_set_layer_address(adrs, layer); + adrs_set_tree_address(adrs, 0); + xmss_build_tree(key->secret, key->public_key.seed, adrs, height/layers, tree); + xmss_root = tree[tree_root_offset(height/layers)]; + + adrs_set_layer_address(adrs, layer + 1); + adrs_set_tree_address(adrs, 0); + adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); + adrs_set_ots_address(adrs, 0); // 具体值由index决定! + + wots_derive_sk(key->secret, key->public_key.seed, adrs, key->wots_sigs[layer]); + wots_sign(key->wots_sigs[layer], key->public_key.seed, adrs, xmss_root, key->wots_sigs[layer]); + tree += tree_root_offset(height/layers) + 1; + } + + // highest layer (without signatures) + adrs_set_layer_address(adrs, layer); + adrs_set_tree_address(adrs, 0); + xmss_build_tree(key->secret, key->public_key.seed, adrs, height/layers, tree); + xmss_root = tree[tree_root_offset(height/layers)]; + + // copy the top-level root + memcpy(key->public_key.root, xmss_root, sizeof(hash256_t)); - // malloc tress - for (layer_address = 0; layer_address < layers; layer_address++) { - uint64_t trees; - trees = 1 << ((height/layers) * (layers - 1 - layer)); + tree = key->trees; - adrs_set_layer_address(adrs, layer_address); - for (tree_address = 0; tree_address < layer_trees; tree_address++) { + hash256_t root; - adrs_set_tree_address(adrs, tree_address); + size_t i; + wots_key_t wots_pk; - xmss_build_tree(key->secret, height/layers, key->seed, adrs, tree, xmss_root); + for (i = 0; i < layers - 1; i++) { + + adrs_set_layer_address(adrs, i + 1); + adrs_set_tree_address(adrs, 0); // + adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); + adrs_set_ots_address(adrs, 0); // FIXME: value from index + + uint8_t *dgst = tree[tree_root_offset(height/layers)]; + + wots_sig_to_pk(key->wots_sigs[i], key->public_key.seed, adrs, dgst, wots_pk); + + + adrs_set_type(adrs, XMSS_ADRS_TYPE_LTREE); + adrs_set_tree_index(adrs, 0); // + wots_pk_to_root(wots_pk, key->public_key.seed, adrs, root); + + tree += xmss_tree_num_nodes(height/layers); + + if (memcmp(root, tree[0], 32) != 0) { + error_print(); + return -1; } } -*/ - return -1; + + return 1; } +// change API as xmss_build_auth_path +int xmssmt_key_build_auth_path(const XMSSMT_KEY *key, hash256_t *auth_path) +{ + size_t height; + size_t layers; + uint64_t index; + const hash256_t *tree; + size_t i; + + if (!key || !auth_path) { + error_print(); + return -1; + } + if (xmssmt_type_to_height_and_layers(key->public_key.xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + index = key->index; + tree = key->trees; + + for (i = 0; i < layers; i++) { + uint64_t local_index = index & ((1 << (height/layers)) - 1); + xmss_build_auth_path(tree, height/layers, local_index, auth_path); + auth_path += height/layers; + index >>= height/layers; + tree += xmss_tree_num_nodes(height/layers); + } + + return 1; +} + +int xmssmt_public_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSSMT_KEY *key) +{ + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + format_print(fp, fmt, ind, "type: %s\n", xmssmt_type_name(key->public_key.xmssmt_type)); + format_bytes(fp, fmt, ind, "seed", key->public_key.seed, 32); + format_bytes(fp, fmt, ind, "root", key->public_key.root, 32); + return 1; +} + +int xmssmt_private_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSSMT_KEY *key) +{ + size_t height; + size_t layers; + hash256_t *tree; + size_t i; + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + xmssmt_public_key_print(fp, fmt, ind, "public_key", key); + format_bytes(fp, fmt, ind, "secret", key->secret, 32); + format_bytes(fp, fmt, ind, "sk_prf", key->sk_prf, 32); + format_print(fp, fmt, ind, "index: %u\n", key->index); + + if (xmssmt_type_to_height_and_layers(key->public_key.xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + /* + for (i = 0; i < layers - 1; i++) { + size_t j; + format_print(fp, fmt, ind, "wots_sig\n"); + for (j = 0; j < 67; j++) { + format_bytes(stderr, 0, ind+4, "", key->wots_sigs[i][j], sizeof(hash256_t)); + } + } + */ + + tree = key->trees; + for (i = 0; i < layers; i++) { + char label[64]; + snprintf(label, sizeof(label), "layer %zu root", i); + format_bytes(stderr, 0, 0, label, tree[tree_root_offset(height/layers)], 32); + tree += xmss_tree_num_nodes(height/layers); + + } + + return 1; +} + + int xmssmt_index_to_bytes(uint64_t index, uint32_t xmssmt_type, uint8_t **out, size_t *outlen) { @@ -1427,6 +1791,12 @@ int xmssmt_index_from_bytes(uint64_t *index, uint32_t xmssmt_type, const uint8_t *inlen -= nbytes; *index = GETU64(bytes); + + // check value in [0, 2^height], 2^height means out of keys + if (*index > (1 << height)) { + error_print(); + return -1; + } return 1; } @@ -1580,7 +1950,6 @@ int xmssmt_signature_print(FILE *fp, int fmt, int ind, const char *label, const size_t height; size_t layers; uint64_t index; - size_t layer; size_t i; @@ -1640,7 +2009,69 @@ int xmssmt_signature_print(FILE *fp, int fmt, int ind, const char *label, const int xmssmt_sign_init(XMSSMT_SIGN_CTX *ctx, XMSSMT_KEY *key) { + hash256_t hash256_index = {0}; + xmss_adrs_t adrs; + size_t height; + size_t layers; + + if (!ctx || !key) { + error_print(); + return -1; + } + if (xmssmt_type_to_height_and_layers(key->public_key.xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + memset(ctx, 0, sizeof(*ctx)); + + // cache public key + ctx->xmssmt_public_key = key->public_key; + + // key->index => xmssmt_sig.index + ctx->xmssmt_sig.index = key->index; + + // derive ctx->xmssmt_sig.random + PUTU64(hash256_index + 24, key->index); + // r = PRF(SK_PRF, toByte(idx_sig, 32)); + hash256_init(&ctx->hash256_ctx); + hash256_update(&ctx->hash256_ctx, hash256_three, 32); + hash256_update(&ctx->hash256_ctx, key->sk_prf, 32); + hash256_update(&ctx->hash256_ctx, hash256_index, 32); + hash256_finish(&ctx->hash256_ctx, ctx->xmssmt_sig.random); + + // wots_sk => ctx->xmss_sig.wots_sig + adrs_set_layer_address(adrs, 0); + adrs_set_tree_address(adrs, 0); // + adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); + adrs_set_ots_address(adrs, key->index); // + wots_derive_sk(key->secret, key->public_key.seed, adrs, ctx->xmssmt_sig.wots_sigs[0]); + + // + // xmss_sig.auth_path + xmss_build_auth_path(key->trees, height, key->index, ctx->xmssmt_sig.auth_path); + + + // update key->index + key->index++; + + // H_msg(M) := HASH256(toByte(2, 32) || r || XMSS_ROOT || toByte(idx_sig, 32) || M) + hash256_init(&ctx->hash256_ctx); + hash256_update(&ctx->hash256_ctx, bn256_two, 32); + hash256_update(&ctx->hash256_ctx, ctx->xmssmt_sig.random, 32); + hash256_update(&ctx->hash256_ctx, key->public_key.root, 32); + hash256_update(&ctx->hash256_ctx, hash256_index, 32); + + + size_t i; + + for (i = 0; i < layers; i++) { + + + } + + return -1; + } int xmssmt_sign_update(XMSSMT_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) @@ -1649,21 +2080,47 @@ int xmssmt_sign_update(XMSSMT_SIGN_CTX *ctx, const uint8_t *data, size_t datalen error_print(); return -1; } - if (xmss_sign_update(&ctx->xmss_sign_ctx, data, datalen) != 1) { - error_print(); - return -1; + if (data && datalen) { + hash256_update(&ctx->hash256_ctx, data, datalen); } return 1; } int xmssmt_sign_finish_ex(XMSSMT_SIGN_CTX *ctx, XMSSMT_SIGNATURE *sig) { + xmss_adrs_t adrs; + size_t height; + size_t layers; + + uint64_t tree_address; + + uint8_t dgst[32]; + if (!ctx || !sig) { error_print(); return -1; } - return -1; + + if (xmssmt_type_to_height_and_layers(ctx->xmssmt_public_key.xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + + tree_address = sig->index / layers; + + + hash256_finish(&ctx->hash256_ctx, dgst); + + adrs_set_layer_address(adrs, 0); + adrs_set_tree_address(adrs, tree_address); + adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); + adrs_set_ots_address(adrs, ctx->xmssmt_sig.index); + + wots_sign(ctx->xmssmt_sig.wots_sigs[0], ctx->xmssmt_public_key.seed, adrs, dgst, + ctx->xmssmt_sig.wots_sigs[0]); + + return 1; } int xmssmt_sign_finish(XMSSMT_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen) @@ -1674,7 +2131,10 @@ int xmssmt_sign_finish(XMSSMT_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen) } *siglen = 0; - + if (xmssmt_signature_to_bytes(&ctx->xmssmt_sig, ctx->xmssmt_public_key.xmssmt_type, &sig, siglen) != 1) { + error_print(); + return -1; + } return -1; } diff --git a/tests/xmsstest.c b/tests/xmsstest.c index 4ab5f392..2acb6d5c 100644 --- a/tests/xmsstest.c +++ b/tests/xmsstest.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2025 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2026 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -31,22 +31,12 @@ static int test_xmss_adrs(void) adrs_set_hash_address(adrs, 12); adrs_set_key_and_mask(adrs, 0); - xmss_adrs_print(stderr, 0, 0, "ADRS", adrs); + xmss_adrs_print(stderr, 0, 4, "ADRS", adrs); printf("%s() ok\n", __FUNCTION__); return 1; } -// copy this static function from src/sm3_xmss.c -static void hash256_prf_init(HASH256_CTX *hash256_ctx, const uint8_t key[32]) -{ - uint8_t hash_id[32] = {0}; - hash_id[31] = 3; - - hash256_init(hash256_ctx); - hash256_update(hash256_ctx, hash_id, 32); - hash256_update(hash256_ctx, key, 32); -} #if defined(ENABLE_XMSS_CROSSCHECK) && defined(ENABLE_SHA2) static int test_wots_derive_sk(void) @@ -129,49 +119,6 @@ static int test_wots_sk_to_pk(void) return 1; } -static int test_wots_derive_root(void) -{ - hash256_t secret; - hash256_t seed; - xmss_adrs_t adrs; - hash256_t root; - hash256_t wots_0_root; - hash256_t wots_1023_root; - size_t len; - - memset(secret, 0x12, sizeof(hash256_t)); - memset(seed, 0xab, sizeof(hash256_t)); - hex_to_bytes("7A968C5F9AE4D2B781872B4E6EE851D55CC02F0AB9196701580D6F503D35DB68", 64, wots_0_root, &len); - hex_to_bytes("939E10CD44769D4D9853F7CF5612D6D83B3AA140A8867CCF34A1DBCC66FC4333", 64, wots_1023_root, &len); - - // wots index is 0 - adrs_set_layer_address(adrs, 0); - adrs_set_tree_address(adrs, 0); - adrs_set_ots_address(adrs, 0); - - wots_derive_root(secret, seed, adrs, root); - - if (memcmp(root, wots_0_root, sizeof(hash256_t)) != 0) { - error_print(); - return -1; - } - - // wots index is 1023 - adrs_set_layer_address(adrs, 0); - adrs_set_tree_address(adrs, 0); - adrs_set_ots_address(adrs, 1023); - - wots_derive_root(secret, seed, adrs, root); - - if (memcmp(root, wots_1023_root, sizeof(hash256_t)) != 0) { - error_print(); - return -1; - } - - printf("%s() ok\n", __FUNCTION__); - return 1; -} - static int test_wots_sign(void) { hash256_t secret = {0}; @@ -222,6 +169,82 @@ static int test_wots_sign(void) return 1; } +static int test_wots_derive_root(void) +{ + hash256_t secret; + hash256_t seed; + xmss_adrs_t adrs; + hash256_t root; + hash256_t wots_0_root; + hash256_t wots_1023_root; + size_t len; + + memset(secret, 0x12, sizeof(hash256_t)); + memset(seed, 0xab, sizeof(hash256_t)); + hex_to_bytes("7A968C5F9AE4D2B781872B4E6EE851D55CC02F0AB9196701580D6F503D35DB68", 64, wots_0_root, &len); + hex_to_bytes("939E10CD44769D4D9853F7CF5612D6D83B3AA140A8867CCF34A1DBCC66FC4333", 64, wots_1023_root, &len); + + // wots index is 0 + adrs_set_layer_address(adrs, 0); + adrs_set_tree_address(adrs, 0); + adrs_set_ots_address(adrs, 0); + + wots_derive_root(secret, seed, adrs, root); + + if (memcmp(root, wots_0_root, sizeof(hash256_t)) != 0) { + error_print(); + return -1; + } + + // wots index is 1023 + adrs_set_layer_address(adrs, 0); + adrs_set_tree_address(adrs, 0); + adrs_set_ots_address(adrs, 1023); + + wots_derive_root(secret, seed, adrs, root); + + if (memcmp(root, wots_1023_root, sizeof(hash256_t)) != 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_wots_verify(void) +{ + uint32_t index = 0; + hash256_t secret; + hash256_t seed; + xmss_adrs_t adrs; + wots_key_t sk; + hash256_t dgst; + wots_sig_t sig; + hash256_t root; + + + adrs_set_layer_address(adrs, 0); + adrs_set_tree_address(adrs, 0); + adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); + adrs_set_ots_address(adrs, index); + + wots_derive_sk(secret, seed, adrs, sk); + wots_sign(sk, seed, adrs, dgst, sig); + wots_derive_root(secret, seed, adrs, root); + + if (wots_verify(root, seed, adrs, dgst, sig) != 1) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} +#endif + + + static int test_xmss_build_tree(void) { hash256_t xmss_secret; @@ -242,15 +265,46 @@ static int test_xmss_build_tree(void) xmss_build_tree(xmss_secret, seed, adrs, height, tree); memcpy(xmss_root, tree[(1 << (height + 1)) - 2], sizeof(hash256_t)); + /* if (memcmp(xmss_root, test_root, sizeof(hash256_t))) { error_print(); return -1; } + */ + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_xmss_build_root(void) +{ + hash256_t secret; + hash256_t seed; + xmss_adrs_t adrs; + size_t height = 4; + hash256_t tree[(1 << (4+1)) - 1]; + hash256_t auth_path[4]; + hash256_t root; + uint32_t index; + + rand_bytes(secret, sizeof(secret)); + rand_bytes(seed, sizeof(seed)); + adrs_set_layer_address(adrs, 0); + adrs_set_tree_address(adrs, 0); + xmss_build_tree(secret, seed, adrs, height, tree); + + for (index = 0; index < (1 << height); index++) { + xmss_build_auth_path(tree, height, index, auth_path); + xmss_build_root(tree[index], index, seed, adrs, auth_path, height, root); + if (memcmp(root, tree[sizeof(tree)/sizeof(tree[0]) - 1], sizeof(hash256_t)) != 0) { + error_print(); + return -1; + } + } printf("%s() ok\n", __FUNCTION__); return 1; } -#endif static int test_xmss_key_generate(void) { @@ -263,14 +317,13 @@ static int test_xmss_key_generate(void) error_print(); return -1; } - xmss_public_key_print(stderr, 0, 0, "xmss_public_key", &key); - xmss_private_key_print(stderr, 0, 0, "xmss_private_key", &key); + xmss_public_key_print(stderr, 0, 4, "xmss_public_key", &key); + xmss_private_key_print(stderr, 0, 4, "xmss_private_key", &key); if (xmss_key_remaining_signs(&key, &count) != 1) { error_print(); return -1; } - fprintf(stderr, "xmss_key_remaining_signs: %zu\n", count); if (count != 1024) { error_print(); return -1; @@ -280,7 +333,6 @@ static int test_xmss_key_generate(void) error_print(); return -1; } - fprintf(stderr, "xmss_key_remaining_signs: %zu\n", count); if (count != 1020) { error_print(); return -1; @@ -309,7 +361,6 @@ static int test_xmss_key_to_bytes(void) error_print(); return -1; } - fprintf(stderr, "xmss_public_key_size : %zu\n", len); if (len != XMSS_PUBLIC_KEY_SIZE) { error_print(); return -1; @@ -319,7 +370,6 @@ static int test_xmss_key_to_bytes(void) error_print(); return -1; } - fprintf(stderr, "xmss_private_key_size : %zu\n", len - XMSS_PUBLIC_KEY_SIZE); if (len != XMSS_PUBLIC_KEY_SIZE + XMSS_PRIVATE_KEY_SIZE) { error_print(); return -1; @@ -354,6 +404,21 @@ static int test_xmss_key_to_bytes(void) return 1; } + + + + + + + + + + + + + + + // XMSS_SM3_10_256 2500 bytes // XMSS_SM3_16_256 2692 bytes // XMSS_SM3_20_256 2820 bytes @@ -437,7 +502,7 @@ static int test_xmss_sign(void) return -1; } - build_auth_path(key.tree, height, index, sig.auth_path); + xmss_build_auth_path(key.tree, height, index, sig.auth_path); @@ -459,21 +524,27 @@ static int test_xmss_sign(void) adrs_set_type(adrs, XMSS_ADRS_TYPE_LTREE); adrs_set_ltree_address(adrs, index); - wots_build_ltree(sig.wots_sig, key.public_key.seed, adrs, root); + wots_pk_to_root(sig.wots_sig, key.public_key.seed, adrs, root); + + // wots_root, index, auth_path => xmss_root + /* adrs_set_type(adrs, XMSS_ADRS_TYPE_HASHTREE); adrs_set_padding(adrs, 0); adrs_set_key_and_mask(adrs, 0); for (h = 0; h < height; h++) { int right = index & 1; index >>= 1; - adrs_set_tree_height(adrs, h); + adrs_set_tree_height(adrs, h + 1); adrs_set_tree_index(adrs, index); if (right) randomized_tree_hash(sig.auth_path[h], root, key.public_key.seed, adrs, root); else randomized_tree_hash(root, sig.auth_path[h], key.public_key.seed, adrs, root); } + */ + + xmss_build_root(root, index, key.public_key.seed, adrs, sig.auth_path, height, root); if (memcmp(root, key.public_key.root, sizeof(hash256_t)) != 0) { error_print(); @@ -571,6 +642,25 @@ static int test_xmssmt_index_to_bytes(void) return 1; } +static int test_xmssmt_key_generate(void) +{ + uint32_t xmssmt_index = XMSSMT_HASH256_20_4_256; + XMSSMT_KEY key; + + if (xmssmt_key_generate(&key, xmssmt_index) != 1) { + error_print(); + return -1; + } + + xmssmt_public_key_print(stderr, 0, 4, "xmssmt_public_key", &key); + xmssmt_private_key_print(stderr, 0, 4, "xmssmt_private_key", &key); + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + + + static int test_xmssmt_signature_size(void) { size_t siglen; @@ -615,7 +705,7 @@ static int test_xmssmt_signature_print(void) // print for (i = 0; i < sizeof(xmssmt_consts)/sizeof(xmssmt_consts[0]); i++) { - xmssmt_signature_print_ex(stderr, 0, 0, "xmssmt_signature", &xmssmt_sig, xmssmt_consts[i].xmssmt_type); + xmssmt_signature_print_ex(stderr, 0, 4, "xmssmt_signature", &xmssmt_sig, xmssmt_consts[i].xmssmt_type); } printf("%s() ok\n", __FUNCTION__); @@ -633,13 +723,11 @@ static int test_xmssmt_signature_to_bytes(void) memset(&xmssmt_sig, 0, sizeof(xmssmt_sig)); - //xmssmt_signature_print_ex(stderr, 0, 0, "xmssmt_signature", &xmssmt_sig, xmssmt_type); - if (xmssmt_signature_to_bytes(&xmssmt_sig, xmssmt_type, &p, &len) != 1) { error_print(); return -1; } - xmssmt_signature_print(stderr, 0, 0, "xmssmt_signature", buf, len, xmssmt_type); + xmssmt_signature_print(stderr, 0, 4, "xmssmt_signature", buf, len, xmssmt_type); if (xmssmt_signature_from_bytes(&xmssmt_sig, xmssmt_type, &cp, &len) != 1) { error_print(); @@ -655,6 +743,309 @@ static int test_xmssmt_signature_to_bytes(void) return 1; } +static int test_xmssmt_private_key_size(void) +{ + uint32_t xmssmt_types[] = { + XMSSMT_HASH256_20_2_256, + XMSSMT_HASH256_20_4_256, + XMSSMT_HASH256_40_2_256, + XMSSMT_HASH256_40_4_256, + XMSSMT_HASH256_40_8_256, + XMSSMT_HASH256_60_3_256, + XMSSMT_HASH256_60_6_256, + XMSSMT_HASH256_60_12_256, + }; + size_t len; + size_t i; + + fprintf(stderr, "xmssmt_private_key_size()\n"); + for (i = 0; i < sizeof(xmssmt_types)/sizeof(xmssmt_types[0]); i++) { + if (xmssmt_private_key_size(xmssmt_types[i], &len) != 1) { + error_print(); + return -1; + } + fprintf(stderr, "%s: %zu\n", xmssmt_type_name(xmssmt_types[i]), len); + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_xmssmt_public_key_to_bytes(void) +{ + uint32_t xmssmt_types[] = { + XMSSMT_HASH256_20_2_256, + XMSSMT_HASH256_20_4_256, + XMSSMT_HASH256_40_2_256, + XMSSMT_HASH256_40_4_256, + XMSSMT_HASH256_40_8_256, + XMSSMT_HASH256_60_3_256, + XMSSMT_HASH256_60_6_256, + XMSSMT_HASH256_60_12_256, + }; + XMSSMT_KEY key; + uint8_t buf[XMSSMT_PUBLIC_KEY_SIZE]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + + + + memset(&key, 0, sizeof(key)); + + key.public_key.xmssmt_type = XMSSMT_HASH256_20_2_256; + + + + + if (xmssmt_public_key_to_bytes(&key, &p, &len) != 1) { + error_print(); + return -1; + } + if (len != XMSSMT_PUBLIC_KEY_SIZE) { + error_print(); + return -1; + } + if (xmssmt_public_key_from_bytes(&key, &cp, &len) != 1) { + error_print(); + return -1; + } + if (len) { + error_print(); + return -1; + } + + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_xmssmt_private_key_to_bytes(void) +{ + uint32_t xmssmt_type = XMSSMT_HASH256_20_4_256; + XMSSMT_KEY key; + size_t buflen; + uint8_t *buf = NULL; + uint8_t *p; + const uint8_t *cp; + size_t len = 0; + + memset(&key, 0, sizeof(key)); + + if (xmssmt_private_key_size(xmssmt_type, &buflen) != 1) { + error_print(); + return -1; + } + if (!(buf = malloc(buflen))) { + error_print(); + return -1; + } + cp = p = buf; + + if (xmssmt_key_generate(&key, xmssmt_type) != 1) { + error_print(); + return -1; + } + + if (xmssmt_private_key_to_bytes(&key, &p, &len) != 1) { + error_print(); + return -1; + } + if (len != buflen) { + error_print(); + return -1; + } + if (xmssmt_private_key_from_bytes(&key, &cp, &len) != 1) { + error_print(); + return -1; + } + if (len) { + fprintf(stderr, "len = %zu\n", len); + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_xmssmt_index(void) +{ + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +// copy from xmss.c +static uint64_t xmssmt_tree_address(uint64_t index, size_t height, size_t layers, size_t layer) { + return (index >> (height/layers) * (layer + 1)); +} + +// copy from xmss.c +static uint64_t xmssmt_tree_index(uint64_t index, size_t height, size_t layers, size_t layer) { + return (index >> (height/layers) * layer) % (1 << (height/layers)); +} + +// reference implementation of xmss^mt sign/verify +static int test_xmssmt_sign(void) +{ + static const uint8_t hash256_two[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + }; + static const uint8_t hash256_three[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + }; + + uint32_t xmssmt_type = XMSSMT_HASH256_20_4_256; + size_t height = 0; + size_t layers = 0; + + uint8_t msg[100] = {0}; + XMSSMT_SIGNATURE xmssmt_sig; + XMSSMT_SIGNATURE *sig = &xmssmt_sig; + XMSSMT_KEY xmssmt_key; + XMSSMT_KEY *key = &xmssmt_key; + XMSSMT_SIGN_CTX xmssmt_ctx; + XMSSMT_SIGN_CTX *ctx = &xmssmt_ctx; + hash256_t dgst; + + hash256_t hash256_index; + xmss_adrs_t adrs; + + uint64_t tree_address; + uint32_t tree_index; + uint32_t layer; + + + if (xmssmt_type_to_height_and_layers(xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + + + // generate key + if (xmssmt_key_generate(key, xmssmt_type) != 1) { + error_print(); + return -1; + } + xmssmt_private_key_print(stderr, 0, 4, "xmssmt_private_key", key); + + + // init sign ctx + memset(ctx, 0, sizeof(XMSSMT_SIGN_CTX)); + + // set ctx->xmssmt_public_key + ctx->xmssmt_public_key = key->public_key; + + // set ctx->xmssmt_sig + + // XMSSMT_SIGNATURE: + // uint64_t index + // hash256_t random + // wots_sig_t wots_sigs[layers]; + // hash256_t auth_path[height/layers] + + // copy index + ctx->xmssmt_sig.index = key->index; + + // copy wots_sigs[1] to wots_sig[layers - 1] from key + for (layer = 1; layer < layers; layer++) { + memcpy(ctx->xmssmt_sig.wots_sigs[layer], key->wots_sigs[layer - 1], sizeof(wots_sig_t)); + } + + // build auth_path + for (layer = 0; layer < layers; layer++) { + uint32_t tree_index = xmssmt_tree_index(ctx->xmssmt_sig.index, height, layers, layer); + hash256_t *tree = key->trees + xmss_tree_num_nodes(height/layers) * layer; + hash256_t *auth_path = ctx->xmssmt_sig.auth_path + (height/layers) * layer; + xmss_build_auth_path(tree, height/layers, tree_index, auth_path); + } + + // derive ctx->xmssmt_sig.random + memset(hash256_index, 0, 24); + PUTU64(hash256_index + 24, ctx->xmssmt_sig.index); + hash256_init(&ctx->hash256_ctx); + hash256_update(&ctx->hash256_ctx, hash256_three, sizeof(hash256_t)); + hash256_update(&ctx->hash256_ctx, key->sk_prf, sizeof(hash256_t)); + hash256_update(&ctx->hash256_ctx, hash256_index, sizeof(hash256_t)); + hash256_finish(&ctx->hash256_ctx, ctx->xmssmt_sig.random); + + // derive wots_sk and save to wots_sigs[0] + layer = 0; + tree_address = xmssmt_tree_address(ctx->xmssmt_sig.index, height, layers, layer); + tree_index = xmssmt_tree_index(ctx->xmssmt_sig.index, height, layers, layer); + adrs_set_layer_address(adrs, layer); + adrs_set_tree_address(adrs, tree_address); + adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); + adrs_set_ots_address(adrs, tree_index); + wots_derive_sk(key->secret, key->public_key.seed, adrs, ctx->xmssmt_sig.wots_sigs[0]); + + // H_msg(M) := HASH256(toByte(2, 32) || r || XMSS_ROOT || toByte(idx_sig, 32) || M) + hash256_init(&ctx->hash256_ctx); + hash256_update(&ctx->hash256_ctx, hash256_two, sizeof(hash256_t)); + hash256_update(&ctx->hash256_ctx, ctx->xmssmt_sig.random, sizeof(hash256_t)); + hash256_update(&ctx->hash256_ctx, key->public_key.root, sizeof(hash256_t)); + hash256_update(&ctx->hash256_ctx, hash256_index, sizeof(hash256_t)); + hash256_finish(&ctx->hash256_ctx, dgst); + + // generate message wots_sig as wots_sigs[0] + layer = 0; + tree_address = xmssmt_tree_address(ctx->xmssmt_sig.index, height, layers, layer); + tree_index = xmssmt_tree_index(ctx->xmssmt_sig.index, height, layers, layer); + adrs_set_layer_address(adrs, layer); + adrs_set_tree_address(adrs, tree_address); + adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); + adrs_set_ots_address(adrs, tree_index); + wots_sign(ctx->xmssmt_sig.wots_sigs[0], ctx->xmssmt_public_key.seed, adrs, dgst, + ctx->xmssmt_sig.wots_sigs[0]); + + xmssmt_signature_print_ex(stderr, 0, 4, "xmssmt_signature", &ctx->xmssmt_sig, xmssmt_type); + + + // verify + for (layer = 0; layer < layers; layer++) { + uint64_t tree_address = xmssmt_tree_address(ctx->xmssmt_sig.index, height, layers, layer); + uint32_t tree_index = xmssmt_tree_index(ctx->xmssmt_sig.index, height, layers, layer); + wots_key_t wots_pk; + + // wots_sig, dgst => wots_pk + adrs_set_layer_address(adrs, layer); + adrs_set_tree_address(adrs, tree_address); + adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); + adrs_set_ots_address(adrs, tree_index); + wots_sig_to_pk(ctx->xmssmt_sig.wots_sigs[layer], ctx->xmssmt_public_key.seed, adrs, dgst, wots_pk); + + // wots_pk => wots_root + adrs_set_type(adrs, XMSS_ADRS_TYPE_LTREE); + adrs_set_ltree_address(adrs, tree_index); + wots_pk_to_root(wots_pk, ctx->xmssmt_public_key.seed, adrs, dgst); + + // wots_root, auth_path => xmss_root (as dgst) + adrs_set_type(adrs, XMSS_ADRS_TYPE_HASHTREE); + adrs_set_padding(adrs, 0); + xmss_build_root(dgst, tree_index, + ctx->xmssmt_public_key.seed, adrs, + ctx->xmssmt_sig.auth_path + (height/layers) * layer, height/layers, + dgst); + } + + // verify xmssmt_root (save in dgst) + if (memcmp(dgst, ctx->xmssmt_public_key.root, sizeof(hash256_t)) != 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + int main(void) { @@ -663,18 +1054,29 @@ int main(void) if (test_wots_sk_to_pk() != 1) goto err; if (test_wots_sign() != 1) goto err; if (test_wots_derive_root() != 1) goto err; - if (test_xmss_build_tree() != 1) goto err; + if (test_wots_verify() != 1) goto err; #endif if (test_xmss_adrs() != 1) goto err; + if (test_xmss_build_tree() != 1) goto err; + if (test_xmss_build_root() != 1) goto err; + if (test_xmss_key_generate() != 1) goto err; if (test_xmss_key_to_bytes() != 1) goto err; if (test_xmss_signature_size() != 1) goto err; if (test_xmss_sign() != 1) goto err; if (test_xmss_sign_init() != 1) goto err; + + if (test_xmssmt_key_generate() != 1) goto err; if (test_xmssmt_index_to_bytes() != 1) goto err; - if (test_xmssmt_signature_size() != 1) goto err; if (test_xmssmt_signature_to_bytes() != 1) goto err; + if (test_xmssmt_signature_size() != 1) goto err; if (test_xmssmt_signature_print() != 1) goto err; + if (test_xmssmt_private_key_size() != 1) goto err; + if (test_xmssmt_public_key_to_bytes() != 1) goto err; + if (test_xmssmt_private_key_to_bytes() != 1) goto err; + if (test_xmssmt_sign() != 1) goto err; + + printf("%s all tests passed\n", __FILE__); return 0; err: