diff --git a/CMakeLists.txt b/CMakeLists.txt index e379842c..5f22ec77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,7 @@ option(ENABLE_SM4_CBC_MAC "Enable SM4-CBC-MAC" ON) option(ENABLE_SM2_EXTS "Enable SM2 Extensions" OFF) option(ENABLE_LMS_HSS "Enable LMS/HSS signature" ON) -option(ENABLE_SM3_XMSS "Enable SM3-XMSS signature" OFF) +option(ENABLE_XMSS "Enable XMSS/XMSS^MT signature" OFF) option(ENABLE_SHA1 "Enable SHA1" ON) @@ -432,16 +432,17 @@ if (ENABLE_LMS_HSS) endif() -if (ENABLE_SM3_XMSS) - message(STATUS "ENABLE_SM3_XMSS is ON") - add_definitions(-DENABLE_SM3_XMSS) - list(APPEND src src/sm3_xmss.c) +if (ENABLE_XMSS) + message(STATUS "ENABLE_XMSS is ON") + add_definitions(-DENABLE_XMSS) + list(APPEND src src/xmss.c) + list(APPEND tools tools/xmsskeygen.c tools/xmsssign.c tools/xmssverify.c) + list(APPEND tests xmss) - option(ENABLE_SM3_XMSS_CROSSCHECK "Enable XMSS SHA-256 cross-check" OFF) - if (ENABLE_SM3_XMSS_CROSSCHECK) - message(STATUS "ENABLE_SM3_XMSS_CROSSCHECK is ON") - add_definitions(-DENABLE_SM3_XMSS_CROSSCHECK) - list(APPEND tests sm3_xmss) + option(ENABLE_XMSS_CROSSCHECK "Enable XMSS SHA-256 cross-check" ON) + if (ENABLE_XMSS_CROSSCHECK) + message(STATUS "ENABLE_XMSS_CROSSCHECK is ON") + add_definitions(-DENABLE_XMSS_CROSSCHECK) endif() endif() diff --git a/include/gmssl/hash256.h b/include/gmssl/hash256.h new file mode 100644 index 00000000..640ca861 --- /dev/null +++ b/include/gmssl/hash256.h @@ -0,0 +1,28 @@ +/* + * 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. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +#ifndef GMSSL_HASH256_H +#define GMSSL_HASH256_H + + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef uint8_t hash256_t[32]; + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/lms.h b/include/gmssl/lms.h index af319f10..9cfd4431 100644 --- a/include/gmssl/lms.h +++ b/include/gmssl/lms.h @@ -10,28 +10,22 @@ #ifndef GMSSL_LMS_H #define GMSSL_LMS_H -#include -#include -#include -#include - #include #include #include #include +#include #ifdef ENABLE_SHA2 #include #endif + #ifdef __cplusplus extern "C" { #endif -typedef uint8_t hash256_t[32]; - - #define HSS_MAX_LEVELS 5 #define LMS_MAX_HEIGHT 25 diff --git a/include/gmssl/sm3_xmss.h b/include/gmssl/sm3_xmss.h deleted file mode 100644 index 1c10a781..00000000 --- a/include/gmssl/sm3_xmss.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2014-2023 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. - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ - -#ifndef GMSSL_SM3_XMSS_H -#define GMSSL_SM3_XMSS_H - -#include -#include -#include -#include -#ifdef ENABLE_SHA2 -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - - -// Crosscheck with data from xmss-reference (SHA-256), except the XMSS signature. -#if defined(ENABLE_SM3_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 -#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 -#endif - -typedef uint8_t hash256_bytes_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_bytes_t sk[67]); -void sm3_wots_derive_pk(const hash256_bytes_t sk[67], - const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], - hash256_bytes_t pk[67]); -void sm3_wots_do_sign(const hash256_bytes_t sk[67], - const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], - const uint8_t dgst[32], hash256_bytes_t sig[67]); -void sm3_wots_sig_to_pk(const hash256_bytes_t sig[67], const uint8_t dgst[32], - const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], - hash256_bytes_t pk[67]); - -void sm3_xmss_derive_root(const uint8_t xmss_secret[32], int height, - const uint8_t seed[32], - hash256_bytes_t *tree, uint8_t xmss_root[32]); -void sm3_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_bytes_t *tree, - const uint8_t dgst[32], - hash256_bytes_t wots_sig[67], - hash256_bytes_t *auth_path); - -void sm3_xmss_sig_to_root(const hash256_bytes_t wots_sig[67], int index, const hash256_bytes_t *auth_path, - const uint8_t seed[32], const uint8_t in_adrs[32], int height, - const uint8_t dgst[32], - 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, -}; - -int sm3_xmss_height_from_oid(uint32_t *height, uint32_t id); - -typedef struct { - uint32_t oid; - uint8_t seed[32]; - uint8_t root[32]; - uint8_t secret[32]; - uint8_t prf_key[32]; - uint32_t index; - hash256_bytes_t *tree; -} SM3_XMSS_KEY; - -int sm3_xmss_key_generate(SM3_XMSS_KEY *key, uint32_t oid); -int sm3_xmss_key_print(FILE *fp, int fmt, int ind, const char *label, const SM3_XMSS_KEY *key); -int sm3_xmss_key_get_height(const SM3_XMSS_KEY *key, uint32_t *height); -int sm3_xmss_key_to_bytes(const SM3_XMSS_KEY *key, uint8_t *out, size_t *outlen); -int sm3_xmss_key_from_bytes(SM3_XMSS_KEY *key, const uint8_t *in, size_t inlen); -int sm3_xmss_public_key_to_bytes(const SM3_XMSS_KEY *key, uint8_t *out, size_t *outlen); -int sm3_xmss_public_key_from_bytes(SM3_XMSS_KEY *key, const uint8_t *in, size_t inlen); -void sm3_xmss_key_cleanup(SM3_XMSS_KEY *key); - -typedef struct { - uint8_t index[4]; - uint8_t random[32]; - hash256_bytes_t wots_sig[67]; - hash256_bytes_t auth_path[20]; -} SM3_XMSS_SIGNATURE; - -int sm3_xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *in, size_t inlen); - -typedef struct { - uint8_t random[32]; - HASH256_CTX hash256_ctx; -} SM3_XMSS_SIGN_CTX; - -int sm3_xmss_sign_init(SM3_XMSS_SIGN_CTX *ctx, const SM3_XMSS_KEY *key); -int sm3_xmss_sign_update(SM3_XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); -int sm3_xmss_sign_finish(SM3_XMSS_SIGN_CTX *ctx, const SM3_XMSS_KEY *key, uint8_t *sigbuf, size_t *siglen); -int sm3_xmss_verify_init(SM3_XMSS_SIGN_CTX *ctx, const SM3_XMSS_KEY *key, const uint8_t *sigbuf, size_t siglen); -int sm3_xmss_verify_update(SM3_XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); -int sm3_xmss_verify_finish(SM3_XMSS_SIGN_CTX *ctx, const SM3_XMSS_KEY *key, const uint8_t *sigbuf, size_t siglen); - - -#ifdef __cplusplus -} -#endif -#endif diff --git a/include/gmssl/xmss.h b/include/gmssl/xmss.h new file mode 100644 index 00000000..7c93b934 --- /dev/null +++ b/include/gmssl/xmss.h @@ -0,0 +1,181 @@ +/* + * 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. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +#ifndef GMSSL_XMSS_H +#define GMSSL_XMSS_H + + +#include +#include +#include +#include +#include +#ifdef ENABLE_SHA2 +#include +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +// 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 +#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 +#endif + + + +#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 + + + +// 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]); + +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]); +void xmss_do_sign(const uint8_t xmss_secret[32], int index, + const uint8_t seed[32], const uint8_t in_adrs[32], int height, + const hash256_t *tree, + const uint8_t dgst[32], + hash256_t wots_sig[67], + hash256_t *auth_path); + +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, + const uint8_t dgst[32], + 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); + + +// 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]; + + uint8_t secret[32]; + uint8_t prf_key[32]; + uint32_t index; // change this to int, update every signing + hash256_t *tree; +} XMSS_KEY; + + +#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_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); +void xmss_key_cleanup(XMSS_KEY *key); + + + + +typedef struct { + uint8_t index[4]; + uint8_t random[32]; + hash256_t wots_sig[67]; + hash256_t auth_path[XMSS_MAX_HEIGHT]; +} XMSS_SIGNATURE; + + + +// XMSS_SM3_10_256 2500 bytes +// XMSS_SM3_16_256 2692 bytes +// XMSS_SM3_20_256 2820 bytes +#define XMSS_SIGNATURE_MIN_SIZE (4 + 32 + 32*67 + 32 * XMSS_MIN_HEIGHT) // = 2500 bytes +#define XMSS_SIGNATURE_MAX_SIZE (4 + 32 + 32*67 + 32 * XMSS_MAX_HEIGHT) // = 2820 bytes + +int xmss_signature_size(uint32_t oid, size_t *siglen); + +// TODO: impl this +int xmss_key_get_signature_size(const XMSS_KEY *key, size_t siglen); + +int xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *in, size_t inlen); + +typedef struct { + uint8_t random[32]; + HASH256_CTX hash256_ctx; + // TODO: cache signing key +} XMSS_SIGN_CTX; + + +// 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); +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_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); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/sm3_xmss.c b/src/xmss.c similarity index 80% rename from src/sm3_xmss.c rename to src/xmss.c index 0dc2ce0c..4a6bcea2 100644 --- a/src/sm3_xmss.c +++ b/src/xmss.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #define uint32_from_bytes(ptr) \ @@ -134,6 +134,8 @@ static void hash256_prf_keygen_init(HASH256_CTX *hash256_ctx, const uint8_t key[ 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]) { @@ -173,7 +175,7 @@ static void wots_chain(const uint8_t x[32], int start, int steps, 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_bytes_t sk[67]) +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]) { HASH256_CTX prf_keygen_ctx; HASH256_CTX prf_ctx; @@ -196,9 +198,9 @@ void sm3_wots_derive_sk(const uint8_t secret[32], const uint8_t seed[32], const } } -void sm3_wots_derive_pk(const hash256_bytes_t sk[67], +void sm3_wots_derive_pk(const hash256_t sk[67], const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], - hash256_bytes_t pk[67]) + hash256_t pk[67]) { uint8_t adrs[32]; int i; @@ -238,9 +240,9 @@ static void base_w_and_checksum(const uint8_t dgst[32], uint8_t msg[67]) msg[66] = csum_bytes[1] >> 4; } -void sm3_wots_do_sign(const hash256_bytes_t sk[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_bytes_t sig[67]) + const uint8_t dgst[32], hash256_t sig[67]) { uint8_t adrs[32]; uint8_t msg[67]; @@ -256,9 +258,9 @@ void sm3_wots_do_sign(const hash256_bytes_t sk[67], } } -void sm3_wots_sig_to_pk(const hash256_bytes_t sig[67], const uint8_t dgst[32], +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_bytes_t pk[67]) + hash256_t pk[67]) { uint8_t adrs[32]; uint8_t msg[67]; @@ -311,11 +313,11 @@ static void randomized_hash(const uint8_t left[32], const uint8_t right[32], hash256_finish(&hash256_ctx, out); } -static void build_ltree(const hash256_bytes_t in_pk[67], +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]) { - hash256_bytes_t pk[67]; + hash256_t pk[67]; uint8_t adrs[32]; uint32_t tree_height = 0; int len = 67; @@ -344,9 +346,9 @@ static void build_ltree(const hash256_bytes_t in_pk[67], // len(tree) = 2^h - 1 // root = tree[len(tree) - 1] = tree[2^h - 2] -static void build_hash_tree(const hash256_bytes_t *leaves, int height, +static void build_hash_tree(const hash256_t *leaves, int height, const HASH256_CTX *prf_seed_ctx, const uint8_t in_adrs[32], - hash256_bytes_t *tree) + hash256_t *tree) { uint8_t adrs[32]; int n = 1 << height; @@ -368,9 +370,9 @@ static void build_hash_tree(const hash256_bytes_t *leaves, int height, } } -void sm3_xmss_derive_root(const uint8_t xmss_secret[32], int height, +void xmss_derive_root(const uint8_t xmss_secret[32], int height, const uint8_t seed[32], - hash256_bytes_t *tree, uint8_t xmss_root[32]) + hash256_t *tree, uint8_t xmss_root[32]) { HASH256_CTX prf_keygen_ctx; HASH256_CTX prf_seed_ctx; @@ -383,8 +385,8 @@ void sm3_xmss_derive_root(const uint8_t xmss_secret[32], int height, // 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 @@ -405,7 +407,7 @@ void sm3_xmss_derive_root(const uint8_t xmss_secret[32], int height, memcpy(xmss_root, tree + (1 << (height + 1)) - 2, 32); } -static void build_auth_path(const hash256_bytes_t *tree, int height, int index, hash256_bytes_t *path) +static void build_auth_path(const hash256_t *tree, int height, int index, hash256_t *path) { int h; for (h = 0; h < height; h++) { @@ -415,16 +417,16 @@ static void build_auth_path(const hash256_bytes_t *tree, int height, int index, } } -void sm3_xmss_do_sign(const uint8_t xmss_secret[32], int index, +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_bytes_t *tree, + const hash256_t *tree, const uint8_t dgst[32], - hash256_bytes_t wots_sig[67], - hash256_bytes_t *auth_path) + hash256_t wots_sig[67], + hash256_t *auth_path) { HASH256_CTX prf_seed_ctx; uint8_t adrs[32]; - hash256_bytes_t wots_sk[67]; + hash256_t wots_sk[67]; hash256_prf_init(&prf_seed_ctx, seed); memcpy(adrs, in_adrs, 32); @@ -439,14 +441,14 @@ void sm3_xmss_do_sign(const uint8_t xmss_secret[32], int index, build_auth_path(tree, height, index, auth_path); } -void sm3_xmss_sig_to_root(const hash256_bytes_t wots_sig[67], int index, const hash256_bytes_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, const uint8_t dgst[32], uint8_t xmss_root[32]) { HASH256_CTX prf_seed_ctx; uint8_t adrs[32]; - hash256_bytes_t wots_pk[67]; + hash256_t wots_pk[67]; uint8_t *node = xmss_root; int h; @@ -475,7 +477,7 @@ void sm3_xmss_sig_to_root(const hash256_bytes_t wots_sig[67], int index, const h } } -int sm3_xmss_height_from_oid(uint32_t *height, uint32_t id) +int xmss_height_from_oid(uint32_t *height, uint32_t id) { switch (id) { case XMSS_SM3_10: *height = 10; break; @@ -491,11 +493,27 @@ int sm3_xmss_height_from_oid(uint32_t *height, uint32_t id) return 1; } -int sm3_xmss_key_generate(SM3_XMSS_KEY *key, uint32_t oid) +int xmss_oid_to_height(uint32_t oid, size_t *height) +{ + 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; + } + return 1; +} + +int xmss_key_generate(XMSS_KEY *key, uint32_t oid) { uint32_t height; - if (sm3_xmss_height_from_oid(&height, oid) != 1) { + if (xmss_height_from_oid(&height, oid) != 1) { error_print(); return -1; } @@ -509,12 +527,12 @@ int sm3_xmss_key_generate(SM3_XMSS_KEY *key, uint32_t oid) error_print(); return -1; } - sm3_xmss_derive_root(key->secret, height, key->seed, key->tree, key->root); + xmss_derive_root(key->secret, height, key->seed, key->tree, key->root); return 1; } -void sm3_xmss_key_cleanup(SM3_XMSS_KEY *key) +void xmss_key_cleanup(XMSS_KEY *key) { if (key->tree) { free(key->tree); @@ -522,7 +540,7 @@ void sm3_xmss_key_cleanup(SM3_XMSS_KEY *key) gmssl_secure_clear(key, sizeof(*key)); } -int sm3_xmss_key_print(FILE *fp, int fmt, int ind, const char *label, const SM3_XMSS_KEY *key) +int xmss_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; @@ -535,16 +553,18 @@ int sm3_xmss_key_print(FILE *fp, int fmt, int ind, const char *label, const SM3_ return 1; } -int sm3_xmss_key_get_height(const SM3_XMSS_KEY *key, uint32_t *height) + +int xmss_key_get_height(const XMSS_KEY *key, uint32_t *height) { - if (sm3_xmss_height_from_oid(height, key->oid) != 1) { + if (xmss_height_from_oid(height, key->oid) != 1) { error_print(); return -1; } return 1; } -int sm3_xmss_key_to_bytes(const SM3_XMSS_KEY *key, uint8_t *out, size_t *outlen) +// 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) { uint32_t height; size_t tree_size; @@ -555,7 +575,7 @@ int sm3_xmss_key_to_bytes(const SM3_XMSS_KEY *key, uint8_t *out, size_t *outlen) return -1; } - if (sm3_xmss_height_from_oid(&height, key->oid) != 1) { + if (xmss_height_from_oid(&height, key->oid) != 1) { error_print(); return -1; } @@ -583,7 +603,7 @@ int sm3_xmss_key_to_bytes(const SM3_XMSS_KEY *key, uint8_t *out, size_t *outlen) return 1; } -int sm3_xmss_key_from_bytes(SM3_XMSS_KEY *key, const uint8_t *in, size_t inlen) +int xmss_key_from_bytes(XMSS_KEY *key, const uint8_t *in, size_t inlen) { uint32_t height; size_t tree_size; @@ -596,7 +616,7 @@ int sm3_xmss_key_from_bytes(SM3_XMSS_KEY *key, const uint8_t *in, size_t inlen) p = in; key->oid = uint32_from_bytes(p); p += 4; - if (sm3_xmss_height_from_oid(&height, key->oid) != 1) { + if (xmss_height_from_oid(&height, key->oid) != 1) { error_print(); return -1; } @@ -624,7 +644,7 @@ int sm3_xmss_key_from_bytes(SM3_XMSS_KEY *key, const uint8_t *in, size_t inlen) return 1; } -int sm3_xmss_public_key_to_bytes(const SM3_XMSS_KEY *key, uint8_t *out, size_t *outlen) +int xmss_public_key_to_bytes(const XMSS_KEY *key, uint8_t *out, size_t *outlen) { uint32_t height; uint8_t *p; @@ -634,7 +654,7 @@ int sm3_xmss_public_key_to_bytes(const SM3_XMSS_KEY *key, uint8_t *out, size_t * return -1; } - if (sm3_xmss_height_from_oid(&height, key->oid) != 1) { + if (xmss_height_from_oid(&height, key->oid) != 1) { error_print(); return -1; } @@ -654,7 +674,7 @@ int sm3_xmss_public_key_to_bytes(const SM3_XMSS_KEY *key, uint8_t *out, size_t * } // FIXME: check input length -int sm3_xmss_public_key_from_bytes(SM3_XMSS_KEY *key, const uint8_t *in, size_t inlen) +int xmss_public_key_from_bytes(XMSS_KEY *key, const uint8_t *in, size_t inlen) { uint32_t height; const uint8_t *p; @@ -665,7 +685,7 @@ int sm3_xmss_public_key_from_bytes(SM3_XMSS_KEY *key, const uint8_t *in, size_t } p = in; key->oid = uint32_from_bytes(p); p += 4; - if (sm3_xmss_height_from_oid(&height, key->oid) != 1) { + if (xmss_height_from_oid(&height, key->oid) != 1) { error_print(); return -1; } @@ -674,10 +694,10 @@ int sm3_xmss_public_key_from_bytes(SM3_XMSS_KEY *key, const uint8_t *in, size_t return 1; } -int sm3_xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *in, size_t inlen) +int xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *in, size_t inlen) { uint32_t index; - SM3_XMSS_SIGNATURE *sig = (SM3_XMSS_SIGNATURE *)in; + XMSS_SIGNATURE *sig = (XMSS_SIGNATURE *)in; int i; format_print(fp, fmt, ind, "%s\n", label); @@ -693,7 +713,7 @@ int sm3_xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, cons } format_print(fp, fmt, ind, "auth_path\n"); - assert(sizeof(SM3_XMSS_SIGNATURE) == 4 + 32 * (68 + 20)); + assert(sizeof(XMSS_SIGNATURE) == 4 + 32 * (68 + 20)); inlen -= 4 + 32 * 68; for (i = 0; i < 20 && inlen >= 32; i++) { format_print(fp, fmt, ind+4, "%d ", i); @@ -704,7 +724,31 @@ int sm3_xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, cons return 1; } -int sm3_xmss_sign_init(SM3_XMSS_SIGN_CTX *ctx, const SM3_XMSS_KEY *key) + +// (4 + n + (len + h) * n) +int xmss_signature_size(uint32_t oid, size_t *siglen) +{ + size_t height; + + if (!siglen) { + error_print(); + return -1; + } + if (xmss_oid_to_height(oid, &height) != 1) { + error_print(); + return -1; + } + *siglen = 4 // OID + + 32 // random + + 32 * 67 // WOTS signature size + + 32 * height // path + ; + return 1; +} + + + +int xmss_sign_init(XMSS_SIGN_CTX *ctx, const XMSS_KEY *key) { HASH256_CTX prf_ctx; uint8_t hash_id[32] = {0}; @@ -727,7 +771,7 @@ int sm3_xmss_sign_init(SM3_XMSS_SIGN_CTX *ctx, const SM3_XMSS_KEY *key) return 1; } -int sm3_xmss_sign_update(SM3_XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) +int xmss_sign_update(XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) { if (data && datalen) { hash256_update(&ctx->hash256_ctx, data, datalen); @@ -735,17 +779,17 @@ int sm3_xmss_sign_update(SM3_XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t dat return 1; } -int sm3_xmss_sign_finish(SM3_XMSS_SIGN_CTX *ctx, const SM3_XMSS_KEY *key, uint8_t *sigbuf, size_t *siglen) +int xmss_sign_finish(XMSS_SIGN_CTX *ctx, const XMSS_KEY *key, uint8_t *sigbuf, size_t *siglen) { - SM3_XMSS_SIGNATURE *sig = (SM3_XMSS_SIGNATURE *)sigbuf; + XMSS_SIGNATURE *sig = (XMSS_SIGNATURE *)sigbuf; uint8_t adrs[32] = {0}; uint8_t dgst[32]; uint32_t height; hash256_finish(&ctx->hash256_ctx, dgst); - sm3_xmss_key_get_height(key, &height); - sm3_xmss_do_sign(key->secret, key->index, key->seed, adrs, height, key->tree, 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); uint32_to_bytes(key->index, sig->index); @@ -755,9 +799,9 @@ int sm3_xmss_sign_finish(SM3_XMSS_SIGN_CTX *ctx, const SM3_XMSS_KEY *key, uint8_ return 1; } -int sm3_xmss_verify_init(SM3_XMSS_SIGN_CTX *ctx, const SM3_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 *sigbuf, size_t siglen) { - SM3_XMSS_SIGNATURE *sig = (SM3_XMSS_SIGNATURE *)sigbuf; + XMSS_SIGNATURE *sig = (XMSS_SIGNATURE *)sigbuf; uint8_t hash_id[32] = {0}; uint8_t index_buf[32] = {0}; @@ -773,7 +817,7 @@ int sm3_xmss_verify_init(SM3_XMSS_SIGN_CTX *ctx, const SM3_XMSS_KEY *key, const return 1; } -int sm3_xmss_verify_update(SM3_XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) +int xmss_verify_update(XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) { if (data && datalen) { hash256_update(&ctx->hash256_ctx, data, datalen); @@ -781,10 +825,10 @@ int sm3_xmss_verify_update(SM3_XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t d return 1; } -int sm3_xmss_verify_finish(SM3_XMSS_SIGN_CTX *ctx, const SM3_XMSS_KEY *key, const uint8_t *sigbuf, size_t siglen) +int xmss_verify_finish(XMSS_SIGN_CTX *ctx, const XMSS_KEY *key, const uint8_t *sigbuf, size_t siglen) { - const SM3_XMSS_SIGNATURE *sig = (const SM3_XMSS_SIGNATURE *)sigbuf; + const XMSS_SIGNATURE *sig = (const XMSS_SIGNATURE *)sigbuf; uint8_t adrs[32] = {0}; uint8_t dgst[32]; uint32_t index, height; @@ -792,10 +836,10 @@ int sm3_xmss_verify_finish(SM3_XMSS_SIGN_CTX *ctx, const SM3_XMSS_KEY *key, cons hash256_finish(&ctx->hash256_ctx, dgst); - sm3_xmss_key_get_height(key, &height); + xmss_key_get_height(key, &height); index = uint32_from_bytes(sig->index); - sm3_xmss_sig_to_root(sig->wots_sig, index, sig->auth_path, key->seed, adrs, height, dgst, xmss_root); + xmss_sig_to_root(sig->wots_sig, index, sig->auth_path, key->seed, adrs, height, dgst, xmss_root); if (memcmp(xmss_root, key->root, 32) != 0) { error_print(); diff --git a/tests/sm3_xmsstest.c b/tests/xmsstest.c similarity index 77% rename from tests/sm3_xmsstest.c rename to tests/xmsstest.c index 6ba12c83..7d2e0205 100644 --- a/tests/sm3_xmsstest.c +++ b/tests/xmsstest.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include // copy this static function from src/sm3_xmss.c @@ -31,8 +31,8 @@ static int test_sm3_wots_derive_sk(void) uint8_t wots_secret[32] = {0}; uint8_t seed[32] = {0}; uint8_t adrs[32] = {0}; - hash256_bytes_t wots_sk[67]; - hash256_bytes_t test_sk[67]; + hash256_t wots_sk[67]; + hash256_t test_sk[67]; size_t len; // sha256 test 1 @@ -76,9 +76,9 @@ static int test_sm3_wots_derive_pk(void) uint8_t wots_secret[32] = {0}; uint8_t seed[32] = {0}; uint8_t adrs[32] = {0}; - hash256_bytes_t wots_sk[67]; - hash256_bytes_t wots_pk[67]; - hash256_bytes_t test_pk[67]; + hash256_t wots_sk[67]; + hash256_t wots_pk[67]; + hash256_t test_pk[67]; HASH256_CTX prf_seed_ctx; size_t len; @@ -111,11 +111,11 @@ static int test_sm3_wots_do_sign(void) uint8_t seed[32] = {0}; uint8_t adrs[32] = {0}; uint8_t dgst[32] = {0}; - hash256_bytes_t wots_sk[67]; - hash256_bytes_t wots_pk[67]; - hash256_bytes_t wots_sig[67]; - hash256_bytes_t test_sig[67]; - hash256_bytes_t sig_pk[67]; + 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; size_t len; int i; @@ -154,12 +154,12 @@ static int test_sm3_wots_do_sign(void) return 1; } -static int test_sm3_xmss_derive_root(void) +static int test_xmss_derive_root(void) { uint8_t xmss_secret[32]; uint8_t seed[32]; int height = 10; - hash256_bytes_t *tree = malloc(32 * (1< #include #include -#include +#include static const char *usage = "-oid oid [-out file] [-pubout file]\n"; @@ -29,7 +29,7 @@ static const char *help = " -pubout file Output public key\n" "\n"; -int sm3xmss_keygen_main(int argc, char **argv) +int xmsskeygen_main(int argc, char **argv) { int ret = 1; char *prog = argv[0]; @@ -39,7 +39,7 @@ int sm3xmss_keygen_main(int argc, char **argv) char *puboutfile = NULL; FILE *outfp = stdout; FILE *puboutfp = stdout; - SM3_XMSS_KEY key; + XMSS_KEY key; uint8_t *out = NULL; uint8_t *pubout = NULL; size_t outlen, puboutlen; @@ -103,12 +103,12 @@ bad: } - if (sm3_xmss_key_generate(&key, oid_val) != 1) { + if (xmss_key_generate(&key, oid_val) != 1) { error_print(); return -1; } - if (sm3_xmss_key_to_bytes(&key, NULL, &outlen) != 1) { + if (xmss_key_to_bytes(&key, NULL, &outlen) != 1) { error_print(); goto end; } @@ -116,11 +116,11 @@ bad: error_print(); goto end; } - if (sm3_xmss_key_to_bytes(&key, out, &outlen) != 1) { + if (xmss_key_to_bytes(&key, out, &outlen) != 1) { error_print(); } - if (sm3_xmss_public_key_to_bytes(&key, NULL, &puboutlen) != 1) { + if (xmss_public_key_to_bytes(&key, NULL, &puboutlen) != 1) { error_print(); goto end; } @@ -128,7 +128,7 @@ bad: error_print(); goto end; } - if (sm3_xmss_public_key_to_bytes(&key, pubout, &puboutlen) != 1) { + if (xmss_public_key_to_bytes(&key, pubout, &puboutlen) != 1) { error_print(); goto end; } diff --git a/tools/sm3xmss_sign.c b/tools/xmsssign.c similarity index 81% rename from tools/sm3xmss_sign.c rename to tools/xmsssign.c index b62d02c0..398cd926 100644 --- a/tools/sm3xmss_sign.c +++ b/tools/xmsssign.c @@ -12,8 +12,10 @@ #include #include #include +#include +#include #include -#include +#include static const char *usage = "-key file [-in file] [-out file]\n"; @@ -24,7 +26,7 @@ static const char *help = " -out file Output signature file\n" "\n"; -int sm3xmss_sign_main(int argc, char **argv) +int xmsssign_main(int argc, char **argv) { int ret = 1; char *prog = argv[0]; @@ -34,8 +36,10 @@ int sm3xmss_sign_main(int argc, char **argv) FILE *keyfp = NULL; FILE *infp = stdin; FILE *outfp = stdout; - SM3_XMSS_KEY key; - SM3_XMSS_SIGN_CTX sign_ctx; + uint8_t *keybuf = NULL; + size_t keylen; + XMSS_KEY key; + XMSS_SIGN_CTX sign_ctx; uint8_t *sigbuf = NULL; size_t siglen; @@ -56,10 +60,16 @@ int sm3xmss_sign_main(int argc, char **argv) } else if (!strcmp(*argv, "-key")) { if (--argc < 1) goto bad; keyfile = *(++argv); + /* 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); @@ -91,17 +101,13 @@ bad: goto end; } - if (sm3_xmss_key_from_bytes(&key, NULL, 0) != 1) { + + if (xmss_key_from_bytes(&key, keybuf, keylen) != 1) { error_print(); goto end; } - if (fread(&key, 1, sizeof(key), keyfp) != sizeof(key)) { - fprintf(stderr, "%s: read private key failure\n", prog); - goto end; - } - - if (sm3_xmss_sign_init(&sign_ctx, &key) != 1) { + if (xmss_sign_init(&sign_ctx, &key) != 1) { error_print(); goto end; } @@ -112,13 +118,13 @@ bad: if (len == 0) { break; } - if (sm3_xmss_sign_update(&sign_ctx, buf, len) != 1) { + if (xmss_sign_update(&sign_ctx, buf, len) != 1) { error_print(); goto end; } } - if (sm3_xmss_sign_finish(&sign_ctx, &key, NULL, &siglen) != 1) { + if (xmss_sign_finish(&sign_ctx, &key, NULL, &siglen) != 1) { error_print(); goto end; } @@ -128,7 +134,7 @@ bad: goto end; } - if (sm3_xmss_sign_finish(&sign_ctx, &key, sigbuf, &siglen) != 1) { + if (xmss_sign_finish(&sign_ctx, &key, sigbuf, &siglen) != 1) { error_print(); goto end; } @@ -147,7 +153,11 @@ end: gmssl_secure_clear(sigbuf, siglen); free(sigbuf); } - if (keyfp) fclose(keyfp); + if (keybuf) { + gmssl_secure_clear(keybuf, keylen); + free(keybuf); + } + //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 new file mode 100644 index 00000000..7229ede5 --- /dev/null +++ b/tools/xmssverify.c @@ -0,0 +1,158 @@ +/* + * 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. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include + +static const char *usage = "-pubkey file [-in file] -sig file [-verbose]\n"; + +static const char *options = +"Options\n" +" -pubkey file Input public key file\n" +" -in file Input data file (if not using stdin)\n" +" -sig file Input signature file\n" +" -verbose Print public key and signature\n" +"\n"; + +int xmssverify_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + char *pubkeyfile = NULL; + char *infile = NULL; + char *sigfile = NULL; + int verbose = 0; + FILE *pubkeyfp = NULL; + FILE *infp = stdin; + FILE *sigfp = NULL; + uint8_t pubkeybuf[XMSS_PUBLIC_KEY_SIZE]; + size_t pubkeylen = XMSS_PUBLIC_KEY_SIZE; + const uint8_t *cp = pubkeybuf; + uint8_t sig[XMSS_SIGNATURE_MAX_SIZE]; + size_t siglen; + XMSS_KEY key; + XMSS_SIGN_CTX ctx; + int vr; + + argc--; + argv++; + + if (argc < 1) { + 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", options); + ret = 0; + goto end; + } else if (!strcmp(*argv, "-pubkey")) { + if (--argc < 1) goto bad; + pubkeyfile = *(++argv); + if (!(pubkeyfp = fopen(pubkeyfile, "rb"))) { + fprintf(stderr, "%s: open '%s' failure: %s\n", prog, pubkeyfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-in")) { + if (--argc < 1) goto bad; + infile = *(++argv); + if (!(infp = fopen(infile, "rb"))) { + fprintf(stderr, "%s: open '%s' failure: %s\n", prog, infile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-sig")) { + if (--argc < 1) goto bad; + sigfile = *(++argv); + if (!(sigfp = fopen(sigfile, "rb"))) { + fprintf(stderr, "%s: open '%s' failure: %s\n", prog, sigfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-verbose")) { + verbose = 1; + } else { + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + goto end; +bad: + fprintf(stderr, "%s: `%s` option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + if (!pubkeyfile) { + fprintf(stderr, "%s: `-key` option required\n", prog); + goto end; + } + if (!sigfile) { + fprintf(stderr, "%s: `-sig` option required\n", prog); + goto end; + } + + if (fread(pubkeybuf, 1, pubkeylen, pubkeyfp) != pubkeylen) { + fprintf(stderr, "%s: read public key failure\n", prog); + goto end; + } + 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); + } + + // read signature even if signature not compatible with the public key + if ((siglen = fread(sig, 1, XMSS_SIGNATURE_MAX_SIZE, sigfp)) <= 0) { + fprintf(stderr, "%s: read signature failure\n", prog); + goto end; + } + if (verbose) { + xmss_signature_print(stderr, 0, 0, "xmss_signature", sig, siglen); + } + if (xmss_verify_init(&ctx, &key, sig, siglen) != 1) { + error_print(); + goto end; + } + + while (1) { + uint8_t buf[1024]; + size_t len = fread(buf, 1, sizeof(buf), infp); + if (len == 0) { + break; + } + if (xmss_verify_update(&ctx, buf, len) != 1) { + error_print(); + goto end; + } + } + if ((vr = xmss_verify_finish(&ctx, &key, sig, siglen)) < 0) { + error_print(); + goto end; + } + fprintf(stdout, "verify : %s\n", vr == 1 ? "success" : "failure"); + if (vr == 1) { + ret = 0; + } + +end: + if (pubkeyfp) fclose(pubkeyfp); + if (infp && infp != stdin) fclose(infp); + if (sigfp) fclose(sigfp); + return ret; +}