diff --git a/include/gmssl/error.h b/include/gmssl/error.h index 3185a688..50ad803b 100644 --- a/include/gmssl/error.h +++ b/include/gmssl/error.h @@ -1,5 +1,5 @@ /* - * Copyright 2014-2022 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2025 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. @@ -17,6 +17,8 @@ #include #include #include +#include + #ifdef __cplusplus extern "C" { diff --git a/include/gmssl/xmss.h b/include/gmssl/xmss.h index 7c93b934..e9109f44 100644 --- a/include/gmssl/xmss.h +++ b/include/gmssl/xmss.h @@ -26,57 +26,221 @@ extern "C" { #endif + + +// 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 -# define hash256_init sha256_init -# define hash256_update sha256_update -# define hash256_finish sha256_finish -# define hash256_digest sha256_digest -# define LMS_HASH256_10 XMSS_SHA256_10 -# define LMS_HASH256_16 XMSS_SHA256_16 -# define LMS_HASH256_20 XMSS_SHA256_20 +# define HASH256_CTX SHA256_CTX +# define hash256_init sha256_init +# define hash256_update sha256_update +# define hash256_finish sha256_finish +# define XMSS_HASH256_10_256 XMSS_SHA2_10_256 +# define XMSS_HASH256_16_256 XMSS_SHA2_16_256 +# define XMSS_HASH256_20_256 XMSS_SHA2_20_256 +# define XMSS_HASH256_10_256_NAME "XMSS_SHA2_10_256" +# define XMSS_HASH256_16_256_NAME "XMSS_SHA2_16_256" +# define XMSS_HASH256_20_256_NAME "XMSS_SHA2_20_256" #else -# define HASH256_CTX SM3_CTX -# define hash256_init sm3_init -# define hash256_update sm3_update -# define hash256_finish sm3_finish -# define hash256_digest sm3_digest -# define LMS_HASH256_10 XMSS_SM3_10 -# define LMS_HASH256_16 XMSS_SM3_16 -# define LMS_HASH256_20 XMSS_SM3_20 +# define HASH256_CTX SM3_CTX +# define hash256_init sm3_init +# define hash256_update sm3_update +# define hash256_finish sm3_finish +# define XMSS_HASH256_10_256 XMSS_SM3_10_256 +# define XMSS_HASH256_16_256 XMSS_SM3_16_256 +# define XMSS_HASH256_20_256 XMSS_SM3_20_256 +# define XMSS_HASH256_10_256_NAME "XMSS_SM3_10_256" +# define XMSS_HASH256_16_256_NAME "XMSS_SM3_16_256" +# define XMSS_HASH256_20_256_NAME "XMSS_SM3_20_256" #endif +// from RFC 8391 table 6 +enum { + WOTSP_RESERVED = 0x00000000, + WOTSP_SHA2_256 = 0x00000001, + WOTSP_SHA2_512 = 0x00000002, + WOTSP_SHAKE_256 = 0x00000003, + WOTSP_SHAKE_512 = 0x00000004, +}; + + +// from RFC 8391 table 7 +enum { + XMSS_RESERVED = 0x00000000, + XMSS_SHA2_10_256 = 0x00000001, + XMSS_SHA2_16_256 = 0x00000002, + XMSS_SHA2_20_256 = 0x00000003, + XMSS_SHA2_10_512 = 0x00000004, + XMSS_SHA2_16_512 = 0x00000005, + XMSS_SHA2_20_512 = 0x00000006, + XMSS_SHAKE_10_256 = 0x00000007, + XMSS_SHAKE_16_256 = 0x00000008, + XMSS_SHAKE_20_256 = 0x00000009, + XMSS_SHAKE_10_512 = 0x0000000A, + XMSS_SHAKE_16_512 = 0x0000000B, + XMSS_SHAKE_20_512 = 0x0000000C, +}; + +enum { + XMSS_SM3_10_256 = 0x10000001, // xmss tree height = 10, total 2^10 = 1 * 1024 sigs + XMSS_SM3_16_256 = 0x10000002, // xmss tree height = 16, total 2^16 = 64 * 1024 sigs + XMSS_SM3_20_256 = 0x10000003, // xmss tree height = 20, total 2^20 = 1024 * 1024 sigs +}; + + +#define XMSS_ADRS_LAYER_ADDRESS 0 +#define XMSS_ADRS_TREE_ADDRESS 0 + +enum { + XMSS_ADRS_TYPE_OTS = 0, + XMSS_ADRS_TYPE_LTREE = 1, + XMSS_ADRS_TYPE_HASHTREE = 2, +}; + +enum { + XMSS_ADRS_GENERATE_KEY = 0, + XMSS_ADRS_GENERATE_BITMASK = 1, +}; + + + + + + +char *xmss_type_name(uint32_t xmss_type); +uint32_t xmss_type_from_name(const char *name); +int xmss_type_to_height(uint32_t xmss_type, size_t *height); + + + + + + + + + + + +// rfc 8391 named algors only support w = 2^4 = 16 +#define XMSS_WOTS_WINTERNITZ_W 16 +#define WOTS_NUM_CHAINS 67 + + +#define XMSS_WOTS_SIGNATURE_SIZE (sizeof(hash256_t) * WOTS_NUM_CHAINS) + #define XMSS_MIX_HEIGHT 16 #define XMSS_MAX_HEIGHT 20 -// TODO: -// * change uint8[32] to hash256_t -// * key_to_bytes, from_bytes, use **out, *outlen style -// * support private key/ public key functions + + +typedef uint8_t xmss_adrs_t[32]; -// Derive wots+ sk from a secret seed use the spec of xmss-reference. -void sm3_wots_derive_sk(const uint8_t secret[32], - const uint8_t seed[32], const uint8_t in_adrs[32], - hash256_t sk[67]); // change number 67 to a DEFINE -void sm3_wots_derive_pk(const hash256_t sk[67], - const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], - hash256_t pk[67]); -void sm3_wots_do_sign(const hash256_t sk[67], - const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], - const uint8_t dgst[32], hash256_t sig[67]); -void sm3_wots_sig_to_pk(const hash256_t sig[67], const uint8_t dgst[32], - const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], - hash256_t pk[67]); +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 } -void xmss_derive_root(const uint8_t xmss_secret[32], int height, - const uint8_t seed[32], - hash256_t *tree, uint8_t xmss_root[32]); + 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; + +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; + +void adrs_copy_layer_address(xmss_adrs_t dst, const xmss_adrs_t src); +void adrs_copy_tree_address(xmss_adrs_t dst, const xmss_adrs_t src); +void adrs_copy_type(xmss_adrs_t dst, const xmss_adrs_t src); +void adrs_copy_ots_address(xmss_adrs_t dst, const xmss_adrs_t src); +void adrs_copy_chain_address(xmss_adrs_t dst, const xmss_adrs_t src); +void adrs_copy_hash_address(xmss_adrs_t dst, const xmss_adrs_t src); +void adrs_copy_key_and_mask(xmss_adrs_t dst, const xmss_adrs_t src); +void adrs_copy_ltree_address(xmss_adrs_t dst, const xmss_adrs_t src); +void adrs_copy_tree_height(xmss_adrs_t dst, const xmss_adrs_t src); +void adrs_copy_tree_index(xmss_adrs_t dst, const xmss_adrs_t src); +void adrs_copy_padding(xmss_adrs_t dst, const xmss_adrs_t src); + +void adrs_set_layer_address(uint8_t adrs[32], uint32_t layer); +void adrs_set_tree_address(uint8_t adrs[32], uint64_t tree_addr); +void adrs_set_type(uint8_t adrs[32], uint32_t type); +void adrs_set_ots_address(uint8_t adrs[32], uint32_t address); +void adrs_set_chain_address(uint8_t adrs[32], uint32_t address); +void adrs_set_hash_address(uint8_t adrs[32], uint32_t address); +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); + +int xmss_adrs_print(FILE *fp, int fmt, int ind, const char *label, const hash256_t adrs); + + + + + + + + +typedef hash256_t wots_key_t[67]; +typedef hash256_t wots_sig_t[67]; + + +void wots_chain(const hash256_t x, + const hash256_t seed, const xmss_adrs_t adrs, + int start, int steps, hash256_t pk); +void wots_sk_to_pk(const wots_key_t sk, + const hash256_t seed, const xmss_adrs_t adrs, + wots_key_t pk); +void wots_sign(const wots_key_t sk, + const hash256_t seed, const xmss_adrs_t adrs, + const hash256_t dgst, wots_sig_t sig); +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, + 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); + +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, @@ -84,60 +248,55 @@ void xmss_do_sign(const uint8_t xmss_secret[32], int index, hash256_t wots_sig[67], hash256_t *auth_path); -void xmss_sig_to_root(const hash256_t wots_sig[67], int index, const hash256_t *auth_path, - const uint8_t seed[32], const uint8_t in_adrs[32], int height, +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]); -enum { - XMSS_SM3_10 = 0x10000001, - XMSS_SM3_16 = 0x10000002, - XMSS_SM3_20 = 0x10000003, - XMSS_SHA256_10 = 0x00000001, - XMSS_SHA256_16 = 0x00000002, - XMSS_SHA256_20 = 0x00000003, -}; - -// delete this func -int xmss_height_from_oid(uint32_t *height, uint32_t id); +typedef struct { + uint32_t xmss_type; + uint8_t seed[32]; + uint8_t root[32]; +} XMSS_PUBLIC_KEY; // PK = OID || root || SEED // SK = idx || wots_sk || SK_PRF || root || SEED; typedef struct { - uint32_t oid; - uint8_t seed[32]; - uint8_t root[32]; + XMSS_PUBLIC_KEY public_key; + // private key uint8_t secret[32]; - uint8_t prf_key[32]; - uint32_t index; // change this to int, update every signing - hash256_t *tree; + uint8_t sk_prf[32]; // secret key for prf + uint32_t index; + hash256_t *tree; // merkle tree with wots+ public keys as leafs } 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 -// TODO: add public_key, private_key funcs -// TODO: key_update func -// TODO: build tree in private_key_from_bytes +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_print(FILE *fp, int fmt, int ind, const char *label, const XMSS_KEY *key); -int xmss_key_get_height(const XMSS_KEY *key, uint32_t *height); -int xmss_key_to_bytes(const XMSS_KEY *key, uint8_t *out, size_t *outlen); -int xmss_key_from_bytes(XMSS_KEY *key, const uint8_t *in, size_t inlen); -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_key_remaining_signs(const XMSS_KEY *key, size_t *count); + +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 { - uint8_t index[4]; + uint32_t index; // < 2^(XMSS_MAX_HEIGHT) = 2^20, always encode to 4 bytes uint8_t random[32]; hash256_t wots_sig[67]; hash256_t auth_path[XMSS_MAX_HEIGHT]; @@ -154,25 +313,217 @@ typedef struct { 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_key_get_signature_size(const XMSS_KEY *key, 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); + typedef struct { - uint8_t random[32]; + XMSS_PUBLIC_KEY xmss_public_key; + XMSS_SIGNATURE xmss_sig; HASH256_CTX hash256_ctx; - // TODO: cache signing key } 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); -// TODO: change the API to LMS/HSS style -// TODO: remove const before XMSS_KEY in sign_init -int xmss_sign_init(XMSS_SIGN_CTX *ctx, const XMSS_KEY *key); +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, const XMSS_KEY *key, uint8_t *sigbuf, size_t *siglen); +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, const XMSS_KEY *key, const uint8_t *sigbuf, size_t siglen); +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) + +#define XMSSMT_HASH256_20_2_256 XMSSMT_SHA2_20_2_256 +#define XMSSMT_HASH256_20_4_256 XMSSMT_SHA2_20_4_256 +#define XMSSMT_HASH256_40_2_256 XMSSMT_SHA2_40_2_256 +#define XMSSMT_HASH256_40_4_256 XMSSMT_SHA2_40_4_256 +#define XMSSMT_HASH256_40_8_256 XMSSMT_SHA2_40_8_256 +#define XMSSMT_HASH256_60_3_256 XMSSMT_SHA2_60_3_256 +#define XMSSMT_HASH256_60_6_256 XMSSMT_SHA2_60_6_256 +#define XMSSMT_HASH256_60_12_256 XMSSMT_SHA2_60_12_256 + +#define XMSSMT_HASH256_20_2_256_NAME "XMSSMT_SHA2_20_2_256" +#define XMSSMT_HASH256_20_4_256_NAME "XMSSMT_SHA2_20_4_256" +#define XMSSMT_HASH256_40_2_256_NAME "XMSSMT_SHA2_40_2_256" +#define XMSSMT_HASH256_40_4_256_NAME "XMSSMT_SHA2_40_4_256" +#define XMSSMT_HASH256_40_8_256_NAME "XMSSMT_SHA2_40_8_256" +#define XMSSMT_HASH256_60_3_256_NAME "XMSSMT_SHA2_60_3_256" +#define XMSSMT_HASH256_60_6_256_NAME "XMSSMT_SHA2_60_6_256" +#define XMSSMT_HASH256_60_12_256_NAME "XMSSMT_SHA2_60_12_256" + +#else + +#define XMSSMT_HASH256_20_2_256 XMSSMT_SM3_20_2_256 +#define XMSSMT_HASH256_20_4_256 XMSSMT_SM3_20_4_256 +#define XMSSMT_HASH256_40_2_256 XMSSMT_SM3_40_2_256 +#define XMSSMT_HASH256_40_4_256 XMSSMT_SM3_40_4_256 +#define XMSSMT_HASH256_40_8_256 XMSSMT_SM3_40_8_256 +#define XMSSMT_HASH256_60_3_256 XMSSMT_SM3_60_3_256 +#define XMSSMT_HASH256_60_6_256 XMSSMT_SM3_60_6_256 +#define XMSSMT_HASH256_60_12_256 XMSSMT_SM3_60_12_256 + +#define XMSSMT_HASH256_20_2_256_NAME "XMSSMT_SM3_20_2_256" +#define XMSSMT_HASH256_20_4_256_NAME "XMSSMT_SM3_20_4_256" +#define XMSSMT_HASH256_40_2_256_NAME "XMSSMT_SM3_40_2_256" +#define XMSSMT_HASH256_40_4_256_NAME "XMSSMT_SM3_40_4_256" +#define XMSSMT_HASH256_40_8_256_NAME "XMSSMT_SM3_40_8_256" +#define XMSSMT_HASH256_60_3_256_NAME "XMSSMT_SM3_60_3_256" +#define XMSSMT_HASH256_60_6_256_NAME "XMSSMT_SM3_60_6_256" +#define XMSSMT_HASH256_60_12_256_NAME "XMSSMT_SM3_60_12_256" + +#endif + + + +#define XMSSMT_MAX_HEIGHT 60 + +#define XMSSMT_MIN_LAYERS 2 +#define XMSSMT_MAX_LAYERS 12 + +//#define XMSSMT_MIN_XMSS_HEIGHT 5 +//#define XMSSMT_MAX_XMSS_HEIGHT 20 + +enum { // layers height sigs private + 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 + XMSSMT_SM3_40_4_256 = 0x00000004, // 4 10 + XMSSMT_SM3_40_8_256 = 0x00000005, // 8 5 + XMSSMT_SM3_60_3_256 = 0x00000006, // 3 20 + XMSSMT_SM3_60_6_256 = 0x00000007, // 6 10 + XMSSMT_SM3_60_12_256 = 0x00000008, // 12 5 +}; + +enum { + // from RFC 8391 table 8 + XMSSMT_RESERVED = 0x00000000, + XMSSMT_SHA2_20_2_256 = 0x00000001, + XMSSMT_SHA2_20_4_256 = 0x00000002, + XMSSMT_SHA2_40_2_256 = 0x00000003, + XMSSMT_SHA2_40_4_256 = 0x00000004, + XMSSMT_SHA2_40_8_256 = 0x00000005, + 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, + XMSSMT_SHA2_40_4_512 = 0x0000000C, + XMSSMT_SHA2_40_8_512 = 0x0000000D, + 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, + XMSSMT_SHAKE_40_4_256 = 0x00000014, + XMSSMT_SHAKE_40_8_256 = 0x00000015, + 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, + XMSSMT_SHAKE_40_4_512 = 0x0000001C, + XMSSMT_SHAKE_40_8_512 = 0x0000001D, + XMSSMT_SHAKE_60_3_512 = 0x0000001E, + XMSSMT_SHAKE_60_6_512 = 0x0000001F, + XMSSMT_SHAKE_60_12_512 = 0x00000020, +}; + + +char *xmssmt_type_name(uint32_t xmssmt_type); +uint32_t xmssmt_type_from_name(const char *name); +int xmssmt_type_to_height_and_layers(uint32_t xmssmt_type, size_t *height, size_t *layers); + + +typedef struct { + uint32_t xmssmt_type; + hash256_t seed; + hash256_t root; +} XMSSMT_PUBLIC_KEY; + +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]; +} XMSSMT_KEY; + +int xmssmt_key_generate(XMSSMT_KEY *key, uint32_t xmssmt_type); + + +typedef struct { + uint64_t index; + hash256_t random; + hash256_t wots_sigs[XMSSMT_MAX_LAYERS][67]; + hash256_t auth_path[XMSSMT_MAX_HEIGHT]; +} XMSSMT_SIGNATURE; + +#define XMSSMT_SIGNATURE_MAX_SIZE \ + (sizeof(uint64_t) + 32 + sizeof(wots_sig_t) * XMSSMT_MAX_LAYERS + sizeof(hash256_t) * XMSSMT_MAX_HEIGHT) + + +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); +int xmssmt_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const XMSSMT_SIGNATURE *sig, uint32_t xmssmt_type); +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_SIGN_CTX; + +int xmssmt_sign_init(XMSSMT_SIGN_CTX *ctx, XMSSMT_KEY *key); +int xmssmt_sign_update(XMSSMT_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); +int xmssmt_sign_finish(XMSSMT_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen); +int xmssmt_sign_finish_ex(XMSSMT_SIGN_CTX *ctx, XMSSMT_SIGNATURE *sig); +int xmssmt_verify_init_ex(XMSSMT_SIGN_CTX *ctx, const XMSSMT_KEY *key, const XMSSMT_SIGNATURE *sig); +int xmssmt_verify_init(XMSSMT_SIGN_CTX *ctx, const XMSSMT_KEY *key, const uint8_t *sigbuf, size_t siglen); +int xmssmt_verify_update(XMSSMT_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); +int xmssmt_verify_finish(XMSSMT_SIGN_CTX *ctx); + #ifdef __cplusplus diff --git a/src/xmss.c b/src/xmss.c index 4a6bcea2..a8406f22 100644 --- a/src/xmss.c +++ b/src/xmss.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2025 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. @@ -18,213 +18,383 @@ #include #include #include +#include #include -#define uint32_from_bytes(ptr) \ - ((uint32_t)(ptr)[0] << 24 | \ - (uint32_t)(ptr)[1] << 16 | \ - (uint32_t)(ptr)[2] << 8 | \ - (uint32_t)(ptr)[3]) +// TODO: not here +static uint8_t bn256_zero[] = { + 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, 0x00, +}; -#define uint32_to_bytes(a,ptr) \ - ((ptr)[0] = (uint8_t)((a) >> 24), \ - (ptr)[1] = (uint8_t)((a) >> 16), \ - (ptr)[2] = (uint8_t)((a) >> 8), \ - (ptr)[3] = (uint8_t)(a)) +static const uint8_t bn256_one[] = { + 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, 0x01, +}; -static void adrs_set_type(uint8_t adrs[32], uint32_t type) { - uint32_to_bytes(type, adrs + 4*3); +static const uint8_t bn256_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, +}; + + +static void uint32_to_bytes(uint32_t a, uint8_t **out, size_t *outlen) +{ + if (out && *out) { + PUTU32(*out, a); + *out += 4; + } + *outlen += 4; +} + +static void uint32_from_bytes(uint32_t *a, const uint8_t **in, size_t *inlen) +{ + *a = GETU32(*in); + *in += 4; + *inlen -= 4; +} + +static void hash256_to_bytes(const hash256_t hash, uint8_t **out, size_t *outlen) +{ + if (out && *out) { + memcpy(*out, hash, 32); + *out += 32; + } + *outlen += 32; +} + +static void hash256_from_bytes(hash256_t hash, const uint8_t **in, size_t *inlen) +{ + memcpy(hash, *in, 32); + *in += 32; + *inlen -= 32; +} + + +void adrs_copy_layer_address(xmss_adrs_t dst, const xmss_adrs_t src) { + memcpy(dst, src, 4); +} + +void adrs_copy_tree_address(xmss_adrs_t dst, const xmss_adrs_t src) { + memcpy(dst + 4, src + 4, 8); +} + +void adrs_copy_type(xmss_adrs_t dst, const xmss_adrs_t src) { + memcpy(dst + 12, src + 12, 4); +} + +void adrs_copy_ots_address(xmss_adrs_t dst, const xmss_adrs_t src) { + memcpy(dst + 16, src + 16, 4); +} + +void adrs_copy_chain_address(xmss_adrs_t dst, const xmss_adrs_t src) { + memcpy(dst + 20, src + 20, 4); +} + +void adrs_copy_hash_address(xmss_adrs_t dst, const xmss_adrs_t src) { + memcpy(dst + 24, src + 24, 4); +} + +void adrs_copy_key_and_mask(xmss_adrs_t dst, const xmss_adrs_t src) { + memcpy(dst + 28, src + 28, 4); +} + +void adrs_copy_ltree_address(xmss_adrs_t dst, const xmss_adrs_t src) { + memcpy(dst + 16, src + 16, 4); +} + +void adrs_copy_tree_height(xmss_adrs_t dst, const xmss_adrs_t src) { + memcpy(dst + 20, src + 20, 4); +} + +void adrs_copy_tree_index(xmss_adrs_t dst, const xmss_adrs_t src) { + memcpy(dst + 24, src + 24, 4); +} + +void adrs_copy_padding(xmss_adrs_t dst, const xmss_adrs_t src) { + memcpy(dst + 16, src + 16, 4); +} + +void adrs_set_layer_address(uint8_t adrs[32], uint32_t layer) { + PUTU32(adrs, layer); +} + +void adrs_set_tree_address(uint8_t adrs[32], uint64_t tree_addr) { + PUTU64(adrs + 4, tree_addr); +} + +void adrs_set_type(uint8_t adrs[32], uint32_t type) { + PUTU32(adrs + 4*3, type); memset(adrs + 16, 0, 16); } -static void adrs_set_ots_address(uint8_t adrs[32], uint32_t address) { - uint32_to_bytes(address, adrs + 4*4); +void adrs_set_ots_address(uint8_t adrs[32], uint32_t address) { + PUTU32(adrs + 4*4, address); } -static void adrs_set_chain_address(uint8_t adrs[32], uint32_t address) { - uint32_to_bytes(address, adrs + 4*5); +void adrs_set_chain_address(uint8_t adrs[32], uint32_t address) { + PUTU32(adrs + 4*5, address); } -static void adrs_set_hash_address(uint8_t adrs[32], uint32_t address) { - uint32_to_bytes(address, adrs + 4*6); +void adrs_set_hash_address(uint8_t adrs[32], uint32_t address) { + PUTU32(adrs + 4*6, address); } -static void adrs_set_ltree_address(uint8_t adrs[32], uint32_t address) { - uint32_to_bytes(address, adrs + 4*4); +void adrs_set_ltree_address(uint8_t adrs[32], uint32_t address) { + PUTU32(adrs + 4*4, address); } -static void adrs_set_tree_height(uint8_t adrs[32], uint32_t height) { - uint32_to_bytes(height, adrs + 4*5); +void adrs_set_padding(uint8_t adrs[32], uint32_t padding) { + PUTU32(adrs + 4*4, padding); } -static void adrs_set_tree_index(uint8_t adrs[32], uint32_t index) { - uint32_to_bytes(index, adrs + 4*6); +void adrs_set_tree_height(uint8_t adrs[32], uint32_t height) { + PUTU32(adrs + 4*5, height); } -static void adrs_set_key_and_mask(uint8_t adrs[32], uint8_t key_and_mask) { - uint32_to_bytes((uint32_t)key_and_mask, adrs + 4*7); +void adrs_set_tree_index(uint8_t adrs[32], uint32_t index) { + PUTU32(adrs + 4*6, index); } -/* -static void adrs_print(const uint8_t adrs[32]) +void adrs_set_key_and_mask(uint8_t adrs[32], uint8_t key_and_mask) { + PUTU32(adrs + 4*7, key_and_mask); +} + + + + + + + + + + + + + + + + + + + + + + + + + +int xmss_adrs_print(FILE *fp, int fmt, int ind, const char *label, const hash256_t adrs) { - const uint32_t *p = (uint32_t *)adrs; - int i; - for (i = 0; i < 8; i++) { - fprintf(stderr, "%08x ", p[i]); + uint32_t layer_address; + uint64_t tree_address; + uint32_t type; + uint32_t key_and_mask; + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + + layer_address = GETU32(adrs); + adrs += 4; + format_print(fp, fmt, ind, "layer_address: %"PRIu32"\n", layer_address); + + tree_address = GETU64(adrs); + adrs += 8; + format_print(fp, fmt, ind, "tree_address: %"PRIu64"\n", tree_address); + + type = GETU32(adrs); + adrs += 4; + format_print(fp, fmt, ind, "type: %"PRIu32"\n", layer_address); + + if (type == XMSS_ADRS_TYPE_OTS) { + uint32_t ots_address; + uint32_t chain_address; + uint32_t hash_address; + + ots_address = GETU32(adrs); + adrs += 4; + format_print(fp, fmt, ind, "ots_address: %"PRIu32"\n", ots_address); + chain_address = GETU32(adrs); + adrs += 4; + format_print(fp, fmt, ind, "chain_address: %"PRIu32"\n", chain_address); + hash_address = GETU32(adrs); + adrs += 4; + format_print(fp, fmt, ind, "hash_address: %"PRIu32"\n", hash_address); + } else if (type == XMSS_ADRS_TYPE_LTREE) { + uint32_t ltree_address; + uint32_t tree_height; + uint32_t tree_index; + + ltree_address = GETU32(adrs); + adrs += 4; + format_print(fp, fmt, ind, "ltree_address: %"PRIu32"\n", ltree_address); + tree_height = GETU32(adrs); + adrs += 4; + format_print(fp, fmt, ind, "tree_height: %"PRIu32"\n", tree_height); + tree_index = GETU32(adrs); + adrs += 4; + format_print(fp, fmt, ind, "tree_index: %"PRIu32"\n", tree_index); + } else if (type == XMSS_ADRS_TYPE_HASHTREE) { + uint32_t padding; + uint32_t tree_height; + uint32_t tree_index; + + padding = GETU32(adrs); + adrs += 4; + format_print(fp, fmt, ind, "padding: %"PRIu32"\n", padding); + tree_height = GETU32(adrs); + adrs += 4; + format_print(fp, fmt, ind, "tree_height: %"PRIu32"\n", tree_height); + tree_index = GETU32(adrs); + adrs += 4; + format_print(fp, fmt, ind, "tree_index: %"PRIu32"\n", tree_index); + } else { + error_print(); } - fprintf(stderr, "\n"); -} -*/ + key_and_mask = GETU32(adrs); + adrs += 4; + format_print(fp, fmt, ind, "key_and_mask: %"PRIu32"\n", key_and_mask); -// F: HASH256(toByte(0, 32) || KEY || M) -static void hash256_f_init(HASH256_CTX *hash256_ctx, const uint8_t key[32]) -{ - uint8_t hash_id[32] = {0}; - - hash256_init(hash256_ctx); - hash256_update(hash256_ctx, hash_id, 32); - hash256_update(hash256_ctx, key, 32); + return 1; } -// H: HASH256(toByte(1, 32) || KEY || M), M = (LEFT XOR BM_0) || (RIGHT XOR BM_1) -static void hash256_h_init(HASH256_CTX *hash256_ctx, const uint8_t key[32]) + + + +void wots_derive_sk(const hash256_t secret, + const hash256_t seed, const xmss_adrs_t ots_adrs, + wots_key_t sk) { - uint8_t hash_id[32] = {0}; - hash_id[31] = 1; - - hash256_init(hash256_ctx); - hash256_update(hash256_ctx, hash_id, 32); - hash256_update(hash256_ctx, key, 32); -} - -// H_msg: HASH256(toByte(2, 32) || KEY || M), u[64] KEY = r[32] || XMSS_ROOT[32] || toByte(idx_sig, 32) -static void hash256_h_msg_init(HASH256_CTX *hash256_ctx, const uint8_t key[96]) -{ - uint8_t hash_id[32] = {0}; - hash_id[31] = 2; - - hash256_init(hash256_ctx); - hash256_update(hash256_ctx, hash_id, 32); - hash256_update(hash256_ctx, key, 96); -} - -// PRF: HASH256(toByte(3, 32) || KEY[32] || M) -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); -} - -// PRF_keygen: HASH256(toByte(4, 32) || KEY[32] || M) -// follow github.com/XMSS/xmss-reference -static void hash256_prf_keygen_init(HASH256_CTX *hash256_ctx, const uint8_t key[32]) -{ - uint8_t hash_id[32] = {0}; - hash_id[31] = 4; - - hash256_init(hash256_ctx); - hash256_update(hash256_ctx, hash_id, 32); - hash256_update(hash256_ctx, key, 32); -} - -// compute wots+ chain, start from the secret x or a signature, output the final value -// 最终的这个结果应该不是PK啊? -static void wots_chain(const uint8_t x[32], int start, int steps, - const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], uint8_t pk[32]) -{ - HASH256_CTX hash256_ctx; - uint8_t state[32]; - uint8_t adrs[32]; - uint8_t key[32]; - uint8_t bitmask[32]; + static const uint8_t hash256_four[] = { + 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, 0x04, + }; + HASH256_CTX ctx; + xmss_adrs_t adrs; int i; - memcpy(adrs, in_adrs, 32); - memcpy(state, x, 32); - assert(start + steps <= 15); + adrs_copy_layer_address(adrs, ots_adrs); + adrs_copy_tree_address(adrs, ots_adrs); + adrs_copy_type(adrs, ots_adrs); + adrs_copy_ots_address(adrs, ots_adrs); + + for (i = 0; i < 67; i++) { + adrs_set_chain_address(adrs, i); + adrs_set_hash_address(adrs, 0); + adrs_set_key_and_mask(adrs, 0); + + hash256_init(&ctx); + hash256_update(&ctx, hash256_four, sizeof(hash256_t)); + hash256_update(&ctx, secret, sizeof(hash256_t)); + hash256_update(&ctx, seed, sizeof(hash256_t)); + hash256_update(&ctx, adrs, sizeof(xmss_adrs_t)); + hash256_finish(&ctx, sk[i]); + } +} + +void wots_chain(const hash256_t x, + const hash256_t seed, const xmss_adrs_t ots_adrs, + int start, int steps, hash256_t pk) +{ + HASH256_CTX ctx; + uint8_t adrs[32]; + int i; + + //assert(start >= 0 && start <= 15); + //assert(steps >= 0 && steps <= 15); + //assert(start + steps <= 15); + + memcpy(pk, x, 32); + + // 4 * 6 = 24, copy 24 bytes + adrs_copy_layer_address(adrs, ots_adrs); + adrs_copy_tree_address(adrs, ots_adrs); + adrs_copy_type(adrs, ots_adrs); + adrs_copy_ots_address(adrs, ots_adrs); + adrs_copy_chain_address(adrs, ots_adrs); for (i = start; i < start + steps; i++) { + uint8_t key[32]; + uint8_t bitmask[32]; + adrs_set_hash_address(adrs, i); // key = prf(seed, adrs) - hash256_ctx = *prf_seed_ctx; - adrs_set_key_and_mask(adrs, 0); - hash256_update(&hash256_ctx, adrs, sizeof(adrs)); - hash256_finish(&hash256_ctx, key); + adrs_set_key_and_mask(adrs, XMSS_ADRS_GENERATE_KEY); + hash256_init(&ctx); + hash256_update(&ctx, hash256_three, 32); + hash256_update(&ctx, seed, 32); + hash256_update(&ctx, adrs, 32); + hash256_finish(&ctx, key); // bitmask = prf(seed, adrs) - hash256_ctx = *prf_seed_ctx; - adrs_set_key_and_mask(adrs, 1); - hash256_update(&hash256_ctx, adrs, sizeof(adrs)); - hash256_finish(&hash256_ctx, bitmask); + adrs_set_key_and_mask(adrs, XMSS_ADRS_GENERATE_BITMASK); + hash256_init(&ctx); + hash256_update(&ctx, hash256_three, 32); + hash256_update(&ctx, seed, 32); + hash256_update(&ctx, adrs, 32); + hash256_finish(&ctx, bitmask); - // state = f(key, state xor bitmask) - gmssl_memxor(state, state, bitmask, 32); - hash256_f_init(&hash256_ctx, key); - hash256_update(&hash256_ctx, state, 32); - hash256_finish(&hash256_ctx, state); + // tmp = f(key, tmp xor bitmask) + gmssl_memxor(pk, pk, bitmask, 32); + hash256_init(&ctx); + hash256_update(&ctx, bn256_zero, 32); + hash256_update(&ctx, key, 32); + hash256_update(&ctx, pk, 32); + hash256_finish(&ctx, pk); } - memcpy(pk, state, 32); } -void sm3_wots_derive_sk(const uint8_t secret[32], const uint8_t seed[32], const uint8_t in_adrs[32], hash256_t sk[67]) +void wots_sk_to_pk(const wots_key_t sk, + const hash256_t seed, const xmss_adrs_t ots_adrs, + wots_key_t pk) { - HASH256_CTX prf_keygen_ctx; - HASH256_CTX prf_ctx; - uint8_t adrs[32]; + xmss_adrs_t adrs; int i; - hash256_prf_keygen_init(&prf_keygen_ctx, secret); - - memcpy(adrs, in_adrs, 32); - adrs_set_hash_address(adrs, 0); - adrs_set_key_and_mask(adrs, 0); - - for (i = 0; i < 67; i++) { - // sk[i] = prf(secret, toBytes(i,32)) - prf_ctx = prf_keygen_ctx; - adrs_set_chain_address(adrs, i); - hash256_update(&prf_ctx, seed, 32); - hash256_update(&prf_ctx, adrs, 32); - hash256_finish(&prf_ctx, sk[i]); - } -} - -void sm3_wots_derive_pk(const hash256_t sk[67], - const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], - hash256_t pk[67]) -{ - uint8_t adrs[32]; - int i; - - memcpy(adrs, in_adrs, 32); + adrs_copy_layer_address(adrs, ots_adrs); + adrs_copy_tree_address(adrs, ots_adrs); + adrs_copy_type(adrs, ots_adrs); + adrs_copy_ots_address(adrs, ots_adrs); for (i = 0; i < 67; i++) { adrs_set_chain_address(adrs, i); - wots_chain(sk[i], 0, 15, prf_seed_ctx, adrs, pk[i]); + wots_chain(sk[i], seed, adrs, 0, 15, pk[i]); } } -static void base_w_and_checksum(const uint8_t dgst[32], uint8_t msg[67]) +// seperate 256 bit digest into 256/4 = 64 step values, generate 3 checksum step values +// output steps[i] in [0, w-1] = [0, 16-1] +static void base_w_and_checksum(const hash256_t dgst, uint8_t steps[67]) { int csum = 0; int sbits; int i; for (i = 0; i < 32; i++) { - msg[2 * i] = dgst[i] >> 4; - msg[2 * i + 1] = dgst[i] & 0xf; + steps[2 * i] = dgst[i] >> 4; + steps[2 * i + 1] = dgst[i] & 0xf; } for (i = 0; i < 64; i++) { - csum += 15 - msg[i]; + csum += 15 - steps[i]; } // csum = csum << (8 - ((len_2 * lg(w)) %8)) = (8 - (3*4)%8) = 8 - 4 = 4 sbits = (8 - ((3 * 4) % 8)); @@ -235,103 +405,131 @@ static void base_w_and_checksum(const uint8_t dgst[32], uint8_t msg[67]) csum_bytes[0] = (csum >> 8) & 0xff; csum_bytes[1] = csum & 0xff; - msg[64] = csum_bytes[0] >> 4; - msg[65] = csum_bytes[0] & 0xf; - msg[66] = csum_bytes[1] >> 4; + steps[64] = csum_bytes[0] >> 4; + steps[65] = csum_bytes[0] & 0xf; + steps[66] = csum_bytes[1] >> 4; } -void sm3_wots_do_sign(const hash256_t sk[67], - const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], - const uint8_t dgst[32], hash256_t sig[67]) +void wots_sign(const wots_key_t sk, + const hash256_t seed, const xmss_adrs_t wots_adrs, + const hash256_t dgst, wots_key_t sig) { - uint8_t adrs[32]; - uint8_t msg[67]; - uint32_t i; - - memcpy(adrs, in_adrs, 32); - - base_w_and_checksum(dgst, msg); - - for (i = 0; i < 67; i++) { - adrs_set_chain_address(adrs, i); - wots_chain(sk[i], 0, msg[i], prf_seed_ctx, adrs, sig[i]); - } -} - -void sm3_wots_sig_to_pk(const hash256_t sig[67], const uint8_t dgst[32], - const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], - hash256_t pk[67]) -{ - uint8_t adrs[32]; - uint8_t msg[67]; + hash256_t adrs; + uint8_t steps[WOTS_NUM_CHAINS]; int i; - memcpy(adrs, in_adrs, 32); + adrs_copy_layer_address(adrs, wots_adrs); + adrs_copy_tree_address(adrs, wots_adrs); + adrs_copy_type(adrs, wots_adrs); + adrs_copy_ots_address(adrs, wots_adrs); - base_w_and_checksum(dgst, msg); + base_w_and_checksum(dgst, steps); - for (i = 0; i < 67; i++) { + for (i = 0; i < WOTS_NUM_CHAINS; i++) { adrs_set_chain_address(adrs, i); - wots_chain(sig[i], msg[i], 15 - msg[i], prf_seed_ctx, adrs, pk[i]); + wots_chain(sk[i], seed, adrs, 0, steps[i], sig[i]); } } -static void randomized_hash(const uint8_t left[32], const uint8_t right[32], - const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], - uint8_t out[32]) +void wots_sig_to_pk(const wots_sig_t sig, + const hash256_t seed, const xmss_adrs_t ots_adrs, + const hash256_t dgst, wots_key_t pk) { - HASH256_CTX hash256_ctx; - uint8_t adrs[32]; - uint8_t key[32]; - uint8_t bitmask[64]; + hash256_t adrs; + uint8_t steps[67]; + int i; - memcpy(adrs, in_adrs, 32); + adrs_copy_layer_address(adrs, ots_adrs); + adrs_copy_tree_address(adrs, ots_adrs); + adrs_copy_type(adrs, ots_adrs); + adrs_copy_ots_address(adrs, ots_adrs); - // key = prf(seed, adrs) - hash256_ctx = *prf_seed_ctx; - adrs_set_key_and_mask(adrs, 0); - hash256_update(&hash256_ctx, adrs, 32); - hash256_finish(&hash256_ctx, key); + base_w_and_checksum(dgst, steps); - // bm_0 = prf(seed, adrs) - hash256_ctx = *prf_seed_ctx; - adrs_set_key_and_mask(adrs, 1); - hash256_update(&hash256_ctx, adrs, 32); - hash256_finish(&hash256_ctx, bitmask); - - // bm_1 = prf(seed, adrs) - hash256_ctx = *prf_seed_ctx; - adrs_set_key_and_mask(adrs, 2); - hash256_update(&hash256_ctx, adrs, 32); - hash256_finish(&hash256_ctx, bitmask + 32); - - // return h(key, (left xor bm_0) || (right xor bm_1)) - hash256_h_init(&hash256_ctx, key); - gmssl_memxor(bitmask, bitmask, left, 32); - gmssl_memxor(bitmask + 32, bitmask + 32, right, 32); - hash256_update(&hash256_ctx, bitmask, 64); - hash256_finish(&hash256_ctx, out); + for (i = 0; i < 67; i++) { + adrs_set_chain_address(adrs, i); + wots_chain(sig[i], seed, adrs, steps[i], 15 - steps[i], pk[i]); + } } -static void build_ltree(const hash256_t in_pk[67], - const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], - uint8_t wots_root[32]) +// TODO: need test and test vector +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) { - hash256_t pk[67]; - uint8_t adrs[32]; + HASH256_CTX ctx; + xmss_adrs_t adrs; + hash256_t key; + hash256_t bm_0; + hash256_t bm_1; + + // copy adrs (and set the last key_and_mask) + adrs_copy_layer_address(adrs, tree_adrs); + adrs_copy_tree_address(adrs, tree_adrs); + adrs_copy_type(adrs, tree_adrs); + adrs_copy_ltree_address(adrs, tree_adrs); + adrs_copy_tree_height(adrs, tree_adrs); + adrs_copy_tree_index(adrs, tree_adrs); + + adrs_set_key_and_mask(adrs, 0); + // key = prf(seed, adrs) + hash256_init(&ctx); + hash256_update(&ctx, hash256_three, sizeof(hash256_t)); + hash256_update(&ctx, seed, sizeof(hash256_t)); + hash256_update(&ctx, adrs, sizeof(xmss_adrs_t)); + hash256_finish(&ctx, key); + + adrs_set_key_and_mask(adrs, 1); + // bm_0 = prf(seed, adrs) + hash256_init(&ctx); + hash256_update(&ctx, hash256_three, sizeof(hash256_t)); + hash256_update(&ctx, seed, sizeof(hash256_t)); + hash256_update(&ctx, adrs, sizeof(xmss_adrs_t)); + hash256_finish(&ctx, bm_0); + + adrs_set_key_and_mask(adrs, 2); + // bm_1 = prf(seed, adrs) + hash256_init(&ctx); + hash256_update(&ctx, hash256_three, sizeof(hash256_t)); + hash256_update(&ctx, seed, sizeof(hash256_t)); + hash256_update(&ctx, adrs, sizeof(xmss_adrs_t)); + hash256_finish(&ctx, bm_1); + + // parent = Hash( tobyte(1, 32) || key || (left xor bm_0) || (right xor bm_1) ) + gmssl_memxor(bm_0, bm_0, left_child, sizeof(hash256_t)); + gmssl_memxor(bm_1, bm_1, right_child, sizeof(hash256_t)); + hash256_init(&ctx); + hash256_update(&ctx, bn256_one, sizeof(hash256_t)); + hash256_update(&ctx, key, sizeof(hash256_t)); + hash256_update(&ctx, bm_0, sizeof(hash256_t)); + hash256_update(&ctx, bm_1, sizeof(hash256_t)); + hash256_finish(&ctx, parent); +} + +// ltree is wots+ leaf tree, (un-balanced) merkle tree from the 67 wots+ hashs +void wots_build_ltree(const wots_key_t in_pk, + const hash256_t seed, const xmss_adrs_t in_adrs, + hash256_t wots_root) +{ + wots_key_t pk; + xmss_adrs_t adrs; uint32_t tree_height = 0; - int len = 67; + int len = WOTS_NUM_CHAINS; uint32_t i; - memcpy(pk, in_pk, sizeof(pk)); - memcpy(adrs, in_adrs, 32); + memcpy(pk, in_pk, sizeof(wots_key_t)); + + adrs_copy_layer_address(adrs, in_adrs); + adrs_copy_tree_address(adrs, in_adrs); + adrs_copy_type(adrs, in_adrs); + adrs_copy_ltree_address(adrs, in_adrs); adrs_set_tree_height(adrs, tree_height++); while (len > 1) { for (i = 0; i < (uint32_t)len/2; i++) { adrs_set_tree_index(adrs, i); - randomized_hash(pk[2 * i], pk[2 * i + 1], prf_seed_ctx, adrs, pk[i]); + randomized_tree_hash(pk[2 * i], pk[2 * i + 1], seed, adrs, pk[i]); } if (len % 2) { memcpy(pk[len/2], pk[len-1], 32); //pk[len/2] = pk[len - 1]; @@ -344,70 +542,74 @@ static void build_ltree(const hash256_t in_pk[67], memcpy(wots_root, pk[0], 32); } -// len(tree) = 2^h - 1 -// root = tree[len(tree) - 1] = tree[2^h - 2] -static void build_hash_tree(const hash256_t *leaves, int height, - const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], - hash256_t *tree) +// 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, + hash256_t wots_root) { - uint8_t adrs[32]; - int n = 1 << height; - int h, i; + wots_key_t wots_key; + xmss_adrs_t wots_adrs; + xmss_adrs_t ltree_adrs; - memcpy(adrs, in_adrs, 32); - adrs_set_type(adrs, 2); + adrs_copy_layer_address(wots_adrs, adrs); + adrs_copy_tree_address(wots_adrs, adrs); + adrs_set_type(wots_adrs, XMSS_ADRS_TYPE_OTS); + adrs_copy_ots_address(wots_adrs, adrs); + wots_derive_sk(secret, seed, wots_adrs, wots_key); + wots_sk_to_pk(wots_key, seed, wots_adrs, wots_key); + + adrs_copy_layer_address(ltree_adrs, adrs); + adrs_copy_tree_address(ltree_adrs, adrs); + 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); +} + +static size_t tree_root_offset(size_t height) { + return (1 << (height + 1)) - 2; +} + +// 2^(height + 1) - 1 +void xmss_build_tree(const hash256_t secret, + const hash256_t seed, const xmss_adrs_t tree_adrs, + size_t height, hash256_t *tree) +{ + xmss_adrs_t adrs; + hash256_t *children; + hash256_t *parents; + size_t n = 1 << height; + size_t h; + size_t i; + + adrs_copy_layer_address(adrs, tree_adrs); + adrs_copy_tree_address(adrs, tree_adrs); + + // derive 2^h wots+ roots as leaves of xmss tree + adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); + for (i = 0; i < n; i++) { + adrs_set_ots_address(adrs, i); + wots_derive_root(secret, seed, adrs, tree[i]); + } + + // build xmss tree + adrs_set_type(adrs, XMSS_ADRS_TYPE_HASHTREE); + children = tree; + parents = tree + n; for (h = 0; h < height; h++) { adrs_set_tree_height(adrs, h); - n >>= 1; for (i = 0; i < n; i++) { adrs_set_tree_index(adrs, i); - randomized_hash(leaves[2*i], leaves[2*i + 1], prf_seed_ctx, adrs, tree[i]); + randomized_tree_hash(children[2*i], children[2*i + 1], seed, adrs, parents[i]); } - leaves = tree; - tree += n; + children = parents; + parents += n; } } -void xmss_derive_root(const uint8_t xmss_secret[32], int height, - const uint8_t seed[32], - hash256_t *tree, uint8_t xmss_root[32]) -{ - HASH256_CTX prf_keygen_ctx; - HASH256_CTX prf_seed_ctx; - uint8_t adrs[32] = {0}; - uint32_t i; - - hash256_prf_keygen_init(&prf_keygen_ctx, xmss_secret); - hash256_prf_init(&prf_seed_ctx, seed); - - // generate all the wots pk[] - for (i = 0; i < (uint32_t)(1< wots_sk[0..67] => wots_pk[0..67] - // follow github.com/XMSS/xmss-reference - adrs_set_type(adrs, 0); - adrs_set_ots_address(adrs, i); - sm3_wots_derive_sk(xmss_secret, seed, adrs, wots_sk); - sm3_wots_derive_pk(wots_sk, &prf_seed_ctx, adrs, wots_pk); - - // wots_pk[0..67] => wots_root - adrs_set_type(adrs, 1); - adrs_set_ltree_address(adrs, i); - build_ltree(wots_pk, &prf_seed_ctx, adrs, tree[i]); - } - - // build full hash_tree - memset(adrs, 0, sizeof(adrs)); - build_hash_tree(tree, height, &prf_seed_ctx, adrs, tree + (1< wots_sk[0..67] => wots_pk[0..67] - adrs_set_type(adrs, 0); - adrs_set_ots_address(adrs, index); - sm3_wots_derive_sk(xmss_secret, seed, adrs, wots_sk); - - sm3_wots_do_sign(wots_sk, &prf_seed_ctx, adrs, dgst, wots_sig); - - build_auth_path(tree, height, index, auth_path); -} - -void xmss_sig_to_root(const hash256_t wots_sig[67], int index, const hash256_t *auth_path, - const uint8_t seed[32], const uint8_t in_adrs[32], int height, +// remove this function +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]) { - HASH256_CTX prf_seed_ctx; - uint8_t adrs[32]; - hash256_t wots_pk[67]; + xmss_adrs_t adrs; + wots_key_t wots_pk; uint8_t *node = xmss_root; int h; + uint32_t index; - hash256_prf_init(&prf_seed_ctx, seed); + // wots_sig to wots_pk + 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(wots_sig, seed, adrs, dgst, wots_pk); - memcpy(adrs, in_adrs, 32); + // 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); - adrs_set_type(adrs, 0); - adrs_set_ots_address(adrs, index); - sm3_wots_sig_to_pk(wots_sig, dgst, &prf_seed_ctx, adrs, wots_pk); + index = GETU32(in_adrs + 16); - adrs_set_type(adrs, 1); - adrs_set_ltree_address(adrs, index); - build_ltree(wots_pk, &prf_seed_ctx, adrs, node); - - adrs_set_type(adrs, 2); - adrs_set_tree_index(adrs, index); + // wots_root, 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_index(adrs, index); if (right) - randomized_hash(auth_path[h], node, &prf_seed_ctx, adrs, node); - else randomized_hash(node, auth_path[h], &prf_seed_ctx, adrs, node); + randomized_tree_hash(auth_path[h], node, seed, adrs, node); + else randomized_tree_hash(node, auth_path[h], seed, adrs, node); } } -int xmss_height_from_oid(uint32_t *height, uint32_t id) + +int xmss_type_to_height(uint32_t xmss_type, size_t *height) { - switch (id) { - case XMSS_SM3_10: *height = 10; break; - case XMSS_SM3_16: *height = 16; break; - case XMSS_SM3_20: *height = 20; break; - case XMSS_SHA256_10: *height = 10; break; - case XMSS_SHA256_16: *height = 16; break; - case XMSS_SHA256_20: *height = 20; break; + switch (xmss_type) { + case XMSS_HASH256_10_256: *height = 10; break; + case XMSS_HASH256_16_256: *height = 16; break; + case XMSS_HASH256_20_256: *height = 20; break; default: error_print(); return -1; @@ -493,218 +675,328 @@ int xmss_height_from_oid(uint32_t *height, uint32_t id) return 1; } -int xmss_oid_to_height(uint32_t oid, size_t *height) +char *xmss_type_name(uint32_t type) { - switch (oid) { - case XMSS_SM3_10: *height = 10; break; - case XMSS_SM3_16: *height = 16; break; - case XMSS_SM3_20: *height = 20; break; - case XMSS_SHA256_10: *height = 10; break; - case XMSS_SHA256_16: *height = 16; break; - case XMSS_SHA256_20: *height = 20; break; - default: - error_print(); - return -1; + switch (type) { + case XMSS_HASH256_10_256: return XMSS_HASH256_10_256_NAME; + case XMSS_HASH256_16_256: return XMSS_HASH256_16_256_NAME; + case XMSS_HASH256_20_256: return XMSS_HASH256_20_256_NAME; } - return 1; + return NULL; } -int xmss_key_generate(XMSS_KEY *key, uint32_t oid) +uint32_t xmss_type_from_name(const char *name) { - uint32_t height; + if (!strcmp(name, XMSS_HASH256_10_256_NAME)) { + return XMSS_HASH256_10_256; + } else if (!strcmp(name, XMSS_HASH256_16_256_NAME)) { + return XMSS_HASH256_16_256; + } else if (!strcmp(name, XMSS_HASH256_20_256_NAME)) { + return XMSS_HASH256_20_256; + } + return 0; +} - if (xmss_height_from_oid(&height, oid) != 1) { +int xmss_key_generate(XMSS_KEY *key, uint32_t xmss_type) +{ + size_t height; + size_t tree_nodes; // = 2^(h + 1) - 1 + xmss_adrs_t adrs; + + if (!key) { error_print(); return -1; } + if (xmss_type_to_height(xmss_type, &height) != 1) { + error_print(); + return -1; + } + memset(key, 0, sizeof(*key)); - key->oid = oid; - key->index = 0; - if (rand_bytes(key->seed, 32) != 1 + key->public_key.xmss_type = xmss_type; + + if (rand_bytes(key->public_key.seed, 32) != 1 || rand_bytes(key->secret, 32) != 1 - || rand_bytes(key->prf_key, 32) != 1 - || !(key->tree = malloc(32 * (1 << height) * 2 - 1))) { + || rand_bytes(key->sk_prf, 32) != 1) { + error_print(); + return -1; + } + tree_nodes = (1 << height) * 2 - 1; + if (!(key->tree = malloc(sizeof(hash256_t) * tree_nodes))) { error_print(); return -1; } - xmss_derive_root(key->secret, height, key->seed, key->tree, key->root); + adrs_set_layer_address(adrs, 0); + adrs_set_tree_address(adrs, 0); + xmss_build_tree(key->secret, key->public_key.seed, adrs, height, key->tree); + memcpy(key->public_key.root, key->tree[tree_root_offset(height)], sizeof(hash256_t)); + key->index = 0; + 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; + size_t n; + + if (!key || !count) { + error_print(); + return -1; + } + if (xmss_type_to_height(key->public_key.xmss_type, &height) != 1) { + error_print(); + return -1; + } + n = 1 << height; + if (key->index > n) { + error_print(); + return -1; + } + *count = n - key->index; return 1; } void xmss_key_cleanup(XMSS_KEY *key) { - if (key->tree) { - free(key->tree); + if (key) { + gmssl_secure_clear(key->secret, sizeof(hash256_t)); + gmssl_secure_clear(key->sk_prf, sizeof(hash256_t)); + if (key->tree) { + free(key->tree); + } + memset(key, 0, sizeof(*key)); } - gmssl_secure_clear(key, sizeof(*key)); } -int xmss_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSS_KEY *key) +int xmss_public_key_to_bytes(const XMSS_KEY *key, uint8_t **out, size_t *outlen) +{ + if (!key || !outlen) { + error_print(); + return -1; + } + uint32_to_bytes(key->public_key.xmss_type, out, outlen); + hash256_to_bytes(key->public_key.root, out, outlen); + hash256_to_bytes(key->public_key.seed, out, outlen); + return 1; +} + +int xmss_public_key_from_bytes(XMSS_KEY *key, const uint8_t **in, size_t *inlen) +{ + if (!key || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (*inlen < XMSS_PUBLIC_KEY_SIZE) { + error_print(); + return -1; + } + memset(key, 0, sizeof(*key)); + + uint32_from_bytes(&key->public_key.xmss_type, in, inlen); + if (!xmss_type_name(key->public_key.xmss_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 xmss_public_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSS_KEY *key) { format_print(fp, fmt, ind, "%s\n", label); ind += 4; - format_print(fp, fmt, ind, "oid: 0x%08X\n", key->oid); - format_bytes(fp, fmt, ind, "seed", key->seed, 32); - format_bytes(fp, fmt, ind, "root", key->root, 32); + format_print(fp, fmt, ind, "type: %s\n", xmss_type_name(key->public_key.xmss_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 xmss_private_key_to_bytes(const XMSS_KEY *key, uint8_t **out, size_t *outlen) +{ + if (!key || !outlen) { + error_print(); + return -1; + } + uint32_to_bytes(key->public_key.xmss_type, out, outlen); + hash256_to_bytes(key->public_key.root, out, outlen); + hash256_to_bytes(key->public_key.seed, out, outlen); + uint32_to_bytes(key->index, out, outlen); + hash256_to_bytes(key->secret, out, outlen); + hash256_to_bytes(key->sk_prf, out, outlen); + return 1; +} + +int xmss_private_key_from_bytes(XMSS_KEY *key, const uint8_t **in, size_t *inlen) +{ + size_t height; + size_t tree_nodes; + xmss_adrs_t adrs; + + if (!key || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (*inlen < XMSS_PRIVATE_KEY_SIZE) { + error_print(); + return -1; + } + memset(key, 0, sizeof(*key)); + + // xmss_type + uint32_from_bytes(&key->public_key.xmss_type, in, inlen); + if (xmss_type_to_height(key->public_key.xmss_type, &height) != 1) { + error_print(); + return -1; + } + // root + hash256_from_bytes(key->public_key.root, in, inlen); + // seed + hash256_from_bytes(key->public_key.seed, in, inlen); + + // index, allow index == 2^h, which means out-of-keys + uint32_from_bytes(&key->index, in, inlen); + if (key->index > (1 << height)) { + error_print(); + return -1; + } + // prepare buffer (might failure ops) before load secrets + tree_nodes = (1 << (height + 1)) - 1; + if (!(key->tree = malloc(sizeof(hash256_t) * tree_nodes))) { + error_print(); + return -1; + } + + // secret + hash256_from_bytes(key->secret, in, inlen); + // sk_prf + hash256_from_bytes(key->sk_prf, in, inlen); + + // build_tree + adrs_set_layer_address(adrs, 0); + adrs_set_tree_address(adrs, 0); + xmss_build_tree(key->secret, key->public_key.seed, adrs, height, key->tree); + // check + if (memcmp(key->tree[tree_root_offset(height)], + key->public_key.root, sizeof(hash256_t)) != 0) { + xmss_key_cleanup(key); + error_print(); + return -1; + } + return 1; +} + +int xmss_private_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSS_KEY *key) +{ + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + format_print(fp, fmt, ind, "type: %s\n", xmss_type_name(key->public_key.xmss_type)); + format_bytes(fp, fmt, ind, "seed", key->public_key.seed, 32); + format_bytes(fp, fmt, ind, "root", key->public_key.root, 32); format_bytes(fp, fmt, ind, "secret", key->secret, 32); - format_bytes(fp, fmt, ind, "prf_key", key->prf_key, 32); + format_bytes(fp, fmt, ind, "sk_prf", key->sk_prf, 32); format_print(fp, fmt, ind, "index: %u\n", key->index); return 1; } - -int xmss_key_get_height(const XMSS_KEY *key, uint32_t *height) +int xmss_signature_size(uint32_t xmss_type, size_t *siglen) { - if (xmss_height_from_oid(height, key->oid) != 1) { + XMSS_SIGNATURE sig; + size_t height; + + if (!siglen) { error_print(); return -1; } + if (xmss_type_to_height(xmss_type, &height) != 1) { + error_print(); + return -1; + } + *siglen = sizeof(sig.index) + + sizeof(sig.random) + + sizeof(sig.wots_sig) + + sizeof(hash256_t) * height; return 1; } -// save the full tree, should use a flag to choose cache tree or not -int xmss_key_to_bytes(const XMSS_KEY *key, uint8_t *out, size_t *outlen) +int xmss_signature_from_bytes(uint32_t xmss_type, XMSS_SIGNATURE *sig, const uint8_t **in, size_t *inlen) { - uint32_t height; - size_t tree_size; - uint8_t *p; + size_t height; + size_t siglen; + size_t i; - if (!outlen) { + if (xmss_type_to_height(xmss_type, &height) != 1) { + error_print(); + return -1; + } + if (xmss_signature_size(xmss_type, &siglen) != 1) { + error_print(); + return -1; + } + if (*inlen < siglen) { error_print(); return -1; } - if (xmss_height_from_oid(&height, key->oid) != 1) { - error_print(); - return -1; - } - tree_size = 32 * ((1 << (height + 1)) - 1); - if (!key->tree) { - error_print(); - return -1; - } - - if (!out) { - *outlen = 4 + 32*4 + 4 + tree_size; - return 1; - } - - p = out; - uint32_to_bytes(key->oid, p); p += 4; - memcpy(p, key->seed, 32); p += 32; - memcpy(p, key->root, 32); p += 32; - memcpy(p, key->secret, 32); p += 32; - memcpy(p, key->prf_key, 32); p += 32; - uint32_to_bytes(key->index, p); p += 4; - memcpy(p, key->tree, tree_size); p += tree_size; - *outlen = p - out; + uint32_from_bytes(&sig->index, in, inlen); + hash256_from_bytes(sig->random, in, inlen); + for (i = 0; i < 67; i++) + hash256_from_bytes(sig->wots_sig[i], in, inlen); + for (i = 0; i < height; i++) + hash256_from_bytes(sig->auth_path[i], in, inlen); return 1; } -int xmss_key_from_bytes(XMSS_KEY *key, const uint8_t *in, size_t inlen) +int xmss_signature_to_bytes(uint32_t xmss_type, const XMSS_SIGNATURE *sig, uint8_t **out, size_t *outlen) { - uint32_t height; - size_t tree_size; - const uint8_t *p; + size_t height; + size_t i; - if (inlen < 4) { + if (!sig || !outlen) { error_print(); return -1; } - p = in; - key->oid = uint32_from_bytes(p); p += 4; - - if (xmss_height_from_oid(&height, key->oid) != 1) { + if (xmss_type_to_height(xmss_type, &height) != 1) { error_print(); return -1; } - tree_size = 32 * ((1 << (height + 1)) - 1); - if (inlen != (4 + 32 * 4 + 4 + tree_size)) { - error_print(); - return -1; + uint32_to_bytes(sig->index, out, outlen); + hash256_to_bytes(sig->random, out, outlen); + for (i = 0; i < 67; i++) { + hash256_to_bytes(sig->wots_sig[i], out, outlen); } - memcpy(key->seed, p, 32); p += 32; - memcpy(key->root, p, 32); p += 32; - memcpy(key->secret, p, 32); p += 32; - memcpy(key->prf_key, p, 32); p += 32; - - key->index = uint32_from_bytes(p); p += 4; - if (key->index >= (uint32_t)(1 << height)) { - error_print(); - return -1; + for (i = 0; i < height; i++) { + hash256_to_bytes(sig->auth_path[i], out, outlen); } - - if (!(key->tree = malloc(tree_size))) { - error_print(); - return -1; - } - memcpy(key->tree, p, tree_size); return 1; } -int xmss_public_key_to_bytes(const XMSS_KEY *key, uint8_t *out, size_t *outlen) +int xmss_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const XMSS_SIGNATURE *sig) { - uint32_t height; - uint8_t *p; + uint32_t xmss_type; + size_t height; + size_t i; - if (!outlen) { + xmss_type = (uint32_t)fmt; + if (xmss_type_to_height(xmss_type, &height) != 1) { error_print(); return -1; } - if (xmss_height_from_oid(&height, key->oid) != 1) { - error_print(); - return -1; - } - - if (!out) { - *outlen = 4 + 32 + 32; - return 1; - } - - p = out; - uint32_to_bytes(key->oid, p); p += 4; - memcpy(p, key->seed, 32); p += 32; - memcpy(p, key->root, 32); p += 32; - *outlen = p - out; - - return 1; -} - -// FIXME: check input length -int xmss_public_key_from_bytes(XMSS_KEY *key, const uint8_t *in, size_t inlen) -{ - uint32_t height; - const uint8_t *p; - - if (inlen != 4 + 32 * 2) { - error_print(); - return -1; - } - p = in; - key->oid = uint32_from_bytes(p); p += 4; - if (xmss_height_from_oid(&height, key->oid) != 1) { - error_print(); - return -1; - } - memcpy(key->seed, p, 32); p += 32; - memcpy(key->root, p, 32); p += 32; - return 1; -} - -int xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *in, size_t inlen) -{ - uint32_t index; - XMSS_SIGNATURE *sig = (XMSS_SIGNATURE *)in; - int i; - format_print(fp, fmt, ind, "%s\n", label); ind += 4; - - index = uint32_from_bytes(sig->index); - format_print(fp, fmt, ind, "index: %u\n", index); + format_print(fp, fmt, ind, "index: %u\n", sig->index); format_bytes(fp, fmt, ind, "random", sig->random, 32); format_print(fp, fmt, ind, "wots_sig\n"); for (i = 0; i < 67; i++) { @@ -712,60 +1004,114 @@ int xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, const ui format_bytes(fp, fmt, 0, "", sig->wots_sig[i], 32); } format_print(fp, fmt, ind, "auth_path\n"); - - assert(sizeof(XMSS_SIGNATURE) == 4 + 32 * (68 + 20)); - inlen -= 4 + 32 * 68; - for (i = 0; i < 20 && inlen >= 32; i++) { + for (i = 0; i < height; i++) { format_print(fp, fmt, ind+4, "%d ", i); format_bytes(fp, fmt, 0, "", sig->auth_path[i], 32); - inlen -= 32; } + return 1; +} + +int xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen) +{ + uint32_t index; + int i; + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + + if (siglen < 4) { + error_print(); + return -1; + } + index = GETU32(sig); + format_print(fp, fmt, ind, "index: %u\n", index); + sig += 4; + siglen -= 4; + + + if (siglen < 32) { + error_print(); + return -1; + } + format_bytes(fp, fmt, ind, "random", sig, 32); + sig += 32; + siglen -= 32; + + format_print(fp, fmt, ind, "wots_sig\n"); + for (i = 0; i < 67; i++) { + if (siglen < 32) { + error_print(); + return -1; + } + format_print(fp, fmt, ind+4, "%d ", i); + format_bytes(fp, fmt, 0, "", sig, 32); + sig += 32; + siglen -= 32; + } + + format_print(fp, fmt, ind, "auth_path\n"); + for (i = 0; i < XMSS_MAX_HEIGHT && siglen >= 32; i++) { + format_print(fp, fmt, ind+4, "%d ", i); + format_bytes(fp, fmt, 0, "", sig, 32); + sig += 32; + siglen -= 32; + } + + format_print(fp, fmt, ind, "[left %zu bytes]\n", siglen); return 1; } -// (4 + n + (len + h) * n) -int xmss_signature_size(uint32_t oid, size_t *siglen) +int xmss_sign_init(XMSS_SIGN_CTX *ctx, XMSS_KEY *key) { + uint8_t index_buf[32] = {0}; + uint8_t adrs[32]; size_t height; - if (!siglen) { + if (!ctx || !key) { error_print(); return -1; } - if (xmss_oid_to_height(oid, &height) != 1) { + if (xmss_type_to_height(key->public_key.xmss_type, &height) != 1) { error_print(); return -1; } - *siglen = 4 // OID - + 32 // random - + 32 * 67 // WOTS signature size - + 32 * height // path - ; - return 1; -} + memset(ctx, 0, sizeof(*ctx)); + // cache public key + ctx->xmss_public_key = key->public_key; + // key->index => xmss_sig.index + ctx->xmss_sig.index = key->index; -int xmss_sign_init(XMSS_SIGN_CTX *ctx, const XMSS_KEY *key) -{ - HASH256_CTX prf_ctx; - uint8_t hash_id[32] = {0}; - uint8_t index_buf[32] = {0}; - + // derive ctx->xmss_sig.random + PUTU32(index_buf + 28, key->index); // r = PRF(SK_PRF, toByte(idx_sig, 32)); - hash256_prf_init(&prf_ctx, key->prf_key); - uint32_to_bytes(key->index, index_buf + 28); - hash256_update(&prf_ctx, index_buf, 32); - hash256_finish(&prf_ctx, ctx->random); + 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, index_buf, 32); + hash256_finish(&ctx->hash256_ctx, ctx->xmss_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->xmss_sig.wots_sig); + + // xmss_sig.auth_path + build_auth_path(key->tree, height, key->index, ctx->xmss_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); - hash_id[31] = 2; - hash256_update(&ctx->hash256_ctx, hash_id, 32); - hash256_update(&ctx->hash256_ctx, ctx->random, 32); - hash256_update(&ctx->hash256_ctx, key->root, 32); + hash256_update(&ctx->hash256_ctx, bn256_two, 32); + hash256_update(&ctx->hash256_ctx, ctx->xmss_sig.random, 32); + hash256_update(&ctx->hash256_ctx, key->public_key.root, 32); hash256_update(&ctx->hash256_ctx, index_buf, 32); return 1; @@ -779,40 +1125,56 @@ int xmss_sign_update(XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) return 1; } -int xmss_sign_finish(XMSS_SIGN_CTX *ctx, const XMSS_KEY *key, uint8_t *sigbuf, size_t *siglen) +int xmss_sign_finish(XMSS_SIGN_CTX *ctx, uint8_t *sigbuf, size_t *siglen) { - XMSS_SIGNATURE *sig = (XMSS_SIGNATURE *)sigbuf; - uint8_t adrs[32] = {0}; + xmss_adrs_t adrs; uint8_t dgst[32]; - uint32_t height; hash256_finish(&ctx->hash256_ctx, dgst); - xmss_key_get_height(key, &height); - xmss_do_sign(key->secret, key->index, key->seed, adrs, height, key->tree, dgst, - sig->wots_sig, sig->auth_path); + 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, ctx->xmss_sig.index); - uint32_to_bytes(key->index, sig->index); - memcpy(sig->random, ctx->random, 32); + wots_sign(ctx->xmss_sig.wots_sig, ctx->xmss_public_key.seed, adrs, dgst, + ctx->xmss_sig.wots_sig); + + *siglen = 0; + if (xmss_signature_to_bytes(ctx->xmss_public_key.xmss_type, &ctx->xmss_sig, &sigbuf, siglen) != 1) { + error_print(); + return -1; + } - *siglen = 4 + 32 * (68 + height); return 1; } -int xmss_verify_init(XMSS_SIGN_CTX *ctx, const XMSS_KEY *key, const uint8_t *sigbuf, size_t siglen) +int xmss_verify_init(XMSS_SIGN_CTX *ctx, const XMSS_KEY *key, const uint8_t *sig, size_t siglen) { - XMSS_SIGNATURE *sig = (XMSS_SIGNATURE *)sigbuf; - uint8_t hash_id[32] = {0}; - uint8_t index_buf[32] = {0}; + uint8_t sig_index[32]; - memcpy(index_buf + 28, sig->index, 4); + if (!ctx || !key || !sig || !siglen) { + error_print(); + return -1; + } + + // cache xmss_public_key + ctx->xmss_public_key = key->public_key; + + // parse signature + if (xmss_signature_from_bytes(key->public_key.xmss_type, &ctx->xmss_sig, &sig, &siglen) != 1) { + error_print(); + return -1; + } + + memset(sig_index, 0, 28); + PUTU32(sig_index + 28, ctx->xmss_sig.index); hash256_init(&ctx->hash256_ctx); - hash_id[31] = 2; - hash256_update(&ctx->hash256_ctx, hash_id, 32); - hash256_update(&ctx->hash256_ctx, sig->random, 32); - hash256_update(&ctx->hash256_ctx, key->root, 32); - hash256_update(&ctx->hash256_ctx, index_buf, 32); + hash256_update(&ctx->hash256_ctx, bn256_two, 32); + hash256_update(&ctx->hash256_ctx, ctx->xmss_sig.random, 32); + hash256_update(&ctx->hash256_ctx, key->public_key.root, 32); + hash256_update(&ctx->hash256_ctx, sig_index, 32); return 1; } @@ -825,25 +1187,518 @@ int xmss_verify_update(XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) return 1; } -int xmss_verify_finish(XMSS_SIGN_CTX *ctx, const XMSS_KEY *key, const uint8_t *sigbuf, size_t siglen) +int xmss_verify_finish(XMSS_SIGN_CTX *ctx) { + size_t height, h; + uint32_t index; + hash256_t dgst; + xmss_adrs_t adrs; + hash256_t root; + int right; - const XMSS_SIGNATURE *sig = (const XMSS_SIGNATURE *)sigbuf; - uint8_t adrs[32] = {0}; - uint8_t dgst[32]; - uint32_t index, height; - uint8_t xmss_root[32]; + if (!ctx) { + error_print(); + return -1; + } + if (xmss_type_to_height(ctx->xmss_public_key.xmss_type, &height) != 1) { + error_print(); + return -1; + } + if (ctx->xmss_sig.index >= (1 << height)) { + error_print(); + return -1; + } + index = ctx->xmss_sig.index; + // dgst hash256_finish(&ctx->hash256_ctx, dgst); - xmss_key_get_height(key, &height); - index = uint32_from_bytes(sig->index); + // wots_sig => wots_pk + 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, ctx->xmss_sig.index); + wots_sig_to_pk(ctx->xmss_sig.wots_sig, ctx->xmss_public_key.seed, adrs, dgst, ctx->xmss_sig.wots_sig); - xmss_sig_to_root(sig->wots_sig, index, sig->auth_path, key->seed, adrs, height, dgst, xmss_root); + // 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); - if (memcmp(xmss_root, key->root, 32) != 0) { + // 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++) { + right = index & 1; + index >>= 1; + adrs_set_tree_height(adrs, h); + 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); + else randomized_tree_hash(root, ctx->xmss_sig.auth_path[h], ctx->xmss_public_key.seed, adrs, root); + } + + if (memcmp(root, ctx->xmss_public_key.root, 32) != 0) { error_print(); return 0; } return 1; } + +char *xmssmt_type_name(uint32_t xmssmt_type) +{ + switch (xmssmt_type) { + case XMSSMT_HASH256_20_2_256: return XMSSMT_HASH256_20_2_256_NAME; + case XMSSMT_HASH256_20_4_256: return XMSSMT_HASH256_20_4_256_NAME; + case XMSSMT_HASH256_40_2_256: return XMSSMT_HASH256_40_2_256_NAME; + case XMSSMT_HASH256_40_4_256: return XMSSMT_HASH256_40_4_256_NAME; + case XMSSMT_HASH256_40_8_256: return XMSSMT_HASH256_40_8_256_NAME; + case XMSSMT_HASH256_60_3_256: return XMSSMT_HASH256_60_3_256_NAME; + case XMSSMT_HASH256_60_6_256: return XMSSMT_HASH256_60_6_256_NAME; + case XMSSMT_HASH256_60_12_256: return XMSSMT_HASH256_60_12_256_NAME; + } + return NULL; +} + +uint32_t xmssmt_type_from_name(const char *name) +{ + if (!strcmp(name, XMSSMT_HASH256_20_2_256_NAME)) { + return XMSSMT_HASH256_20_2_256; + } else if (!strcmp(name, XMSSMT_HASH256_20_4_256_NAME)) { + return XMSSMT_HASH256_20_4_256; + } else if (!strcmp(name, XMSSMT_HASH256_40_2_256_NAME)) { + return XMSSMT_HASH256_40_2_256; + } else if (!strcmp(name, XMSSMT_HASH256_40_4_256_NAME)) { + return XMSSMT_HASH256_40_4_256; + } else if (!strcmp(name, XMSSMT_HASH256_40_8_256_NAME)) { + return XMSSMT_HASH256_40_8_256; + } else if (!strcmp(name, XMSSMT_HASH256_60_3_256_NAME)) { + return XMSSMT_HASH256_60_3_256; + } else if (!strcmp(name, XMSSMT_HASH256_60_6_256_NAME)) { + return XMSSMT_HASH256_60_6_256; + } else if (!strcmp(name, XMSSMT_HASH256_60_12_256_NAME)) { + return XMSSMT_HASH256_60_12_256; + } + return 0; +} + +int xmssmt_type_to_height_and_layers(uint32_t xmssmt_type, size_t *height, size_t *layers) +{ + if (!height || !layers) { + error_print(); + return -1; + } + switch (xmssmt_type) { + case XMSSMT_HASH256_20_2_256: *height = 20; *layers = 2; break; + case XMSSMT_HASH256_20_4_256: *height = 20; *layers = 4; break; + case XMSSMT_HASH256_40_2_256: *height = 40; *layers = 2; break; + case XMSSMT_HASH256_40_4_256: *height = 40; *layers = 4; break; + case XMSSMT_HASH256_40_8_256: *height = 40; *layers = 8; break; + case XMSSMT_HASH256_60_3_256: *height = 60; *layers = 3; break; + case XMSSMT_HASH256_60_6_256: *height = 60; *layers = 6; break; + case XMSSMT_HASH256_60_12_256: *height = 60; *layers = 12; break; + default: + error_print(); + return -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_address; + uint64_t tree_address; + +/* + if (!key) { + error_print(); + return -1; + } + if (!xmssmt_type_to_height_and_layers(xmssmt_type, &height, &layers)) { + error_print(); + return -1; + } + memset(key, 0, sizeof(*key)); + + xmss_height = height/layers; + xmss_trees = 1 << xmss_height; + + // idx_MT + key->index = 0; + + // SK_PRF + if (rand_bytes(key->sk_prf, sizeof(hash256_t)) != 1) { + error_print(); + return -1; + } + + // SEED + if (rand_bytes(key->seed, sizeof(hash256_t)) != 1) { + error_print(); + return -1; + } + + // ADRS = toByte(0, 32) + memset(adrs, 0, sizeof(xmss_adrs_t)); + + + // malloc tress + + for (layer_address = 0; layer_address < layers; layer_address++) { + uint64_t trees; + + trees = 1 << ((height/layers) * (layers - 1 - layer)); + + adrs_set_layer_address(adrs, layer_address); + + for (tree_address = 0; tree_address < layer_trees; tree_address++) { + + adrs_set_tree_address(adrs, tree_address); + + xmss_build_tree(key->secret, height/layers, key->seed, adrs, tree, xmss_root); + } + } +*/ + return -1; +} + + +int xmssmt_index_to_bytes(uint64_t index, uint32_t xmssmt_type, uint8_t **out, size_t *outlen) +{ + size_t height; + size_t layers; + uint8_t bytes[8]; + size_t nbytes; + + if (!outlen) { + error_print(); + return -1; + } + if (xmssmt_type_to_height_and_layers(xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + if (index >= ((uint64_t)1 << height)) { + error_print(); + return -1; + } + + nbytes = (height + 7)/8; + if (out && *out) { + PUTU64(bytes, index); + memcpy(*out, bytes + 8 - nbytes, nbytes); + *out += nbytes; + } + *outlen += nbytes; + return 1; +} + +int xmssmt_index_from_bytes(uint64_t *index, uint32_t xmssmt_type, const uint8_t **in, size_t *inlen) +{ + size_t height; + size_t layers; + uint8_t bytes[8] = {0}; + size_t nbytes; + + if (!index || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (xmssmt_type_to_height_and_layers(xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + nbytes = (height + 7)/8; + if (*inlen < nbytes) { + error_print(); + return -1; + } + + memcpy(bytes + 8 - nbytes, *in, nbytes); + *in += nbytes; + *inlen -= nbytes; + + *index = GETU64(bytes); + return 1; +} + +int xmssmt_signature_size(uint32_t xmssmt_type, size_t *siglen) +{ + size_t height; + size_t layers; + + if (xmssmt_type_to_height_and_layers(xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + if (!siglen) { + error_print(); + return -1; + } + *siglen = 0; + + if (xmssmt_index_to_bytes(0, xmssmt_type, NULL, siglen) != 1) { + error_print(); + return -1; + } + *siglen += sizeof(hash256_t); + *siglen += XMSS_WOTS_SIGNATURE_SIZE * layers; + *siglen += sizeof(hash256_t) * height; + return 1; +} + +int xmssmt_signature_to_bytes(const XMSSMT_SIGNATURE *sig, uint32_t xmssmt_type, uint8_t **out, size_t *outlen) +{ + size_t height; + size_t layers; + size_t i; + + if (!sig) { + error_print(); + return -1; + } + if (xmssmt_type_to_height_and_layers(xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + + if (out && *out) { + if (xmssmt_index_to_bytes(sig->index, xmssmt_type, out, outlen) != 1) { + error_print(); + return -1; + } + hash256_to_bytes(sig->random, out, outlen); + size_t layer; + + for (layer = 0; layer < layers; layer++) { + for (i = 0; i < 67; i++) { + hash256_to_bytes(sig->wots_sigs[layer][i], out, outlen); + } + for (i = 0; i < height/layers; i++) { + hash256_to_bytes(sig->auth_path[(height/layers) * layer + i], out, outlen); + } + } + } + + return 1; +} + +int xmssmt_signature_from_bytes(XMSSMT_SIGNATURE *sig, uint32_t xmssmt_type, const uint8_t **in, size_t *inlen) +{ + size_t height; + size_t layers; + size_t siglen; + size_t layer; + size_t i; + + if (!sig || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (xmssmt_type_to_height_and_layers(xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + if (xmssmt_signature_size(xmssmt_type, &siglen) != 1) { + error_print(); + return -1; + } + if (*inlen < siglen) { + error_print(); + return -1; + } + + + // index + if (xmssmt_index_from_bytes(&sig->index, xmssmt_type, in, inlen) != 1) { + error_print(); + return -1; + } + + // random + hash256_from_bytes(sig->random, in, inlen); + + for (layer = 0; layer < layers; layer++) { + int i; + // wots_sig + for (i = 0; i < 67; i++) { + hash256_from_bytes(sig->wots_sigs[layer][i], in, inlen); + } + // auth_path + for (i = 0; i < height/layers; i++) { + hash256_from_bytes(sig->auth_path[(height/layers) * layer + i], in, inlen); + } + } + + return 1; +} + +int xmssmt_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const XMSSMT_SIGNATURE *sig, uint32_t xmssmt_type) +{ + size_t height; + size_t layers; + size_t layer; + size_t i; + + if (xmssmt_type_to_height_and_layers(xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + format_print(fp, fmt, ind, "index: %"PRIu64"\n", sig->index); + format_bytes(fp, fmt, ind, "random", sig->random, 32); + + for (layer = 0; layer < layers; layer++) { + format_print(fp, fmt, ind, "redurced_xmss_signature[%zu]\n", layer); + format_print(fp, fmt, ind+4, "wots_sig\n"); + for (i = 0; i < 67; i++) { + format_print(fp, fmt, ind+4, "%d ", i); + format_bytes(fp, fmt, 0, "", sig->wots_sigs[layer][i], 32); + } + + format_print(fp, fmt, ind+4, "auth_path\n"); + for (i = 0; i < height/layers; i++) { + format_print(fp, fmt, ind+8, "%d ", i); + format_bytes(fp, fmt, 0, "", sig->auth_path[(height/layers) * layer + i], 32); + } + } + return 1; +} + +int xmssmt_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen, uint32_t xmssmt_type) +{ + size_t height; + size_t layers; + uint64_t index; + + size_t layer; + size_t i; + + if (xmssmt_type_to_height_and_layers(xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + + if (xmssmt_index_from_bytes(&index, xmssmt_type, &sig, &siglen) != 1) { + error_print(); + return -1; + } + format_print(fp, fmt, ind, "index: %u"PRIu64"\n", index); + + if (siglen < sizeof(hash256_t)) { + error_print(); + return -1; + } + format_bytes(fp, fmt, ind, "random", sig, sizeof(hash256_t)); + sig += sizeof(hash256_t); + siglen -= sizeof(hash256_t); + + for (layer = 0; layer < layers; layer++) { + format_print(fp, fmt, ind, "redurced_xmss_signature[%zu]\n", layer); + format_print(fp, fmt, ind+4, "wots_sig\n"); + for (i = 0; i < 67; i++) { + format_print(fp, fmt, ind+4, "%d ", i); + if (siglen < sizeof(hash256_t)) { + error_print(); + return -1; + } + format_bytes(fp, fmt, 0, "", sig, sizeof(hash256_t)); + sig += sizeof(hash256_t); + siglen -= sizeof(hash256_t); + } + format_print(fp, fmt, ind+4, "auth_path\n"); + for (i = 0; i < height/layers; i++) { + format_print(fp, fmt, ind+8, "%d ", i); + if (siglen < sizeof(hash256_t)) { + error_print(); + return -1; + } + format_bytes(fp, fmt, 0, "", sig, sizeof(hash256_t)); + sig += sizeof(hash256_t); + siglen -= sizeof(hash256_t); + } + } + if (siglen) { + error_print(); + return -1; + } + return 1; +} + +int xmssmt_sign_init(XMSSMT_SIGN_CTX *ctx, XMSSMT_KEY *key) +{ + return -1; +} + +int xmssmt_sign_update(XMSSMT_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) +{ + if (!ctx) { + error_print(); + return -1; + } + if (xmss_sign_update(&ctx->xmss_sign_ctx, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int xmssmt_sign_finish_ex(XMSSMT_SIGN_CTX *ctx, XMSSMT_SIGNATURE *sig) +{ + if (!ctx || !sig) { + error_print(); + return -1; + } + + return -1; +} + +int xmssmt_sign_finish(XMSSMT_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen) +{ + if (!ctx || !sig || !siglen) { + error_print(); + return -1; + } + + *siglen = 0; + + return -1; +} + +int xmssmt_verify_init_ex(XMSSMT_SIGN_CTX *ctx, const XMSSMT_KEY *key, const XMSSMT_SIGNATURE *sig) +{ + if (!ctx || !key || !sig) { + error_print(); + return -1; + } + + return -1; +} + +int xmssmt_verify_init(XMSSMT_SIGN_CTX *ctx, const XMSSMT_KEY *key, const uint8_t *sig, size_t siglen) +{ + return -1; +} + +int xmssmt_verify_update(XMSSMT_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) +{ + return -1; +} + +int xmssmt_verify_finish(XMSSMT_SIGN_CTX *ctx) +{ + return -1; +} diff --git a/tests/xmsstest.c b/tests/xmsstest.c index 7d2e0205..4ab5f392 100644 --- a/tests/xmsstest.c +++ b/tests/xmsstest.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2025 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. @@ -11,10 +11,32 @@ #include #include #include +#include #include +#include #include + +static int test_xmss_adrs(void) +{ + xmss_adrs_t adrs; + + + adrs_set_layer_address(adrs, 0); + adrs_set_tree_address(adrs, 1); + adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); + adrs_set_ots_address(adrs, 0); + adrs_set_chain_address(adrs, 1); + adrs_set_hash_address(adrs, 12); + adrs_set_key_and_mask(adrs, 0); + + xmss_adrs_print(stderr, 0, 0, "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]) { @@ -26,24 +48,26 @@ static void hash256_prf_init(HASH256_CTX *hash256_ctx, const uint8_t key[32]) hash256_update(hash256_ctx, key, 32); } -static int test_sm3_wots_derive_sk(void) +#if defined(ENABLE_XMSS_CROSSCHECK) && defined(ENABLE_SHA2) +static int test_wots_derive_sk(void) { - uint8_t wots_secret[32] = {0}; - uint8_t seed[32] = {0}; - uint8_t adrs[32] = {0}; - hash256_t wots_sk[67]; - hash256_t test_sk[67]; + hash256_t secret = {0}; + hash256_t seed = {0}; + xmss_adrs_t adrs = {0}; + wots_key_t wots_sk; + wots_key_t test_sk; size_t len; // sha256 test 1 - memset(wots_secret, 0, 32); - memset(seed, 0, 32); - memset(adrs, 0, 32); + memset(secret, 0, sizeof(secret)); + memset(seed, 0, sizeof(seed)); + memset(adrs, 0, sizeof(adrs)); hex_to_bytes("0cb52ea67abd5da0328099db02de310e4ab01ac39d0bbeb71e97eb7e83c467b5", 64, test_sk[0], &len); hex_to_bytes("382c16f94b77905d4a6f78e1f38faf5ef914ac42324e356aeede056d356a5eeb", 64, test_sk[1], &len); hex_to_bytes("ab08e768529903e533c9bf8b3ea8c69d36aedcee5ac78801f92d23ef758cfe03", 64, test_sk[66], &len); - sm3_wots_derive_sk(wots_secret, seed, adrs, wots_sk); + wots_derive_sk(secret, seed, adrs, wots_sk); + if (memcmp(wots_sk[0], test_sk[0], 32) || memcmp(wots_sk[1], test_sk[1], 32) || memcmp(wots_sk[66], test_sk[66], 32)) { @@ -52,14 +76,15 @@ static int test_sm3_wots_derive_sk(void) } // sha256 test 2 - memset(wots_secret, 0x12, 32); - memset(seed, 0xab, 32); - memset(adrs, 0, 32); + memset(secret, 0x12, sizeof(secret)); + memset(seed, 0xab, sizeof(seed)); + memset(adrs, 0, sizeof(adrs)); hex_to_bytes("1a50a39a53e6ef2480db612cef9456d0f33222f934c58bcba9d04fa91108faf6", 64, test_sk[0], &len); hex_to_bytes("e45dad76c1b23975e898a365b8c73d13695a887ba2ba2377f840d3a3b7bf806c", 64, test_sk[1], &len); hex_to_bytes("aaad735aa51662b8a48258561fb857b3f2b12a5802593522145b3b68355abf3b", 64, test_sk[66], &len); - sm3_wots_derive_sk(wots_secret, seed, adrs, wots_sk); + wots_derive_sk(secret, seed, adrs, wots_sk); + if (memcmp(wots_sk[0], test_sk[0], 32) || memcmp(wots_sk[1], test_sk[1], 32) || memcmp(wots_sk[66], test_sk[66], 32)) { @@ -71,28 +96,27 @@ static int test_sm3_wots_derive_sk(void) return 1; } -static int test_sm3_wots_derive_pk(void) +static int test_wots_sk_to_pk(void) { - uint8_t wots_secret[32] = {0}; - uint8_t seed[32] = {0}; - uint8_t adrs[32] = {0}; - hash256_t wots_sk[67]; - hash256_t wots_pk[67]; - hash256_t test_pk[67]; - HASH256_CTX prf_seed_ctx; + hash256_t secret = {0}; + hash256_t seed = {0}; + xmss_adrs_t adrs = {0}; + wots_key_t wots_sk; + wots_key_t wots_pk; + wots_key_t test_pk; size_t len; // sha256 test 2 - memset(wots_secret, 0x12, 32); - memset(seed, 0xab, 32); - memset(adrs, 0, 32); + memset(secret, 0x12, sizeof(secret)); + memset(seed, 0xab, sizeof(seed)); + memset(adrs, 0, sizeof(adrs)); hex_to_bytes("0c74a626695831994961641c487b70da83cd2aba2ba5c63c38ce72479b8a0ab9", 64, test_pk[0], &len); hex_to_bytes("acf6be724d4b074d67330559ec24b3d42c9b9d87fa103e7f6be402ec3a2d41c1", 64, test_pk[1], &len); hex_to_bytes("98691d83a657840d4b6f410e25fcd9a6480670ac9c090d3b79bc904ba7e131aa", 64, test_pk[66], &len); - sm3_wots_derive_sk(wots_secret, seed, adrs, wots_sk); - hash256_prf_init(&prf_seed_ctx, seed); - sm3_wots_derive_pk(wots_sk, &prf_seed_ctx, adrs, wots_pk); + wots_derive_sk(secret, seed, adrs, wots_sk); + + wots_sk_to_pk(wots_sk, seed, adrs, wots_pk); if (memcmp(wots_pk[0], test_pk[0], 32) || memcmp(wots_pk[1], test_pk[1], 32) @@ -105,24 +129,66 @@ static int test_sm3_wots_derive_pk(void) return 1; } -static int test_sm3_wots_do_sign(void) +static int test_wots_derive_root(void) { - uint8_t wots_secret[32] = {0}; - uint8_t seed[32] = {0}; - uint8_t adrs[32] = {0}; - uint8_t dgst[32] = {0}; - hash256_t wots_sk[67]; - hash256_t wots_pk[67]; - hash256_t wots_sig[67]; - hash256_t test_sig[67]; - hash256_t sig_pk[67]; - HASH256_CTX prf_seed_ctx; + 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}; + hash256_t seed = {0}; + xmss_adrs_t adrs = {0}; + hash256_t dgst = {0}; + wots_key_t wots_sk; + wots_key_t wots_pk; + wots_sig_t wots_sig; + wots_sig_t test_sig; + wots_key_t sig_pk; size_t len; int i; - memset(wots_secret, 0x12, 32); - memset(seed, 0xab, 32); - memset(adrs, 0, 32); + memset(secret, 0x12, sizeof(secret)); + memset(seed, 0xab, sizeof(seed)); + memset(adrs, 0, sizeof(adrs)); for (i = 0; i < 32; i++) { dgst[i] = i; // try different dgst, check base_w and checksum } @@ -131,21 +197,23 @@ static int test_sm3_wots_do_sign(void) hex_to_bytes("75d2cfddd6ca9773fb9d0d17efe5c731c1a44f4b31352e26767623abf52911f9", 64, test_sig[15], &len); hex_to_bytes("aaad735aa51662b8a48258561fb857b3f2b12a5802593522145b3b68355abf3b", 64, test_sig[66], &len); - sm3_wots_derive_sk(wots_secret, seed, adrs, wots_sk); - hash256_prf_init(&prf_seed_ctx, seed); - sm3_wots_derive_pk(wots_sk, &prf_seed_ctx, adrs, wots_pk); - sm3_wots_do_sign(wots_sk, &prf_seed_ctx, adrs, dgst, wots_sig); + wots_derive_sk(secret, seed, adrs, wots_sk); - if (memcmp(wots_sig[0], test_sig[0], 32) - || memcmp(wots_sig[1], test_sig[1], 32) - || memcmp(wots_sig[15], test_sig[15], 32) - || memcmp(wots_sig[66], test_sig[66], 32)) { + wots_sk_to_pk(wots_sk, seed, adrs, wots_pk); + + wots_sign(wots_sk, seed, adrs, dgst, wots_sig); + + if (memcmp(wots_sig[0], test_sig[0], sizeof(hash256_t)) + || memcmp(wots_sig[1], test_sig[1], sizeof(hash256_t)) + || memcmp(wots_sig[15], test_sig[15], sizeof(hash256_t)) + || memcmp(wots_sig[66], test_sig[66], sizeof(hash256_t))) { error_print(); return -1; } - sm3_wots_sig_to_pk(wots_sig, dgst, &prf_seed_ctx, adrs, sig_pk); - if (memcmp(sig_pk ,wots_pk, 32 * 67)) { + wots_sig_to_pk(wots_sig, seed, adrs, dgst, sig_pk); + + if (memcmp(sig_pk ,wots_pk, sizeof(wots_key_t))) { error_print(); return -1; } @@ -154,23 +222,66 @@ static int test_sm3_wots_do_sign(void) return 1; } -static int test_xmss_derive_root(void) +static int test_xmss_build_tree(void) { - uint8_t xmss_secret[32]; - uint8_t seed[32]; + hash256_t xmss_secret; + hash256_t seed; + xmss_adrs_t adrs; int height = 10; hash256_t *tree = malloc(32 * (1< 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, index); + wots_derive_sk(key.secret, key.public_key.seed, adrs, sig.wots_sig); + + // check wots_root + wots_derive_root(key.secret, key.public_key.seed, adrs, root); + if (memcmp(root, key.tree[index], sizeof(hash256_t)) != 0) { + xmss_key_cleanup(&key); + error_print(); + return -1; + } + + build_auth_path(key.tree, height, index, sig.auth_path); + + + + PUTU32(hash256_index + 28, index); + hash256_init(&ctx); + hash256_update(&ctx, hash256_two, sizeof(hash256_t)); + hash256_update(&ctx, sig.random, sizeof(hash256_t)); + hash256_update(&ctx, key.public_key.root, sizeof(hash256_t)); + hash256_update(&ctx, hash256_index, sizeof(hash256_t)); + hash256_update(&ctx, msg, sizeof(msg)); + hash256_finish(&ctx, dgst); + + wots_sign(sig.wots_sig, key.public_key.seed, adrs, dgst, sig.wots_sig); + + // verify + + // wots_sig => wots_root + wots_sig_to_pk(sig.wots_sig, key.public_key.seed, adrs, dgst, sig.wots_sig); + + 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_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_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); + } + + if (memcmp(root, key.public_key.root, sizeof(hash256_t)) != 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + + + +static int test_xmss_sign_init(void) +{ + uint32_t xmss_type = XMSS_HASH256_10_256; XMSS_KEY key; XMSS_SIGN_CTX sign_ctx; - uint8_t sig[sizeof(XMSS_SIGNATURE)]; + uint8_t sig[XMSS_SIGNATURE_MAX_SIZE]; size_t siglen; uint8_t msg[100] = {0}; int i; - xmss_key_generate(&key, oid); - xmss_key_print(stderr, 0, 0, "XMSS Key", &key); + if (xmss_key_generate(&key, xmss_type) != 1) { + error_print(); + return -1; + } - for (i = 0; i < 3; i++) { - xmss_sign_init(&sign_ctx, &key); - xmss_sign_update(&sign_ctx, msg, sizeof(msg)); - xmss_sign_finish(&sign_ctx, &key, sig, &siglen); + if (xmss_sign_init(&sign_ctx, &key) != 1) { + error_print(); + return -1; + } + if (xmss_sign_update(&sign_ctx, msg, sizeof(msg)) != 1) { + error_print(); + return -1; + } + if (xmss_sign_finish(&sign_ctx, sig, &siglen) != 1) { + error_print(); + return -1; + } - (key.index)++; - - xmss_signature_print(stderr, 0, 0, "XMSS Signature", sig, siglen); - - xmss_verify_init(&sign_ctx, &key, sig, siglen); - xmss_verify_update(&sign_ctx, msg, sizeof(msg)); - if (xmss_verify_finish(&sign_ctx, &key, sig, siglen) != 1) { - error_print(); - return -1; - } + if (xmss_verify_init(&sign_ctx, &key, sig, siglen) != 1) { + error_print(); + return -1; + } + if (xmss_verify_update(&sign_ctx, msg, sizeof(msg)) != 1) { + error_print(); + return -1; + } + if (xmss_verify_finish(&sign_ctx) != 1) { + error_print(); + return -1; } xmss_key_cleanup(&key); @@ -255,14 +532,149 @@ static int test_xmss_sign(void) return 1; } + + +struct { + uint32_t xmssmt_type; + size_t indexlen; + size_t siglen; +} xmssmt_consts[] = { + { XMSSMT_HASH256_20_2_256, 3, 4963 }, + { XMSSMT_HASH256_20_4_256, 3, 9251 }, + { XMSSMT_HASH256_40_2_256, 5, 5605 }, + { XMSSMT_HASH256_40_4_256, 5, 9893 }, + { XMSSMT_HASH256_40_8_256, 5, 18469 }, + { XMSSMT_HASH256_60_3_256, 8, 8392 }, + { XMSSMT_HASH256_60_6_256, 8, 14824 }, + { XMSSMT_HASH256_60_12_256, 8, 27688 }, +}; + +static int test_xmssmt_index_to_bytes(void) +{ + uint64_t index = 0; + size_t indexlen; + size_t i; + + for (i = 0; i < sizeof(xmssmt_consts)/sizeof(xmssmt_consts[0]); i++) { + indexlen = 0; + if (xmssmt_index_to_bytes(index, xmssmt_consts[i].xmssmt_type, NULL, &indexlen) != 1) { + error_print(); + return -1; + } + if (indexlen != xmssmt_consts[i].indexlen) { + error_print(); + return -1; + } + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_xmssmt_signature_size(void) +{ + size_t siglen; + size_t i; + + for (i = 0; i < sizeof(xmssmt_consts)/sizeof(xmssmt_consts[0]); i++) { + if (xmssmt_signature_size(xmssmt_consts[i].xmssmt_type, &siglen) != 1) { + error_print(); + return -1; + } + if (siglen != xmssmt_consts[i].siglen) { + error_print(); + return -1; + } + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_xmssmt_signature_print(void) +{ + XMSSMT_SIGNATURE xmssmt_sig; + size_t layer, i; + + // set xmssmt_sig + memset(&xmssmt_sig, 0, sizeof(xmssmt_sig)); + xmssmt_sig.index = 1; + rand_bytes(xmssmt_sig.random, 32); + + for (layer = 0; layer < XMSSMT_MAX_LAYERS; layer++) { + for (i = 0; i < 67; i++) { + xmssmt_sig.wots_sigs[layer][i][0] = 0x0a; + xmssmt_sig.wots_sigs[layer][i][1] = 0xff & layer; + xmssmt_sig.wots_sigs[layer][i][2] = 0xff & i; + } + } + for (i = 0; i < XMSSMT_MAX_HEIGHT; i++) { + xmssmt_sig.auth_path[i][0] = 0x0b; + xmssmt_sig.auth_path[i][1] = 0xff & i; + } + + // 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); + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_xmssmt_signature_to_bytes(void) +{ + uint32_t xmssmt_type = XMSSMT_HASH256_20_2_256; + XMSSMT_SIGNATURE xmssmt_sig; + uint8_t buf[XMSSMT_SIGNATURE_MAX_SIZE]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + 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); + + if (xmssmt_signature_from_bytes(&xmssmt_sig, xmssmt_type, &cp, &len) != 1) { + error_print(); + return -1; + } + if (len) { + fprintf(stderr, "xmssmt_signature_len: %zu\n", len); + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + + int main(void) { - if (test_sm3_wots_derive_sk() != 1) goto err; - if (test_sm3_wots_derive_pk() != 1) goto err; - if (test_sm3_wots_do_sign() != 1) goto err; - if (test_xmss_derive_root() != 1) goto err; - if (test_xmss_do_sign() != 1) goto err; +#if defined(ENABLE_LMS_CROSSCHECK) && defined(ENABLE_SHA2) + if (test_wots_derive_sk() != 1) goto err; + 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; +#endif + if (test_xmss_adrs() != 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_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_print() != 1) goto err; printf("%s all tests passed\n", __FILE__); return 0; err: diff --git a/tools/xmsskeygen.c b/tools/xmsskeygen.c index 0f69f4d0..034ba1b2 100644 --- a/tools/xmsskeygen.c +++ b/tools/xmsskeygen.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2025 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. @@ -17,58 +17,58 @@ #include -static const char *usage = "-oid oid [-out file] [-pubout file]\n"; +static const char *usage = "-xmss_type type -out file [-pubout file] [-verbose]\n"; -static const char *help = +static const char *options = "Options\n" -" -oid oid XMSS algorithm OID\n" -" XMSS_SM3_10\n" -" XMSS_SM3_16\n" -" XMSS_SM3_20\n" +" -xmss_type type XMSS Algorithm Type\n" +" "XMSS_HASH256_10_256_NAME"\n" +" "XMSS_HASH256_16_256_NAME"\n" +" "XMSS_HASH256_20_256_NAME"\n" " -out file Output private key\n" " -pubout file Output public key\n" +" -verbose Print public key\n" "\n"; int xmsskeygen_main(int argc, char **argv) { int ret = 1; char *prog = argv[0]; - char *oid = NULL; - uint32_t oid_val = 0; + char *xmss_type = NULL; + int xmss_type_val = 0; char *outfile = NULL; char *puboutfile = NULL; - FILE *outfp = stdout; + int verbose = 0; + FILE *outfp = NULL; FILE *puboutfp = stdout; XMSS_KEY key; - uint8_t *out = NULL; - uint8_t *pubout = NULL; - size_t outlen, puboutlen; + uint8_t out[XMSS_PRIVATE_KEY_SIZE]; + uint8_t pubout[XMSS_PUBLIC_KEY_SIZE]; + uint8_t *pout = out; + uint8_t *ppubout = pubout; + size_t outlen = 0, puboutlen = 0; + + memset(&key, 0, sizeof(key)); argc--; argv++; if (argc < 1) { - fprintf(stderr, "usage: %s %s\n", prog, help); + fprintf(stderr, "usage: gmssl %s %s\n", prog, usage); return 1; } while (argc > 0) { if (!strcmp(*argv, "-help")) { - printf("usage: %s %s\n", prog, usage); - printf("%s\n", help); + printf("usage: gmssl %s %s\n", prog, usage); + printf("%s\n", options); ret = 0; goto end; - } else if (!strcmp(*argv, "-oid")) { + } else if (!strcmp(*argv, "-xmss_type")) { if (--argc < 1) goto bad; - oid = *(++argv); - if (strcmp(oid, "XMSS_SM3_10") == 0) { - oid_val = XMSS_SM3_10; - } else if (strcmp(oid, "XMSS_SM3_16") == 0) { - oid_val = XMSS_SM3_16; - } else if (strcmp(oid, "XMSS_SM3_20") == 0) { - oid_val = XMSS_SM3_20; - } else { - fprintf(stderr, "%s: invalid XMSS algor ID `%s`\n", prog, oid); + xmss_type = *(++argv); + if (!(xmss_type_val = xmss_type_from_name(xmss_type))) { + fprintf(stderr, "%s: invalid xmss_type `%s`\n", prog, xmss_type); goto end; } } else if (!strcmp(*argv, "-out")) { @@ -85,6 +85,8 @@ int xmsskeygen_main(int argc, char **argv) fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); goto end; } + } else if (!strcmp(*argv, "-verbose")) { + verbose = 1; } else { fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); goto end; @@ -97,46 +99,36 @@ bad: argv++; } - if (!oid) { - fprintf(stderr, "%s: `-oid` option required\n", prog); + if (!xmss_type) { + fprintf(stderr, "%s: `-xmss_type` option required\n", prog); + goto end; + } + if (!outfp) { + fprintf(stderr, "%s: `-out` option required\n", prog); goto end; } - - if (xmss_key_generate(&key, oid_val) != 1) { + if (xmss_key_generate(&key, xmss_type_val) != 1) { error_print(); return -1; } - - if (xmss_key_to_bytes(&key, NULL, &outlen) != 1) { - error_print(); - goto end; - } - if (!(out = malloc(outlen))) { - error_print(); - goto end; - } - if (xmss_key_to_bytes(&key, out, &outlen) != 1) { - error_print(); + if (verbose) { + xmss_public_key_print(stderr, 0, 0, "xmss_public_key", &key); } - if (xmss_public_key_to_bytes(&key, NULL, &puboutlen) != 1) { + if (xmss_private_key_to_bytes(&key, &pout, &outlen) != 1) { error_print(); goto end; } - if (!(pubout = malloc(puboutlen))) { - error_print(); - goto end; - } - if (xmss_public_key_to_bytes(&key, pubout, &puboutlen) != 1) { - error_print(); - goto end; - } - if (fwrite(out, 1, outlen, outfp) != outlen) { error_print(); goto end; } + + if (xmss_public_key_to_bytes(&key, &ppubout, &puboutlen) != 1) { + error_print(); + goto end; + } if (fwrite(pubout, 1, puboutlen, puboutfp) != puboutlen) { error_print(); goto end; @@ -144,15 +136,8 @@ bad: ret = 0; end: - gmssl_secure_clear(&key, sizeof(key)); - if (out) { - gmssl_secure_clear(out, outlen); - free(out); - } - if (pubout) { - gmssl_secure_clear(pubout, puboutlen); - free(pubout); - } + xmss_key_cleanup(&key); + gmssl_secure_clear(out, outlen); if (outfile && outfp) fclose(outfp); if (puboutfile && puboutfp) fclose(puboutfp); return ret; diff --git a/tools/xmsssign.c b/tools/xmsssign.c index 398cd926..8cee58bd 100644 --- a/tools/xmsssign.c +++ b/tools/xmsssign.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2025 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. @@ -13,17 +13,17 @@ #include #include #include -#include #include #include -static const char *usage = "-key file [-in file] [-out file]\n"; +static const char *usage = "-key file [-in file] [-out file] [-verbose]\n"; -static const char *help = +static const char *options = "Options\n" " -key file Input private key file\n" " -in file Input data file (if not using stdin)\n" " -out file Output signature file\n" +" -verbose Print public key and signature\n" "\n"; int xmsssign_main(int argc, char **argv) @@ -33,43 +33,42 @@ int xmsssign_main(int argc, char **argv) char *keyfile = NULL; char *infile = NULL; char *outfile = NULL; + int verbose = 0; FILE *keyfp = NULL; FILE *infp = stdin; FILE *outfp = stdout; - uint8_t *keybuf = NULL; - size_t keylen; + uint8_t keybuf[XMSS_PRIVATE_KEY_SIZE]; + size_t keylen = XMSS_PRIVATE_KEY_SIZE; + const uint8_t *cp = keybuf; + uint8_t *p = keybuf; XMSS_KEY key; - XMSS_SIGN_CTX sign_ctx; - uint8_t *sigbuf = NULL; + XMSS_SIGN_CTX ctx; + uint8_t sig[XMSS_SIGNATURE_MAX_SIZE]; size_t siglen; + memset(&key, 0, sizeof(key)); + argc--; argv++; if (argc < 1) { - fprintf(stderr, "usage: %s %s\n", prog, usage); + fprintf(stderr, "usage: gmssl %s %s\n", prog, usage); return 1; } while (argc > 0) { if (!strcmp(*argv, "-help")) { printf("usage: %s %s\n", prog, usage); - printf("%s\n", help); + printf("%s\n", options); ret = 0; goto end; } else if (!strcmp(*argv, "-key")) { if (--argc < 1) goto bad; keyfile = *(++argv); - /* - if (!(keyfp = fopen(keyfile, "rb"))) { + if (!(keyfp = fopen(keyfile, "rb+"))) { fprintf(stderr, "%s: open '%s' failure: %s\n", prog, keyfile, strerror(errno)); goto end; } - */ - if (file_read_all(keyfile, &keybuf, &keylen) != 1) { - error_print(); - goto end; - } } else if (!strcmp(*argv, "-in")) { if (--argc < 1) goto bad; infile = *(++argv); @@ -84,6 +83,8 @@ int xmsssign_main(int argc, char **argv) fprintf(stderr, "%s: open '%s' failure: %s\n", prog, outfile, strerror(errno)); goto end; } + } else if (!strcmp(*argv, "-verbose")) { + verbose = 1; } else { fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); goto end; @@ -101,15 +102,38 @@ bad: goto end; } + if (fread(keybuf, 1, keylen, keyfp) != keylen) { + fprintf(stderr, "%s: read private key failure\n", prog); + goto end; + } + if (xmss_private_key_from_bytes(&key, &cp, &keylen) != 1) { + error_print(); + goto end; + } + if (keylen) { + error_print(); + return -1; + } - if (xmss_key_from_bytes(&key, keybuf, keylen) != 1) { + if (verbose) { + xmss_public_key_print(stderr, 0, 0, "lms_public_key", &key); + } + + if (xmss_sign_init(&ctx, &key) != 1) { error_print(); goto end; } - if (xmss_sign_init(&sign_ctx, &key) != 1) { + // write updated key back to file + // TODO: write back `q` only + if (xmss_private_key_to_bytes(&key, &p, &keylen) != 1) { error_print(); - goto end; + return -1; + } + rewind(keyfp); + if (fwrite(keybuf, 1, keylen, keyfp) != keylen) { + error_print(); + return -1; } while (1) { @@ -118,46 +142,30 @@ bad: if (len == 0) { break; } - if (xmss_sign_update(&sign_ctx, buf, len) != 1) { + if (xmss_sign_update(&ctx, buf, len) != 1) { error_print(); goto end; } } - - if (xmss_sign_finish(&sign_ctx, &key, NULL, &siglen) != 1) { + if (xmss_sign_finish(&ctx, sig, &siglen) != 1) { error_print(); goto end; } - - if (!(sigbuf = malloc(siglen))) { - fprintf(stderr, "%s: malloc failure\n", prog); - goto end; - } - - if (xmss_sign_finish(&sign_ctx, &key, sigbuf, &siglen) != 1) { + if (fwrite(sig, 1, siglen, outfp) != siglen) { error_print(); goto end; } - - if (fwrite(sigbuf, 1, siglen, outfp) != siglen) { - error_print(); - goto end; + if (verbose) { + xmss_signature_print(stderr, 0, 0, "lms_signature", sig, siglen); } ret = 0; end: - gmssl_secure_clear(&key, sizeof(key)); - gmssl_secure_clear(&sign_ctx, sizeof(sign_ctx)); - if (sigbuf) { - gmssl_secure_clear(sigbuf, siglen); - free(sigbuf); - } - if (keybuf) { - gmssl_secure_clear(keybuf, keylen); - free(keybuf); - } - //if (keyfp) fclose(keyfp); + xmss_key_cleanup(&key); + gmssl_secure_clear(keybuf, sizeof(keybuf)); + gmssl_secure_clear(&ctx, sizeof(ctx)); + if (keyfp) fclose(keyfp); if (infp && infp != stdin) fclose(infp); if (outfp && outfp != stdout) fclose(outfp); return ret; diff --git a/tools/xmssverify.c b/tools/xmssverify.c index 7229ede5..e75d37d4 100644 --- a/tools/xmssverify.c +++ b/tools/xmssverify.c @@ -108,13 +108,13 @@ bad: fprintf(stderr, "%s: read public key failure\n", prog); goto end; } - if (xmss_public_key_from_bytes(&key, cp, pubkeylen) != 1) { + if (xmss_public_key_from_bytes(&key, &cp, &pubkeylen) != 1) { error_print(); fprintf(stderr, "%s: invalid public key data\n", prog); goto end; } if (verbose) { - xmss_key_print(stderr, 0, 0, "xmss_public_key", &key); + xmss_public_key_print(stderr, 0, 0, "xmss_public_key", &key); } // read signature even if signature not compatible with the public key @@ -141,7 +141,7 @@ bad: goto end; } } - if ((vr = xmss_verify_finish(&ctx, &key, sig, siglen)) < 0) { + if ((vr = xmss_verify_finish(&ctx)) < 0) { error_print(); goto end; }