From 6a51ca01dcbac715a638f29d05e00e3a1b143c9a Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Thu, 4 Dec 2025 11:46:16 +0800 Subject: [PATCH] Add SM3 LMS/HSS hash-based post-quantum signatures --- CMakeLists.txt | 23 +- include/gmssl/sm3_lms.h | 299 +++++++ include/gmssl/version.h | 4 +- src/sm3_lms.c | 1892 ++++++++++++++++++++++++++------------- tests/sm3_lmstest.c | 903 +++++++++++++++++++ tools/gmssl.c | 46 +- tools/sm3hsskeygen.c | 158 ++++ tools/sm3hsssign.c | 170 ++++ tools/sm3hssverify.c | 157 ++++ tools/sm3lmskeygen.c | 144 +++ tools/sm3lmssign.c | 170 ++++ tools/sm3lmsverify.c | 157 ++++ 12 files changed, 3515 insertions(+), 608 deletions(-) create mode 100644 include/gmssl/sm3_lms.h create mode 100644 tests/sm3_lmstest.c create mode 100644 tools/sm3hsskeygen.c create mode 100644 tools/sm3hsssign.c create mode 100644 tools/sm3hssverify.c create mode 100644 tools/sm3lmskeygen.c create mode 100644 tools/sm3lmssign.c create mode 100644 tools/sm3lmsverify.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d7d12d9..3d8d6fc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,8 @@ option(ENABLE_SM4_XTS "Enable SM4 XTS mode" ON) option(ENABLE_SM4_CBC_MAC "Enable SM4-CBC-MAC" ON) option(ENABLE_SM2_EXTS "Enable SM2 Extensions" OFF) -option(ENABLE_SM3_XMSS "Enable SM3-XMSS signature" ON) +option(ENABLE_SM3_LMS "Enable SM3-LMS signature" ON) +option(ENABLE_SM3_XMSS "Enable SM3-XMSS signature" OFF) option(ENABLE_SHA1 "Enable SHA1" ON) @@ -141,7 +142,6 @@ set(tools tools/sm3.c tools/sm3hmac.c tools/sm3_pbkdf2.c - tools/sm3xmss_keygen.c tools/sm2keygen.c tools/sm2sign.c tools/sm2verify.c @@ -416,8 +416,25 @@ if (ENABLE_SM2_EXTS) endif() +if (ENABLE_SM3_LMS) + message(STATUS "ENABLE_SM3_LMS is ON") + add_definitions(-DENABLE_SM3_LMS) + list(APPEND src src/sm3_lms.c) + list(APPEND tools tools/sm3lmskeygen.c tools/sm3lmssign.c tools/sm3lmsverify.c) + list(APPEND tools tools/sm3hsskeygen.c tools/sm3hsssign.c tools/sm3hssverify.c) + list(APPEND tests sm3_lms) + + option(ENABLE_SM3_LMS_CROSSCHECK "Enable LMS SHA-256 cross-check" OFF) + if (ENABLE_SM3_LMS_CROSSCHECK) + message(STATUS "ENABLE_SM3_LMS_CROSSCHECK is ON") + add_definitions(-DENABLE_SM3_LMS_CROSSCHECK) + endif() +endif() + + if (ENABLE_SM3_XMSS) message(STATUS "ENABLE_SM3_XMSS is ON") + add_definitions(-DENABLE_SM3_XMSS) list(APPEND src src/sm3_xmss.c) option(ENABLE_SM3_XMSS_CROSSCHECK "Enable XMSS SHA-256 cross-check" OFF) @@ -644,7 +661,7 @@ endif() # set(CPACK_PACKAGE_NAME "GmSSL") set(CPACK_PACKAGE_VENDOR "GmSSL develop team") -set(CPACK_PACKAGE_VERSION "3.1.2-Dev") +set(CPACK_PACKAGE_VERSION "3.1.3-Dev") set(CPACK_PACKAGE_DESCRIPTION_FILE ${PROJECT_SOURCE_DIR}/README.md) set(CPACK_NSIS_MODIFY_PATH ON) include(CPack) diff --git a/include/gmssl/sm3_lms.h b/include/gmssl/sm3_lms.h new file mode 100644 index 00000000..f2e40cbb --- /dev/null +++ b/include/gmssl/sm3_lms.h @@ -0,0 +1,299 @@ +/* + * 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_SM3_LMS_H +#define GMSSL_SM3_LMS_H + +#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 SM3_HSS_MAX_LEVELS 5 +#define SM3_LMS_MAX_HEIGHT 25 + + +// Crosscheck with data from LMS-reference (SHA-256), except the LMS signature. +#if defined(ENABLE_SM3_LMS_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 LMOTS_HASH256_N32_W8 LMOTS_SHA256_N32_W8 +# define LMOTS_HASH256_N32_W8_NAME "LMOTS_SHA256_N32_W8" +# define LMS_HASH256_M32_H5 LMS_SHA256_M32_H5 +# define LMS_HASH256_M32_H10 LMS_SHA256_M32_H10 +# define LMS_HASH256_M32_H15 LMS_SHA256_M32_H15 +# define LMS_HASH256_M32_H20 LMS_SHA256_M32_H20 +# define LMS_HASH256_M32_H25 LMS_SHA256_M32_H25 +# define LMS_HASH256_M32_H5_NAME "LMS_SHA256_M32_H5" +# define LMS_HASH256_M32_H10_NAME "LMS_SHA256_M32_H10" +# define LMS_HASH256_M32_H15_NAME "LMS_SHA256_M32_H15" +# define LMS_HASH256_M32_H20_NAME "LMS_SHA256_M32_H20" +# define LMS_HASH256_M32_H25_NAME "LMS_SHA256_M32_H25" +#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 LMOTS_HASH256_N32_W8 LMOTS_SM3_N32_W8 +# define LMOTS_HASH256_N32_W8_NAME "LMOTS_SM3_N32_W8" +# define LMS_HASH256_M32_H5 LMS_SM3_M32_H5 +# define LMS_HASH256_M32_H10 LMS_SM3_M32_H10 +# define LMS_HASH256_M32_H15 LMS_SM3_M32_H15 +# define LMS_HASH256_M32_H20 LMS_SM3_M32_H20 +# define LMS_HASH256_M32_H25 LMS_SM3_M32_H25 +# define LMS_HASH256_M32_H5_NAME "LMS_SM3_M32_H5" +# define LMS_HASH256_M32_H10_NAME "LMS_SM3_M32_H10" +# define LMS_HASH256_M32_H15_NAME "LMS_SM3_M32_H15" +# define LMS_HASH256_M32_H20_NAME "LMS_SM3_M32_H20" +# define LMS_HASH256_M32_H25_NAME "LMS_SM3_M32_H25" +#endif + +enum { + LMOTS_RESERVED = 0, + LMOTS_SHA256_N32_W1 = 1, + LMOTS_SHA256_N32_W2 = 2, + LMOTS_SHA256_N32_W4 = 3, + LMOTS_SHA256_N32_W8 = 4, + LMOTS_SM3_N32_W1 = 11, + LMOTS_SM3_N32_W2 = 12, + LMOTS_SM3_N32_W4 = 13, + LMOTS_SM3_N32_W8 = 14, +}; + +enum { +#if defined(ENABLE_SM3_LMS_CROSSCHECK) && defined(ENABLE_SHA2) + LMS_SHA256_M32_H5 = 5, + LMS_SHA256_M32_H10 = 6, + LMS_SHA256_M32_H15 = 7, + LMS_SHA256_M32_H20 = 8, + LMS_SHA256_M32_H25 = 9, +#else + // TODO: submit to IETF + LMS_SM3_M32_H5 = 5, + LMS_SM3_M32_H10 = 6, + LMS_SM3_M32_H15 = 7, + LMS_SM3_M32_H20 = 8, + LMS_SM3_M32_H25 = 9, +#endif +}; + + +char *sm3_lmots_type_name(int lmots_type); +void sm3_lmots_derive_secrets(const hash256_t seed, const uint8_t I[16], int q, hash256_t x[34]); +void sm3_lmots_secrets_to_public_hash(const uint8_t I[16], int q, const hash256_t x[34], hash256_t pub); +void sm3_lmots_compute_signature(const uint8_t I[16], int q, const hash256_t dgst, const hash256_t x[34], hash256_t y[34]); +void sm3_lmots_signature_to_public_hash(const uint8_t I[16], int q, const hash256_t y[34], const hash256_t dgst, hash256_t pub); + + +char *sm3_lms_type_name(int lms_type); +int sm3_lms_type_from_name(const char *name); +int sm3_lms_type_to_height(int type, size_t *height); +void sm3_lms_derive_merkle_tree(const hash256_t seed, const uint8_t I[16], int height, hash256_t *tree); +void sm3_lms_derive_merkle_root(const hash256_t seed, const uint8_t I[16], int height, hash256_t root); + + +typedef struct { + int lms_type; + int lmots_type; + uint8_t I[16]; // lms key identifier + hash256_t root; // merkle tree root +} SM3_LMS_PUBLIC_KEY; + +#define SM3_LMS_PUBLIC_KEY_SIZE (4 + 4 + 16 + 32) // = 56 bytes + +typedef struct { + SM3_LMS_PUBLIC_KEY public_key; + hash256_t *tree; + hash256_t seed; + uint32_t q; // in [0, 2^h - 1], q++ after every sign +} SM3_LMS_KEY; + +#define SM3_LMS_PRIVATE_KEY_SIZE (SM3_LMS_PUBLIC_KEY_SIZE + 32 + 4) // = 92 bytes + +// FIXME: do we need a function to update lms_key->q ? + +int sm3_lms_key_generate_ex(SM3_LMS_KEY *key, int lms_type, const hash256_t seed, const uint8_t I[16], int cache_tree); +int sm3_lms_key_generate(SM3_LMS_KEY *key, int lms_type); +int sm3_lms_key_check(const SM3_LMS_KEY *key, const SM3_LMS_PUBLIC_KEY *pub); +int sm3_lms_key_remaining_signs(const SM3_LMS_KEY *key, size_t *count); +int sm3_lms_public_key_to_bytes(const SM3_LMS_KEY *key, uint8_t **out, size_t *outlen); +int sm3_lms_public_key_from_bytes_ex(const SM3_LMS_PUBLIC_KEY **key, const uint8_t **in, size_t *inlen); +int sm3_lms_public_key_from_bytes(SM3_LMS_KEY *key, const uint8_t **in, size_t *inlen); +int sm3_lms_private_key_to_bytes(const SM3_LMS_KEY *key, uint8_t **out, size_t *outlen); +int sm3_lms_private_key_from_bytes(SM3_LMS_KEY *key, const uint8_t **in, size_t *inlen); +int sm3_lms_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SM3_LMS_PUBLIC_KEY *pub); +int sm3_lms_key_print(FILE *fp, int fmt, int ind, const char *label, const SM3_LMS_KEY *key); +void sm3_lms_key_cleanup(SM3_LMS_KEY *key); + + + +typedef struct { + int q; // index of LMS tree leaf, in [0, 2^h - 1] + struct { + int lmots_type; // LMOTS_SM3_N32_W8 or LMOTS_SHA256_N32_W8 in compile time + hash256_t C; // randomness of every LMOTS signature + hash256_t y[34]; // for w = 8 and hash256, 34 winternitz chains + } lmots_sig; + int lms_type; + hash256_t path[25]; // max tree height = 25 when LMS_SM3_M32_H25 +} SM3_LMS_SIGNATURE; + +// encoded size, SHOULD be changed when supporting text/der encoding +#define SM3_LMS_SIGNATURE_MIN_SIZE (4 + 4 + 32 + 32*34 + 4 + 32*5) // = 1292 bytes +#define SM3_LMS_SIGNATURE_MAX_SIZE (4 + 4 + 32 + 32*34 + 4 + 32*25) // = 1932 bytes + + +int sm3_lms_signature_to_merkle_root(const uint8_t I[16], size_t h, int q, + const hash256_t y[34], const hash256_t *path, + const hash256_t dgst, hash256_t root); + +int sm3_lms_key_get_signature_size(const SM3_LMS_KEY *key, size_t *siglen); +int sm3_lms_signature_size(int lms_type, size_t *siglen); + +int sm3_lms_signature_to_bytes(const SM3_LMS_SIGNATURE *sig, uint8_t **out, size_t *outlen); +int sm3_lms_signature_from_bytes_ex(const SM3_LMS_SIGNATURE **sig, size_t *siglen, const uint8_t **in, size_t *inlen); +int sm3_lms_signature_from_bytes(SM3_LMS_SIGNATURE *sig, const uint8_t **in, size_t *inlen); +int sm3_lms_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const SM3_LMS_SIGNATURE *sig); +int sm3_lms_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen); + + +typedef struct { + HASH256_CTX hash256_ctx; + SM3_LMS_PUBLIC_KEY lms_public_key; // FIXME: or use LMS_PUBLIC_KEY to re-use tree? + SM3_LMS_SIGNATURE lms_sig; +} SM3_LMS_SIGN_CTX; + +int sm3_lms_sign_init(SM3_LMS_SIGN_CTX *ctx, SM3_LMS_KEY *key); +int sm3_lms_sign_update(SM3_LMS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); +int sm3_lms_sign_finish(SM3_LMS_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen); +int sm3_lms_sign_finish_ex(SM3_LMS_SIGN_CTX *ctx, SM3_LMS_SIGNATURE *sig); +int sm3_lms_verify_init_ex(SM3_LMS_SIGN_CTX *ctx, const SM3_LMS_KEY *key, const SM3_LMS_SIGNATURE *sig); +int sm3_lms_verify_init(SM3_LMS_SIGN_CTX *ctx, const SM3_LMS_KEY *key, const uint8_t *sigbuf, size_t siglen); +int sm3_lms_verify_update(SM3_LMS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); +int sm3_lms_verify_finish(SM3_LMS_SIGN_CTX *ctx); + +// `sm3_lms_sign_init` copy lmots private to ctx->lms_sig.y +// call `sm3_lms_sign_ctx_cleanup` incase `sm3_lms_sign_finish` not called nor finished +void sm3_lms_sign_ctx_cleanup(SM3_LMS_SIGN_CTX *ctx); + + +/* +// just for reference, HSS_PUBLIC_KEY memory layout might not compatible with HSS_KEY +typedef struct { + uint32_t levels; + SM3_LMS_PUBLIC_KEY lms_public_key; +} SM3_HSS_PUBLIC_KEY; +*/ + +// SM3_HSS_PUBLIC_KEY: { level, lms_key[0].public_key } +#define SM3_HSS_PUBLIC_KEY_SIZE (4 + SM3_LMS_PUBLIC_KEY_SIZE) + + +// TODO: LMS_KEY should be a tree other than a vector +// when updated, low level lms keys will lost, maybe a good feature +typedef struct { + uint32_t levels; // should be checked to prevent memory error + SM3_LMS_KEY lms_key[5]; + SM3_LMS_SIGNATURE lms_sig[4]; +} SM3_HSS_KEY; + + +#define SM3_HSS_PRIVATE_KEY_MAX_SIZE sizeof(SM3_HSS_KEY) +int sm3_hss_private_key_size(const int *lms_types, size_t levels, size_t *len); + +int sm3_hss_key_generate(SM3_HSS_KEY *key, const int *lms_types, size_t levels); +int sm3_hss_key_update(SM3_HSS_KEY *key); + +int sm3_hss_public_key_to_bytes(const SM3_HSS_KEY *key, uint8_t **out, size_t *outlen); +int sm3_hss_private_key_to_bytes(const SM3_HSS_KEY *key, uint8_t **out, size_t *outlen); +int sm3_hss_public_key_from_bytes(SM3_HSS_KEY *key, const uint8_t **in, size_t *inlen); +int sm3_hss_private_key_from_bytes(SM3_HSS_KEY *key, const uint8_t **in, size_t *inlen); +int sm3_hss_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SM3_HSS_KEY *key); +int sm3_hss_key_print(FILE *fp, int fmt, int ind, const char *label, const SM3_HSS_KEY *key); +void sm3_hss_key_cleanup(SM3_HSS_KEY *key); + + + +typedef struct { + uint32_t num_signed_public_keys; // = hss_key->levels - 1 + struct { + SM3_LMS_SIGNATURE lms_sig; // lms_sig[i] = sign(hss_key->lms_key[i], lms_public_key[i]) + SM3_LMS_PUBLIC_KEY lms_public_key; // signed_public_keys[i] = hss_key->lms_key[i+1].public_key + } signed_public_keys[SM3_HSS_MAX_LEVELS - 1]; + SM3_LMS_SIGNATURE msg_lms_sig; // = sign(hss->lms_key[levels-1], msg) +} SM3_HSS_SIGNATURE; + + +#define SM3_HSS_SIGNATURE_MAX_SIZE sizeof(SM3_HSS_SIGNATURE) +int sm3_hss_signature_size(const int *lms_types, size_t levels, size_t *len); +int sm3_hss_key_get_signature_size(const SM3_HSS_KEY *key, size_t *siglen); + +int sm3_hss_signature_to_bytes(const SM3_HSS_SIGNATURE *sig, uint8_t **out, size_t *outlen); +int sm3_hss_signature_from_bytes(SM3_HSS_SIGNATURE *sig, const uint8_t **in, size_t *inlen); +int sm3_hss_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const SM3_HSS_SIGNATURE *sig); +int sm3_hss_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen); + + +typedef struct { + SM3_LMS_SIGN_CTX lms_ctx; + uint32_t levels; + SM3_LMS_SIGNATURE lms_sigs[SM3_HSS_MAX_LEVELS - 1]; + SM3_LMS_PUBLIC_KEY lms_public_keys[SM3_HSS_MAX_LEVELS - 1]; +} SM3_HSS_SIGN_CTX; + + +int sm3_hss_sign_init(SM3_HSS_SIGN_CTX *ctx, SM3_HSS_KEY *key); +int sm3_hss_sign_update(SM3_HSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); +int sm3_hss_sign_finish(SM3_HSS_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen); +int sm3_hss_sign_finish_ex(SM3_HSS_SIGN_CTX *ctx, SM3_HSS_SIGNATURE *sig); +int sm3_hss_verify_init_ex(SM3_HSS_SIGN_CTX *ctx, const SM3_HSS_KEY *key, const SM3_HSS_SIGNATURE *sig); +int sm3_hss_verify_init(SM3_HSS_SIGN_CTX *ctx, const SM3_HSS_KEY *key, const uint8_t *sigbuf, size_t siglen); +int sm3_hss_verify_update(SM3_HSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); +int sm3_hss_verify_finish(SM3_HSS_SIGN_CTX *ctx); + + +/* +from RFC 9708 + +id-alg-hss-lms-hashsig OBJECT IDENTIFIER ::= { + iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) + pkcs-9(9) smime(16) alg(3) 17 +} +*/ +#include + +#define oid_hss_lms_hashsig oid_pkcs,9,16,3,17 + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/version.h b/include/gmssl/version.h index c516bd8b..223a17b2 100644 --- a/include/gmssl/version.h +++ b/include/gmssl/version.h @@ -18,8 +18,8 @@ extern "C" { // Also update CPACK_PACKAGE_VERSION in CMakeLists.txt -#define GMSSL_VERSION_NUM 30102 -#define GMSSL_VERSION_STR "GmSSL 3.1.2 Dev" +#define GMSSL_VERSION_NUM 30103 +#define GMSSL_VERSION_STR "GmSSL 3.1.3 Dev" int gmssl_version_num(void); const char *gmssl_version_str(void); diff --git a/src/sm3_lms.c b/src/sm3_lms.c index b9f5ba41..65743b47 100644 --- a/src/sm3_lms.c +++ b/src/sm3_lms.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2024 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. @@ -7,84 +7,18 @@ * http://www.apache.org/licenses/LICENSE-2.0 */ -#include -#include -#include -#include -#include #include -#include #include #include -#include -#include #include +#include - -#define SM3_HSS_MAX_LEVELS 5 -#define SM3_LMS_MAX_HEIGHT 25 - -#define SM3_LMOTS_TYPE LMOTS_SHA256_N32_W8 - -# define HASH256_CTX SHA256_CTX -# define hash256_init sha256_init -# define hash256_update sha256_update -# define hash256_finish sha256_finish - -typedef uint8_t hash256_t[32]; - -enum { - LMOTS_RESERVED = 0, - LMOTS_SHA256_N32_W1 = 1, - LMOTS_SHA256_N32_W2 = 2, - LMOTS_SHA256_N32_W4 = 3, - LMOTS_SHA256_N32_W8 = 4, - LMOTS_SM3_N32_W1 = 11, - LMOTS_SM3_N32_W2 = 12, - LMOTS_SM3_N32_W4 = 13, - LMOTS_SM3_N32_W8 = 14, -}; - -char *sm3_lmots_type_name(int lmots_type) -{ - switch (lmots_type) { - case LMOTS_RESERVED: - return "LMOTS_RESERVED"; - case LMOTS_SHA256_N32_W1: - return "LMOTS_SHA256_N32_W1"; - case LMOTS_SHA256_N32_W2: - return "LMOTS_SHA256_N32_W2"; - case LMOTS_SHA256_N32_W4: - return "LMOTS_SHA256_N32_W4"; - case LMOTS_SHA256_N32_W8: - return "LMOTS_SHA256_N32_W8"; - case LMOTS_SM3_N32_W1: - return "LMOTS_SM3_N32_W1"; - case LMOTS_SM3_N32_W2: - return "LMOTS_SM3_N32_W2"; - case LMOTS_SM3_N32_W4: - return "LMOTS_SM3_N32_W4"; - case LMOTS_SM3_N32_W8: - return "LMOTS_SM3_N32_W8"; - } - return NULL; -} - -enum { - LMS_SM3_M32_H5 = 5, - LMS_SM3_M32_H10 = 6, - LMS_SM3_M32_H15 = 7, - LMS_SM3_M32_H20 = 8, - LMS_SM3_M32_H25 = 9, - /* - LMS_SHA256_M32_H5 = 5, - LMS_SHA256_M32_H10 = 6, - LMS_SHA256_M32_H15 = 7, - LMS_SHA256_M32_H20 = 8, - LMS_SHA256_M32_H25 = 9, - */ -}; - +/* + * TODO: + * 1. add key_update callback + * 2. only update q, and updated elments of hss key of files + * 3. consider append only mode of files + */ static const uint8_t D_PBLC[2] = { 0x80, 0x80 }; static const uint8_t D_MESG[2] = { 0x81, 0x81 }; @@ -92,42 +26,65 @@ static const uint8_t D_LEAF[2] = { 0x82, 0x82 }; static const uint8_t D_INTR[2] = { 0x83, 0x83 }; - -// TODO: SM3/SHA256 lms_types has same number! -char *sm3_lms_type_name(int lms_type) +char *sm3_lmots_type_name(int lmots_type) { - switch (lms_type) { - case LMS_SM3_M32_H5: - return "LMS_SM3_M32_H5"; - case LMS_SM3_M32_H10: - return "LMS_SM3_M32_H10"; - case LMS_SM3_M32_H15: - return "LMS_SM3_M32_H15"; - case LMS_SM3_M32_H20: - return "LMS_SM3_M32_H20"; - case LMS_SM3_M32_H25: - return "LMS_SM3_M32_H25"; + switch (lmots_type) { + case LMOTS_HASH256_N32_W8: + return LMOTS_HASH256_N32_W8_NAME; } return NULL; } -int sm3_lms_type_to_height(int type, int *h) +char *sm3_lms_type_name(int lms_type) +{ + switch (lms_type) { + case LMS_HASH256_M32_H5: + return LMS_HASH256_M32_H5_NAME; + case LMS_HASH256_M32_H10: + return LMS_HASH256_M32_H10_NAME; + case LMS_HASH256_M32_H15: + return LMS_HASH256_M32_H15_NAME; + case LMS_HASH256_M32_H20: + return LMS_HASH256_M32_H20_NAME; + case LMS_HASH256_M32_H25: + return LMS_HASH256_M32_H25_NAME; + } + return NULL; +} + +int sm3_lms_type_from_name(const char *name) +{ + if (!strcmp(name, LMS_HASH256_M32_H5_NAME)) { + return LMS_HASH256_M32_H5; + } else if (!strcmp(name, LMS_HASH256_M32_H10_NAME)) { + return LMS_HASH256_M32_H10; + } else if (!strcmp(name, LMS_HASH256_M32_H15_NAME)) { + return LMS_HASH256_M32_H15; + } else if (!strcmp(name, LMS_HASH256_M32_H20_NAME)) { + return LMS_HASH256_M32_H20; + } else if (!strcmp(name, LMS_HASH256_M32_H25_NAME)) { + return LMS_HASH256_M32_H25; + } + return 0; +} + +int sm3_lms_type_to_height(int type, size_t *height) { switch (type) { - case LMS_SM3_M32_H5: - *h = 5; + case LMS_HASH256_M32_H5: + *height = 5; break; - case LMS_SM3_M32_H10: - *h = 10; + case LMS_HASH256_M32_H10: + *height = 10; break; - case LMS_SM3_M32_H15: - *h = 15; + case LMS_HASH256_M32_H15: + *height = 15; break; - case LMS_SM3_M32_H20: - *h = 20; + case LMS_HASH256_M32_H20: + *height = 20; break; - case LMS_SM3_M32_H25: - *h = 25; + case LMS_HASH256_M32_H25: + *height = 25; break; default: error_print(); @@ -136,7 +93,6 @@ int sm3_lms_type_to_height(int type, int *h) return 1; } - void sm3_lmots_derive_secrets(const hash256_t seed, const uint8_t I[16], int q, hash256_t x[34]) { HASH256_CTX ctx; @@ -214,6 +170,7 @@ static void winternitz_checksum(const hash256_t dgst, uint8_t checksum[2]) PUTU16(checksum, sum); } +// signed digest Q = H(I || u32str(q) || u16str(D_MESG) || C || message) void sm3_lmots_compute_signature(const uint8_t I[16], int q, const hash256_t dgst, const hash256_t x[34], hash256_t y[34]) { HASH256_CTX ctx; @@ -291,34 +248,8 @@ void sm3_lmots_signature_to_public_hash(const uint8_t I[16], int q, const hash25 hash256_finish(&ctx, pub); } -static int test_sm3_lmots(void) -{ - hash256_t seed = {0}; // TODO: change to test vector - uint8_t I[16] = {0}; - int q = 0; - hash256_t dgst = {0}; - hash256_t x[34]; - hash256_t y[34]; - hash256_t pub; - hash256_t pub2; - - sm3_lmots_derive_secrets(seed, I, q, x); // TODO: compare results with test vector - sm3_lmots_secrets_to_public_hash(I, q, x, pub); // TODO: compare results with test vector - - sm3_lmots_compute_signature(I, q, dgst, x, y); // TODO: compare results with test vector - sm3_lmots_signature_to_public_hash(I, q, y, dgst, pub2); - - if (memcmp(pub, pub2, 32) != 0) { - error_print(); - return -1; - } - - printf("%s() ok\n", __FUNCTION__); - return 1; -} - // derive full merkle tree[2^h * 2 - 1] from seed, tree[0] is the root -void sm3_lms_derive_merkle_tree(const uint8_t seed[32], const uint8_t I[16], int h, hash256_t *tree) +void sm3_lms_derive_merkle_tree(const hash256_t seed, const uint8_t I[16], int h, hash256_t *tree) { int r, n = (1 << h); uint8_t rbytes[4]; @@ -407,60 +338,165 @@ void sm3_lms_derive_merkle_root(const hash256_t seed, const uint8_t I[16], int h memcpy(root, stack[0], 32); } -static int test_sm3_lms_derive_merkle_root(void) +int sm3_lms_public_key_to_bytes(const SM3_LMS_KEY *key, uint8_t **out, size_t *outlen) { - hash256_t seed = {0}; // TODO: change to test vector - uint8_t I[16] = {0}; - int h = 5; - int n = 1<public_key.lms_type); + *out += 4; + PUTU32(*out, key->public_key.lmots_type); + *out += 4; + memcpy(*out, key->public_key.I, 16); + *out += 16; + memcpy(*out, key->public_key.root, 32); + *out += 32; } - free(tree); - - printf("%s() ok\n", __FUNCTION__); + *outlen += SM3_LMS_PUBLIC_KEY_SIZE; return 1; } +int sm3_lms_private_key_to_bytes(const SM3_LMS_KEY *key, uint8_t **out, size_t *outlen) +{ + if (sm3_lms_public_key_to_bytes(key, out, outlen) != 1) { + error_print(); + return -1; + } + if (out && *out) { + memcpy(*out, key->seed, 32); + *out += 32; + PUTU32(*out, key->q); + *out += 4; + } + *outlen += 32 + 4; + return 1; +} -typedef struct { - uint8_t lms_type[4]; - uint8_t lmots_type[4]; - uint8_t I[16]; - hash256_t root; -} SM3_LMS_PUBLIC_KEY; +int sm3_lms_public_key_from_bytes(SM3_LMS_KEY *key, const uint8_t **in, size_t *inlen) +{ + if (!key || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (*inlen < SM3_LMS_PUBLIC_KEY_SIZE) { + error_print(); + return -1; + } + memset(key, 0, sizeof(*key)); -typedef struct { - SM3_LMS_PUBLIC_KEY public_key; - hash256_t *tree; - hash256_t seed; - int q; -} SM3_LMS_KEY; + key->public_key.lms_type = GETU32(*in); + if (!sm3_lms_type_name(key->public_key.lms_type)) { + error_print(); + return -1; + } + *in += 4; + *inlen -= 4; -#define SM3_LMS_PUBLIC_KEY_SIZE sizeof(SM3_LMS_PUBLIC_KEY) + key->public_key.lmots_type = GETU32(*in); + if (!sm3_lmots_type_name(key->public_key.lmots_type)) { + error_print(); + return -1; + } + *in += 4; + *inlen -= 4; + memcpy(key->public_key.I, *in, 16); + *in += 16; + *inlen -= 16; + memcpy(key->public_key.root, *in, 32); + *in += 32; + *inlen -= 32; + + return 1; +} + +int sm3_lms_key_check(const SM3_LMS_KEY *key, const SM3_LMS_PUBLIC_KEY *pub) +{ + // FIXME: implement this + return 1; +} + +int sm3_lms_key_remaining_signs(const SM3_LMS_KEY *key, size_t *count) +{ + size_t height; + size_t n; + + if (!key || !count) { + error_print(); + return -1; + } + if (sm3_lms_type_to_height(key->public_key.lms_type, &height) != 1) { + error_print(); + return -1; + } + n = 1 << height; + if (key->q > n) { + error_print(); + return -1; + } + *count = n - key->q; + return 1; +} + +int sm3_lms_private_key_from_bytes(SM3_LMS_KEY *key, const uint8_t **in, size_t *inlen) +{ + size_t height; + int cache_tree = 1; + + if (!key || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (*inlen < SM3_LMS_PRIVATE_KEY_SIZE) { + error_print(); + return -1; + } + + if (sm3_lms_public_key_from_bytes(key, in, inlen) != 1) { + error_print(); + return -1; + } + + memcpy(key->seed, *in, 32); + *in += 32; + *inlen -= 32; + + key->q = GETU32(*in); + *in += 4; + *inlen -= 4; + + if (sm3_lms_type_to_height(key->public_key.lms_type, &height) != 1) { + error_print(); + return -1; + } + if (key->q >= (1 << height)) { + error_print(); + return -1; + } + + if (cache_tree) { + size_t n = 1 << height; + if (!(key->tree = (hash256_t *)malloc(sizeof(hash256_t) * (2*n - 1)))) { + error_print(); + return -1; + } + sm3_lms_derive_merkle_tree(key->seed, key->public_key.I, height, key->tree); + memcpy(key->public_key.root, key->tree[0], 32); + } + + return 1; +} int sm3_lms_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SM3_LMS_PUBLIC_KEY *pub) { format_print(fp, fmt, ind, "%s\n", label); ind += 4; - format_print(fp, fmt, ind, "lms_type: %s\n", sm3_lms_type_name(GETU32(pub->lms_type))); - format_print(fp, fmt, ind, "lmots_type: %s\n", sm3_lmots_type_name(GETU32(pub->lmots_type))); + format_print(fp, fmt, ind, "lms_type: %s\n", sm3_lms_type_name(pub->lms_type)); + format_print(fp, fmt, ind, "lmots_type: %s\n", sm3_lmots_type_name(pub->lmots_type)); format_bytes(fp, fmt, ind, "I", pub->I, 16); format_bytes(fp, fmt, ind, "root", pub->root, 32); return 1; @@ -470,14 +506,13 @@ int sm3_lms_key_print(FILE *fp, int fmt, int ind, const char *label, const SM3_L { format_print(fp, fmt, ind, "%s\n", label); ind += 4; - sm3_lms_public_key_print(fp, fmt, ind, "PublicKey", &key->public_key); + sm3_lms_public_key_print(fp, fmt, ind, "lms_public_key", &key->public_key); format_bytes(fp, fmt, ind, "seed", key->seed, 32); format_print(fp, fmt, ind, "q = %d\n", key->q); if (key->tree && fmt) { int i; format_print(fp, fmt, ind, "tree\n"); for (i = 0; i < 63; i++) { - format_print(fp, fmt, ind + 4, "%d", i); format_bytes(fp, fmt, 0, "", key->tree[i], 32); } @@ -485,35 +520,6 @@ int sm3_lms_key_print(FILE *fp, int fmt, int ind, const char *label, const SM3_L return 1; } -int sm3_lms_public_key_from_bytes_ex(const SM3_LMS_PUBLIC_KEY **key, const uint8_t **in, size_t *inlen) -{ - int lms_type; - int lmots_type; - int h; - - if (*inlen < sizeof(SM3_LMS_PUBLIC_KEY)) { - error_print(); - return -1; - } - - lms_type = GETU32(*in); - if (sm3_lms_type_to_height(lms_type, &h) != 1) { - error_print(); - return -1; - } - - lmots_type = GETU32((*in) + 4); - if (lmots_type != SM3_LMOTS_TYPE) { - error_print(); - return -1; - } - - (*key) = (const SM3_LMS_PUBLIC_KEY *)(*in); - (*in) += SM3_LMS_PUBLIC_KEY_SIZE; - (*inlen) -= SM3_LMS_PUBLIC_KEY_SIZE; - return 1; -} - void sm3_lms_key_cleanup(SM3_LMS_KEY *key) { if (key) { @@ -526,9 +532,14 @@ void sm3_lms_key_cleanup(SM3_LMS_KEY *key) } } -int sm3_lms_key_generate_ex(SM3_LMS_KEY *key, int lms_type, const uint8_t seed[32], const uint8_t I[16], int cache_tree) +int sm3_lms_key_generate_ex(SM3_LMS_KEY *key, int lms_type, const hash256_t seed, const uint8_t I[16], int cache_tree) { - int h, n; + size_t h, n; + + if (!key || !seed || !I) { + error_print(); + return -1; + } if (sm3_lms_type_to_height(lms_type, &h) != 1) { error_print(); @@ -536,26 +547,11 @@ int sm3_lms_key_generate_ex(SM3_LMS_KEY *key, int lms_type, const uint8_t seed[3 } n = 1 << h; - PUTU32(key->public_key.lms_type, lms_type); - PUTU32(key->public_key.lmots_type, SM3_LMOTS_TYPE); + key->public_key.lms_type = lms_type; + key->public_key.lmots_type = LMOTS_HASH256_N32_W8; - if (I) { - memcpy(key->public_key.I, I, 16); - } else { - if (rand_bytes(key->public_key.I, 16) != 1) { - error_print(); - return -1; - } - } - - if (seed) { - memcpy(key->seed, seed, 32); - } else { - if (rand_bytes(key->seed, 32) != 1) { - error_print(); - return -1; - } - } + memcpy(key->public_key.I, I, 16); + memcpy(key->seed, seed, 32); if (cache_tree) { if (!(key->tree = (hash256_t *)malloc(sizeof(hash256_t) * (2*n - 1)))) { @@ -575,188 +571,259 @@ int sm3_lms_key_generate_ex(SM3_LMS_KEY *key, int lms_type, const uint8_t seed[3 int sm3_lms_key_generate(SM3_LMS_KEY *key, int lms_type) { - if (sm3_lms_key_generate_ex(key, lms_type, NULL, NULL, 1) != 1) { + hash256_t seed; + uint8_t I[16]; + int cache_tree = 1; + + if (rand_bytes(seed, sizeof(seed)) != 1) { + error_print(); + return -1; + } + if (rand_bytes(I, sizeof(I)) != 1) { + error_print(); + return -1; + } + if (sm3_lms_key_generate_ex(key, lms_type, seed, I, cache_tree) != 1) { error_print(); return -1; } return 1; } -static int test_sm3_lms_key_generate(void) +int sm3_lms_signature_size(int lms_type, size_t *len) { - SM3_LMS_KEY lms_key; - int lms_type = LMS_SM3_M32_H5; + size_t height; - if (sm3_lms_key_generate(&lms_key, lms_type) != 1) { + if (!len) { error_print(); return -1; } - //sm3_lms_key_print(stdout, 0, 0, "lms_key", &lms_key); - - printf("%s() ok\n", __FUNCTION__); + if (sm3_lms_type_to_height(lms_type, &height) != 1) { + error_print(); + return -1; + } + *len = sizeof(uint32_t) // q + + sizeof(uint32_t) // lmots_type + + sizeof(hash256_t) // C + + sizeof(hash256_t) * 34 // y[34] + + sizeof(uint32_t) // lms_type + + sizeof(hash256_t) * height; // path[hegith] return 1; } -// lmots_signature = u32str(type) || C || y[0] || ... || y[p-1] - -// lms_signature = u32str(q) || lmots_signature || u32str(type) || -// path[0] || path[1] || path[2] || ... || path[h-1] - -typedef struct { - uint8_t lms_type[4]; // FIXME: move lms_type before path - uint8_t q[4]; - struct { - uint8_t lmots_type[4]; - hash256_t y[34]; - hash256_t C; - } lmots_sig; - hash256_t path[25]; -} SM3_LMS_SIGNATURE; - - -static size_t sm3_lms_signature_size(int tree_height) +int sm3_lms_key_get_signature_size(const SM3_LMS_KEY *key, size_t *siglen) { - return 4 * 3 + 32*34 + 32 + 32*tree_height; + if (!key || !siglen) { + error_print(); + return -1; + } + if (sm3_lms_signature_size(key->public_key.lms_type, siglen) != 1) { + error_print(); + return -1; + } + return 1; } - -int sm3_lms_signature_print(FILE *fp, int fmt, int ind, const char *label, const SM3_LMS_SIGNATURE *sig) +int sm3_lms_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const SM3_LMS_SIGNATURE *sig) { - int lms_type; - int h; - int i; + size_t h; + size_t i; - lms_type = GETU32(sig->lms_type); - if (sm3_lms_type_to_height(lms_type, &h) != 1) { + if (sm3_lms_type_to_height(sig->lms_type, &h) != 1) { error_print(); return -1; } format_print(fp, fmt, ind, "%s\n", label); ind += 4; - format_print(fp, fmt, ind, "lms_type: %s\n", sm3_lms_type_name(GETU32(sig->lms_type))); - format_print(fp, fmt, ind, "q: %d\n", GETU32(sig->q)); - format_print(fp, fmt, ind, "lmots_type: %s\n", sm3_lmots_type_name(GETU32(sig->lmots_sig.lmots_type))); + format_print(fp, fmt, ind, "q: %d\n", sig->q); + format_print(fp, fmt, ind, "lmots_type: %s\n", sm3_lmots_type_name(sig->lmots_sig.lmots_type)); + format_bytes(fp, fmt, ind, "lmots_sig.C", sig->lmots_sig.C, 32); format_print(fp, fmt, ind, "lmots_sig.y\n"); for (i = 0; i < 34; i++) { - format_print(fp, fmt, ind + 4, "%d", i); + format_print(fp, fmt, ind + 4, "zu", i); format_bytes(fp, fmt, 0, "", sig->lmots_sig.y[i], 32); } - format_bytes(fp, fmt, ind, "lmots_sig.C", sig->lmots_sig.C, 32); + format_print(fp, fmt, ind, "lms_type: %s\n", sm3_lms_type_name(sig->lms_type)); format_print(fp, fmt, ind, "path\n"); for (i = 0; i < h; i++) { - format_bytes(fp, fmt, ind + 4, "", sig->path[i], 32); + format_print(fp, fmt, ind + 4, "%zu", i); + format_bytes(fp, fmt, 0, "", sig->path[i], 32); } return 1; } -int sm3_lms_signature_to_bytes(const SM3_LMS_SIGNATURE *sig, uint8_t *out, size_t *outlen) +int sm3_lms_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen) { - int h; - if (sm3_lms_type_to_height(GETU32(sig->lms_type), &h) != 1) { + uint32_t q, lmots_type, lms_type; + size_t height, i; + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + + if (siglen < 4) { error_print(); return -1; } - *outlen = sm3_lms_signature_size(h); - memcpy(out, sig, *outlen); - return 1; -} + q = GETU32(sig); + format_print(fp, fmt, ind, "q: %zu\n", q); + sig += 4; + siglen -= 4; -int sm3_lms_signature_from_bytes_ex(const SM3_LMS_SIGNATURE **sig, size_t *siglen, const uint8_t **in, size_t *inlen) -{ - int lms_type; - int h; - - if (*inlen < 4) { + if (siglen < 4) { error_print(); return -1; } + lmots_type = GETU32(sig); + sig += 4; + siglen -= 4; + format_print(fp, fmt, ind, "lmots_type: %s\n", sm3_lmots_type_name(lmots_type)); - lms_type = GETU32(*in); - if (sm3_lms_type_to_height(lms_type, &h) != 1) { + if (siglen < 32) { error_print(); return -1; } + format_bytes(fp, fmt, ind, "lmots_sig.C", sig, 32); + sig += 32; + siglen -= 32; - *sig = (const SM3_LMS_SIGNATURE *)(*in); - *siglen = sm3_lms_signature_size(h); - - if (*inlen < *siglen) { - error_print(); - return -1; - } - - (*in) += *siglen; - (*inlen) -= *siglen; - return 1; -} - -int sm3_lms_signature_from_bytes(SM3_LMS_SIGNATURE *sig, const uint8_t *in, size_t inlen) -{ - const SM3_LMS_SIGNATURE *ptr; - size_t siglen; - - if (sm3_lms_signature_from_bytes_ex(&ptr, &siglen, &in, &inlen) != 1) { - error_print(); - return -1; - } - if (inlen) { - error_print(); - return -1; - } - *sig = *ptr; - return 1; -} - -int sm3_lms_do_sign(SM3_LMS_KEY *key, const hash256_t C, const hash256_t dgst, SM3_LMS_SIGNATURE *sig) -{ - int lms_type; - int h, n, r; - const hash256_t *T; - int i; - - lms_type = GETU32(key->public_key.lms_type); - if (sm3_lms_type_to_height(lms_type, &h) != 1) { - error_print(); - return -1; - } - n = 1 << h; - r = n + key->q; - - if (!key->tree) { - if (!(key->tree = (hash256_t *)malloc(sizeof(hash256_t) * (2*n - 1)))) { + format_print(fp, fmt, ind, "lmots_sig.y\n"); + for (i = 0; i < 34; i++) { + if (siglen < 32) { error_print(); return -1; } - sm3_lms_derive_merkle_tree(key->seed, key->public_key.I, h, key->tree); + format_print(fp, fmt, ind + 4, "%zu", i); + format_bytes(fp, fmt, 0, "", sig, 32); + sig += 32; + siglen -= 32; } - T = key->tree - 1; - PUTU32(sig->lms_type, lms_type); - PUTU32(sig->q, key->q); - PUTU32(sig->lmots_sig.lmots_type, SM3_LMOTS_TYPE); - - sm3_lmots_derive_secrets(key->seed, key->public_key.I, key->q, sig->lmots_sig.y); - sm3_lmots_compute_signature(key->public_key.I, key->q, dgst, sig->lmots_sig.y, sig->lmots_sig.y); - (key->q)++; - - memcpy(sig->lmots_sig.C, C, 32); - - for (i = 0; i < h; i++) { - memcpy(sig->path[i], T[r ^ 0x1], 32); - r /= 2; + if (siglen < 4) { + error_print(); + return -1; } + lms_type = GETU32(sig); + format_print(fp, fmt, ind, "lms_type: %s\n", sm3_lms_type_name(lms_type)); + if (sm3_lms_type_to_height(lms_type, &height) != 1) { + error_print(); + return -1; + } + sig += 4; + siglen -= 4; + + format_print(fp, fmt, ind, "path\n"); + + for (i = 0; i < height; i++) { + if (siglen < 32) { + error_print(); + return -1; + } + format_print(fp, fmt, ind + 4, "%zu", i); + format_bytes(fp, fmt, 0, "", sig, 32); + sig += 32; + siglen -= 32; + } + return 1; } -int sm3_lms_signature_to_merkle_root(const uint8_t I[16], int h, int q, +int sm3_lms_signature_to_bytes(const SM3_LMS_SIGNATURE *sig, uint8_t **out, size_t *outlen) +{ + size_t height; + + if (!sig || !outlen) { + error_print(); + return -1; + } + if (sm3_lms_type_to_height(sig->lms_type, &height) != 1) { + error_print(); + return -1; + } + if (out && *out) { + PUTU32(*out, sig->q); + *out += 4; + PUTU32(*out, sig->lmots_sig.lmots_type); + *out += 4; + memcpy(*out, sig->lmots_sig.C, 32); + *out += 32; + memcpy(*out, sig->lmots_sig.y, 32*34); + *out += 32*34; + PUTU32(*out, sig->lms_type); + *out += 4; + memcpy(*out, sig->path, 32*height); + *out += 32*height; + } + *outlen += 4 + 4 + 32 + 32*34 + 4 + 32*height; + return 1; +} + +int sm3_lms_signature_from_bytes(SM3_LMS_SIGNATURE *sig, const uint8_t **in, size_t *inlen) +{ + size_t height; + + if (!sig || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + + if (*inlen < SM3_LMS_SIGNATURE_MIN_SIZE) { + error_print(); + return -1; + } + memset(sig, 0, sizeof(*sig)); + + sig->q = GETU32(*in); + *in += 4; + *inlen -= 4; + + sig->lmots_sig.lmots_type = GETU32(*in); + if (!sm3_lmots_type_name(sig->lmots_sig.lmots_type)) { + error_print(); + return -1; + } + *in += 4; + *inlen -= 4; + + memcpy(sig->lmots_sig.C, *in, 32); + *in += 32; + *inlen -= 32; + + memcpy(sig->lmots_sig.y, *in, 32*34); + *in += 32*34; + *inlen -= 32*34; + + sig->lms_type = GETU32(*in); + if (sm3_lms_type_to_height(sig->lms_type, &height) != 1) { + error_print(); + return -1; + } + if (sig->q < 0 || sig->q >= (1 << height)) { + error_print(); + return -1; + } + *in += 4; + *inlen -= 4; + + if (*inlen < 32*height) { + error_print(); + return -1; + } + memcpy(sig->path, *in, 32*height); + *in += 32*height; + *inlen -= 32*height; + + return 1; +} + +int sm3_lms_signature_to_merkle_root(const uint8_t I[16], size_t h, int q, const hash256_t y[34], const hash256_t *path, const hash256_t dgst, hash256_t root) { - int n, r; + size_t n, r; uint8_t rbytes[4]; HASH256_CTX ctx; - int i; + size_t i; n = 1 << h; if (q >= n) { @@ -797,104 +864,186 @@ int sm3_lms_signature_to_merkle_root(const uint8_t I[16], int h, int q, return 1; } -int sm3_lms_do_verify(const SM3_LMS_PUBLIC_KEY *pub, const uint8_t dgst[32], const SM3_LMS_SIGNATURE *sig) +void sm3_lms_sign_ctx_cleanup(SM3_LMS_SIGN_CTX *ctx) { - int lms_type; - int lmots_type; - int h, n, q; - hash256_t root; - - lms_type = GETU32(sig->lms_type); - if (sm3_lms_type_to_height(lms_type, &h) != 1) { - error_print(); - return -1; - } - n = 1 << h; - - if (lms_type != GETU32(pub->lms_type)) { - error_print(); - return -1; - } - - q = GETU32(sig->q); - if (q >= n) { - error_print(); - return -1; - } - - if (sm3_lms_signature_to_merkle_root(pub->I, h, q, sig->lmots_sig.y, sig->path, dgst, root) != 1) { - error_print(); - return -1; - } - - if (memcmp(root, pub->root, 32) == 0) { - return 1; - } else { - error_print(); - return 0; + if (ctx) { + gmssl_secure_clear(ctx->lms_sig.lmots_sig.y, sizeof(hash256_t)*34); } } -static int test_sm3_lms_do_sign(void) +int sm3_lms_sign_init(SM3_LMS_SIGN_CTX *ctx, SM3_LMS_KEY *key) { - int lms_type = LMS_SM3_M32_H5; - SM3_LMS_KEY key; - hash256_t C = {0}; - hash256_t dgst; - SM3_LMS_SIGNATURE sig; + SM3_LMS_SIGNATURE *lms_sig; + uint8_t qbytes[4]; + const hash256_t *T; + size_t height, r, i; - if (sm3_lms_key_generate(&key, lms_type) != 1) { + if (!ctx || !key) { error_print(); return -1; } - if (rand_bytes(dgst, 32) != 1) { + // check key state + if (sm3_lms_type_to_height(key->public_key.lms_type, &height) != 1) { + error_print(); + return -1; + } + if (key->q >= (1 << height)) { + error_print(); + return -1; + } + r = (1 << height) + key->q; + + memset(ctx, 0, sizeof(*ctx)); + memcpy(ctx->lms_public_key.I, key->public_key.I, 16); + + lms_sig = &ctx->lms_sig; + lms_sig->q = key->q; + PUTU32(qbytes, key->q); + + lms_sig->lmots_sig.lmots_type = key->public_key.lmots_type; + + if (rand_bytes(lms_sig->lmots_sig.C, 32) != 1) { error_print(); return -1; } - if (sm3_lms_do_sign(&key, C, dgst, &sig) != 1) { + // cache lmots private in lmots_sig.y, overwitten by sign_finish + sm3_lmots_derive_secrets(key->seed, key->public_key.I, key->q, lms_sig->lmots_sig.y); + + // update key state, SHOULD not use the updated key->q + (key->q)++; + + lms_sig->lms_type = key->public_key.lms_type; + + + // FIXME: re-generate tree? + if (!key->tree) { error_print(); return -1; } - - if (sm3_lms_do_verify(&key.public_key, dgst, &sig) != 1) { - error_print(); - return -1; + T = key->tree - 1; + for (i = 0; i < height; i++) { + memcpy(lms_sig->path[i], T[r ^ 0x1], 32); + r /= 2; } - printf("%s() ok\n", __FUNCTION__); + hash256_init(&ctx->hash256_ctx); + hash256_update(&ctx->hash256_ctx, key->public_key.I, 16); + hash256_update(&ctx->hash256_ctx, qbytes, 4); + hash256_update(&ctx->hash256_ctx, D_MESG, 2); + hash256_update(&ctx->hash256_ctx, lms_sig->lmots_sig.C, 32); + return 1; } - -void sm3_lms_digest(const SM3_LMS_PUBLIC_KEY *pub, int q, const hash256_t C, const uint8_t *data, size_t datalen, hash256_t dgst) +int sm3_lms_sign_update(SM3_LMS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) { - HASH256_CTX ctx; - uint8_t qbytes[4]; - - PUTU32(qbytes, q); - - hash256_init(&ctx); - hash256_update(&ctx, pub->I, 16); - hash256_update(&ctx, qbytes, 4); - hash256_update(&ctx, D_MESG, 2); - hash256_update(&ctx, C, 32); - hash256_update(&ctx, data, datalen); - hash256_finish(&ctx, dgst); + if (!ctx) { + error_print(); + return -1; + } + if (data && datalen > 0) { + hash256_update(&ctx->hash256_ctx, data, datalen); + } + return 1; } -int sm3_lms_verify_data(const SM3_LMS_PUBLIC_KEY *pub, const uint8_t *data, size_t datalen, const uint8_t *sigbuf, size_t siglen) +int sm3_lms_sign_finish_ex(SM3_LMS_SIGN_CTX *ctx, SM3_LMS_SIGNATURE *sig) { - const SM3_LMS_SIGNATURE *sig; - size_t len; - HASH256_CTX ctx; - hash256_t dgst; - hash256_t Kc; - int ret; + SM3_LMS_SIGNATURE *lms_sig; + uint8_t dgst[32]; + if (!ctx || !sig) { + error_print(); + return -1; + } - if (sm3_lms_signature_from_bytes_ex(&sig, &len, &sigbuf, &siglen) != 1) { + hash256_finish(&ctx->hash256_ctx, dgst); + + lms_sig = &ctx->lms_sig; + sm3_lmots_compute_signature(ctx->lms_public_key.I, lms_sig->q, dgst, lms_sig->lmots_sig.y, lms_sig->lmots_sig.y); + + *sig = *lms_sig; + return 1; +} + +int sm3_lms_sign_finish(SM3_LMS_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen) +{ + SM3_LMS_SIGNATURE *lms_sig; + uint8_t dgst[32]; + + if (!ctx || !sig || !siglen) { + error_print(); + return -1; + } + + hash256_finish(&ctx->hash256_ctx, dgst); + + lms_sig = &ctx->lms_sig; + sm3_lmots_compute_signature(ctx->lms_public_key.I, lms_sig->q, dgst, lms_sig->lmots_sig.y, lms_sig->lmots_sig.y); + + *siglen = 0; + if (sm3_lms_signature_to_bytes(lms_sig, &sig, siglen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm3_lms_verify_init_ex(SM3_LMS_SIGN_CTX *ctx, const SM3_LMS_KEY *key, const SM3_LMS_SIGNATURE *sig) +{ + SM3_LMS_SIGNATURE *lms_sig; + uint8_t qbytes[4]; + + if (!ctx || !key || !sig) { + error_print(); + return -1; + } + + memset(ctx, 0, sizeof(*ctx)); + + ctx->lms_public_key = key->public_key; + + ctx->lms_sig = *sig; + lms_sig = &ctx->lms_sig; + + if (lms_sig->lmots_sig.lmots_type != key->public_key.lmots_type) { + error_print(); + return -1; + } + if (lms_sig->lms_type != key->public_key.lms_type) { + error_print(); + return -1; + } + + PUTU32(qbytes, lms_sig->q); + + hash256_init(&ctx->hash256_ctx); + hash256_update(&ctx->hash256_ctx, key->public_key.I, 16); + hash256_update(&ctx->hash256_ctx, qbytes, 4); + hash256_update(&ctx->hash256_ctx, D_MESG, 2); + hash256_update(&ctx->hash256_ctx, lms_sig->lmots_sig.C, 32); + + return 1; +} + +int sm3_lms_verify_init(SM3_LMS_SIGN_CTX *ctx, const SM3_LMS_KEY *key, const uint8_t *sig, size_t siglen) +{ + SM3_LMS_SIGNATURE *lms_sig; + uint8_t qbytes[4]; + + if (!ctx || !key || !sig || !siglen) { + error_print(); + return -1; + } + + memset(ctx, 0, sizeof(*ctx)); + + ctx->lms_public_key = key->public_key; + + lms_sig = &ctx->lms_sig; + if (sm3_lms_signature_from_bytes(lms_sig, &sig, &siglen) != 1) { error_print(); return -1; } @@ -903,28 +1052,228 @@ int sm3_lms_verify_data(const SM3_LMS_PUBLIC_KEY *pub, const uint8_t *data, size return -1; } - ret = sm3_lms_do_verify(pub, dgst, sig); + if (lms_sig->lmots_sig.lmots_type != key->public_key.lmots_type) { + error_print(); + return -1; + } + if (lms_sig->lms_type != key->public_key.lms_type) { + error_print(); + return -1; + } - return ret; + PUTU32(qbytes, lms_sig->q); + + hash256_init(&ctx->hash256_ctx); + hash256_update(&ctx->hash256_ctx, key->public_key.I, 16); + hash256_update(&ctx->hash256_ctx, qbytes, 4); + hash256_update(&ctx->hash256_ctx, D_MESG, 2); + hash256_update(&ctx->hash256_ctx, lms_sig->lmots_sig.C, 32); + + return 1; } -typedef struct { - int levels; - SM3_LMS_PUBLIC_KEY lms_pub; -} SM3_HSS_PUBLIC_KEY; +int sm3_lms_verify_update(SM3_LMS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) +{ + if (!ctx) { + error_print(); + return -1; + } + if (data && datalen > 0) { + hash256_update(&ctx->hash256_ctx, data, datalen); + } + return 1; +} -typedef struct { - SM3_HSS_PUBLIC_KEY public_key; - SM3_LMS_KEY lms_key[5]; - SM3_LMS_SIGNATURE lms_sig[4]; -} SM3_HSS_KEY; +int sm3_lms_verify_finish(SM3_LMS_SIGN_CTX *ctx) +{ + SM3_LMS_SIGNATURE *lms_sig; + hash256_t dgst; + size_t height; + hash256_t root; -int sm3_hss_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SM3_HSS_PUBLIC_KEY *pub) + if (!ctx) { + error_print(); + return -1; + } + + lms_sig = &ctx->lms_sig; + if (sm3_lms_type_to_height(lms_sig->lms_type, &height) != 1) { + error_print(); + return -1; + } + + hash256_finish(&ctx->hash256_ctx, dgst); + + if (sm3_lms_signature_to_merkle_root(ctx->lms_public_key.I, height, + lms_sig->q, lms_sig->lmots_sig.y, lms_sig->path, dgst, root) != 1) { + error_print(); + return -1; + } + + if (memcmp(root, ctx->lms_public_key.root, 32) == 0) { + return 1; + } else { + error_print(); + return 0; + } +} + +int sm3_hss_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SM3_HSS_KEY *key) { format_print(fp, fmt, ind, "%s\n", label); ind += 4; - format_print(fp, fmt, ind, "levels: %d\n", pub->levels); - sm3_lms_public_key_print(fp, fmt, ind, "lms_pub", &pub->lms_pub); + format_print(fp, fmt, ind, "levels: %d\n", key->levels); + sm3_lms_public_key_print(fp, fmt, ind, "lms_public_key", &key->lms_key[0].public_key); + return 1; +} + +int sm3_hss_public_key_to_bytes(const SM3_HSS_KEY *key, uint8_t **out, size_t *outlen) +{ + if (!key || !outlen) { + error_print(); + return -1; + } + if (out && *out) { + PUTU32(*out, key->levels); + *out += 4; + PUTU32(*out, key->lms_key[0].public_key.lms_type); + *out += 4; + PUTU32(*out, key->lms_key[0].public_key.lmots_type); + *out += 4; + memcpy(*out, key->lms_key[0].public_key.I, 16); + *out += 16; + memcpy(*out, key->lms_key[0].public_key.root, 32); + *out += 32; + } + *outlen += SM3_HSS_PUBLIC_KEY_SIZE; + return 1; +} + +int sm3_hss_public_key_from_bytes(SM3_HSS_KEY *key, const uint8_t **in, size_t *inlen) +{ + if (!key || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (*inlen < SM3_HSS_PUBLIC_KEY_SIZE) { + error_print(); + return -1; + } + + memset(key, 0, sizeof(*key)); + + key->levels = GETU32(*in); + if (key->levels > SM3_HSS_MAX_LEVELS) { + error_print(); + return -1; + } + *in += 4; + *inlen -= 4; + + if (sm3_lms_public_key_from_bytes(&key->lms_key[0], in, inlen) != 1) { + error_print(); + return -1; + } + + return 1; +} + +int sm3_hss_private_key_to_bytes(const SM3_HSS_KEY *key, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + if (!key || !out) { + error_print(); + return -1; + } + if (key->levels < 1 || key->levels > SM3_HSS_MAX_LEVELS) { + error_print(); + return -1; + } + + if (out && *out) { + uint32_t i; + + PUTU32(*out, key->levels); + *out += 4; + len += 4; + + if (sm3_lms_private_key_to_bytes(&key->lms_key[0], out, &len) != 1) { + error_print(); + return -1; + } + + for (i = 1; i < key->levels; i++) { + if (sm3_lms_private_key_to_bytes(&key->lms_key[i], out, &len) != 1) { + error_print(); + return -1; + } + if (sm3_lms_signature_to_bytes(&key->lms_sig[i - 1], out, &len) != 1) { + error_print(); + return -1; + } + } + } + + *outlen += len; + return 1; +} + +int sm3_hss_private_key_from_bytes(SM3_HSS_KEY *key, const uint8_t **in, size_t *inlen) +{ + size_t i; + + if (!key || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + + if (*inlen < 4) { + error_print(); + return -1; + } + + key->levels = GETU32(*in); + if (key->levels < 1 || key->levels > SM3_HSS_MAX_LEVELS) { + error_print(); + return -1; + } + *in += 4; + *inlen -= 4; + + if (sm3_lms_private_key_from_bytes(&key->lms_key[0], in, inlen) != 1) { + error_print(); + return -1; + } + + for (i = 1; i < key->levels; i++) { + SM3_LMS_SIGN_CTX ctx; + uint8_t buf[SM3_LMS_PUBLIC_KEY_SIZE]; + uint8_t *p = buf; + size_t len = 0; + + if (sm3_lms_private_key_from_bytes(&key->lms_key[i], in, inlen) != 1) { + error_print(); + return -1; + } + if (sm3_lms_signature_from_bytes(&key->lms_sig[i - 1], in, inlen) != 1) { + error_print(); + return -1; + } + + // verify public_key[i] by key[i - 1] + if (sm3_lms_public_key_to_bytes(&key->lms_key[i], &p, &len) != 1) { + error_print(); + return -1; + } + if (sm3_lms_verify_init_ex(&ctx, &key->lms_key[i - 1], &key->lms_sig[i - 1]) != 1 + || sm3_lms_verify_update(&ctx, buf, len) != 1 + || sm3_lms_verify_finish(&ctx) != 1) { + error_print(); + return -1; + } + } + return 1; } @@ -934,13 +1283,16 @@ int sm3_hss_key_print(FILE *fp, int fmt, int ind, const char *label, const SM3_H format_print(fp, fmt, ind, "%s\n", label); ind += 4; - format_print(fp, fmt, ind, "levels: %d\n", key->public_key.levels); + format_print(fp, fmt, ind, "levels: %d\n", key->levels); - sm3_lms_key_print(fp, fmt, ind, "lms_key", &key->lms_key[0]); + sm3_lms_key_print(fp, fmt, ind, "lms_key[0]", &key->lms_key[0]); - for (i = 1; i < key->public_key.levels; i++) { - sm3_lms_signature_print(fp, fmt, ind, "lms_signature", &key->lms_sig[i - 1]); - sm3_lms_key_print(fp, fmt, ind, "lms_key", &key->lms_key[i]); + for (i = 1; i < key->levels; i++) { + char title[64]; + snprintf(title, sizeof(title), "lms_signature[%d]", i - 1); + sm3_lms_signature_print_ex(fp, fmt, ind, title, &key->lms_sig[i - 1]); + snprintf(title, sizeof(title), "lms_key[%d]", i); + sm3_lms_key_print(fp, fmt, ind, title, &key->lms_key[i]); } return 1; @@ -950,230 +1302,498 @@ void sm3_hss_key_cleanup(SM3_HSS_KEY *key) { if (key) { int i; - for (i = 0; i < key->public_key.levels; i++) { + for (i = 0; i < key->levels; i++) { sm3_lms_key_cleanup(&key->lms_key[i]); } memset(key, 0, sizeof(SM3_HSS_KEY)); } } -int sm3_hss_key_generate(SM3_HSS_KEY *key, int levels, int *lms_types) +int sm3_hss_key_generate(SM3_HSS_KEY *key, const int *lms_types, size_t levels) { int ret = -1; - uint8_t seed[32]; + hash256_t seed; + uint8_t I[16]; + SM3_LMS_SIGN_CTX ctx; + uint8_t buf[SM3_LMS_SIGNATURE_MAX_SIZE]; // SM3_LMS_SIGNATURE_MAX_SIZE > SM3_PUBLIC_KEY_SIZE + int cache_tree = 1; const int q = 0; - int i; + size_t i; - //printf("sm3_hss_key_generate\n"); - - if (levels <= 0 || levels > SM3_HSS_MAX_LEVELS) { + if (!key || !lms_types) { error_print(); return -1; } - if (rand_bytes(seed, 32) != 1) { + if (levels > SM3_HSS_MAX_LEVELS) { error_print(); return -1; } + for (i = 0; i < levels; i++) { + if (!sm3_lms_type_name(lms_types[i])) { + error_print(); + return -1; + } + } - memset(key, 0, sizeof(SM3_HSS_KEY)); - if (sm3_lms_key_generate_ex(&key->lms_key[0], lms_types[0], seed, NULL, cache_tree) != 1) { + memset(key, 0, sizeof(*key)); + + key->levels = (uint32_t)levels; + + // level-0 lms key + if (rand_bytes(seed, sizeof(seed)) != 1) { + error_print(); + goto end; + } + if (rand_bytes(I, sizeof(I)) != 1) { + error_print(); + goto end; + } + if (sm3_lms_key_generate_ex(&key->lms_key[0], lms_types[0], seed, I, cache_tree) != 1) { error_print(); goto end; } - key->public_key.levels = levels; - key->public_key.lms_pub = key->lms_key[0].public_key; - for (i = 1; i < levels; i++) { - hash256_t C; - hash256_t dgst; + uint8_t *p = buf; + size_t len = 0; - if (sm3_lms_key_generate_ex(&key->lms_key[i], lms_types[i], seed, NULL, cache_tree) != 1) { + if (rand_bytes(seed, sizeof(seed)) != 1) { error_print(); goto end; } - if (rand_bytes(C, 32) != 1) { + if (rand_bytes(I, sizeof(I)) != 1) { + error_print(); + goto end; + } + if (sm3_lms_key_generate_ex(&key->lms_key[i], lms_types[i], seed, I, cache_tree) != 1) { error_print(); goto end; } - sm3_lms_digest(&key->lms_key[i - 1].public_key, q, C, - (uint8_t *)&key->lms_key[i].public_key, SM3_LMS_PUBLIC_KEY_SIZE, dgst); - - if (sm3_lms_do_sign(&key->lms_key[i - 1], C, dgst, &key->lms_sig[i - 1]) != 1) { + // sign public_key[i] by key[i - 1] + if (sm3_lms_public_key_to_bytes(&key->lms_key[i], &p, &len) != 1) { error_print(); goto end; } + if (sm3_lms_sign_init(&ctx, &key->lms_key[i - 1]) != 1 + || sm3_lms_sign_update(&ctx, buf, len) != 1 + || sm3_lms_sign_finish(&ctx, buf, &len) != 1) { + error_print(); + goto end; + } + // save SM3_LMS_SIGNATURE struct + key->lms_sig[i - 1] = ctx.lms_sig; } ret = 1; end: gmssl_secure_clear(seed, sizeof(seed)); + sm3_lms_sign_ctx_cleanup(&ctx); if (ret != 1) sm3_hss_key_cleanup(key); return ret; } -static int test_sm3_hss_key_generate(void) +int sm3_hss_signature_size(const int *lms_types, size_t levels, size_t *siglen) { - int lms_types[] = { - LMS_SM3_M32_H5, - LMS_SM3_M32_H5, - LMS_SM3_M32_H5, - LMS_SM3_M32_H5, - }; - SM3_HSS_KEY key; + size_t i; - if (sm3_hss_key_generate(&key, sizeof(lms_types)/sizeof(lms_types[0]), lms_types) != 1) { + if (!lms_types || !siglen) { + error_print(); + return -1; + } + if (levels < 1 || levels > SM3_HSS_MAX_LEVELS) { error_print(); return -1; } - printf("%s() ok\n", __FUNCTION__); - return 1; -} - - -int sm3_hss_sign(SM3_HSS_KEY *key, const hash256_t C, const hash256_t dgst, uint8_t *sig, size_t *siglen) -{ - int num; - int i; - uint8_t *out = sig; - size_t len; - SM3_LMS_SIGNATURE msg_sig; - - num = key->public_key.levels - 1; - PUTU32(out, num); - out += 4; - - for (i = 0; i < num; i++) { - sm3_lms_signature_to_bytes(&(key->lms_sig[i]), out, &len); - out += len; - memcpy(out, (const uint8_t *)&(key->lms_key[i + 1].public_key), SM3_LMS_PUBLIC_KEY_SIZE); - out += SM3_LMS_PUBLIC_KEY_SIZE; + *siglen = 4; + for (i = 0; i < levels - 1; i++) { + size_t lms_siglen; + if (sm3_lms_signature_size(lms_types[i], &lms_siglen) != 1) { + error_print(); + return -1; + } + *siglen += lms_siglen; } - - if (sm3_lms_do_sign(&key->lms_key[i], C, dgst, &msg_sig) != 1) { - error_print(); - return -1; - } - sm3_lms_signature_to_bytes(&msg_sig, out, &len); - - out += len; - *siglen = out - sig; + *siglen += SM3_LMS_PUBLIC_KEY_SIZE * (levels - 1); return 1; } -int sm3_hss_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen) +int sm3_hss_key_get_signature_size(const SM3_HSS_KEY *key, size_t *siglen) { - const SM3_LMS_SIGNATURE *lms_sig; - size_t lms_siglen; - const SM3_LMS_PUBLIC_KEY *lms_pub; - - int num; + int lms_types[5]; int i; - format_print(fp, fmt, ind, "%s\n", label); - ind += 4; - - - if (siglen < 4) { + if (!key || !siglen) { error_print(); return -1; } - num = GETU32(sig); - sig += 4; - siglen -= 4; - - format_print(fp, fmt, ind, "num: %d\n", num); - - for (i = 0; i < num; i++) { - - if (sm3_lms_signature_from_bytes_ex(&lms_sig, &lms_siglen, &sig, &siglen) != 1) { - error_print(); - return -1; - } - sm3_lms_signature_print(fp, fmt, ind, "lms_sig(pub)", lms_sig); - - if (sm3_lms_public_key_from_bytes_ex(&lms_pub, &sig, &siglen) != 1) { - error_print(); - return -1; - } - sm3_lms_public_key_print(fp, fmt, ind, "lms_pub", lms_pub); + for (i = 0; i < key->levels; i++) { + lms_types[i] = key->lms_key[i].public_key.lms_type; } - - if (sm3_lms_signature_from_bytes_ex(&lms_sig, &lms_siglen, &sig, &siglen) != 1) { + if (sm3_hss_signature_size(lms_types, key->levels, siglen) != 1) { error_print(); return -1; } - sm3_lms_signature_print(fp, fmt, ind, "lms_sig(msg)", lms_sig); return 1; } -int sm3_hss_verify(const SM3_HSS_PUBLIC_KEY *pub, const hash256_t dgst, const uint8_t *sig, size_t siglen) +int sm3_hss_signature_from_bytes(SM3_HSS_SIGNATURE *sig, const uint8_t **in, size_t *inlen) { - int num, i; - const SM3_LMS_PUBLIC_KEY *lms_pub; - const SM3_LMS_PUBLIC_KEY *next_lms_pub; - const SM3_LMS_SIGNATURE *lms_sig; - size_t lms_siglen; + size_t i; - if (siglen < 4) { + if (!sig || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if (*inlen < 4) { error_print(); return -1; } - num = GETU32(sig); - sig += 4; - siglen -= 4; + sig->num_signed_public_keys = GETU32(*in); + if (sig->num_signed_public_keys >= SM3_HSS_MAX_LEVELS) { + error_print(); + return -1; + } + *in += 4; + *inlen -= 4; - if (num != pub->levels - 1) { + for (i = 0; i < sig->num_signed_public_keys; i++) { + SM3_LMS_SIGNATURE *lms_sig = &sig->signed_public_keys[i].lms_sig; + SM3_LMS_KEY *lms_key = (SM3_LMS_KEY *)&sig->signed_public_keys[i].lms_public_key; + + if (sm3_lms_signature_from_bytes(lms_sig, in, inlen) != 1) { + error_print(); + return -1; + } + if (sm3_lms_public_key_from_bytes(lms_key, in, inlen) != 1) { + error_print(); + return -1; + } + } + if (sm3_lms_signature_from_bytes(&sig->msg_lms_sig, in, inlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm3_hss_signature_to_bytes(const SM3_HSS_SIGNATURE *sig, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + if (!sig || !outlen) { + error_print(); + return -1; + } + if (sig->num_signed_public_keys >= SM3_HSS_MAX_LEVELS) { error_print(); return -1; } - lms_pub = &pub->lms_pub; + if (out && *out) { + size_t i; - for (i = 0; i < num; i++) { + PUTU32(*out, sig->num_signed_public_keys); + *out += 4; + len += 4; - hash256_t pub_dgst; + for (i = 0; i < sig->num_signed_public_keys; i++) { + if (sm3_lms_signature_to_bytes(&sig->signed_public_keys[i].lms_sig, out, &len) != 1) { + error_print(); + return -1; + } + if (sm3_lms_public_key_to_bytes((SM3_LMS_KEY *)&sig->signed_public_keys[i].lms_public_key, out, &len) != 1) { + error_print(); + return -1; + } + } - if (sm3_lms_signature_from_bytes_ex(&lms_sig, &lms_siglen, &sig, &siglen) != 1) { + if (sm3_lms_signature_to_bytes(&sig->msg_lms_sig, out, &len) != 1) { error_print(); return -1; } - - if (sm3_lms_public_key_from_bytes_ex(&next_lms_pub, &sig, &siglen) != 1) { - error_print(); - return -1; - } - - - int lms_type = GETU32(lms_sig->lms_type); - int q = GETU32(lms_sig->q); - int lmots_type = GETU32(lms_sig->lmots_sig.lmots_type); - - sm3_lms_digest(lms_pub, q, lms_sig->lmots_sig.C, - (uint8_t *)next_lms_pub, SM3_LMS_PUBLIC_KEY_SIZE, pub_dgst); - - - if (sm3_lms_do_verify(lms_pub, pub_dgst, lms_sig) != 1) { - error_print(); - return -1; - } - - lms_pub = next_lms_pub; } - if (sm3_lms_signature_from_bytes_ex(&lms_sig, &lms_siglen, &sig, &siglen) != 1) { + *outlen += len; + return 1; +} + + +int sm3_hss_key_update(SM3_HSS_KEY *key) +{ + int level; + SM3_LMS_KEY *lms_key; + size_t count; + + + for (level = key->levels; level > 0; level--) { + lms_key = &key->lms_key[level - 1]; + if (sm3_lms_key_remaining_signs(lms_key, &count) != 1) { + error_print(); + return -1; + } + if (count > 0) { + break; + } + } + // the lowest level is not out of keys + if (level >= key->levels) { + + fprintf(stderr, "key->levels = %d\n", key->levels); + fprintf(stderr, "level out of key = %d\n", level); + + + error_print(); + return -1; + } + // all levels are out of keys + if (level == 0) { + return 0; + } + + for (; level < key->levels; level++) { + int lms_type = key->lms_key[level].public_key.lms_type; + SM3_LMS_SIGN_CTX ctx; + uint8_t buf[SM3_LMS_PUBLIC_KEY_SIZE]; + uint8_t *p = buf; + size_t len = 0; + + sm3_lms_key_cleanup(&key->lms_key[level]); + + if (sm3_lms_key_generate(&key->lms_key[level], lms_type) != 1) { + error_print(); + return -1; + } + if (sm3_lms_public_key_to_bytes(&key->lms_key[level], &p, &len) != 1) { + error_print(); + return -1; + } + + if (sm3_lms_sign_init(&ctx, &key->lms_key[level - 1]) != 1) { + error_print(); + return -1; + } + if (sm3_lms_sign_update(&ctx, buf, len) != 1) { + error_print(); + return -1; + } + if (sm3_lms_sign_finish_ex(&ctx, &key->lms_sig[level - 1]) != 1) { + error_print(); + return -1; + } + } + + return 1; +} + +int sm3_hss_sign_init(SM3_HSS_SIGN_CTX *ctx, SM3_HSS_KEY *key) +{ + size_t count; + size_t i; + + if (!ctx || !key) { + error_print(); + return -1; + } + if (key->levels < 1 || key->levels > SM3_HSS_MAX_LEVELS) { error_print(); return -1; } - if (sm3_lms_do_verify(lms_pub, dgst, lms_sig) != 1) { + memset(ctx, 0, sizeof(*ctx)); + + if (sm3_lms_sign_init(&ctx->lms_ctx, &key->lms_key[key->levels - 1]) != 1) { + error_print(); + return -1; + } + + ctx->levels = key->levels; + + for (i = 0; i < key->levels; i++) { + ctx->lms_public_keys[i] = key->lms_key[i + 1].public_key; + ctx->lms_sigs[i] = key->lms_sig[i]; + } + + if (sm3_lms_key_remaining_signs(&key->lms_key[key->levels - 1], &count) != 1) { + error_print(); + return -1; + } + if (count == 0) { + if (sm3_hss_key_update(key) != 1) { + error_print(); + return -1; + } + } + + return 1; +} + +int sm3_hss_sign_update(SM3_HSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) +{ + if (!ctx) { + error_print(); + return -1; + } + if (data && datalen) { + if (sm3_lms_sign_update(&ctx->lms_ctx, data, datalen) != 1) { + error_print(); + return -1; + } + } + return 1; +} + +int sm3_hss_sign_finish(SM3_HSS_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen) +{ + SM3_HSS_SIGNATURE signature; + uint8_t *p = sig; + + if (!ctx || !sig || !siglen) { + error_print(); + return -1; + } + if (sm3_hss_sign_finish_ex(ctx, &signature) != 1) { + error_print(); + return -1; + } + + *siglen = 0; + if (sm3_hss_signature_to_bytes(&signature, &p, siglen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm3_hss_sign_finish_ex(SM3_HSS_SIGN_CTX *ctx, SM3_HSS_SIGNATURE *sig) +{ + size_t i; + + if (!ctx || !sig) { + error_print(); + return -1; + } + + sig->num_signed_public_keys = ctx->levels - 1; + + for (i = 0; i < ctx->levels - 1; i++) { + sig->signed_public_keys[i].lms_sig = ctx->lms_sigs[i]; + sig->signed_public_keys[i].lms_public_key = ctx->lms_public_keys[i]; + } + + if (sm3_lms_sign_finish_ex(&ctx->lms_ctx, &sig->msg_lms_sig) != 1) { + error_print(); + return -1; + } + + return 1; +} + + +// optimize this function, +int sm3_hss_verify_init_ex(SM3_HSS_SIGN_CTX *ctx, const SM3_HSS_KEY *key, const SM3_HSS_SIGNATURE *sig) +{ + uint8_t buf[SM3_LMS_PUBLIC_KEY_SIZE]; + uint8_t *p = buf; + size_t len = 0; + size_t i; + + if (!ctx || !key || !sig) { + error_print(); + return -1; + } + + if (key->levels < 1 || key->levels > SM3_HSS_MAX_LEVELS) { + error_print(); + return -1; + } + if (sig->num_signed_public_keys != key->levels - 1) { + error_print(); + return -1; + } + + if (sig->num_signed_public_keys == 0) { + if (sm3_lms_verify_init_ex(&ctx->lms_ctx, &key->lms_key[0], + &sig->msg_lms_sig) != 1) { + error_print(); + return -1; + } + return 1; + } + + // verify(public_root, sig->pk[0], sig[0]) + if (sm3_lms_public_key_to_bytes((SM3_LMS_KEY *)&sig->signed_public_keys[0].lms_public_key, &p, &len) != 1) { + error_print(); + return -1; + } + + if (sm3_lms_verify_init_ex(&ctx->lms_ctx, &key->lms_key[0], + &sig->signed_public_keys[0].lms_sig) != 1) { + error_print(); + return -1; + } + + if (sm3_lms_verify_update(&ctx->lms_ctx, buf, len) != 1) { + error_print(); + return -1; + } + if (sm3_lms_verify_finish(&ctx->lms_ctx) != 1) { + error_print(); + return -1; + } + + // verify(pk[i - 1], pk[i], sig[i]) + for (i = 1; i < sig->num_signed_public_keys; i++) { + p = buf; + len = 0; + if (sm3_lms_public_key_to_bytes((SM3_LMS_KEY *)&sig->signed_public_keys[i].lms_public_key, &p, &len) != 1) { + error_print(); + return -1; + } + + if (sm3_lms_verify_init_ex(&ctx->lms_ctx, + (SM3_LMS_KEY *)&sig->signed_public_keys[i - 1].lms_public_key, + &sig->signed_public_keys[i].lms_sig) != 1) { + error_print(); + return -1; + } + if (sm3_lms_verify_update(&ctx->lms_ctx, buf, len) != 1) { + error_print(); + return -1; + } + + if (sm3_lms_verify_finish(&ctx->lms_ctx) != 1) { + error_print(); + return -1; + } + } + + // verify(pk[last], msg, msg_sig) + if (sm3_lms_verify_init_ex(&ctx->lms_ctx, + (SM3_LMS_KEY *)&sig->signed_public_keys[sig->num_signed_public_keys - 1].lms_public_key, + &sig->msg_lms_sig) != 1) { + error_print(); + return -1; + } + + return 1; +} + +int sm3_hss_verify_init(SM3_HSS_SIGN_CTX *ctx, const SM3_HSS_KEY *key, const uint8_t *sig, size_t siglen) +{ + SM3_HSS_SIGNATURE signature; + + if (!ctx || !key || !sig) { + error_print(); + return -1; + } + if (sm3_hss_signature_from_bytes(&signature, &sig, &siglen) != 1) { error_print(); return -1; } @@ -1182,60 +1802,136 @@ int sm3_hss_verify(const SM3_HSS_PUBLIC_KEY *pub, const hash256_t dgst, const ui return -1; } + if (sm3_hss_verify_init_ex(ctx, key, &signature) != 1) { + error_print(); + return -1; + } + return 1; } -static int test_sm3_hss_sign(void) +int sm3_hss_verify_update(SM3_HSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) { - int lms_types[] = { - LMS_SM3_M32_H5, - LMS_SM3_M32_H5, - LMS_SM3_M32_H5, - }; - SM3_HSS_KEY key; - uint8_t sig[1024 * 16]; - size_t siglen; - uint8_t dgst[32]; - - if (sm3_hss_key_generate(&key, sizeof(lms_types)/sizeof(lms_types[0]), lms_types) != 1) { + if (!ctx) { error_print(); return -1; } - - int level = key.public_key.levels; - const SM3_LMS_PUBLIC_KEY *last_lms_pub = &key.lms_key[level - 1].public_key; - - hash256_t C; - int q = 0; - rand_bytes(C, 32); - - sm3_lms_digest(last_lms_pub, q, C, (uint8_t *)last_lms_pub, SM3_LMS_PUBLIC_KEY_SIZE, dgst); - - if (sm3_hss_sign(&key, C, dgst, sig, &siglen) != 1) { - error_print(); - return -1; + if (data && datalen) { + if (sm3_lms_verify_update(&ctx->lms_ctx, data, datalen) != 1) { + error_print(); + return -1; + } } - if (sm3_hss_verify((SM3_HSS_PUBLIC_KEY *)&key, dgst, sig, siglen) != 1) { - error_print(); - return -1; - } - - printf("%s() ok\n", __FUNCTION__); return 1; } -int main(void) +int sm3_hss_verify_finish(SM3_HSS_SIGN_CTX *ctx) { - if (test_sm3_lmots() != 1) goto err; - if (test_sm3_lms_derive_merkle_root() != 1) goto err; - if (test_sm3_lms_key_generate() != 1) goto err; - if (test_sm3_lms_do_sign() != 1) goto err; - if (test_sm3_hss_key_generate() != 1) goto err; - if (test_sm3_hss_sign() != 1) goto err; - - printf("%s all tests passed\n", __FILE__); - return 0; -err: - error_print(); + int ret = -1; + if (!ctx) { + error_print(); + return -1; + } + if ((ret = sm3_lms_verify_finish(&ctx->lms_ctx)) != 1) { + error_print(); + return ret; + } + return 1; +} + +int sm3_hss_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const SM3_HSS_SIGNATURE *sig) +{ + size_t i; + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + + format_print(fp, fmt, ind, "num_signed_public_keys: %d\n", sig->num_signed_public_keys); + + for (i = 0; i < sig->num_signed_public_keys; i++) { + char title[64]; + snprintf(title, sizeof(title), "lms_signature[%zu]", i); + sm3_lms_signature_print_ex(fp, fmt, ind, title, &sig->signed_public_keys[0].lms_sig); + snprintf(title, sizeof(title), "lms_public_key[%zu]", i + 1); + sm3_lms_public_key_print(fp, fmt, ind, title, &sig->signed_public_keys[0].lms_public_key); + } + sm3_lms_signature_print_ex(fp, fmt, ind, "message_signature", &sig->msg_lms_sig); + + return 1; +} + +int sm3_hss_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen) +{ + SM3_LMS_SIGNATURE lms_sig; + size_t lms_siglen; + SM3_LMS_PUBLIC_KEY lms_pub; + + int num; + int i; + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + + if (siglen < 4) { + error_print(); + return -1; + } + num = GETU32(sig); + sig += 4; + siglen -= 4; + + + format_print(fp, fmt, ind, "num_signed_public_keys: %d\n", num); + + for (i = 0; i < num; i++) { + char title[64]; + + if (sm3_lms_signature_from_bytes(&lms_sig, &sig, &siglen) != 1) { + error_print(); + return -1; + } + snprintf(title, sizeof(title), "lms_signature[%d]", i); + sm3_lms_signature_print_ex(fp, fmt, ind, title, &lms_sig); + + if (sm3_lms_public_key_from_bytes((SM3_LMS_KEY *)&lms_pub, &sig, &siglen) != 1) { + error_print(); + return -1; + } + snprintf(title, sizeof(title), "lms_public_key[%d]", i + 1); + sm3_lms_public_key_print(fp, fmt, ind, title, &lms_pub); + } + + if (sm3_lms_signature_from_bytes(&lms_sig, &sig, &siglen) != 1) { + error_print(); + return -1; + } + sm3_lms_signature_print_ex(fp, fmt, ind, "message_signature", &lms_sig); + + return 1; +} + +int sm3_hss_private_key_size(const int *lms_types, size_t levels, size_t *len) +{ + size_t i; + + if (!lms_types || !len) { + error_print(); + return -1; + } + if (levels < 1 || levels > SM3_HSS_MAX_LEVELS) { + error_print(); + return -1; + } + + *len = sizeof(uint32_t) + SM3_LMS_PRIVATE_KEY_SIZE * levels; + for (i = 0; i < levels - 1; i++) { + size_t siglen; + if (sm3_lms_signature_size(lms_types[i], &siglen) != 1) { + error_print(); + return -1; + } + *len += siglen; + } + return 1; } diff --git a/tests/sm3_lmstest.c b/tests/sm3_lmstest.c new file mode 100644 index 00000000..3352db77 --- /dev/null +++ b/tests/sm3_lmstest.c @@ -0,0 +1,903 @@ +/* + * 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 int lms_types[] = { + LMS_HASH256_M32_H5, + LMS_HASH256_M32_H5, + LMS_HASH256_M32_H5, +}; + + +#if defined(ENABLE_SM3_LMS_CROSSCHECK) && defined(ENABLE_SHA2) +static int test_rfc8554_test1(void) +{ + size_t i; + + // HSS Public key + int levels = 2; + int lms_type = LMS_SHA256_M32_H5; + int lmots_type = LMOTS_SHA256_N32_W8; + char *I = "61a5d57d37f5e46bfb7520806b07a1b8"; + char *K = "50650e3b31fe4a773ea29a07f09cf2ea30e579f0df58ef8e298da0434cb2b878"; + + // Message + char *msg = + "54686520706f77657273206e6f742064656c65676174656420746f2074686520" + "556e69746564205374617465732062792074686520436f6e737469747574696f" + "6e2c206e6f722070726f6869626974656420627920697420746f207468652053" + "74617465732c2061726520726573657276656420746f20746865205374617465" + "7320726573706563746976656c792c206f7220746f207468652070656f706c65" + "2e0a"; // MUST NOT use strlen(msg), which will not count the last 0x0a + + // Signature + int Nspk = 1; + + int sig0_q = 5; + int sig0_lmots_type = LMOTS_SHA256_N32_W8; + char *sig0_C = + "d32b56671d7eb98833c49b433c272586" + "bc4a1c8a8970528ffa04b966f9426eb9"; + char *sig0_y[34] = { + "965a25bfd37f196b9073f3d4a232feb69128ec45146f86292f9dff9610a7bf95", + "a64c7f60f6261a62043f86c70324b7707f5b4a8a6e19c114c7be866d488778a0", + "e05fd5c6509a6e61d559cf1a77a970de927d60c70d3de31a7fa0100994e162a2", + "582e8ff1b10cd99d4e8e413ef469559f7d7ed12c838342f9b9c96b83a4943d16", + "81d84b15357ff48ca579f19f5e71f18466f2bbef4bf660c2518eb20de2f66e3b", + "14784269d7d876f5d35d3fbfc7039a462c716bb9f6891a7f41ad133e9e1f6d95", + "60b960e7777c52f060492f2d7c660e1471e07e72655562035abc9a701b473ecb", + "c3943c6b9c4f2405a3cb8bf8a691ca51d3f6ad2f428bab6f3a30f55dd9625563", + "f0a75ee390e385e3ae0b906961ecf41ae073a0590c2eb6204f44831c26dd768c", + "35b167b28ce8dc988a3748255230cef99ebf14e730632f27414489808afab1d1", + "e783ed04516de012498682212b07810579b250365941bcc98142da13609e9768", + "aaf65de7620dabec29eb82a17fde35af15ad238c73f81bdb8dec2fc0e7f93270", + "1099762b37f43c4a3c20010a3d72e2f606be108d310e639f09ce7286800d9ef8", + "a1a40281cc5a7ea98d2adc7c7400c2fe5a101552df4e3cccfd0cbf2ddf5dc677", + "9cbbc68fee0c3efe4ec22b83a2caa3e48e0809a0a750b73ccdcf3c79e6580c15", + "4f8a58f7f24335eec5c5eb5e0cf01dcf4439424095fceb077f66ded5bec73b27", + "c5b9f64a2a9af2f07c05e99e5cf80f00252e39db32f6c19674f190c9fbc506d8", + "26857713afd2ca6bb85cd8c107347552f30575a5417816ab4db3f603f2df56fb", + "c413e7d0acd8bdd81352b2471fc1bc4f1ef296fea1220403466b1afe78b94f7e", + "cf7cc62fb92be14f18c2192384ebceaf8801afdf947f698ce9c6ceb696ed70e9", + "e87b0144417e8d7baf25eb5f70f09f016fc925b4db048ab8d8cb2a661ce3b57a", + "da67571f5dd546fc22cb1f97e0ebd1a65926b1234fd04f171cf469c76b884cf3", + "115cce6f792cc84e36da58960c5f1d760f32c12faef477e94c92eb75625b6a37", + "1efc72d60ca5e908b3a7dd69fef0249150e3eebdfed39cbdc3ce9704882a2072", + "c75e13527b7a581a556168783dc1e97545e31865ddc46b3c957835da252bb732", + "8d3ee2062445dfb85ef8c35f8e1f3371af34023cef626e0af1e0bc017351aae2", + "ab8f5c612ead0b729a1d059d02bfe18efa971b7300e882360a93b025ff97e9e0", + "eec0f3f3f13039a17f88b0cf808f488431606cb13f9241f40f44e537d302c64a", + "4f1f4ab949b9feefadcb71ab50ef27d6d6ca8510f150c85fb525bf25703df720", + "9b6066f09c37280d59128d2f0f637c7d7d7fad4ed1c1ea04e628d221e3d8db77", + "b7c878c9411cafc5071a34a00f4cf07738912753dfce48f07576f0d4f94f42c6", + "d76f7ce973e9367095ba7e9a3649b7f461d9f9ac1332a4d1044c96aefee67676", + "401b64457c54d65fef6500c59cdfb69af7b6dddfcb0f086278dd8ad0686078df", + "b0f3f79cd893d314168648499898fbc0ced5f95b74e8ff14d735cdea968bee74", + }; + int sig0_lms_type = LMS_SHA256_M32_H5; + char *sig0_path[5] = { + "d8b8112f9200a5e50c4a262165bd342cd800b8496810bc716277435ac376728d", + "129ac6eda839a6f357b5a04387c5ce97382a78f2a4372917eefcbf93f63bb591", + "12f5dbe400bd49e4501e859f885bf0736e90a509b30a26bfac8c17b5991c157e", + "b5971115aa39efd8d564a6b90282c3168af2d30ef89d51bf14654510a12b8a14", + "4cca1848cf7da59cc2b3d9d0692dd2a20ba3863480e25b1b85ee860c62bf5136", + }; + + int pub0_lms_type = LMS_SHA256_M32_H5; + int pub0_lmots_type = LMOTS_SHA256_N32_W8; + char *pub0_I = "d2f14ff6346af964569f7d6cb880a1b6"; + char *pub0_K = "6c5004917da6eafe4d9ef6c6407b3db0e5485b122d9ebe15cda93cfec582d7ab"; + + int sig1_q = 0x0a; + int sig1_lmots_type = LMOTS_SHA256_N32_W8; + char *sig1_C = "0703c491e7558b35011ece3592eaa5da4d918786771233e8353bc4f62323185c"; + char *sig1_y[34] = { + "95cae05b899e35dffd717054706209988ebfdf6e37960bb5c38d7657e8bffeef", + "9bc042da4b4525650485c66d0ce19b317587c6ba4bffcc428e25d08931e72dfb", + "6a120c5612344258b85efdb7db1db9e1865a73caf96557eb39ed3e3f426933ac", + "9eeddb03a1d2374af7bf77185577456237f9de2d60113c23f846df26fa942008", + "a698994c0827d90e86d43e0df7f4bfcdb09b86a373b98288b7094ad81a0185ac", + "100e4f2c5fc38c003c1ab6fea479eb2f5ebe48f584d7159b8ada03586e65ad9c", + "969f6aecbfe44cf356888a7b15a3ff074f771760b26f9c04884ee1faa329fbf4", + "e61af23aee7fa5d4d9a5dfcf43c4c26ce8aea2ce8a2990d7ba7b57108b47dabf", + "beadb2b25b3cacc1ac0cef346cbb90fb044beee4fac2603a442bdf7e507243b7", + "319c9944b1586e899d431c7f91bcccc8690dbf59b28386b2315f3d36ef2eaa3c", + "f30b2b51f48b71b003dfb08249484201043f65f5a3ef6bbd61ddfee81aca9ce6", + "0081262a00000480dcbc9a3da6fbef5c1c0a55e48a0e729f9184fcb1407c3152", + "9db268f6fe50032a363c9801306837fafabdf957fd97eafc80dbd165e435d0e2", + "dfd836a28b354023924b6fb7e48bc0b3ed95eea64c2d402f4d734c8dc26f3ac5", + "91825daef01eae3c38e3328d00a77dc657034f287ccb0f0e1c9a7cbdc828f627", + "205e4737b84b58376551d44c12c3c215c812a0970789c83de51d6ad787271963", + "327f0a5fbb6b5907dec02c9a90934af5a1c63b72c82653605d1dcce51596b3c2", + "b45696689f2eb382007497557692caac4d57b5de9f5569bc2ad0137fd47fb47e", + "664fcb6db4971f5b3e07aceda9ac130e9f38182de994cff192ec0e82fd6d4cb7", + "f3fe00812589b7a7ce515440456433016b84a59bec6619a1c6c0b37dd1450ed4", + "f2d8b584410ceda8025f5d2d8dd0d2176fc1cf2cc06fa8c82bed4d944e71339e", + "ce780fd025bd41ec34ebff9d4270a3224e019fcb444474d482fd2dbe75efb203", + "89cc10cd600abb54c47ede93e08c114edb04117d714dc1d525e11bed8756192f", + "929d15462b939ff3f52f2252da2ed64d8fae88818b1efa2c7b08c8794fb1b214", + "aa233db3162833141ea4383f1a6f120be1db82ce3630b3429114463157a64e91", + "234d475e2f79cbf05e4db6a9407d72c6bff7d1198b5c4d6aad2831db61274993", + "715a0182c7dc8089e32c8531deed4f7431c07c02195eba2ef91efb5613c37af7", + "ae0c066babc69369700e1dd26eddc0d216c781d56e4ce47e3303fa73007ff7b9", + "49ef23be2aa4dbf25206fe45c20dd888395b2526391a724996a44156beac8082", + "12858792bf8e74cba49dee5e8812e019da87454bff9e847ed83db07af3137430", + "82f880a278f682c2bd0ad6887cb59f652e155987d61bbf6a88d36ee93b6072e6", + "656d9ccbaae3d655852e38deb3a2dcf8058dc9fb6f2ab3d3b3539eb77b248a66", + "1091d05eb6e2f297774fe6053598457cc61908318de4b826f0fc86d4bb117d33", + "e865aa805009cc2918d9c2f840c4da43a703ad9f5b5806163d7161696b5a0adc", + }; + int sig1_lms_type = LMS_SHA256_M32_H5; + char *sig1_path[5] = { + "d5c0d1bebb06048ed6fe2ef2c6cef305b3ed633941ebc8b3bec9738754cddd60", + "e1920ada52f43d055b5031cee6192520d6a5115514851ce7fd448d4a39fae2ab", + "2335b525f484e9b40d6a4a969394843bdcf6d14c48e8015e08ab92662c05c6e9", + "f90b65a7a6201689999f32bfd368e5e3ec9cb70ac7b8399003f175c40885081a", + "09ab3034911fe125631051df0408b3946b0bde790911e8978ba07dd56c73e7ee", + }; + + SM3_HSS_KEY key; + SM3_HSS_SIGNATURE sig; + SM3_LMS_SIGNATURE *lms_sig; + SM3_LMS_PUBLIC_KEY *lms_pub; + size_t len; + + // hss public key + memset(&key, 0, sizeof(key)); + key.levels = levels; + lms_pub = &key.lms_key[0].public_key; + lms_pub->lms_type = lms_type; + lms_pub->lmots_type = lmots_type; + hex_to_bytes(I, strlen(I), lms_pub->I, &len); + hex_to_bytes(K, strlen(K), lms_pub->root, &len); + + // hss signature + memset(&sig, 0, sizeof(sig)); + sig.num_signed_public_keys = Nspk; + + // sig[0] + lms_sig = &sig.signed_public_keys[0].lms_sig; + lms_sig->q = sig0_q; + lms_sig->lmots_sig.lmots_type = sig0_lmots_type; + hex_to_bytes(sig0_C, 64, lms_sig->lmots_sig.C, &len); + for (i = 0; i < 34; i++) { + hex_to_bytes(sig0_y[i], 64, lms_sig->lmots_sig.y[i], &len); + } + lms_sig->lms_type = sig0_lms_type; + for (i = 0; i < 5; i++) { + hex_to_bytes(sig0_path[i], 64, lms_sig->path[i], &len); + } + + // pub[0] + lms_pub = &sig.signed_public_keys[0].lms_public_key; + lms_pub->lms_type = pub0_lms_type; + lms_pub->lmots_type = pub0_lmots_type; + hex_to_bytes(pub0_I, 32, lms_pub->I, &len); + hex_to_bytes(pub0_K, 64, lms_pub->root, &len); + + // sig[1] + lms_sig = &sig.msg_lms_sig; + lms_sig->q = sig1_q; + lms_sig->lmots_sig.lmots_type = sig1_lmots_type; + hex_to_bytes(sig1_C, 64, lms_sig->lmots_sig.C, &len); + for (i = 0; i < 34; i++) { + hex_to_bytes(sig1_y[i], 64, lms_sig->lmots_sig.y[i], &len); + } + lms_sig->lms_type = sig1_lms_type; + for (i = 0; i < 5; i++) { + hex_to_bytes(sig1_path[i], 64, lms_sig->path[i], &len); + } + + sm3_hss_public_key_print(stderr, 0, 0, "hss_public_key", &key); + + sm3_hss_signature_print_ex(stderr, 0, 0, "hss_signature", &sig); + + + SM3_HSS_SIGN_CTX ctx; + uint8_t data[162]; + + hex_to_bytes(msg, strlen(msg), data, &len); + + if (sm3_hss_verify_init_ex(&ctx, &key, &sig) != 1) { + error_print(); + return -1; + } + if (sm3_hss_verify_update(&ctx, data, len) != 1) { + error_print(); + return -1; + } + if (sm3_hss_verify_finish(&ctx) != 1) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} +#endif + + +static int test_sm3_lmots(void) +{ + hash256_t seed = {0}; // TODO: change to test vector + uint8_t I[16] = {0}; + int q = 0; + hash256_t dgst = {0}; + hash256_t x[34]; + hash256_t y[34]; + hash256_t pub; + hash256_t pub2; + + sm3_lmots_derive_secrets(seed, I, q, x); // TODO: compare results with test vector + sm3_lmots_secrets_to_public_hash(I, q, x, pub); // TODO: compare results with test vector + + sm3_lmots_compute_signature(I, q, dgst, x, y); // TODO: compare results with test vector + sm3_lmots_signature_to_public_hash(I, q, y, dgst, pub2); + + if (memcmp(pub, pub2, 32) != 0) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} + +static int test_sm3_lms_derive_merkle_root(void) +{ + hash256_t seed = {0}; // TODO: change to test vector + uint8_t I[16] = {0}; + int h = 5; + int n = 1< +#include +#include +#include +#include +#include +#include + + +static const char *usage = "-lms_types types -out file [-pubout file] [-verbose]\n"; + +static const char *options = +"Options\n" +" -lms_types types LMS Algorithm Types, start from level 0, seperate by ':'\n" +" such as "LMS_HASH256_M32_H5_NAME":"LMS_HASH256_M32_H10_NAME"\n" +" Supported types:\n" +" "LMS_HASH256_M32_H5_NAME"\n" +" "LMS_HASH256_M32_H10_NAME"\n" +" "LMS_HASH256_M32_H15_NAME"\n" +" "LMS_HASH256_M32_H20_NAME"\n" +" "LMS_HASH256_M32_H25_NAME"\n" +" -out file Output private key\n" +" -pubout file Output public key\n" +" -verbose Print public key\n" +"\n"; + +#define LMS_TYPES_STR_MAX_SIZE (sizeof("LMS_SM3_M32_H20_NAME") * 5) + +int sm3hsskeygen_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + char *lms_types = NULL; + char *outfile = NULL; + char *puboutfile = NULL; + int verbose = 0; + char lms_types_str[LMS_TYPES_STR_MAX_SIZE]; + int lms_types_val[5]; + int levels = 0; + FILE *outfp = NULL; + FILE *puboutfp = stdout; + SM3_HSS_KEY key; + uint8_t out[SM3_HSS_PRIVATE_KEY_MAX_SIZE]; + uint8_t pubout[SM3_HSS_PUBLIC_KEY_SIZE]; + uint8_t *pout = out; + uint8_t *ppubout = pubout; + size_t outlen = 0, puboutlen = 0; + + 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: gmssl %s %s\n", prog, usage); + printf("%s\n", options); + ret = 0; + goto end; + } else if (!strcmp(*argv, "-lms_types")) { + char *tok; + if (--argc < 1) goto bad; + lms_types = *(++argv); + strncpy(lms_types_str, lms_types, sizeof(lms_types_str)); + + tok = strtok(lms_types_str, ":"); + while (tok) { + if (!(lms_types_val[levels] = sm3_lms_type_from_name(tok))) { + fprintf(stderr, "%s: invalid lms_type `%s`\n", prog, tok); + goto end; + } + tok = strtok(NULL, ":"); + levels++; + } + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "wb"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-pubout")) { + if (--argc < 1) goto bad; + puboutfile = *(++argv); + if (!(puboutfp = fopen(puboutfile, "wb"))) { + 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; +bad: + fprintf(stderr, "%s: `%s` option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + if (!lms_types) { + fprintf(stderr, "%s: `-lms_types` option required\n", prog); + goto end; + } + if (!outfp) { + fprintf(stderr, "%s: `-out` option required\n", prog); + goto end; + } + + if (sm3_hss_key_generate(&key, lms_types_val, levels) != 1) { + error_print(); + return -1; + } + if (verbose) { + sm3_hss_public_key_print(stderr, 0, 0, "hss_public_key", &key); + } + + if (sm3_hss_private_key_to_bytes(&key, &pout, &outlen) != 1) { + error_print(); + goto end; + } + if (fwrite(out, 1, outlen, outfp) != outlen) { + error_print(); + goto end; + } + + if (sm3_hss_public_key_to_bytes(&key, &ppubout, &puboutlen) != 1) { + error_print(); + goto end; + } + if (fwrite(pubout, 1, puboutlen, puboutfp) != puboutlen) { + error_print(); + goto end; + } + + ret = 0; +end: + gmssl_secure_clear(&key, sizeof(key)); + gmssl_secure_clear(out, outlen); + if (outfile && outfp) fclose(outfp); + if (puboutfile && puboutfp) fclose(puboutfp); + return ret; +} diff --git a/tools/sm3hsssign.c b/tools/sm3hsssign.c new file mode 100644 index 00000000..538aa464 --- /dev/null +++ b/tools/sm3hsssign.c @@ -0,0 +1,170 @@ +/* + * 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 = "-key file [-in file] [-out file] [-verbose]\n"; + +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 sm3hsssign_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + char *keyfile = NULL; + char *infile = NULL; + char *outfile = NULL; + int verbose = 0; + FILE *keyfp = NULL; + FILE *infp = stdin; + FILE *outfp = stdout; + uint8_t keybuf[SM3_HSS_PRIVATE_KEY_MAX_SIZE]; + size_t keylen = SM3_HSS_PRIVATE_KEY_MAX_SIZE; + const uint8_t *cp = keybuf; + uint8_t *p = keybuf; + SM3_HSS_KEY key; + SM3_HSS_SIGN_CTX ctx; + uint8_t sig[SM3_HSS_SIGNATURE_MAX_SIZE]; + size_t siglen; + + 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, "-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; + } + } 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, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "wb"))) { + 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; +bad: + fprintf(stderr, "%s: `%s` option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + if (!keyfile) { + fprintf(stderr, "%s: `-key` option required\n", prog); + goto end; + } + + if ((keylen = fread(keybuf, 1, keylen, keyfp)) <= 0) { + fprintf(stderr, "%s: read private key failure\n", prog); + goto end; + } + if (sm3_hss_private_key_from_bytes(&key, &cp, &keylen) != 1) { + error_print(); + goto end; + } + if (keylen) { + error_print(); + return -1; + } + + if (verbose) { + sm3_hss_public_key_print(stderr, 0, 0, "hss_public_key", &key); + } + + if (sm3_hss_sign_init(&ctx, &key) != 1) { + error_print(); + goto end; + } + + // write updated key back to file + // TODO: write back `q` only + if (sm3_hss_private_key_to_bytes(&key, &p, &keylen) != 1) { + error_print(); + return -1; + } + rewind(keyfp); + if (fwrite(keybuf, 1, keylen, keyfp) != keylen) { + error_print(); + return -1; + } + + while (1) { + uint8_t buf[1024]; + size_t len = fread(buf, 1, sizeof(buf), infp); + if (len == 0) { + break; + } + if (sm3_hss_sign_update(&ctx, buf, len) != 1) { + error_print(); + goto end; + } + } + if (sm3_hss_sign_finish(&ctx, sig, &siglen) != 1) { + error_print(); + goto end; + } + if (fwrite(sig, 1, siglen, outfp) != siglen) { + error_print(); + goto end; + } + if (verbose) { + sm3_hss_signature_print(stderr, 0, 0, "hss_signature", sig, siglen); + } + + ret = 0; + +end: + gmssl_secure_clear(keybuf, sizeof(keybuf)); + gmssl_secure_clear(&key, sizeof(key)); + 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/sm3hssverify.c b/tools/sm3hssverify.c new file mode 100644 index 00000000..83e13da5 --- /dev/null +++ b/tools/sm3hssverify.c @@ -0,0 +1,157 @@ +/* + * 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 sm3hssverify_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[SM3_HSS_PUBLIC_KEY_SIZE]; + size_t pubkeylen = SM3_HSS_PUBLIC_KEY_SIZE; + const uint8_t *cp = pubkeybuf; + uint8_t sig[SM3_HSS_SIGNATURE_MAX_SIZE]; + size_t siglen; + SM3_HSS_KEY key; + SM3_HSS_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 (sm3_hss_public_key_from_bytes(&key, &cp, &pubkeylen) != 1) { + error_print(); + goto end; + } + if (verbose) { + sm3_hss_public_key_print(stderr, 0, 0, "lms_public_key", &key); + } + + // read signature even if signature not compatible with the public key + if ((siglen = fread(sig, 1, SM3_HSS_SIGNATURE_MAX_SIZE, sigfp)) <= 0) { + fprintf(stderr, "%s: read signature failure\n", prog); + goto end; + } + if (verbose) { + sm3_hss_signature_print(stderr, 0, 0, "lms_signature", sig, siglen); + } + if (sm3_hss_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 (sm3_hss_verify_update(&ctx, buf, len) != 1) { + error_print(); + goto end; + } + } + if ((vr = sm3_hss_verify_finish(&ctx)) < 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; +} diff --git a/tools/sm3lmskeygen.c b/tools/sm3lmskeygen.c new file mode 100644 index 00000000..edcb5ff4 --- /dev/null +++ b/tools/sm3lmskeygen.c @@ -0,0 +1,144 @@ +/* + * 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 = "-lms_type type -out file [-pubout file] [-verbose]\n"; + +static const char *options = +"Options\n" +" -lms_type type LMS Algorithm Type\n" +" "LMS_HASH256_M32_H5_NAME"\n" +" "LMS_HASH256_M32_H10_NAME"\n" +" "LMS_HASH256_M32_H15_NAME"\n" +" "LMS_HASH256_M32_H20_NAME"\n" +" "LMS_HASH256_M32_H25_NAME"\n" +" -out file Output private key\n" +" -pubout file Output public key\n" +" -verbose Print public key\n" +"\n"; + +int sm3lmskeygen_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + char *lms_type = NULL; + int lms_type_val = 0; + char *outfile = NULL; + char *puboutfile = NULL; + int verbose = 0; + FILE *outfp = NULL; + FILE *puboutfp = stdout; + SM3_LMS_KEY key; + uint8_t out[SM3_LMS_PRIVATE_KEY_SIZE]; + uint8_t pubout[SM3_LMS_PUBLIC_KEY_SIZE]; + uint8_t *pout = out; + uint8_t *ppubout = pubout; + size_t outlen = 0, puboutlen = 0; + + 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: gmssl %s %s\n", prog, usage); + printf("%s\n", options); + ret = 0; + goto end; + } else if (!strcmp(*argv, "-lms_type")) { + if (--argc < 1) goto bad; + lms_type = *(++argv); + if (!(lms_type_val = sm3_lms_type_from_name(lms_type))) { + fprintf(stderr, "%s: invalid lms_type `%s`\n", prog, lms_type); + goto end; + } + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "wb"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-pubout")) { + if (--argc < 1) goto bad; + puboutfile = *(++argv); + if (!(puboutfp = fopen(puboutfile, "wb"))) { + 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; +bad: + fprintf(stderr, "%s: `%s` option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + if (!lms_type) { + fprintf(stderr, "%s: `-lms_type` option required\n", prog); + goto end; + } + if (!outfp) { + fprintf(stderr, "%s: `-out` option required\n", prog); + goto end; + } + + if (sm3_lms_key_generate(&key, lms_type_val) != 1) { + error_print(); + return -1; + } + if (verbose) { + sm3_lms_public_key_print(stderr, 0, 0, "lms_public_key", &key.public_key); + } + + if (sm3_lms_private_key_to_bytes(&key, &pout, &outlen) != 1) { + error_print(); + goto end; + } + if (fwrite(out, 1, outlen, outfp) != outlen) { + error_print(); + goto end; + } + + if (sm3_lms_public_key_to_bytes(&key, &ppubout, &puboutlen) != 1) { + error_print(); + goto end; + } + if (fwrite(pubout, 1, puboutlen, puboutfp) != puboutlen) { + error_print(); + goto end; + } + + ret = 0; +end: + gmssl_secure_clear(&key, sizeof(key)); + gmssl_secure_clear(out, outlen); + if (outfile && outfp) fclose(outfp); + if (puboutfile && puboutfp) fclose(puboutfp); + return ret; +} diff --git a/tools/sm3lmssign.c b/tools/sm3lmssign.c new file mode 100644 index 00000000..e367afb9 --- /dev/null +++ b/tools/sm3lmssign.c @@ -0,0 +1,170 @@ +/* + * 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 = "-key file [-in file] [-out file] [-verbose]\n"; + +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 sm3lmssign_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + char *keyfile = NULL; + char *infile = NULL; + char *outfile = NULL; + int verbose = 0; + FILE *keyfp = NULL; + FILE *infp = stdin; + FILE *outfp = stdout; + uint8_t keybuf[SM3_LMS_PRIVATE_KEY_SIZE]; + size_t keylen = SM3_LMS_PRIVATE_KEY_SIZE; + const uint8_t *cp = keybuf; + uint8_t *p = keybuf; + SM3_LMS_KEY key; + SM3_LMS_SIGN_CTX ctx; + uint8_t sig[SM3_LMS_SIGNATURE_MAX_SIZE]; + size_t siglen; + + 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, "-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; + } + } 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, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "wb"))) { + 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; +bad: + fprintf(stderr, "%s: `%s` option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + if (!keyfile) { + fprintf(stderr, "%s: `-key` option required\n", prog); + goto end; + } + + if (fread(keybuf, 1, keylen, keyfp) != keylen) { + fprintf(stderr, "%s: read private key failure\n", prog); + goto end; + } + if (sm3_lms_private_key_from_bytes(&key, &cp, &keylen) != 1) { + error_print(); + goto end; + } + if (keylen) { + error_print(); + return -1; + } + + if (verbose) { + sm3_lms_public_key_print(stderr, 0, 0, "lms_public_key", &key.public_key); + } + + if (sm3_lms_sign_init(&ctx, &key) != 1) { + error_print(); + goto end; + } + + // write updated key back to file + // TODO: write back `q` only + if (sm3_lms_private_key_to_bytes(&key, &p, &keylen) != 1) { + error_print(); + return -1; + } + rewind(keyfp); + if (fwrite(keybuf, 1, keylen, keyfp) != keylen) { + error_print(); + return -1; + } + + while (1) { + uint8_t buf[1024]; + size_t len = fread(buf, 1, sizeof(buf), infp); + if (len == 0) { + break; + } + if (sm3_lms_sign_update(&ctx, buf, len) != 1) { + error_print(); + goto end; + } + } + if (sm3_lms_sign_finish(&ctx, sig, &siglen) != 1) { + error_print(); + goto end; + } + if (fwrite(sig, 1, siglen, outfp) != siglen) { + error_print(); + goto end; + } + if (verbose) { + sm3_lms_signature_print(stderr, 0, 0, "lms_signature", sig, siglen); + } + + ret = 0; + +end: + gmssl_secure_clear(keybuf, sizeof(keybuf)); + gmssl_secure_clear(&key, sizeof(key)); + 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/sm3lmsverify.c b/tools/sm3lmsverify.c new file mode 100644 index 00000000..f492369f --- /dev/null +++ b/tools/sm3lmsverify.c @@ -0,0 +1,157 @@ +/* + * 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 sm3lmsverify_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[SM3_LMS_PUBLIC_KEY_SIZE]; + size_t pubkeylen = SM3_LMS_PUBLIC_KEY_SIZE; + const uint8_t *cp = pubkeybuf; + uint8_t sig[SM3_LMS_SIGNATURE_MAX_SIZE]; + size_t siglen; + SM3_LMS_KEY key; + SM3_LMS_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 (sm3_lms_public_key_from_bytes(&key, &cp, &pubkeylen) != 1) { + error_print(); + goto end; + } + if (verbose) { + sm3_lms_public_key_print(stderr, 0, 0, "lms_public_key", &key.public_key); + } + + // read signature even if signature not compatible with the public key + if ((siglen = fread(sig, 1, SM3_LMS_SIGNATURE_MAX_SIZE, sigfp)) <= 0) { + fprintf(stderr, "%s: read signature failure\n", prog); + goto end; + } + if (verbose) { + sm3_lms_signature_print(stderr, 0, 0, "lms_signature", sig, siglen); + } + if (sm3_lms_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 (sm3_lms_verify_update(&ctx, buf, len) != 1) { + error_print(); + goto end; + } + } + if ((vr = sm3_lms_verify_finish(&ctx)) < 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; +}