From 65be2ce54b02f8e0bc27f8e4b7da5c5da4ec021e Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Sun, 4 Jan 2026 18:37:01 +0800 Subject: [PATCH] Update XMSS --- CMakeLists.txt | 1 + src/xmss.c | 216 +++++++++++++++++++++++++++---------------- tests/xmsstest.c | 75 +++++++++++---- tools/gmssl.c | 12 +++ tools/xmssmtkeygen.c | 162 ++++++++++++++++++++++++++++++++ tools/xmssmtsign.c | 199 +++++++++++++++++++++++++++++++++++++++ tools/xmssmtverify.c | 158 +++++++++++++++++++++++++++++++ tools/xmsssign.c | 4 +- 8 files changed, 726 insertions(+), 101 deletions(-) create mode 100644 tools/xmssmtkeygen.c create mode 100644 tools/xmssmtsign.c create mode 100644 tools/xmssmtverify.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 8991eec5..9a160908 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -438,6 +438,7 @@ if (ENABLE_XMSS) add_definitions(-DENABLE_XMSS) list(APPEND src src/xmss.c) list(APPEND tools tools/xmsskeygen.c tools/xmsssign.c tools/xmssverify.c) + list(APPEND tools tools/xmssmtkeygen.c tools/xmssmtsign.c tools/xmssmtverify.c) list(APPEND tests xmss) option(ENABLE_XMSS_CROSSCHECK "Enable XMSS SHA-256 cross-check" ON) diff --git a/src/xmss.c b/src/xmss.c index 372059e9..4dd203b8 100644 --- a/src/xmss.c +++ b/src/xmss.c @@ -1539,11 +1539,69 @@ int xmssmt_private_key_from_bytes(XMSSMT_KEY *key, const uint8_t **in, size_t *i return 1; } -// XMSSMT的密钥生成和密钥更新都是完全一样的, -// 密钥生成的区别是需要生成最高层 -int xmssmt_key_generate(XMSSMT_KEY *key, uint32_t xmssmt_type) +int xmssmt_key_update(XMSSMT_KEY *key) +{ + size_t height; + size_t layers; + size_t layer; + hash256_t *tree; + + uint64_t next_index; + + xmss_adrs_t adrs; + + uint8_t *xmss_root; + + if (xmssmt_type_to_height_and_layers(key->public_key.xmssmt_type, &height, &layers) != 1) { + error_print(); + return -1; + } + + if (key->index > (1 << height)) { + error_print(); + return -1; + } + if (key->index == (1 << height)) { + return 0; + } + + next_index = key->index + 1; + + tree = key->trees; + + for (layer = 0; layer < layers - 1; layer++) { + if (xmssmt_tree_address(next_index, height, layers, layer) == + xmssmt_tree_address(key->index, height, layers, layer)) { + break; + } + + // generate tree of the layer + adrs_set_layer_address(adrs, layer); + adrs_set_tree_address(adrs, xmssmt_tree_address(next_index, height, layers, layer)); + xmss_build_tree(key->secret, key->public_key.seed, adrs, height/layers, tree); + + // sign the new xmss_root + adrs_set_layer_address(adrs, layer + 1); + adrs_set_tree_address(adrs, xmssmt_tree_address(next_index, height, layers, layer + 1)); + adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); + adrs_set_ots_address(adrs, xmssmt_tree_index(next_index, height, layers, layer + 1)); + wots_derive_sk(key->secret, key->public_key.seed, adrs, key->wots_sigs[layer]); + xmss_root = tree[tree_root_offset(height/layers)]; + wots_sign(key->wots_sigs[layer], key->public_key.seed, adrs, xmss_root, key->wots_sigs[layer]); + tree += xmss_tree_num_nodes(height/layers); + } + + key->index++; + + return 1; +} + + + +int xmssmt_key_generate_ex(XMSSMT_KEY *key, uint32_t xmssmt_type, + const hash256_t seed, const hash256_t secret, const hash256_t sk_prf) { size_t height; size_t layers; @@ -1572,25 +1630,14 @@ int xmssmt_key_generate(XMSSMT_KEY *key, uint32_t xmssmt_type) key->public_key.xmssmt_type = xmssmt_type; -#if 0 - memset(key->public_key.seed, 0, 32); - memset(key->secret, 0, 32); - memset(key->sk_prf, 0, 32); -#else - if (rand_bytes(key->public_key.seed, sizeof(hash256_t)) != 1) { - error_print(); - return -1; - } - if (rand_bytes(key->secret, sizeof(hash256_t)) != 1) { - error_print(); - return -1; - } - if (rand_bytes(key->sk_prf, sizeof(hash256_t)) != 1) { - error_print(); - return -1; - } -#endif + memcpy(key->public_key.seed, seed, sizeof(hash256_t)); + memcpy(key->secret, secret, sizeof(hash256_t)); + memcpy(key->sk_prf, sk_prf, sizeof(hash256_t)); + + + + key->index = 0; // malloc tress @@ -1602,8 +1649,6 @@ int xmssmt_key_generate(XMSSMT_KEY *key, uint32_t xmssmt_type) tree = key->trees; - - for (layer = 0; layer < layers; layer++) { // generate tree of the layer @@ -1611,31 +1656,36 @@ int xmssmt_key_generate(XMSSMT_KEY *key, uint32_t xmssmt_type) adrs_set_tree_address(adrs, xmssmt_tree_address(index, height, layers, layer)); xmss_build_tree(key->secret, key->public_key.seed, adrs, height/layers, tree); + + xmss_root = tree[tree_root_offset(height/layers)]; + tree += xmss_tree_num_nodes(height/layers); + // sign xmss_root with higher layer if (layer < layers - 1) { - adrs_set_layer_address(adrs, layer + 1); adrs_set_tree_address(adrs, xmssmt_tree_address(index, height, layers, layer + 1)); adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS); adrs_set_ots_address(adrs, xmssmt_tree_index(index, height, layers, layer + 1)); - wots_derive_sk(key->secret, key->public_key.seed, adrs, key->wots_sigs[layer]); - //tree = key->trees + xmss_tree_num_nodes(height/layers) * layer; - xmss_root = tree[tree_root_offset(height/layers)]; - wots_sign(key->wots_sigs[layer], key->public_key.seed, adrs, xmss_root, key->wots_sigs[layer]); - tree += xmss_tree_num_nodes(height/layers); + /* + hash256_t *tree2 = key->trees + xmss_tree_num_nodes(height/layers) * layer; + hash256_t xmss_root2 = tree2[tree_root_offset(height/layers)]; + + + fprintf(stderr, "%p %p\n", tree, tree2); + fprintf(stderr, "%p %p\n", xmss_root, xmss_root2); + */ + + + wots_sign(key->wots_sigs[layer], key->public_key.seed, adrs, xmss_root, key->wots_sigs[layer]); } } - - - // copy the top-level root memcpy(key->public_key.root, xmss_root, sizeof(hash256_t)); - tree = key->trees; @@ -1643,6 +1693,8 @@ int xmssmt_key_generate(XMSSMT_KEY *key, uint32_t xmssmt_type) wots_key_t wots_pk; + // extra check + for (layer = 0; layer < layers - 1; layer++) { uint8_t *dgst = tree[tree_root_offset(height/layers)]; @@ -1672,6 +1724,37 @@ int xmssmt_key_generate(XMSSMT_KEY *key, uint32_t xmssmt_type) return 1; } +int xmssmt_key_generate(XMSSMT_KEY *key, uint32_t xmssmt_type) +{ + + hash256_t seed; + hash256_t secret; + hash256_t sk_prf; + + + if (rand_bytes(seed, sizeof(hash256_t)) != 1) { + error_print(); + return -1; + } + + if (rand_bytes(secret, sizeof(hash256_t)) != 1) { + error_print(); + return -1; + } + if (rand_bytes(sk_prf, sizeof(hash256_t)) != 1) { + error_print(); + return -1; + } + + if (xmssmt_key_generate_ex(key, xmssmt_type, seed, secret, sk_prf) != 1) { + error_print(); + return -1; + } + + return 1; +} + + // change API as xmss_build_auth_path int xmssmt_key_build_auth_path(const XMSSMT_KEY *key, hash256_t *auth_path) { @@ -1744,10 +1827,9 @@ int xmssmt_private_key_print(FILE *fp, int fmt, int ind, const char *label, cons tree = key->trees; for (i = 0; i < layers; i++) { char label[64]; - snprintf(label, sizeof(label), "layer %zu root", i); - format_bytes(stderr, 0, 0, label, tree[tree_root_offset(height/layers)], 32); + snprintf(label, sizeof(label), "xmss_root[%zu]", i); + format_bytes(fp, fmt, ind, label, tree[tree_root_offset(height/layers)], 32); tree += xmss_tree_num_nodes(height/layers); - } return 1; @@ -1945,7 +2027,9 @@ int xmssmt_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, con format_print(fp, fmt, ind, "%s\n", label); ind += 4; - format_print(fp, fmt, ind, "index: %"PRIu64"\n", sig->index); + + //format_print(fp, fmt, ind, "index: %"PRIu64"----\n", sig->index); + format_print(fp, fmt, ind, "index: %llu\n", (unsigned long long)sig->index); format_bytes(fp, fmt, ind, "random", sig->random, 32); for (layer = 0; layer < layers; layer++) { @@ -1985,7 +2069,8 @@ int xmssmt_signature_print(FILE *fp, int fmt, int ind, const char *label, const error_print(); return -1; } - format_print(fp, fmt, ind, "index: %u"PRIu64"\n", index); + //format_print(fp, fmt, ind, "index: %u"PRIu64"\n", index); + format_print(fp, fmt, ind, "index: %llu\n", (unsigned long long)index); if (siglen < sizeof(hash256_t)) { error_print(); @@ -2028,50 +2113,16 @@ int xmssmt_signature_print(FILE *fp, int fmt, int ind, const char *label, const } -int xmssmt_key_update(XMSSMT_KEY *key) -{ - - size_t height; - size_t layers; - size_t layer; - - - if (xmssmt_type_to_height_and_layers(key->public_key.xmssmt_type, &height, &layers) != 1) { - error_print(); - return -1; - } - - - // 这里我们要检查当前的layer - for (layer = layers - 1; layer > 0; layer--) { - - - - } - - - if (layer >= layers ) { - - - } - - - if (layer == 0) { - return 0; - } - - - for (; layer < layers; layer++) { - } - return 1; -} + + + int xmssmt_sign_init(XMSSMT_SIGN_CTX *ctx, XMSSMT_KEY *key) @@ -2093,6 +2144,11 @@ int xmssmt_sign_init(XMSSMT_SIGN_CTX *ctx, XMSSMT_KEY *key) return -1; } + if (key->index >= (1 << height)) { + error_print(); + return -1; + } + // init sign ctx memset(ctx, 0, sizeof(XMSSMT_SIGN_CTX)); @@ -2143,14 +2199,8 @@ int xmssmt_sign_init(XMSSMT_SIGN_CTX *ctx, XMSSMT_KEY *key) hash256_update(&ctx->hash256_ctx, key->public_key.root, sizeof(hash256_t)); hash256_update(&ctx->hash256_ctx, hash256_index, sizeof(hash256_t)); - size_t remaining_signs; - - // 增加key_update - if (remaining_signs == 0) { - - - } + xmssmt_key_update(key); return 1; } @@ -2258,6 +2308,8 @@ int xmssmt_verify_init_ex(XMSSMT_SIGN_CTX *ctx, const XMSSMT_KEY *key, const XMS return 1; } + +// check compatible publickey and sig int xmssmt_verify_init(XMSSMT_SIGN_CTX *ctx, const XMSSMT_KEY *key, const uint8_t *sig, size_t siglen) { hash256_t hash256_index; diff --git a/tests/xmsstest.c b/tests/xmsstest.c index 2acb6d5c..7b9fed75 100644 --- a/tests/xmsstest.c +++ b/tests/xmsstest.c @@ -404,21 +404,6 @@ static int test_xmss_key_to_bytes(void) return 1; } - - - - - - - - - - - - - - - // XMSS_SM3_10_256 2500 bytes // XMSS_SM3_16_256 2692 bytes // XMSS_SM3_20_256 2820 bytes @@ -743,6 +728,16 @@ static int test_xmssmt_signature_to_bytes(void) return 1; } +/* +XMSSMT_SHA2_20_2_256: 133287 133KB +XMSSMT_SHA2_20_4_256: 14631 14KB +XMSSMT_SHA2_40_2_256: 134219945 134MB +XMSSMT_SHA2_40_4_256: 268585 268KB +XMSSMT_SHA2_40_8_256: 31273 31KB +XMSSMT_SHA2_60_3_256: 201330924 201MB +XMSSMT_SHA2_60_6_256: 403884 403KB +XMSSMT_SHA2_60_12_256: 47916 47KB +*/ static int test_xmssmt_private_key_size(void) { uint32_t xmssmt_types[] = { @@ -764,7 +759,7 @@ static int test_xmssmt_private_key_size(void) error_print(); return -1; } - fprintf(stderr, "%s: %zu\n", xmssmt_type_name(xmssmt_types[i]), len); + fprintf(stderr, " %s: %zu\n", xmssmt_type_name(xmssmt_types[i]), len); } printf("%s() ok\n", __FUNCTION__); @@ -993,6 +988,7 @@ static int test_xmssmt_sign(void) hash256_update(&ctx->hash256_ctx, ctx->xmssmt_sig.random, sizeof(hash256_t)); hash256_update(&ctx->hash256_ctx, key->public_key.root, sizeof(hash256_t)); hash256_update(&ctx->hash256_ctx, hash256_index, sizeof(hash256_t)); + hash256_update(&ctx->hash256_ctx, msg, sizeof(msg)); hash256_finish(&ctx->hash256_ctx, dgst); // generate message wots_sig as wots_sigs[0] @@ -1046,6 +1042,51 @@ static int test_xmssmt_sign(void) return 1; } +static int test_xmssmt_sign_update(void) +{ + uint32_t xmssmt_type = XMSSMT_HASH256_20_4_256; + XMSSMT_KEY key; + XMSSMT_SIGN_CTX ctx; + XMSSMT_SIGNATURE sig; + uint8_t msg[100] = {0}; + + + if (xmssmt_key_generate(&key, xmssmt_type) != 1) { + error_print(); + return -1; + } + + + if (xmssmt_sign_init(&ctx, &key) != 1) { + error_print(); + return -1; + } + if (xmssmt_sign_update(&ctx, msg, sizeof(msg)) != 1) { + error_print(); + return -1; + } + if (xmssmt_sign_finish_ex(&ctx, &sig) != 1) { + error_print(); + return -1; + } + + memset(&ctx, 0, sizeof(ctx)); + if (xmssmt_verify_init_ex(&ctx, &key, &sig) != 1) { + error_print(); + return -1; + } + if (xmssmt_verify_update(&ctx, msg, sizeof(msg)) != 1) { + error_print(); + return -1; + } + if (xmssmt_verify_finish(&ctx) != 1) { + error_print(); + return -1; + } + + printf("%s() ok\n", __FUNCTION__); + return 1; +} int main(void) { @@ -1075,7 +1116,7 @@ int main(void) if (test_xmssmt_public_key_to_bytes() != 1) goto err; if (test_xmssmt_private_key_to_bytes() != 1) goto err; if (test_xmssmt_sign() != 1) goto err; - + if (test_xmssmt_sign_update() != 1) goto err; printf("%s all tests passed\n", __FILE__); return 0; diff --git a/tools/gmssl.c b/tools/gmssl.c index 1701c03f..eeb65eac 100644 --- a/tools/gmssl.c +++ b/tools/gmssl.c @@ -76,6 +76,9 @@ extern int hssverify_main(int argc, char **argv); extern int xmsskeygen_main(int argc, char **argv); extern int xmsssign_main(int argc, char **argv); extern int xmssverify_main(int argc, char **argv); +extern int xmssmtkeygen_main(int argc, char **argv); +extern int xmssmtsign_main(int argc, char **argv); +extern int xmssmtverify_main(int argc, char **argv); #endif #ifdef ENABLE_KYBER extern int kyberkeygen_main(int argc, char **argv); @@ -158,6 +161,9 @@ static const char *options = " xmsskeygen Generate XMSS-SM3 keypair\n" " xmsssign Generate XMSS-SM3 signature\n" " xmssverify Verify XMSS-SM3 signature\n" + " xmssmtkeygen Generate XMSS^MT-SM3 keypair\n" + " xmssmtsign Generate XMSS^MT-SM3 signature\n" + " xmssmtverify Verify XMSS^MT-SM3 signature\n" #endif #ifdef ENABLE_KYBER " kyberkeygen Generate Kyber keypair\n" @@ -339,6 +345,12 @@ int main(int argc, char **argv) return xmsssign_main(argc, argv); } else if (!strcmp(*argv, "xmssverify")) { return xmssverify_main(argc, argv); + } else if (!strcmp(*argv, "xmssmtkeygen")) { + return xmssmtkeygen_main(argc, argv); + } else if (!strcmp(*argv, "xmssmtsign")) { + return xmssmtsign_main(argc, argv); + } else if (!strcmp(*argv, "xmssmtverify")) { + return xmssmtverify_main(argc, argv); #endif #ifdef ENABLE_KYBER } else if (!strcmp(*argv, "kyberkeygen")) { diff --git a/tools/xmssmtkeygen.c b/tools/xmssmtkeygen.c new file mode 100644 index 00000000..18c8869c --- /dev/null +++ b/tools/xmssmtkeygen.c @@ -0,0 +1,162 @@ +/* + * Copyright 2014-2026 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include + + +static const char *usage = "-xmssmt_type type -out file [-pubout file] [-verbose]\n"; + +static const char *options = +"Options\n" +" -xmssmt_type type XMSSMT Algorithm Type\n" +" "XMSSMT_HASH256_20_2_256_NAME"\n" +" "XMSSMT_HASH256_20_4_256_NAME"\n" +" "XMSSMT_HASH256_40_2_256_NAME"\n" +" "XMSSMT_HASH256_40_4_256_NAME"\n" +" "XMSSMT_HASH256_40_8_256_NAME"\n" +" "XMSSMT_HASH256_60_3_256_NAME"\n" +" "XMSSMT_HASH256_60_6_256_NAME"\n" +" "XMSSMT_HASH256_60_12_256_NAME"\n" +" -out file Output private key\n" +" -pubout file Output public key\n" +" -verbose Print public key\n" +"\n"; + +int xmssmtkeygen_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + char *xmssmt_type = NULL; + int xmssmt_type_val = 0; + char *outfile = NULL; + char *puboutfile = NULL; + int verbose = 0; + FILE *outfp = NULL; + FILE *puboutfp = stdout; + XMSSMT_KEY key; + uint8_t *out = NULL; + uint8_t pubout[XMSSMT_PUBLIC_KEY_SIZE]; + uint8_t *pout; + uint8_t *ppubout = pubout; + size_t outlen = 0, puboutlen = 0; + + memset(&key, 0, sizeof(key)); + + 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, "-xmssmt_type")) { + if (--argc < 1) goto bad; + xmssmt_type = *(++argv); + if (!(xmssmt_type_val = xmssmt_type_from_name(xmssmt_type))) { + fprintf(stderr, "%s: invalid xmssmt_type `%s`\n", prog, xmssmt_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 (!xmssmt_type) { + fprintf(stderr, "%s: `-xmssmt_type` option required\n", prog); + goto end; + } + if (!outfp) { + fprintf(stderr, "%s: `-out` option required\n", prog); + goto end; + } + + if (xmssmt_key_generate(&key, xmssmt_type_val) != 1) { + error_print(); + return -1; + } + if (verbose) { + xmssmt_public_key_print(stderr, 0, 0, "xmssmt_public_key", &key); + } + + if (xmssmt_private_key_size(xmssmt_type_val, &outlen) != 1) { + error_print(); + goto end; + } + if (!(out = malloc(outlen))) { + error_print(); + goto end; + } + pout = out; + outlen = 0; + if (xmssmt_private_key_to_bytes(&key, &pout, &outlen) != 1) { + error_print(); + goto end; + } + if (fwrite(out, 1, outlen, outfp) != outlen) { + error_print(); + goto end; + } + + if (xmssmt_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: + //xmss_key_cleanup(&key); + if (out) { + gmssl_secure_clear(out, outlen); + free(out); + } + if (outfile && outfp) fclose(outfp); + if (puboutfile && puboutfp) fclose(puboutfp); + return ret; +} diff --git a/tools/xmssmtsign.c b/tools/xmssmtsign.c new file mode 100644 index 00000000..17a0e605 --- /dev/null +++ b/tools/xmssmtsign.c @@ -0,0 +1,199 @@ +/* + * Copyright 2014-2026 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * 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 xmssmtsign_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 pubkey[XMSSMT_PUBLIC_KEY_SIZE]; + uint8_t *keybuf = NULL; + size_t keylen; + const uint8_t *cp; + uint8_t *p; + XMSSMT_KEY key; + XMSSMT_SIGN_CTX ctx; + uint8_t sig[XMSSMT_SIGNATURE_MAX_SIZE]; + size_t siglen; + + memset(&key, 0, sizeof(key)); + + 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(pubkey, 1, sizeof(pubkey), keyfp) != sizeof(pubkey)) { + error_print(); + goto end; + } + cp = pubkey; + keylen = sizeof(pubkey); + if (xmssmt_public_key_from_bytes(&key, &cp, &keylen) != 1 ) { + error_print(); + goto end; + } + + + if (xmssmt_private_key_size(key.public_key.xmssmt_type, &keylen) != 1) { + error_print(); + goto end; + } + if (!(keybuf = malloc(keylen))) { + error_print(); + goto end; + } + memcpy(keybuf, pubkey, sizeof(pubkey)); + + + if (fread(keybuf + sizeof(pubkey), 1, keylen - sizeof(pubkey), keyfp) != keylen - sizeof(pubkey)) { + fprintf(stderr, "%s: read private key failure\n", prog); + goto end; + } + cp = keybuf; + if (xmssmt_private_key_from_bytes(&key, &cp, &keylen) != 1) { + error_print(); + goto end; + } + if (keylen) { + error_print(); + return -1; + } + + if (verbose) { + xmssmt_public_key_print(stderr, 0, 0, "lms_public_key", &key); + } + + if (xmssmt_sign_init(&ctx, &key) != 1) { + error_print(); + goto end; + } + + // write updated key back to file + // TODO: write back `q` only + p = keybuf; + keylen = 0; + if (xmssmt_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 (xmssmt_sign_update(&ctx, buf, len) != 1) { + error_print(); + goto end; + } + } + if (xmssmt_sign_finish(&ctx, sig, &siglen) != 1) { + error_print(); + goto end; + } + if (fwrite(sig, 1, siglen, outfp) != siglen) { + error_print(); + goto end; + } + if (verbose) { + xmssmt_signature_print(stderr, 0, 0, "xmssmt_signature", sig, siglen, key.public_key.xmssmt_type); + } + + ret = 0; + +end: + //xmss_key_cleanup(&key); + gmssl_secure_clear(keybuf, keylen); + 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/xmssmtverify.c b/tools/xmssmtverify.c new file mode 100644 index 00000000..f4e02bd7 --- /dev/null +++ b/tools/xmssmtverify.c @@ -0,0 +1,158 @@ +/* + * Copyright 2014-2026 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * 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 xmssmtverify_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[XMSSMT_PUBLIC_KEY_SIZE]; + size_t pubkeylen = XMSSMT_PUBLIC_KEY_SIZE; + const uint8_t *cp = pubkeybuf; + uint8_t sig[XMSSMT_SIGNATURE_MAX_SIZE]; + size_t siglen; + XMSSMT_KEY key; + XMSSMT_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 (xmssmt_public_key_from_bytes(&key, &cp, &pubkeylen) != 1) { + error_print(); + fprintf(stderr, "%s: invalid public key data\n", prog); + goto end; + } + if (verbose) { + xmssmt_public_key_print(stderr, 0, 0, "xmssmt_public_key", &key); + } + + // read signature even if signature not compatible with the public key + if ((siglen = fread(sig, 1, XMSSMT_SIGNATURE_MAX_SIZE, sigfp)) <= 0) { + fprintf(stderr, "%s: read signature failure\n", prog); + goto end; + } + if (verbose) { + xmssmt_signature_print(stderr, 0, 0, "xmssmt_signature", sig, siglen, key.public_key.xmssmt_type); + } + if (xmssmt_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 (xmssmt_verify_update(&ctx, buf, len) != 1) { + error_print(); + goto end; + } + } + if ((vr = xmssmt_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/xmsssign.c b/tools/xmsssign.c index 8cee58bd..08366cad 100644 --- a/tools/xmsssign.c +++ b/tools/xmsssign.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2025 The GmSSL Project. All Rights Reserved. + * Copyright 2014-2026 The GmSSL Project. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. @@ -156,7 +156,7 @@ bad: goto end; } if (verbose) { - xmss_signature_print(stderr, 0, 0, "lms_signature", sig, siglen); + xmss_signature_print(stderr, 0, 0, "xmss_signature", sig, siglen); } ret = 0;