Add SPHINCS+ commands to gmssl

Add `sphincskeygen`, `sphincssign`, `sphincsverify`
This commit is contained in:
Zhi Guan
2026-01-11 21:30:05 +08:00
parent 58a51a8474
commit 1f64cb7389
7 changed files with 739 additions and 11 deletions

View File

@@ -56,7 +56,7 @@ option(ENABLE_SM2_EXTS "Enable SM2 Extensions" OFF)
option(ENABLE_LMS_HSS "Enable LMS/HSS signature" ON) option(ENABLE_LMS_HSS "Enable LMS/HSS signature" ON)
option(ENABLE_XMSS "Enable XMSS/XMSS^MT signature" ON) option(ENABLE_XMSS "Enable XMSS/XMSS^MT signature" ON)
option(ENABLE_SPHINCS "Enable SPHINCS+ signature" OFF) option(ENABLE_SPHINCS "Enable SPHINCS+ signature" ON)
option(ENABLE_KYBER "Enable Kyber" OFF) option(ENABLE_KYBER "Enable Kyber" OFF)
option(ENABLE_SHA1 "Enable SHA1" ON) option(ENABLE_SHA1 "Enable SHA1" ON)
@@ -454,7 +454,7 @@ if (ENABLE_SPHINCS)
message(STATUS "ENABLE_SPHINCS is ON") message(STATUS "ENABLE_SPHINCS is ON")
add_definitions(-DENABLE_SPHINCS) add_definitions(-DENABLE_SPHINCS)
list(APPEND src src/sphincs.c) list(APPEND src src/sphincs.c)
#list(APPEND tools tools/sphincskeygen.c tools/sphincssign.c tools/sphincsverify.c) list(APPEND tools tools/sphincskeygen.c tools/sphincssign.c tools/sphincsverify.c)
list(APPEND tests sphincs) list(APPEND tests sphincs)
option(ENABLE_SPHINCS_CROSSCHECK "Enable SPHINCS SHA-256 cross-check" ON) option(ENABLE_SPHINCS_CROSSCHECK "Enable SPHINCS SHA-256 cross-check" ON)
@@ -486,6 +486,7 @@ if (ENABLE_SHA2)
message(STATUS "ENABLE_SHA2 is ON") message(STATUS "ENABLE_SHA2 is ON")
add_definitions(-DENABLE_SHA2) add_definitions(-DENABLE_SHA2)
list(APPEND src src/sha256.c src/sha512.c) list(APPEND src src/sha256.c src/sha512.c)
list(APPEND src src/sha256_hmac.c)
list(APPEND tests sha224 sha256 sha384 sha512) list(APPEND tests sha224 sha256 sha384 sha512)
endif() endif()

View File

@@ -32,12 +32,20 @@ extern "C" {
# define hash256_update sha256_update # define hash256_update sha256_update
# define hash256_finish sha256_finish # define hash256_finish sha256_finish
# define HASH256_BLOCK_SIZE SHA256_BLOCK_SIZE # define HASH256_BLOCK_SIZE SHA256_BLOCK_SIZE
# define HASH256_HMAC_CTX SHA256_HMAC_CTX
# define hash256_hmac_init sha256_hmac_init
# define hash256_hmac_update sha256_hmac_update
# define hash256_hmac_finish sha256_hmac_finish
#else #else
# define HASH256_CTX SM3_CTX # define HASH256_CTX SM3_CTX
# define hash256_init sm3_init # define hash256_init sm3_init
# define hash256_update sm3_update # define hash256_update sm3_update
# define hash256_finish sm3_finish # define hash256_finish sm3_finish
# define HASH256_BLOCK_SIZE SM3_BLOCK_SIZE # define HASH256_BLOCK_SIZE SM3_BLOCK_SIZE
# define HASH256_HMAC_CTX SM3_HMAC_CTX
# define hash256_hmac_init sm3_hmac_init
# define hash256_hmac_update sm3_hmac_update
# define hash256_hmac_finish sm3_hmac_finish
#endif #endif
@@ -256,7 +264,6 @@ void sphincs_wots_pk_to_root(const sphincs_wots_key_t pk,
total: 30 bytes, 1 MGF1-SM3 output total: 30 bytes, 1 MGF1-SM3 output
SPHINCS+_128f/SM3 SPHINCS+_128f/SM3
1. fors_index: 6 * 33 = 198 bits = 25 bytes 1. fors_index: 6 * 33 = 198 bits = 25 bytes
@@ -266,6 +273,14 @@ void sphincs_wots_pk_to_root(const sphincs_wots_key_t pk,
*/ */
#define SPHINCS_TBS_SIZE 30 // sphincs+_128s
#define SPHINCS_TBS_FORS_SIZE 21
#define SPHINCS_TBS_TREE_ADDRESS_SIZE 7
#define SPHINCS_TBS_KEYPAIR_ADDRESS_SIZE 2
// #define SPHINCS_TBS_SIZE 34 // sphincs+_128f
void sphincs_xmss_tree_hash( void sphincs_xmss_tree_hash(
@@ -285,9 +300,15 @@ void sphincs_xmss_build_root(const sphincs_hash128_t wots_root, uint32_t tree_in
typedef struct { typedef struct {
sphincs_wots_sig_t wots_sig; sphincs_wots_sig_t wots_sig;
sphincs_hash128_t auth_path[22]; // sphincs+_128f height = 22 sphincs_hash128_t auth_path[SPHINCS_XMSS_HEIGHT];
} SPHINCS_XMSS_SIGNATURE; } SPHINCS_XMSS_SIGNATURE;
int sphincs_xmss_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const SPHINCS_XMSS_SIGNATURE *sig);
int sphincs_xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen);
int sphincs_xmss_signature_to_bytes(const SPHINCS_XMSS_SIGNATURE *sig, uint8_t **out, size_t *outlen);
int sphincs_xmss_signature_from_bytes(SPHINCS_XMSS_SIGNATURE *sig, const uint8_t **in, size_t *inlen);
void sphincs_xmss_sign(const sphincs_hash128_t secret, void sphincs_xmss_sign(const sphincs_hash128_t secret,
const sphincs_hash128_t seed, const sphincs_adrs_t adrs, uint32_t keypair_address, const sphincs_hash128_t seed, const sphincs_adrs_t adrs, uint32_t keypair_address,
const sphincs_hash128_t tbs_root, // to be signed xmss_root or fors_forest_root const sphincs_hash128_t tbs_root, // to be signed xmss_root or fors_forest_root
@@ -361,6 +382,8 @@ typedef struct {
#define SPHINCS_PUBLIC_KEY_SIZE sizeof(SPHINCS_PUBLIC_KEY) #define SPHINCS_PUBLIC_KEY_SIZE sizeof(SPHINCS_PUBLIC_KEY)
#define SPHINCS_PRIVATE_KEY_SIZE sizeof(SPHINCS_KEY) #define SPHINCS_PRIVATE_KEY_SIZE sizeof(SPHINCS_KEY)
int sphincs_key_generate(SPHINCS_KEY *key);
int sphincs_public_key_to_bytes(const SPHINCS_KEY *key, uint8_t **out, size_t *outlen); int sphincs_public_key_to_bytes(const SPHINCS_KEY *key, uint8_t **out, size_t *outlen);
int sphincs_public_key_from_bytes(SPHINCS_KEY *key, const uint8_t **in, size_t *inlen); int sphincs_public_key_from_bytes(SPHINCS_KEY *key, const uint8_t **in, size_t *inlen);
int sphincs_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SPHINCS_KEY *key); int sphincs_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SPHINCS_KEY *key);
@@ -370,12 +393,15 @@ int sphincs_private_key_print(FILE *fp, int fmt, int ind, const char *label, con
void sphincs_key_cleanup(SPHINCS_KEY *key); void sphincs_key_cleanup(SPHINCS_KEY *key);
typedef struct { typedef struct {
sphincs_hash128_t random; sphincs_hash128_t random;
SPHINCS_FORS_SIGNATURE fors_sig; SPHINCS_FORS_SIGNATURE fors_sig;
SPHINCS_XMSS_SIGNATURE xmss_sigs[SPHINCS_HYPERTREE_LAYERS]; SPHINCS_XMSS_SIGNATURE xmss_sigs[SPHINCS_HYPERTREE_LAYERS];
} SPHINCS_SIGNATURE; } SPHINCS_SIGNATURE;
#define SPHINCS_SIGNATURE_SIZE sizeof(SPHINCS_SIGNATURE)
int sphincs_signature_to_bytes(const SPHINCS_SIGNATURE *sig, uint8_t **out, size_t *outlen); int sphincs_signature_to_bytes(const SPHINCS_SIGNATURE *sig, uint8_t **out, size_t *outlen);
int sphincs_signature_from_bytes(SPHINCS_SIGNATURE *sig, const uint8_t **in, size_t *inlen); int sphincs_signature_from_bytes(SPHINCS_SIGNATURE *sig, const uint8_t **in, size_t *inlen);
int sphincs_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const SPHINCS_SIGNATURE *sig); int sphincs_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const SPHINCS_SIGNATURE *sig);
@@ -383,6 +409,41 @@ int sphincs_signature_print(FILE *fp, int fmt, int ind, const char *label, const
typedef struct {
HASH256_HMAC_CTX hmac_ctx;
HASH256_CTX hash_ctx;
SPHINCS_SIGNATURE sig;
int state; // after init 0, after prepare 1, after update 2
size_t round1_msglen;
size_t round2_msglen;
SPHINCS_KEY key;
} SPHINCS_SIGN_CTX;
int sphincs_sign_init_ex(SPHINCS_SIGN_CTX *ctx, const SPHINCS_KEY *key, int randomize);
int sphincs_sign_init(SPHINCS_SIGN_CTX *ctx, const SPHINCS_KEY *key);
int sphincs_sign_prepare(SPHINCS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
int sphincs_sign_update(SPHINCS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
int sphincs_sign_finish_ex(SPHINCS_SIGN_CTX *ctx, SPHINCS_SIGNATURE *sig);
int sphincs_sign_finish(SPHINCS_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen);
int sphincs_verify_init_ex(SPHINCS_SIGN_CTX *ctx, const SPHINCS_KEY *key, const SPHINCS_SIGNATURE *sig);
int sphincs_verify_init(SPHINCS_SIGN_CTX *ctx, const SPHINCS_KEY *key, const uint8_t *sig, size_t siglen);
int sphincs_verify_update(SPHINCS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
int sphincs_verify_finish(SPHINCS_SIGN_CTX *ctx);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -425,29 +425,212 @@ static int test_sphincs_fors_sign(void)
return 1; return 1;
} }
static int test_sphincs_sign(void) static int test_sphincs_sign(void)
{ {
SPHINCS_KEY key; SPHINCS_KEY _key;
SPHINCS_KEY *key = &_key;
uint8_t msg[100] = {1, 2, 3, 0};
SPHINCS_SIGNATURE _sig;
SPHINCS_SIGNATURE *sig = &_sig;
HASH256_CTX hash_ctx;
HASH256_HMAC_CTX hmac_ctx;
hash256_t dgst;
sphincs_hash128_t opt_rand;
sphincs_adrs_t adrs = {0}; sphincs_adrs_t adrs = {0};
sphincs_hash128_t random; sphincs_hash128_t fors_forest_root;
uint8_t tree_address_buf[8] = {0};
uint8_t keypair_address_buf[4] = {0};
uint64_t tree_address;
uint32_t keypair_address;
int randomize = 0;
uint32_t i;
uint8_t tbs[SPHINCS_TBS_SIZE];
if (sphincs_key_generate(key) != 1) {
error_print();
return -1;
}
uint32_t tree_index; // set opt_rand
uint32_t leaf_index; memcpy(opt_rand, key->public_key.seed, sizeof(sphincs_hash128_t));
if (randomize) {
if (rand_bytes(opt_rand, sizeof(opt_rand)) != 1) {
error_print();
return -1;
}
}
// 如果R是用M生成的这意味着M要读取2遍这就没办法用init/update范式了
// R = PRF_msg(sk_prf, optrand, M) = HMAC(sk_prf, opt_rand|M)
hash256_hmac_init(&hmac_ctx, key->sk_prf, sizeof(sphincs_hash128_t));
hash256_hmac_update(&hmac_ctx, opt_rand, sizeof(sphincs_hash128_t));
hash256_hmac_update(&hmac_ctx, msg, sizeof(msg));
hash256_hmac_finish(&hmac_ctx, dgst);
memcpy(sig->random, dgst, sizeof(sphincs_hash128_t));
// dgst = HASH256(R|seed|root|M)
hash256_init(&hash_ctx);
hash256_update(&hash_ctx, sig->random, sizeof(sphincs_hash128_t));
hash256_update(&hash_ctx, key->public_key.seed, sizeof(sphincs_hash128_t));
hash256_update(&hash_ctx, key->public_key.root, sizeof(sphincs_hash128_t));
hash256_update(&hash_ctx, msg, sizeof(msg));
hash256_finish(&hash_ctx, dgst);
// tbs = H_msg(R, seed, root, M) = MGF1(R|seed|dgst, tbs_len)
for (i = 0; i < (SPHINCS_TBS_SIZE + 31)/32; i++) {
uint8_t count[4];
PUTU32(count, i);
hash256_init(&hash_ctx);
hash256_update(&hash_ctx, sig->random, sizeof(sphincs_hash128_t));
hash256_update(&hash_ctx, key->public_key.seed, sizeof(sphincs_hash128_t));
hash256_update(&hash_ctx, dgst, sizeof(dgst));
hash256_update(&hash_ctx, count, sizeof(count));
hash256_finish(&hash_ctx, tbs + sizeof(dgst) * i);
}
// get tree_address from tbs
memcpy(tree_address_buf + 8 - 7, tbs + 21, 7);
tree_address = GETU64(tree_address_buf); // 54 bits
tree_address >>= 10;
// get keypair_address from tbs
memcpy(keypair_address_buf + 4 - 2, tbs + 21 + 7, 2);
keypair_address = GETU32(keypair_address_buf);
keypair_address >>= (16 - 9);
format_bytes(stderr, 0, 4, "tree_address", tree_address_buf, 8);
format_bytes(stderr, 0, 4, "keypair_address", keypair_address_buf, 4);
fprintf(stderr, "tree_address %zu\n", (size_t)tree_address);
fprintf(stderr, "keypair_address %zu\n", (size_t)keypair_address);
// fors_sign
sphincs_adrs_set_layer_address(adrs, 0); sphincs_adrs_set_layer_address(adrs, 0);
sphincs_adrs_set_tree_address(adrs, tree_index); sphincs_adrs_set_tree_address(adrs, tree_address);
sphincs_adrs_set_type(adrs, SPHINCS_ADRS_TYPE_FORS_TREE); sphincs_adrs_set_type(adrs, SPHINCS_ADRS_TYPE_FORS_TREE);
sphincs_adrs_set_keypair_address(adrs, leaf_index); sphincs_adrs_set_keypair_address(adrs, keypair_address);
sphincs_fors_sign(key->secret, key->public_key.seed, adrs, tbs, &sig->fors_sig);
// fors_sig => fors_forest_root
sphincs_fors_sig_to_root(&sig->fors_sig, key->public_key.seed, adrs, tbs, fors_forest_root);
error_print();
// hypertree_sign fors_forest_root
sphincs_adrs_set_type(adrs, SPHINCS_ADRS_TYPE_TREE);
sphincs_hypertree_sign(key->secret, key->public_key.seed, tree_address, keypair_address,
fors_forest_root, sig->xmss_sigs);
error_print();
// sphincs_verify
// --------------
// fors_sig => fors_forest_root
sphincs_adrs_set_layer_address(adrs, 0);
sphincs_adrs_set_tree_address(adrs, tree_address);
sphincs_adrs_set_type(adrs, SPHINCS_ADRS_TYPE_FORS_TREE);
sphincs_adrs_set_keypair_address(adrs, keypair_address);
sphincs_fors_sig_to_root(&sig->fors_sig, key->public_key.seed, adrs, tbs, fors_forest_root);
// hypertree_verify
sphincs_adrs_set_type(adrs, SPHINCS_ADRS_TYPE_TREE);
if (sphincs_hypertree_verify(key->public_key.root, key->public_key.seed,
tree_address, keypair_address, fors_forest_root, sig->xmss_sigs) != 1) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__); printf("%s() ok\n", __FUNCTION__);
return 1; return 1;
} }
static int test_sphincs_sign_update(void)
{
SPHINCS_KEY key;
SPHINCS_SIGN_CTX ctx;
SPHINCS_SIGNATURE sig;
uint8_t msg[100] = { 1,2,3 };
if (sphincs_key_generate(&key) != 1) {
error_print();
return -1;
}
if (sphincs_sign_init(&ctx, &key) != 1) {
error_print();
return -1;
}
if (sphincs_sign_prepare(&ctx, msg, sizeof(msg)) != 1) {
error_print();
return -1;
}
if (sphincs_sign_update(&ctx, msg, sizeof(msg)) != 1) {
error_print();
return -1;
}
if (sphincs_sign_finish_ex(&ctx, &sig) != 1) {
error_print();
return -1;
}
// verify
if (sphincs_verify_init_ex(&ctx, &key, &sig) != 1) {
error_print();
return -1;
}
if (sphincs_verify_update(&ctx, msg, sizeof(msg)) != 1) {
error_print();
return -1;
}
if (sphincs_verify_finish(&ctx) != 1) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
int main(void) int main(void)
{ {
if (test_sphincs_fors_sign() != 1) goto err; if (test_sphincs_sign_update() != 1) goto err;
// if (test_sphincs_sign() != 1) goto err;
// if (test_sphincs_fors_sign() != 1) goto err;
//if (test_sphincs_xmss_build_tree() != 1) goto err; //if (test_sphincs_xmss_build_tree() != 1) goto err;
//if (test_sphincs_hypertree() != 1) goto err; //if (test_sphincs_hypertree() != 1) goto err;
// if (test_sphincs_hypertree_sign() != 1) goto err; // if (test_sphincs_hypertree_sign() != 1) goto err;

View File

@@ -80,6 +80,11 @@ extern int xmssmtkeygen_main(int argc, char **argv);
extern int xmssmtsign_main(int argc, char **argv); extern int xmssmtsign_main(int argc, char **argv);
extern int xmssmtverify_main(int argc, char **argv); extern int xmssmtverify_main(int argc, char **argv);
#endif #endif
#ifdef ENABLE_SPHINCS
extern int sphincskeygen_main(int argc, char **argv);
extern int sphincssign_main(int argc, char **argv);
extern int sphincsverify_main(int argc, char **argv);
#endif
#ifdef ENABLE_KYBER #ifdef ENABLE_KYBER
extern int kyberkeygen_main(int argc, char **argv); extern int kyberkeygen_main(int argc, char **argv);
extern int kyberencap_main(int argc, char **argv); extern int kyberencap_main(int argc, char **argv);
@@ -165,6 +170,11 @@ static const char *options =
" xmssmtsign Generate XMSS^MT-SM3 signature\n" " xmssmtsign Generate XMSS^MT-SM3 signature\n"
" xmssmtverify Verify XMSS^MT-SM3 signature\n" " xmssmtverify Verify XMSS^MT-SM3 signature\n"
#endif #endif
#ifdef ENABLE_SPHINCS
" sphincskeygen Generate SPHINCS+_128s-SM3 keypair\n"
" sphincssign Generate SPHINCS+_128s-SM3 signature\n"
" sphincsverify Verify SPHINCS+_128s-SM3 signature\n"
#endif
#ifdef ENABLE_KYBER #ifdef ENABLE_KYBER
" kyberkeygen Generate Kyber keypair\n" " kyberkeygen Generate Kyber keypair\n"
" kyberencap Kyber KEM encap\n" " kyberencap Kyber KEM encap\n"
@@ -352,6 +362,14 @@ int main(int argc, char **argv)
} else if (!strcmp(*argv, "xmssmtverify")) { } else if (!strcmp(*argv, "xmssmtverify")) {
return xmssmtverify_main(argc, argv); return xmssmtverify_main(argc, argv);
#endif #endif
#ifdef ENABLE_SPHINCS
} else if (!strcmp(*argv, "sphincskeygen")) {
return sphincskeygen_main(argc, argv);
} else if (!strcmp(*argv, "sphincssign")) {
return sphincssign_main(argc, argv);
} else if (!strcmp(*argv, "sphincsverify")) {
return sphincsverify_main(argc, argv);
#endif
#ifdef ENABLE_KYBER #ifdef ENABLE_KYBER
} else if (!strcmp(*argv, "kyberkeygen")) { } else if (!strcmp(*argv, "kyberkeygen")) {
return kyberkeygen_main(argc, argv); return kyberkeygen_main(argc, argv);

132
tools/sphincskeygen.c Normal file
View File

@@ -0,0 +1,132 @@
/*
* 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 <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <gmssl/mem.h>
#include <gmssl/error.h>
#include <gmssl/sphincs.h>
static const char *usage = "-out file [-pubout file] [-verbose]\n";
static const char *options =
"Options\n"
" -out file Output private key\n"
" -pubout file Output public key\n"
" -verbose Print public key\n"
"\n";
int sphincskeygen_main(int argc, char **argv)
{
int ret = 1;
char *prog = argv[0];
char *outfile = NULL;
char *puboutfile = NULL;
int verbose = 0;
FILE *outfp = NULL;
FILE *puboutfp = stdout;
SPHINCS_KEY key;
uint8_t out[SPHINCS_PRIVATE_KEY_SIZE];
uint8_t *pout = out;
size_t outlen = 0;
uint8_t pubout[SPHINCS_PUBLIC_KEY_SIZE];
uint8_t *ppubout = pubout;
size_t 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, "-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 (!outfp) {
fprintf(stderr, "%s: `-out` option required\n", prog);
goto end;
}
if (sphincs_key_generate(&key) != 1) {
error_print();
return -1;
}
if (verbose) {
sphincs_public_key_print(stderr, 0, 0, "sphincs_public_key", &key);
}
if (sphincs_private_key_to_bytes(&key, &pout, &outlen) != 1) {
error_print();
goto end;
}
if (fwrite(out, 1, outlen, outfp) != outlen) {
error_print();
goto end;
}
if (sphincs_public_key_to_bytes(&key, &ppubout, &puboutlen) != 1) {
error_print();
goto end;
}
if (puboutlen != sizeof(pubout)) {
error_print();
goto end;
}
if (fwrite(pubout, 1, puboutlen, puboutfp) != puboutlen) {
error_print();
goto end;
}
ret = 0;
end:
sphincs_key_cleanup(&key);
gmssl_secure_clear(out, sizeof(out));
if (outfile && outfp) fclose(outfp);
if (puboutfile && puboutfp) fclose(puboutfp);
return ret;
}

175
tools/sphincssign.c Normal file
View File

@@ -0,0 +1,175 @@
/*
* 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 <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <gmssl/mem.h>
#include <gmssl/error.h>
#include <gmssl/endian.h>
#include <gmssl/sphincs.h>
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 sphincssign_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[SPHINCS_PRIVATE_KEY_SIZE];
const uint8_t *cp = keybuf;
size_t keylen = sizeof(keybuf);
SPHINCS_KEY key;
SPHINCS_SIGN_CTX ctx;
uint8_t sig[SPHINCS_SIGNATURE_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(keybuf, 1, keylen, keyfp) != keylen) {
fprintf(stderr, "%s: read private key failure\n", prog);
goto end;
}
if (sphincs_private_key_from_bytes(&key, &cp, &keylen) != 1) {
error_print();
goto end;
}
if (keylen) {
error_print();
return -1;
}
if (verbose) {
sphincs_public_key_print(stderr, 0, 0, "sphincs_public_key", &key);
}
if (sphincs_sign_init(&ctx, &key) != 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 (sphincs_sign_prepare(&ctx, buf, len) != 1) {
error_print();
goto end;
}
}
rewind(infp);
while (1) {
uint8_t buf[1024];
size_t len = fread(buf, 1, sizeof(buf), infp);
if (len == 0) {
break;
}
if (sphincs_sign_update(&ctx, buf, len) != 1) {
error_print();
goto end;
}
}
if (sphincs_sign_finish(&ctx, sig, &siglen) != 1) {
error_print();
goto end;
}
if (fwrite(sig, 1, siglen, outfp) != siglen) {
error_print();
goto end;
}
if (verbose) {
sphincs_signature_print(stderr, 0, 0, "sphincs_signature", sig, siglen);
}
ret = 0;
end:
sphincs_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;
}

158
tools/sphincsverify.c Normal file
View File

@@ -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 <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <gmssl/mem.h>
#include <gmssl/error.h>
#include <gmssl/sphincs.h>
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 sphincsverify_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[SPHINCS_PUBLIC_KEY_SIZE];
size_t pubkeylen = SPHINCS_PUBLIC_KEY_SIZE;
const uint8_t *cp = pubkeybuf;
uint8_t sig[SPHINCS_SIGNATURE_SIZE];
size_t siglen;
SPHINCS_KEY key;
SPHINCS_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 (sphincs_public_key_from_bytes(&key, &cp, &pubkeylen) != 1) {
error_print();
fprintf(stderr, "%s: invalid public key data\n", prog);
goto end;
}
if (verbose) {
sphincs_public_key_print(stderr, 0, 0, "sphincs_public_key", &key);
}
// read signature even if signature not compatible with the public key
if ((siglen = fread(sig, 1, SPHINCS_SIGNATURE_SIZE, sigfp)) != SPHINCS_SIGNATURE_SIZE) {
fprintf(stderr, "%s: read signature failure\n", prog);
goto end;
}
if (verbose) {
sphincs_signature_print(stderr, 0, 0, "sphincs_signature", sig, siglen);
}
if (sphincs_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 (sphincs_verify_update(&ctx, buf, len) != 1) {
error_print();
goto end;
}
}
if ((vr = sphincs_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;
}