Update XMSS

This commit is contained in:
Zhi Guan
2026-01-04 10:04:53 +08:00
parent f5f3b6a5b2
commit 14e4edede7
3 changed files with 1037 additions and 221 deletions

View File

@@ -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.
@@ -27,9 +27,6 @@ extern "C" {
// TODO: cache ADRS in SIGN_CTX
// Crosscheck with data from xmss-reference (SHA-256), except the XMSS signature.
#if defined(ENABLE_XMSS_CROSSCHECK) && defined(ENABLE_SHA2)
# define HASH256_CTX SHA256_CTX
@@ -145,11 +142,9 @@ typedef struct {
uint32_t layer_address; // layer index of multi-tree, 0 for lowest layer (and xmss, and OTS ADRS)
uint64_t tree_address; // tree index of a layer, 0 for the left most (and xmss), in [0, 2^(h*(layers-1))-1]
uint32_t type; // in { XMSS_ADRS_TYPE_OTS, XMSS_ADRS_TYPE_LTREE, XMSS_ADRS_TYPE_HASHTREE }
uint32_t ots_address; // index of a leaf (wots+ public key) of a layer-0 xmss tree, in [0, 2^h-1]
uint32_t chain_address; // index of wots+ chain, in [0, 67) when w = 16
uint32_t hash_address; // index of hash calls in a wots+ chain, in [0, w-1]
uint32_t key_and_mask; // in { XMSS_ADRS_GENERATE_KEY, XMSS_ADRS_GENERATE_BITMASK }
} XMSS_ADRS_OTS;
@@ -157,24 +152,19 @@ typedef struct {
uint32_t layer_address;
uint64_t tree_address;
uint32_t type; // = 1
uint32_t ltree_address;
uint32_t tree_height;
uint32_t tree_index;
uint32_t key_and_mask;
} XMSS_ADRS_LTREE;
typedef struct {
uint32_t layer_address;
uint64_t tree_address;
uint32_t type; // = 2
uint32_t padding; // = 0
uint32_t tree_height;
uint32_t tree_index;
uint32_t key_and_mask;
} XMSS_ADRS_HASHTREE;
@@ -200,7 +190,7 @@ void adrs_set_ltree_address(uint8_t adrs[32], uint32_t address);
void adrs_set_padding(uint8_t adrs[32], uint32_t padding);
void adrs_set_tree_height(uint8_t adrs[32], uint32_t height);
void adrs_set_tree_index(uint8_t adrs[32], uint32_t index);
void adrs_set_key_and_mask(uint8_t adrs[32], uint8_t key_and_mask);
void adrs_set_key_and_mask(uint8_t adrs[32], uint32_t key_and_mask);
int xmss_adrs_print(FILE *fp, int fmt, int ind, const char *label, const hash256_t adrs);
@@ -214,10 +204,12 @@ int xmss_adrs_print(FILE *fp, int fmt, int ind, const char *label, const hash256
typedef hash256_t wots_key_t[67];
typedef hash256_t wots_sig_t[67];
void wots_derive_sk(const hash256_t secret,
const hash256_t seed, const xmss_adrs_t adrs,
wots_key_t sk);
void wots_chain(const hash256_t x,
const hash256_t seed, const xmss_adrs_t adrs,
int start, int steps, hash256_t pk);
int start, int steps, hash256_t y);
void wots_sk_to_pk(const wots_key_t sk,
const hash256_t seed, const xmss_adrs_t adrs,
wots_key_t pk);
@@ -227,72 +219,58 @@ void wots_sign(const wots_key_t sk,
void wots_sig_to_pk(const wots_sig_t sig,
const hash256_t seed, const xmss_adrs_t adrs,
const hash256_t dgst, wots_key_t pk);
void wots_build_ltree(const wots_key_t pk,
void wots_pk_to_root(const wots_key_t pk,
const hash256_t seed, const xmss_adrs_t adrs,
hash256_t wots_root);
void wots_derive_sk(const hash256_t secret,
const hash256_t seed, const xmss_adrs_t adrs,
wots_key_t sk);
void wots_derive_root(const hash256_t secret,
const hash256_t seed, const xmss_adrs_t adrs,
hash256_t wots_root);
int wots_verify(const hash256_t wots_root,
const hash256_t seed, const xmss_adrs_t adrs,
const hash256_t dgst, const wots_sig_t sig);
size_t xmss_tree_num_nodes(size_t height);
void xmss_build_tree(const hash256_t secret,
const hash256_t seed, const xmss_adrs_t adrs,
size_t height, hash256_t *tree);
void xmss_do_sign(const uint8_t xmss_secret[32], int index,
const uint8_t seed[32], const uint8_t in_adrs[32], int height,
const hash256_t *tree,
const uint8_t dgst[32],
hash256_t wots_sig[67],
hash256_t *auth_path);
size_t height, hash256_t *tree); // tree[xmss_tree_num_nodes(height)]
void xmss_build_auth_path(const hash256_t *tree, size_t height,
uint32_t index, hash256_t *auth_path); // auth_path[height]
void xmss_build_root(const hash256_t wots_root, uint32_t index,
const hash256_t seed, const xmss_adrs_t adrs,
const hash256_t *auth_path, size_t height,
hash256_t xmss_root);
void xmss_sig_to_root(const hash256_t wots_sig[67],
const uint8_t seed[32], const uint8_t in_adrs[32],
const uint8_t dgst[32],
const hash256_t *auth_path, int height,
uint8_t xmss_root[32]);
typedef struct {
uint32_t xmss_type;
uint8_t seed[32];
uint8_t root[32];
hash256_t seed;
hash256_t root;
} XMSS_PUBLIC_KEY;
// PK = OID || root || SEED
// SK = idx || wots_sk || SK_PRF || root || SEED;
#define XMSS_PUBLIC_KEY_SIZE (4 + 32 + 32) // = 68
typedef struct {
XMSS_PUBLIC_KEY public_key;
// private key
uint8_t secret[32];
uint8_t sk_prf[32]; // secret key for prf
hash256_t secret;
hash256_t sk_prf;
uint32_t index;
hash256_t *tree; // merkle tree with wots+ public keys as leafs
hash256_t *tree; // hash256_t[2^(h + 1) - 1]
} XMSS_KEY;
// TODO: support hash256_t tree[1]
#define XMSS_PUBLIC_KEY_SIZE (4 + 32 + 32) // = 68
#define XMSS_PRIVATE_KEY_SIZE (XMSS_PUBLIC_KEY_SIZE + 32 + 32 + 4) // = 136
int xmss_key_match_public_key(const XMSS_KEY *key, const XMSS_KEY *pub);
int xmss_key_generate(XMSS_KEY *key, uint32_t oid);
int xmss_key_generate(XMSS_KEY *key, uint32_t xmss_type);
int xmss_key_remaining_signs(const XMSS_KEY *key, size_t *count);
void xmss_key_cleanup(XMSS_KEY *key);
int xmss_public_key_to_bytes(const XMSS_KEY *key, uint8_t **out, size_t *outlen);
int xmss_public_key_from_bytes(XMSS_KEY *key, const uint8_t **in, size_t *inlen);
int xmss_public_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSS_KEY *key);
int xmss_private_key_to_bytes(const XMSS_KEY *key, uint8_t **out, size_t *outlen);
int xmss_private_key_from_bytes(XMSS_KEY *key, const uint8_t **in, size_t *inlen);
int xmss_private_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSS_KEY *key);
void xmss_key_cleanup(XMSS_KEY *key);
typedef struct {
@@ -302,19 +280,12 @@ typedef struct {
hash256_t auth_path[XMSS_MAX_HEIGHT];
} XMSS_SIGNATURE;
// XMSS_SM3_10_256 2500 bytes
// XMSS_SM3_16_256 2692 bytes
// XMSS_SM3_20_256 2820 bytes
#define XMSS_SIGNATURE_MIN_SIZE (4 + 32 + 32*67 + 32 * XMSS_MIN_HEIGHT) // = 2500 bytes
#define XMSS_SIGNATURE_MAX_SIZE (4 + 32 + 32*67 + 32 * XMSS_MAX_HEIGHT) // = 2820 bytes
int xmss_signature_size(uint32_t oid, size_t *siglen);
// TODO: impl this
int xmss_key_get_signature_size(const XMSS_KEY *key, size_t *siglen);
int xmss_signature_size(uint32_t xmss_type, size_t *siglen);
int xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *in, size_t inlen);
int xmss_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, const XMSS_SIGNATURE *sig);
@@ -326,38 +297,14 @@ typedef struct {
HASH256_CTX hash256_ctx;
} XMSS_SIGN_CTX;
void randomized_tree_hash(const hash256_t left_child, const hash256_t right_child,
const hash256_t seed, const xmss_adrs_t tree_adrs,
hash256_t parent);
void build_auth_path(const hash256_t *tree, int height, int index, hash256_t *path);
int xmss_sign_init(XMSS_SIGN_CTX *ctx, XMSS_KEY *key);
int xmss_sign_update(XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
int xmss_sign_finish(XMSS_SIGN_CTX *ctx, uint8_t *sigbuf, size_t *siglen);
int xmss_verify_init(XMSS_SIGN_CTX *ctx, const XMSS_KEY *key, const uint8_t *sigbuf, size_t siglen);
int xmss_verify_update(XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen);
int xmss_verify_finish(XMSS_SIGN_CTX *ctx);
// TODO: optimize, define XMSSMT_TYPE_HASH256 and XMSSMT_TYPE_PARAMS
#if defined(ENABLE_XMSS_CROSSCHECK) && defined(ENABLE_SHA2)
@@ -411,7 +358,7 @@ int xmss_verify_finish(XMSS_SIGN_CTX *ctx);
//#define XMSSMT_MIN_XMSS_HEIGHT 5
//#define XMSSMT_MAX_XMSS_HEIGHT 20
enum { // layers height sigs private
enum {
XMSSMT_SM3_20_2_256 = 0x00000001, // 2 10 1024*1024 (2^11 - 1) * 2
XMSSMT_SM3_20_4_256 = 0x00000002, // 4 5
XMSSMT_SM3_40_2_256 = 0x00000003, // 2 20
@@ -433,7 +380,6 @@ enum {
XMSSMT_SHA2_60_3_256 = 0x00000006,
XMSSMT_SHA2_60_6_256 = 0x00000007,
XMSSMT_SHA2_60_12_256 = 0x00000008,
XMSSMT_SHA2_20_2_512 = 0x00000009,
XMSSMT_SHA2_20_4_512 = 0x0000000A,
XMSSMT_SHA2_40_2_512 = 0x0000000B,
@@ -442,7 +388,6 @@ enum {
XMSSMT_SHA2_60_3_512 = 0x0000000E,
XMSSMT_SHA2_60_6_512 = 0x0000000F,
XMSSMT_SHA2_60_12_512 = 0x00000010,
XMSSMT_SHAKE_20_2_256 = 0x00000011,
XMSSMT_SHAKE_20_4_256 = 0x00000012,
XMSSMT_SHAKE_40_2_256 = 0x00000013,
@@ -451,7 +396,6 @@ enum {
XMSSMT_SHAKE_60_3_256 = 0x00000016,
XMSSMT_SHAKE_60_6_256 = 0x00000017,
XMSSMT_SHAKE_60_12_256 = 0x00000018,
XMSSMT_SHAKE_20_2_512 = 0x00000019,
XMSSMT_SHAKE_20_4_512 = 0x0000001A,
XMSSMT_SHAKE_40_2_512 = 0x0000001B,
@@ -474,17 +418,28 @@ typedef struct {
hash256_t root;
} XMSSMT_PUBLIC_KEY;
#define XMSSMT_PUBLIC_KEY_SIZE (4 + sizeof(hash256_t) + sizeof(hash256_t)) // = 68 bytes
typedef struct {
XMSSMT_PUBLIC_KEY public_key;
hash256_t secret;
hash256_t sk_prf;
uint64_t index; // in [0, 2^60 - 1]
//hash256_t *trees;
//XMSS_SIGNATURE xmss_sigs[XMSSMT_MAX_LAYERS - 1];
hash256_t *trees;
wots_sig_t wots_sigs[XMSSMT_MAX_LAYERS - 1];
} XMSSMT_KEY;
int xmssmt_private_key_size(uint32_t xmssmt_type, size_t *len);
int xmssmt_key_build_auth_path(const XMSSMT_KEY *key, hash256_t *auth_path);
int xmssmt_key_generate(XMSSMT_KEY *key, uint32_t xmssmt_type);
int xmssmt_public_key_to_bytes(const XMSSMT_KEY *key, uint8_t **out, size_t *outlen);
int xmssmt_public_key_from_bytes(XMSSMT_KEY *key, const uint8_t **in, size_t *inlen);
int xmssmt_public_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSSMT_KEY *key);
int xmssmt_private_key_to_bytes(const XMSSMT_KEY *key, uint8_t **out, size_t *outlen);
int xmssmt_private_key_from_bytes(XMSSMT_KEY *key, const uint8_t **in, size_t *inlen);
int xmssmt_private_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSSMT_KEY *key);
typedef struct {
@@ -501,7 +456,6 @@ typedef struct {
int xmssmt_index_to_bytes(uint64_t index, uint32_t xmssmt_type, uint8_t **out, size_t *outlen);
int xmssmt_index_from_bytes(uint64_t *index, uint32_t xmssmt_type, const uint8_t **in, size_t *inlen);
int xmssmt_signature_size(uint32_t xmssmt_type, size_t *siglen);
int xmssmt_signature_to_bytes(const XMSSMT_SIGNATURE *sig, uint32_t xmssmt_type, uint8_t **out, size_t *outlen);
int xmssmt_signature_from_bytes(XMSSMT_SIGNATURE *sig, uint32_t xmssmt_type, const uint8_t **in, size_t *inlen);
@@ -509,10 +463,10 @@ int xmssmt_signature_print_ex(FILE *fp, int fmt, int ind, const char *label, con
int xmssmt_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen, uint32_t xmssmt_type);
typedef struct {
XMSS_SIGN_CTX xmss_sign_ctx;
// TODO: more...
XMSSMT_PUBLIC_KEY xmssmt_public_key;
XMSSMT_SIGNATURE xmssmt_sig;
HASH256_CTX hash256_ctx;
} XMSSMT_SIGN_CTX;
int xmssmt_sign_init(XMSSMT_SIGN_CTX *ctx, XMSSMT_KEY *key);

View File

@@ -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.
@@ -170,7 +170,7 @@ void adrs_set_tree_index(uint8_t adrs[32], uint32_t index) {
PUTU32(adrs + 4*6, index);
}
void adrs_set_key_and_mask(uint8_t adrs[32], uint8_t key_and_mask) {
void adrs_set_key_and_mask(uint8_t adrs[32], uint32_t key_and_mask) {
PUTU32(adrs + 4*7, key_and_mask);
}
@@ -218,7 +218,7 @@ int xmss_adrs_print(FILE *fp, int fmt, int ind, const char *label, const hash256
type = GETU32(adrs);
adrs += 4;
format_print(fp, fmt, ind, "type: %"PRIu32"\n", layer_address);
format_print(fp, fmt, ind, "type: %"PRIu32"\n", type);
if (type == XMSS_ADRS_TYPE_OTS) {
uint32_t ots_address;
@@ -453,7 +453,7 @@ void wots_sig_to_pk(const wots_sig_t sig,
}
// TODO: need test and test vector
void randomized_tree_hash(const hash256_t left_child, const hash256_t right_child,
static void randomized_tree_hash(const hash256_t left_child, const hash256_t right_child,
const hash256_t seed, const xmss_adrs_t tree_adrs,
hash256_t parent)
{
@@ -507,7 +507,7 @@ void randomized_tree_hash(const hash256_t left_child, const hash256_t right_chil
}
// ltree is wots+ leaf tree, (un-balanced) merkle tree from the 67 wots+ hashs
void wots_build_ltree(const wots_key_t in_pk,
void wots_pk_to_root(const wots_key_t in_pk,
const hash256_t seed, const xmss_adrs_t in_adrs,
hash256_t wots_root)
{
@@ -521,7 +521,7 @@ void wots_build_ltree(const wots_key_t in_pk,
adrs_copy_layer_address(adrs, in_adrs);
adrs_copy_tree_address(adrs, in_adrs);
adrs_copy_type(adrs, in_adrs);
adrs_copy_type(adrs, in_adrs); // type must be LTREE
adrs_copy_ltree_address(adrs, in_adrs);
adrs_set_tree_height(adrs, tree_height++);
@@ -542,6 +542,32 @@ void wots_build_ltree(const wots_key_t in_pk,
memcpy(wots_root, pk[0], 32);
}
int wots_verify(const hash256_t wots_root,
const hash256_t seed, const xmss_adrs_t in_adrs,
const hash256_t dgst, const wots_sig_t sig)
{
xmss_adrs_t adrs;
wots_key_t pk;
hash256_t root;
adrs_copy_layer_address(adrs, in_adrs);
adrs_copy_tree_address(adrs, in_adrs);
adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS);
adrs_copy_ots_address(adrs, in_adrs);
wots_sig_to_pk(sig, seed, adrs, dgst, pk);
adrs_set_type(adrs, XMSS_ADRS_TYPE_LTREE);
adrs_copy_ltree_address(adrs, in_adrs);
wots_pk_to_root(pk, seed, adrs, root);
if (memcmp(root, wots_root, sizeof(hash256_t)) == 0) {
return 1;
} else {
return 0;
}
}
// adrs: layer_address, tree_address, ots_address or ltree_address should be set
void wots_derive_root(const hash256_t secret,
const hash256_t seed, const xmss_adrs_t adrs,
@@ -564,7 +590,7 @@ void wots_derive_root(const hash256_t secret,
adrs_set_type(ltree_adrs, XMSS_ADRS_TYPE_LTREE);
adrs_copy_ltree_address(ltree_adrs, adrs); // ltree_address == ots_address
wots_build_ltree(wots_key, seed, ltree_adrs, wots_root);
wots_pk_to_root(wots_key, seed, ltree_adrs, wots_root);
}
static size_t tree_root_offset(size_t height) {
@@ -588,17 +614,26 @@ void xmss_build_tree(const hash256_t secret,
// derive 2^h wots+ roots as leaves of xmss tree
adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS);
//fprintf(stderr, "xmss_build_tree() progress\n");
for (i = 0; i < n; i++) {
adrs_set_ots_address(adrs, i);
wots_derive_root(secret, seed, adrs, tree[i]);
/*
if (i % (n/100) == 0 && i/(n/100) <= 100) {
fprintf(stderr, " %zu%%\n", i/(n/100) );
}
*/
}
// build xmss tree
adrs_set_type(adrs, XMSS_ADRS_TYPE_HASHTREE);
adrs_set_padding(adrs, 0);
adrs_set_key_and_mask(adrs, 0);
children = tree;
parents = tree + n;
for (h = 0; h < height; h++) {
adrs_set_tree_height(adrs, h);
adrs_set_tree_height(adrs, h + 1);
n >>= 1;
for (i = 0; i < n; i++) {
adrs_set_tree_index(adrs, i);
@@ -609,13 +644,66 @@ void xmss_build_tree(const hash256_t secret,
}
}
void build_auth_path(const hash256_t *tree, int height, int index, hash256_t *path)
void xmss_do_sign(const hash256_t secret, uint32_t index,
const hash256_t seed, const xmss_adrs_t in_adrs,
const hash256_t dgst, wots_sig_t wots_sig)
{
int h;
xmss_adrs_t adrs;
adrs_copy_layer_address(adrs, in_adrs);
adrs_copy_tree_address(adrs, in_adrs);
adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS);
adrs_set_ots_address(adrs, index);
wots_derive_sk(secret, seed, adrs, wots_sig);
wots_sign(wots_sig, seed, adrs, dgst, wots_sig);
}
void xmss_build_auth_path(const hash256_t *tree, size_t height, uint32_t tree_index, hash256_t *auth_path)
{
size_t h;
for (h = 0; h < height; h++) {
memcpy(path[h], tree[index ^ 1], 32);
memcpy(auth_path[h], tree[tree_index ^ 1], sizeof(hash256_t));
tree += (1 << (height - h));
index >>= 1;
tree_index >>= 1;
}
}
static uint64_t xmssmt_tree_address(uint64_t index, size_t height, size_t layers, size_t layer) {
return (index >> (height/layers) * (layer + 1));
}
static uint64_t xmssmt_tree_index(uint64_t index, size_t height, size_t layers, size_t layer) {
return (index >> (height/layers) * layer) % (1 << (height/layers));
}
void xmss_build_root(const hash256_t wots_root, uint32_t tree_index,
const hash256_t seed, const xmss_adrs_t in_adrs,
const hash256_t *auth_path, size_t height,
hash256_t root)
{
xmss_adrs_t adrs;
size_t h;
adrs_copy_layer_address(adrs, in_adrs);
adrs_copy_tree_address(adrs, in_adrs);
adrs_set_type(adrs, XMSS_ADRS_TYPE_HASHTREE);
adrs_set_padding(adrs, 0);
adrs_set_key_and_mask(adrs, 0);
memcpy(root, wots_root, sizeof(hash256_t));
for (h = 0; h < height; h++) {
int right_child = tree_index & 1;
tree_index >>= 1;
adrs_set_tree_height(adrs, h + 1);
adrs_set_tree_index(adrs, tree_index);
if (right_child)
randomized_tree_hash(auth_path[h], root, seed, adrs, root);
else randomized_tree_hash(root, auth_path[h], seed, adrs, root);
}
}
@@ -642,7 +730,7 @@ void xmss_sig_to_root(const hash256_t wots_sig[67],
// wots_pk to wots_root
adrs_set_type(adrs, XMSS_ADRS_TYPE_LTREE);
adrs_copy_ltree_address(adrs, in_adrs);
wots_build_ltree(wots_pk, seed, adrs, xmss_root);
wots_pk_to_root(wots_pk, seed, adrs, xmss_root);
index = GETU32(in_adrs + 16);
@@ -650,6 +738,7 @@ void xmss_sig_to_root(const hash256_t wots_sig[67],
adrs_set_type(adrs, XMSS_ADRS_TYPE_HASHTREE);
adrs_set_padding(adrs, 0);
adrs_set_key_and_mask(adrs, 0);
for (h = 0; h < height; h++) {
int right = index & 1;
index >>= 1;
@@ -661,7 +750,6 @@ void xmss_sig_to_root(const hash256_t wots_sig[67],
}
}
int xmss_type_to_height(uint32_t xmss_type, size_t *height)
{
switch (xmss_type) {
@@ -735,14 +823,6 @@ int xmss_key_generate(XMSS_KEY *key, uint32_t xmss_type)
return 1;
}
int xmss_key_match_public_key(const XMSS_KEY *key, const XMSS_KEY *pub)
{
if (memcmp(key, pub, sizeof(XMSS_PUBLIC_KEY)) != 0) {
return 0;
}
return 1;
}
int xmss_key_remaining_signs(const XMSS_KEY *key, size_t *count)
{
size_t height;
@@ -1062,7 +1142,6 @@ int xmss_signature_print(FILE *fp, int fmt, int ind, const char *label, const ui
return 1;
}
int xmss_sign_init(XMSS_SIGN_CTX *ctx, XMSS_KEY *key)
{
uint8_t index_buf[32] = {0};
@@ -1102,7 +1181,7 @@ int xmss_sign_init(XMSS_SIGN_CTX *ctx, XMSS_KEY *key)
wots_derive_sk(key->secret, key->public_key.seed, adrs, ctx->xmss_sig.wots_sig);
// xmss_sig.auth_path
build_auth_path(key->tree, height, key->index, ctx->xmss_sig.auth_path);
xmss_build_auth_path(key->tree, height, key->index, ctx->xmss_sig.auth_path);
// update key->index
key->index++;
@@ -1117,6 +1196,9 @@ int xmss_sign_init(XMSS_SIGN_CTX *ctx, XMSS_KEY *key)
return 1;
}
int xmss_sign_update(XMSS_SIGN_CTX *ctx, const uint8_t *data, size_t datalen)
{
if (data && datalen) {
@@ -1146,6 +1228,7 @@ int xmss_sign_finish(XMSS_SIGN_CTX *ctx, uint8_t *sigbuf, size_t *siglen)
return -1;
}
return 1;
}
@@ -1223,7 +1306,7 @@ int xmss_verify_finish(XMSS_SIGN_CTX *ctx)
// wots_pk => wots_root
adrs_set_type(adrs, XMSS_ADRS_TYPE_LTREE);
adrs_set_ltree_address(adrs, ctx->xmss_sig.index);
wots_build_ltree(ctx->xmss_sig.wots_sig, ctx->xmss_public_key.seed, adrs, root);
wots_pk_to_root(ctx->xmss_sig.wots_sig, ctx->xmss_public_key.seed, adrs, root);
// wots_root (index), auth_path => xmss_root
adrs_set_type(adrs, XMSS_ADRS_TYPE_HASHTREE);
@@ -1232,7 +1315,7 @@ int xmss_verify_finish(XMSS_SIGN_CTX *ctx)
for (h = 0; h < height; h++) {
right = index & 1;
index >>= 1;
adrs_set_tree_height(adrs, h);
adrs_set_tree_height(adrs, h + 1);
adrs_set_tree_index(adrs, index);
if (right)
randomized_tree_hash(ctx->xmss_sig.auth_path[h], root, ctx->xmss_public_key.seed, adrs, root);
@@ -1305,19 +1388,166 @@ int xmssmt_type_to_height_and_layers(uint32_t xmssmt_type, size_t *height, size_
return 1;
}
size_t xmss_tree_num_nodes(size_t height)
{
return (1 << (height + 1)) - 1;
}
size_t xmssmt_trees_num_nodes(size_t height, size_t layers)
{
return xmss_tree_num_nodes(height/layers) * layers;
}
int xmssmt_public_key_to_bytes(const XMSSMT_KEY *key, uint8_t **out, size_t *outlen)
{
if (!key || !outlen) {
error_print();
return -1;
}
uint32_to_bytes(key->public_key.xmssmt_type, out, outlen);
hash256_to_bytes(key->public_key.root, out, outlen);
hash256_to_bytes(key->public_key.seed, out, outlen);
return 1;
}
int xmssmt_public_key_from_bytes(XMSSMT_KEY *key, const uint8_t **in, size_t *inlen)
{
if (!key || !in || !(*in) || !inlen) {
error_print();
return -1;
}
if (*inlen < XMSSMT_PUBLIC_KEY_SIZE) {
error_print();
return -1;
}
memset(key, 0, sizeof(*key));
uint32_from_bytes(&key->public_key.xmssmt_type, in, inlen);
if (!xmssmt_type_name(key->public_key.xmssmt_type)) {
error_print();
return -1;
}
hash256_from_bytes(key->public_key.root, in, inlen);
hash256_from_bytes(key->public_key.seed, in, inlen);
return 1;
}
int xmssmt_private_key_size(uint32_t xmssmt_type, size_t *len)
{
uint64_t index = 0;
size_t height;
size_t layers;
if (xmssmt_type_to_height_and_layers(xmssmt_type, &height, &layers) != 1) {
error_print();
return -1;
}
*len = XMSSMT_PUBLIC_KEY_SIZE;
*len += sizeof(hash256_t);
*len += sizeof(hash256_t);
xmssmt_index_to_bytes(index, xmssmt_type, NULL, len);
*len += sizeof(hash256_t) * ((1 << (height/layers + 1)) - 1) * layers;
*len += sizeof(wots_sig_t) * (layers - 1);
return 1;
}
int xmssmt_private_key_to_bytes(const XMSSMT_KEY *key, uint8_t **out, size_t *outlen)
{
size_t height;
size_t layers;
size_t treeslen;
if (!key || !outlen) {
error_print();
return -1;
}
if (xmssmt_type_to_height_and_layers(key->public_key.xmssmt_type, &height, &layers) != 1) {
error_print();
return -1;
}
if (xmssmt_public_key_to_bytes(key, out, outlen) != 1) {
error_print();
return -1;
}
xmssmt_index_to_bytes(key->index, key->public_key.xmssmt_type, out, outlen);
hash256_to_bytes(key->secret, out, outlen);
hash256_to_bytes(key->sk_prf, out, outlen);
treeslen = sizeof(hash256_t) * xmssmt_trees_num_nodes(height, layers);
if (out && *out) {
memcpy(*out, key->trees, treeslen);
*out += treeslen;
memcpy(*out, key->wots_sigs, sizeof(wots_sig_t) * (layers - 1));
*out += sizeof(wots_sig_t) * (layers - 1);
}
*outlen += treeslen;
*outlen += sizeof(wots_sig_t) * (layers - 1);
return 1;
}
int xmssmt_private_key_from_bytes(XMSSMT_KEY *key, const uint8_t **in, size_t *inlen)
{
size_t height;
size_t layers;
size_t keylen;
size_t treeslen;
if (!key || !in || !(*in) || !inlen) {
error_print();
return -1;
}
memset(key, 0, sizeof(*key));
if (xmssmt_public_key_from_bytes(key, in, inlen) != 1) {
error_print();
return -1;
}
if (xmssmt_private_key_size(key->public_key.xmssmt_type, &keylen) != 1) {
error_print();
return -1;
}
if (*inlen < keylen - XMSSMT_PUBLIC_KEY_SIZE) {
error_print();
return -1;
}
if (xmssmt_index_from_bytes(&key->index, key->public_key.xmssmt_type, in, inlen) != 1) {
error_print();
return -1;
}
hash256_from_bytes(key->secret, in, inlen);
hash256_from_bytes(key->sk_prf, in, inlen);
if (xmssmt_type_to_height_and_layers(key->public_key.xmssmt_type, &height, &layers) != 1) {
error_print();
return -1;
}
treeslen = sizeof(hash256_t) * xmssmt_trees_num_nodes(height, layers);
if (!(key->trees = malloc(treeslen))) {
error_print();
return -1;
}
memcpy(key->trees, *in, treeslen);
*in += treeslen;
*inlen -= treeslen;
memcpy(key->wots_sigs, *in, sizeof(wots_sig_t) * (layers - 1));
*in += sizeof(wots_sig_t) * (layers - 1);
*inlen -= sizeof(wots_sig_t) * (layers - 1);
return 1;
}
int xmssmt_key_generate(XMSSMT_KEY *key, uint32_t xmssmt_type)
{
xmss_adrs_t adrs;
size_t height;
size_t layers;
size_t xmss_height;
uint32_t layer;
xmss_adrs_t adrs;
hash256_t *tree;
uint8_t *xmss_root;
uint32_t layer_address;
uint64_t tree_address;
/*
if (!key) {
error_print();
return -1;
@@ -1328,48 +1558,182 @@ int xmssmt_key_generate(XMSSMT_KEY *key, uint32_t xmssmt_type)
}
memset(key, 0, sizeof(*key));
xmss_height = height/layers;
xmss_trees = 1 << xmss_height;
key->public_key.xmssmt_type = xmssmt_type;
// idx_MT
key->index = 0;
#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;
}
// SK_PRF
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
key->index = 0;
// SEED
if (rand_bytes(key->seed, sizeof(hash256_t)) != 1) {
// malloc tress
if (!(key->trees = malloc(xmssmt_trees_num_nodes(height, layers) * sizeof(hash256_t)))) {
error_print();
return -1;
}
tree = key->trees;
// ADRS = toByte(0, 32)
memset(adrs, 0, sizeof(xmss_adrs_t));
for (layer = 0; layer < layers - 1; layer++) {
// generate the leftmost tree of the level
adrs_set_layer_address(adrs, layer);
adrs_set_tree_address(adrs, 0);
xmss_build_tree(key->secret, key->public_key.seed, adrs, height/layers, tree);
xmss_root = tree[tree_root_offset(height/layers)];
adrs_set_layer_address(adrs, layer + 1);
adrs_set_tree_address(adrs, 0);
adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS);
adrs_set_ots_address(adrs, 0); // 具体值由index决定
wots_derive_sk(key->secret, key->public_key.seed, adrs, key->wots_sigs[layer]);
wots_sign(key->wots_sigs[layer], key->public_key.seed, adrs, xmss_root, key->wots_sigs[layer]);
tree += tree_root_offset(height/layers) + 1;
}
// highest layer (without signatures)
adrs_set_layer_address(adrs, layer);
adrs_set_tree_address(adrs, 0);
xmss_build_tree(key->secret, key->public_key.seed, adrs, height/layers, tree);
xmss_root = tree[tree_root_offset(height/layers)];
// copy the top-level root
memcpy(key->public_key.root, xmss_root, sizeof(hash256_t));
// malloc tress
for (layer_address = 0; layer_address < layers; layer_address++) {
uint64_t trees;
trees = 1 << ((height/layers) * (layers - 1 - layer));
tree = key->trees;
adrs_set_layer_address(adrs, layer_address);
for (tree_address = 0; tree_address < layer_trees; tree_address++) {
hash256_t root;
adrs_set_tree_address(adrs, tree_address);
size_t i;
wots_key_t wots_pk;
xmss_build_tree(key->secret, height/layers, key->seed, adrs, tree, xmss_root);
for (i = 0; i < layers - 1; i++) {
adrs_set_layer_address(adrs, i + 1);
adrs_set_tree_address(adrs, 0); //
adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS);
adrs_set_ots_address(adrs, 0); // FIXME: value from index
uint8_t *dgst = tree[tree_root_offset(height/layers)];
wots_sig_to_pk(key->wots_sigs[i], key->public_key.seed, adrs, dgst, wots_pk);
adrs_set_type(adrs, XMSS_ADRS_TYPE_LTREE);
adrs_set_tree_index(adrs, 0); //
wots_pk_to_root(wots_pk, key->public_key.seed, adrs, root);
tree += xmss_tree_num_nodes(height/layers);
if (memcmp(root, tree[0], 32) != 0) {
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)
{
size_t height;
size_t layers;
uint64_t index;
const hash256_t *tree;
size_t i;
if (!key || !auth_path) {
error_print();
return -1;
}
if (xmssmt_type_to_height_and_layers(key->public_key.xmssmt_type, &height, &layers) != 1) {
error_print();
return -1;
}
index = key->index;
tree = key->trees;
for (i = 0; i < layers; i++) {
uint64_t local_index = index & ((1 << (height/layers)) - 1);
xmss_build_auth_path(tree, height/layers, local_index, auth_path);
auth_path += height/layers;
index >>= height/layers;
tree += xmss_tree_num_nodes(height/layers);
}
return 1;
}
int xmssmt_public_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSSMT_KEY *key)
{
format_print(fp, fmt, ind, "%s\n", label);
ind += 4;
format_print(fp, fmt, ind, "type: %s\n", xmssmt_type_name(key->public_key.xmssmt_type));
format_bytes(fp, fmt, ind, "seed", key->public_key.seed, 32);
format_bytes(fp, fmt, ind, "root", key->public_key.root, 32);
return 1;
}
int xmssmt_private_key_print(FILE *fp, int fmt, int ind, const char *label, const XMSSMT_KEY *key)
{
size_t height;
size_t layers;
hash256_t *tree;
size_t i;
format_print(fp, fmt, ind, "%s\n", label);
ind += 4;
xmssmt_public_key_print(fp, fmt, ind, "public_key", key);
format_bytes(fp, fmt, ind, "secret", key->secret, 32);
format_bytes(fp, fmt, ind, "sk_prf", key->sk_prf, 32);
format_print(fp, fmt, ind, "index: %u\n", key->index);
if (xmssmt_type_to_height_and_layers(key->public_key.xmssmt_type, &height, &layers) != 1) {
error_print();
return -1;
}
/*
for (i = 0; i < layers - 1; i++) {
size_t j;
format_print(fp, fmt, ind, "wots_sig\n");
for (j = 0; j < 67; j++) {
format_bytes(stderr, 0, ind+4, "", key->wots_sigs[i][j], sizeof(hash256_t));
}
}
*/
return -1;
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);
tree += xmss_tree_num_nodes(height/layers);
}
return 1;
}
int xmssmt_index_to_bytes(uint64_t index, uint32_t xmssmt_type, uint8_t **out, size_t *outlen)
{
@@ -1427,6 +1791,12 @@ int xmssmt_index_from_bytes(uint64_t *index, uint32_t xmssmt_type, const uint8_t
*inlen -= nbytes;
*index = GETU64(bytes);
// check value in [0, 2^height], 2^height means out of keys
if (*index > (1 << height)) {
error_print();
return -1;
}
return 1;
}
@@ -1580,7 +1950,6 @@ int xmssmt_signature_print(FILE *fp, int fmt, int ind, const char *label, const
size_t height;
size_t layers;
uint64_t index;
size_t layer;
size_t i;
@@ -1640,8 +2009,70 @@ int xmssmt_signature_print(FILE *fp, int fmt, int ind, const char *label, const
int xmssmt_sign_init(XMSSMT_SIGN_CTX *ctx, XMSSMT_KEY *key)
{
hash256_t hash256_index = {0};
xmss_adrs_t adrs;
size_t height;
size_t layers;
if (!ctx || !key) {
error_print();
return -1;
}
if (xmssmt_type_to_height_and_layers(key->public_key.xmssmt_type, &height, &layers) != 1) {
error_print();
return -1;
}
memset(ctx, 0, sizeof(*ctx));
// cache public key
ctx->xmssmt_public_key = key->public_key;
// key->index => xmssmt_sig.index
ctx->xmssmt_sig.index = key->index;
// derive ctx->xmssmt_sig.random
PUTU64(hash256_index + 24, key->index);
// r = PRF(SK_PRF, toByte(idx_sig, 32));
hash256_init(&ctx->hash256_ctx);
hash256_update(&ctx->hash256_ctx, hash256_three, 32);
hash256_update(&ctx->hash256_ctx, key->sk_prf, 32);
hash256_update(&ctx->hash256_ctx, hash256_index, 32);
hash256_finish(&ctx->hash256_ctx, ctx->xmssmt_sig.random);
// wots_sk => ctx->xmss_sig.wots_sig
adrs_set_layer_address(adrs, 0);
adrs_set_tree_address(adrs, 0); //
adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS);
adrs_set_ots_address(adrs, key->index); //
wots_derive_sk(key->secret, key->public_key.seed, adrs, ctx->xmssmt_sig.wots_sigs[0]);
//
// xmss_sig.auth_path
xmss_build_auth_path(key->trees, height, key->index, ctx->xmssmt_sig.auth_path);
// update key->index
key->index++;
// H_msg(M) := HASH256(toByte(2, 32) || r || XMSS_ROOT || toByte(idx_sig, 32) || M)
hash256_init(&ctx->hash256_ctx);
hash256_update(&ctx->hash256_ctx, bn256_two, 32);
hash256_update(&ctx->hash256_ctx, ctx->xmssmt_sig.random, 32);
hash256_update(&ctx->hash256_ctx, key->public_key.root, 32);
hash256_update(&ctx->hash256_ctx, hash256_index, 32);
size_t i;
for (i = 0; i < layers; i++) {
}
return -1;
}
int xmssmt_sign_update(XMSSMT_SIGN_CTX *ctx, const uint8_t *data, size_t datalen)
{
@@ -1649,23 +2080,49 @@ int xmssmt_sign_update(XMSSMT_SIGN_CTX *ctx, const uint8_t *data, size_t datalen
error_print();
return -1;
}
if (xmss_sign_update(&ctx->xmss_sign_ctx, data, datalen) != 1) {
error_print();
return -1;
if (data && datalen) {
hash256_update(&ctx->hash256_ctx, data, datalen);
}
return 1;
}
int xmssmt_sign_finish_ex(XMSSMT_SIGN_CTX *ctx, XMSSMT_SIGNATURE *sig)
{
xmss_adrs_t adrs;
size_t height;
size_t layers;
uint64_t tree_address;
uint8_t dgst[32];
if (!ctx || !sig) {
error_print();
return -1;
}
if (xmssmt_type_to_height_and_layers(ctx->xmssmt_public_key.xmssmt_type, &height, &layers) != 1) {
error_print();
return -1;
}
tree_address = sig->index / layers;
hash256_finish(&ctx->hash256_ctx, dgst);
adrs_set_layer_address(adrs, 0);
adrs_set_tree_address(adrs, tree_address);
adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS);
adrs_set_ots_address(adrs, ctx->xmssmt_sig.index);
wots_sign(ctx->xmssmt_sig.wots_sigs[0], ctx->xmssmt_public_key.seed, adrs, dgst,
ctx->xmssmt_sig.wots_sigs[0]);
return 1;
}
int xmssmt_sign_finish(XMSSMT_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen)
{
if (!ctx || !sig || !siglen) {
@@ -1674,7 +2131,10 @@ int xmssmt_sign_finish(XMSSMT_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen)
}
*siglen = 0;
if (xmssmt_signature_to_bytes(&ctx->xmssmt_sig, ctx->xmssmt_public_key.xmssmt_type, &sig, siglen) != 1) {
error_print();
return -1;
}
return -1;
}

View File

@@ -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.
@@ -31,22 +31,12 @@ static int test_xmss_adrs(void)
adrs_set_hash_address(adrs, 12);
adrs_set_key_and_mask(adrs, 0);
xmss_adrs_print(stderr, 0, 0, "ADRS", adrs);
xmss_adrs_print(stderr, 0, 4, "ADRS", adrs);
printf("%s() ok\n", __FUNCTION__);
return 1;
}
// copy this static function from src/sm3_xmss.c
static void hash256_prf_init(HASH256_CTX *hash256_ctx, const uint8_t key[32])
{
uint8_t hash_id[32] = {0};
hash_id[31] = 3;
hash256_init(hash256_ctx);
hash256_update(hash256_ctx, hash_id, 32);
hash256_update(hash256_ctx, key, 32);
}
#if defined(ENABLE_XMSS_CROSSCHECK) && defined(ENABLE_SHA2)
static int test_wots_derive_sk(void)
@@ -129,49 +119,6 @@ static int test_wots_sk_to_pk(void)
return 1;
}
static int test_wots_derive_root(void)
{
hash256_t secret;
hash256_t seed;
xmss_adrs_t adrs;
hash256_t root;
hash256_t wots_0_root;
hash256_t wots_1023_root;
size_t len;
memset(secret, 0x12, sizeof(hash256_t));
memset(seed, 0xab, sizeof(hash256_t));
hex_to_bytes("7A968C5F9AE4D2B781872B4E6EE851D55CC02F0AB9196701580D6F503D35DB68", 64, wots_0_root, &len);
hex_to_bytes("939E10CD44769D4D9853F7CF5612D6D83B3AA140A8867CCF34A1DBCC66FC4333", 64, wots_1023_root, &len);
// wots index is 0
adrs_set_layer_address(adrs, 0);
adrs_set_tree_address(adrs, 0);
adrs_set_ots_address(adrs, 0);
wots_derive_root(secret, seed, adrs, root);
if (memcmp(root, wots_0_root, sizeof(hash256_t)) != 0) {
error_print();
return -1;
}
// wots index is 1023
adrs_set_layer_address(adrs, 0);
adrs_set_tree_address(adrs, 0);
adrs_set_ots_address(adrs, 1023);
wots_derive_root(secret, seed, adrs, root);
if (memcmp(root, wots_1023_root, sizeof(hash256_t)) != 0) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_wots_sign(void)
{
hash256_t secret = {0};
@@ -222,6 +169,82 @@ static int test_wots_sign(void)
return 1;
}
static int test_wots_derive_root(void)
{
hash256_t secret;
hash256_t seed;
xmss_adrs_t adrs;
hash256_t root;
hash256_t wots_0_root;
hash256_t wots_1023_root;
size_t len;
memset(secret, 0x12, sizeof(hash256_t));
memset(seed, 0xab, sizeof(hash256_t));
hex_to_bytes("7A968C5F9AE4D2B781872B4E6EE851D55CC02F0AB9196701580D6F503D35DB68", 64, wots_0_root, &len);
hex_to_bytes("939E10CD44769D4D9853F7CF5612D6D83B3AA140A8867CCF34A1DBCC66FC4333", 64, wots_1023_root, &len);
// wots index is 0
adrs_set_layer_address(adrs, 0);
adrs_set_tree_address(adrs, 0);
adrs_set_ots_address(adrs, 0);
wots_derive_root(secret, seed, adrs, root);
if (memcmp(root, wots_0_root, sizeof(hash256_t)) != 0) {
error_print();
return -1;
}
// wots index is 1023
adrs_set_layer_address(adrs, 0);
adrs_set_tree_address(adrs, 0);
adrs_set_ots_address(adrs, 1023);
wots_derive_root(secret, seed, adrs, root);
if (memcmp(root, wots_1023_root, sizeof(hash256_t)) != 0) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_wots_verify(void)
{
uint32_t index = 0;
hash256_t secret;
hash256_t seed;
xmss_adrs_t adrs;
wots_key_t sk;
hash256_t dgst;
wots_sig_t sig;
hash256_t root;
adrs_set_layer_address(adrs, 0);
adrs_set_tree_address(adrs, 0);
adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS);
adrs_set_ots_address(adrs, index);
wots_derive_sk(secret, seed, adrs, sk);
wots_sign(sk, seed, adrs, dgst, sig);
wots_derive_root(secret, seed, adrs, root);
if (wots_verify(root, seed, adrs, dgst, sig) != 1) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
#endif
static int test_xmss_build_tree(void)
{
hash256_t xmss_secret;
@@ -242,15 +265,46 @@ static int test_xmss_build_tree(void)
xmss_build_tree(xmss_secret, seed, adrs, height, tree);
memcpy(xmss_root, tree[(1 << (height + 1)) - 2], sizeof(hash256_t));
/*
if (memcmp(xmss_root, test_root, sizeof(hash256_t))) {
error_print();
return -1;
}
*/
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_xmss_build_root(void)
{
hash256_t secret;
hash256_t seed;
xmss_adrs_t adrs;
size_t height = 4;
hash256_t tree[(1 << (4+1)) - 1];
hash256_t auth_path[4];
hash256_t root;
uint32_t index;
rand_bytes(secret, sizeof(secret));
rand_bytes(seed, sizeof(seed));
adrs_set_layer_address(adrs, 0);
adrs_set_tree_address(adrs, 0);
xmss_build_tree(secret, seed, adrs, height, tree);
for (index = 0; index < (1 << height); index++) {
xmss_build_auth_path(tree, height, index, auth_path);
xmss_build_root(tree[index], index, seed, adrs, auth_path, height, root);
if (memcmp(root, tree[sizeof(tree)/sizeof(tree[0]) - 1], sizeof(hash256_t)) != 0) {
error_print();
return -1;
}
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
#endif
static int test_xmss_key_generate(void)
{
@@ -263,14 +317,13 @@ static int test_xmss_key_generate(void)
error_print();
return -1;
}
xmss_public_key_print(stderr, 0, 0, "xmss_public_key", &key);
xmss_private_key_print(stderr, 0, 0, "xmss_private_key", &key);
xmss_public_key_print(stderr, 0, 4, "xmss_public_key", &key);
xmss_private_key_print(stderr, 0, 4, "xmss_private_key", &key);
if (xmss_key_remaining_signs(&key, &count) != 1) {
error_print();
return -1;
}
fprintf(stderr, "xmss_key_remaining_signs: %zu\n", count);
if (count != 1024) {
error_print();
return -1;
@@ -280,7 +333,6 @@ static int test_xmss_key_generate(void)
error_print();
return -1;
}
fprintf(stderr, "xmss_key_remaining_signs: %zu\n", count);
if (count != 1020) {
error_print();
return -1;
@@ -309,7 +361,6 @@ static int test_xmss_key_to_bytes(void)
error_print();
return -1;
}
fprintf(stderr, "xmss_public_key_size : %zu\n", len);
if (len != XMSS_PUBLIC_KEY_SIZE) {
error_print();
return -1;
@@ -319,7 +370,6 @@ static int test_xmss_key_to_bytes(void)
error_print();
return -1;
}
fprintf(stderr, "xmss_private_key_size : %zu\n", len - XMSS_PUBLIC_KEY_SIZE);
if (len != XMSS_PUBLIC_KEY_SIZE + XMSS_PRIVATE_KEY_SIZE) {
error_print();
return -1;
@@ -354,6 +404,21 @@ 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
@@ -437,7 +502,7 @@ static int test_xmss_sign(void)
return -1;
}
build_auth_path(key.tree, height, index, sig.auth_path);
xmss_build_auth_path(key.tree, height, index, sig.auth_path);
@@ -459,21 +524,27 @@ static int test_xmss_sign(void)
adrs_set_type(adrs, XMSS_ADRS_TYPE_LTREE);
adrs_set_ltree_address(adrs, index);
wots_build_ltree(sig.wots_sig, key.public_key.seed, adrs, root);
wots_pk_to_root(sig.wots_sig, key.public_key.seed, adrs, root);
// wots_root, index, auth_path => xmss_root
/*
adrs_set_type(adrs, XMSS_ADRS_TYPE_HASHTREE);
adrs_set_padding(adrs, 0);
adrs_set_key_and_mask(adrs, 0);
for (h = 0; h < height; h++) {
int right = index & 1;
index >>= 1;
adrs_set_tree_height(adrs, h);
adrs_set_tree_height(adrs, h + 1);
adrs_set_tree_index(adrs, index);
if (right)
randomized_tree_hash(sig.auth_path[h], root, key.public_key.seed, adrs, root);
else randomized_tree_hash(root, sig.auth_path[h], key.public_key.seed, adrs, root);
}
*/
xmss_build_root(root, index, key.public_key.seed, adrs, sig.auth_path, height, root);
if (memcmp(root, key.public_key.root, sizeof(hash256_t)) != 0) {
error_print();
@@ -571,6 +642,25 @@ static int test_xmssmt_index_to_bytes(void)
return 1;
}
static int test_xmssmt_key_generate(void)
{
uint32_t xmssmt_index = XMSSMT_HASH256_20_4_256;
XMSSMT_KEY key;
if (xmssmt_key_generate(&key, xmssmt_index) != 1) {
error_print();
return -1;
}
xmssmt_public_key_print(stderr, 0, 4, "xmssmt_public_key", &key);
xmssmt_private_key_print(stderr, 0, 4, "xmssmt_private_key", &key);
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_xmssmt_signature_size(void)
{
size_t siglen;
@@ -615,7 +705,7 @@ static int test_xmssmt_signature_print(void)
// print
for (i = 0; i < sizeof(xmssmt_consts)/sizeof(xmssmt_consts[0]); i++) {
xmssmt_signature_print_ex(stderr, 0, 0, "xmssmt_signature", &xmssmt_sig, xmssmt_consts[i].xmssmt_type);
xmssmt_signature_print_ex(stderr, 0, 4, "xmssmt_signature", &xmssmt_sig, xmssmt_consts[i].xmssmt_type);
}
printf("%s() ok\n", __FUNCTION__);
@@ -633,13 +723,11 @@ static int test_xmssmt_signature_to_bytes(void)
memset(&xmssmt_sig, 0, sizeof(xmssmt_sig));
//xmssmt_signature_print_ex(stderr, 0, 0, "xmssmt_signature", &xmssmt_sig, xmssmt_type);
if (xmssmt_signature_to_bytes(&xmssmt_sig, xmssmt_type, &p, &len) != 1) {
error_print();
return -1;
}
xmssmt_signature_print(stderr, 0, 0, "xmssmt_signature", buf, len, xmssmt_type);
xmssmt_signature_print(stderr, 0, 4, "xmssmt_signature", buf, len, xmssmt_type);
if (xmssmt_signature_from_bytes(&xmssmt_sig, xmssmt_type, &cp, &len) != 1) {
error_print();
@@ -655,6 +743,309 @@ static int test_xmssmt_signature_to_bytes(void)
return 1;
}
static int test_xmssmt_private_key_size(void)
{
uint32_t xmssmt_types[] = {
XMSSMT_HASH256_20_2_256,
XMSSMT_HASH256_20_4_256,
XMSSMT_HASH256_40_2_256,
XMSSMT_HASH256_40_4_256,
XMSSMT_HASH256_40_8_256,
XMSSMT_HASH256_60_3_256,
XMSSMT_HASH256_60_6_256,
XMSSMT_HASH256_60_12_256,
};
size_t len;
size_t i;
fprintf(stderr, "xmssmt_private_key_size()\n");
for (i = 0; i < sizeof(xmssmt_types)/sizeof(xmssmt_types[0]); i++) {
if (xmssmt_private_key_size(xmssmt_types[i], &len) != 1) {
error_print();
return -1;
}
fprintf(stderr, "%s: %zu\n", xmssmt_type_name(xmssmt_types[i]), len);
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_xmssmt_public_key_to_bytes(void)
{
uint32_t xmssmt_types[] = {
XMSSMT_HASH256_20_2_256,
XMSSMT_HASH256_20_4_256,
XMSSMT_HASH256_40_2_256,
XMSSMT_HASH256_40_4_256,
XMSSMT_HASH256_40_8_256,
XMSSMT_HASH256_60_3_256,
XMSSMT_HASH256_60_6_256,
XMSSMT_HASH256_60_12_256,
};
XMSSMT_KEY key;
uint8_t buf[XMSSMT_PUBLIC_KEY_SIZE];
uint8_t *p = buf;
const uint8_t *cp = buf;
size_t len = 0;
memset(&key, 0, sizeof(key));
key.public_key.xmssmt_type = XMSSMT_HASH256_20_2_256;
if (xmssmt_public_key_to_bytes(&key, &p, &len) != 1) {
error_print();
return -1;
}
if (len != XMSSMT_PUBLIC_KEY_SIZE) {
error_print();
return -1;
}
if (xmssmt_public_key_from_bytes(&key, &cp, &len) != 1) {
error_print();
return -1;
}
if (len) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_xmssmt_private_key_to_bytes(void)
{
uint32_t xmssmt_type = XMSSMT_HASH256_20_4_256;
XMSSMT_KEY key;
size_t buflen;
uint8_t *buf = NULL;
uint8_t *p;
const uint8_t *cp;
size_t len = 0;
memset(&key, 0, sizeof(key));
if (xmssmt_private_key_size(xmssmt_type, &buflen) != 1) {
error_print();
return -1;
}
if (!(buf = malloc(buflen))) {
error_print();
return -1;
}
cp = p = buf;
if (xmssmt_key_generate(&key, xmssmt_type) != 1) {
error_print();
return -1;
}
if (xmssmt_private_key_to_bytes(&key, &p, &len) != 1) {
error_print();
return -1;
}
if (len != buflen) {
error_print();
return -1;
}
if (xmssmt_private_key_from_bytes(&key, &cp, &len) != 1) {
error_print();
return -1;
}
if (len) {
fprintf(stderr, "len = %zu\n", len);
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
static int test_xmssmt_index(void)
{
printf("%s() ok\n", __FUNCTION__);
return 1;
}
// copy from xmss.c
static uint64_t xmssmt_tree_address(uint64_t index, size_t height, size_t layers, size_t layer) {
return (index >> (height/layers) * (layer + 1));
}
// copy from xmss.c
static uint64_t xmssmt_tree_index(uint64_t index, size_t height, size_t layers, size_t layer) {
return (index >> (height/layers) * layer) % (1 << (height/layers));
}
// reference implementation of xmss^mt sign/verify
static int test_xmssmt_sign(void)
{
static const uint8_t hash256_two[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
};
static const uint8_t hash256_three[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
};
uint32_t xmssmt_type = XMSSMT_HASH256_20_4_256;
size_t height = 0;
size_t layers = 0;
uint8_t msg[100] = {0};
XMSSMT_SIGNATURE xmssmt_sig;
XMSSMT_SIGNATURE *sig = &xmssmt_sig;
XMSSMT_KEY xmssmt_key;
XMSSMT_KEY *key = &xmssmt_key;
XMSSMT_SIGN_CTX xmssmt_ctx;
XMSSMT_SIGN_CTX *ctx = &xmssmt_ctx;
hash256_t dgst;
hash256_t hash256_index;
xmss_adrs_t adrs;
uint64_t tree_address;
uint32_t tree_index;
uint32_t layer;
if (xmssmt_type_to_height_and_layers(xmssmt_type, &height, &layers) != 1) {
error_print();
return -1;
}
// generate key
if (xmssmt_key_generate(key, xmssmt_type) != 1) {
error_print();
return -1;
}
xmssmt_private_key_print(stderr, 0, 4, "xmssmt_private_key", key);
// init sign ctx
memset(ctx, 0, sizeof(XMSSMT_SIGN_CTX));
// set ctx->xmssmt_public_key
ctx->xmssmt_public_key = key->public_key;
// set ctx->xmssmt_sig
// XMSSMT_SIGNATURE:
// uint64_t index
// hash256_t random
// wots_sig_t wots_sigs[layers];
// hash256_t auth_path[height/layers]
// copy index
ctx->xmssmt_sig.index = key->index;
// copy wots_sigs[1] to wots_sig[layers - 1] from key
for (layer = 1; layer < layers; layer++) {
memcpy(ctx->xmssmt_sig.wots_sigs[layer], key->wots_sigs[layer - 1], sizeof(wots_sig_t));
}
// build auth_path
for (layer = 0; layer < layers; layer++) {
uint32_t tree_index = xmssmt_tree_index(ctx->xmssmt_sig.index, height, layers, layer);
hash256_t *tree = key->trees + xmss_tree_num_nodes(height/layers) * layer;
hash256_t *auth_path = ctx->xmssmt_sig.auth_path + (height/layers) * layer;
xmss_build_auth_path(tree, height/layers, tree_index, auth_path);
}
// derive ctx->xmssmt_sig.random
memset(hash256_index, 0, 24);
PUTU64(hash256_index + 24, ctx->xmssmt_sig.index);
hash256_init(&ctx->hash256_ctx);
hash256_update(&ctx->hash256_ctx, hash256_three, sizeof(hash256_t));
hash256_update(&ctx->hash256_ctx, key->sk_prf, sizeof(hash256_t));
hash256_update(&ctx->hash256_ctx, hash256_index, sizeof(hash256_t));
hash256_finish(&ctx->hash256_ctx, ctx->xmssmt_sig.random);
// derive wots_sk and save to wots_sigs[0]
layer = 0;
tree_address = xmssmt_tree_address(ctx->xmssmt_sig.index, height, layers, layer);
tree_index = xmssmt_tree_index(ctx->xmssmt_sig.index, height, layers, layer);
adrs_set_layer_address(adrs, layer);
adrs_set_tree_address(adrs, tree_address);
adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS);
adrs_set_ots_address(adrs, tree_index);
wots_derive_sk(key->secret, key->public_key.seed, adrs, ctx->xmssmt_sig.wots_sigs[0]);
// H_msg(M) := HASH256(toByte(2, 32) || r || XMSS_ROOT || toByte(idx_sig, 32) || M)
hash256_init(&ctx->hash256_ctx);
hash256_update(&ctx->hash256_ctx, hash256_two, sizeof(hash256_t));
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_finish(&ctx->hash256_ctx, dgst);
// generate message wots_sig as wots_sigs[0]
layer = 0;
tree_address = xmssmt_tree_address(ctx->xmssmt_sig.index, height, layers, layer);
tree_index = xmssmt_tree_index(ctx->xmssmt_sig.index, height, layers, layer);
adrs_set_layer_address(adrs, layer);
adrs_set_tree_address(adrs, tree_address);
adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS);
adrs_set_ots_address(adrs, tree_index);
wots_sign(ctx->xmssmt_sig.wots_sigs[0], ctx->xmssmt_public_key.seed, adrs, dgst,
ctx->xmssmt_sig.wots_sigs[0]);
xmssmt_signature_print_ex(stderr, 0, 4, "xmssmt_signature", &ctx->xmssmt_sig, xmssmt_type);
// verify
for (layer = 0; layer < layers; layer++) {
uint64_t tree_address = xmssmt_tree_address(ctx->xmssmt_sig.index, height, layers, layer);
uint32_t tree_index = xmssmt_tree_index(ctx->xmssmt_sig.index, height, layers, layer);
wots_key_t wots_pk;
// wots_sig, dgst => wots_pk
adrs_set_layer_address(adrs, layer);
adrs_set_tree_address(adrs, tree_address);
adrs_set_type(adrs, XMSS_ADRS_TYPE_OTS);
adrs_set_ots_address(adrs, tree_index);
wots_sig_to_pk(ctx->xmssmt_sig.wots_sigs[layer], ctx->xmssmt_public_key.seed, adrs, dgst, wots_pk);
// wots_pk => wots_root
adrs_set_type(adrs, XMSS_ADRS_TYPE_LTREE);
adrs_set_ltree_address(adrs, tree_index);
wots_pk_to_root(wots_pk, ctx->xmssmt_public_key.seed, adrs, dgst);
// wots_root, auth_path => xmss_root (as dgst)
adrs_set_type(adrs, XMSS_ADRS_TYPE_HASHTREE);
adrs_set_padding(adrs, 0);
xmss_build_root(dgst, tree_index,
ctx->xmssmt_public_key.seed, adrs,
ctx->xmssmt_sig.auth_path + (height/layers) * layer, height/layers,
dgst);
}
// verify xmssmt_root (save in dgst)
if (memcmp(dgst, ctx->xmssmt_public_key.root, sizeof(hash256_t)) != 0) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
int main(void)
{
@@ -663,18 +1054,29 @@ int main(void)
if (test_wots_sk_to_pk() != 1) goto err;
if (test_wots_sign() != 1) goto err;
if (test_wots_derive_root() != 1) goto err;
if (test_xmss_build_tree() != 1) goto err;
if (test_wots_verify() != 1) goto err;
#endif
if (test_xmss_adrs() != 1) goto err;
if (test_xmss_build_tree() != 1) goto err;
if (test_xmss_build_root() != 1) goto err;
if (test_xmss_key_generate() != 1) goto err;
if (test_xmss_key_to_bytes() != 1) goto err;
if (test_xmss_signature_size() != 1) goto err;
if (test_xmss_sign() != 1) goto err;
if (test_xmss_sign_init() != 1) goto err;
if (test_xmssmt_key_generate() != 1) goto err;
if (test_xmssmt_index_to_bytes() != 1) goto err;
if (test_xmssmt_signature_size() != 1) goto err;
if (test_xmssmt_signature_to_bytes() != 1) goto err;
if (test_xmssmt_signature_size() != 1) goto err;
if (test_xmssmt_signature_print() != 1) goto err;
if (test_xmssmt_private_key_size() != 1) goto err;
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;
printf("%s all tests passed\n", __FILE__);
return 0;
err: