diff --git a/Makefile b/Makefile index 80db10d..1c93132 100644 --- a/Makefile +++ b/Makefile @@ -57,6 +57,9 @@ test/xmssmt: test/xmss.c $(SOURCES) $(OBJS) $(HEADERS) test/speed: test/speed.c $(SOURCES_FAST) $(OBJS) $(HEADERS_FAST) $(CC) -DXMSSMT -DXMSS_VARIANT=\"XMSSMT-SHA2_20/2_256\" $(CFLAGS) -o $@ $(SOURCES_FAST) $< $(LDLIBS) +test/vectors: test/vectors.c $(SOURCES) $(OBJS) $(HEADERS) + $(CC) -DXMSSMT $(CFLAGS) -o $@ $(SOURCES) $< $(LDLIBS) + test/%: test/%.c $(SOURCES) $(OBJS) $(HEADERS) $(CC) $(CFLAGS) -o $@ $(SOURCES) $< $(LDLIBS) diff --git a/test/vectors.c b/test/vectors.c new file mode 100644 index 0000000..7573bca --- /dev/null +++ b/test/vectors.c @@ -0,0 +1,126 @@ +/* + * Generate intermediate test vectors useful to test implementations. + */ + +#include +#include +#include + +#include "../wots.h" +#include "../randombytes.h" +#include "../params.h" +#include "../fips202.h" +#include "../xmss_commons.h" +#include "../xmss_core.h" + +void print_hex(unsigned char *buf, int len) { + for (int i = 0; i < len; i++) { + printf("%x%x", buf[i] / 16, buf[i] & 15); + } +} + +void print_hash(unsigned char *buf, int len) { + unsigned char tmp[10]; + shake128(tmp, 10, buf, len); + print_hex(tmp, 10); +} + +int vectors_xmss(uint32_t oid, int mt) { + xmss_params params; + + if (mt) { + xmssmt_parse_oid(¶ms, oid); + } else { + xmss_parse_oid(¶ms, oid); + } + + unsigned char seed[params.n * 3]; + unsigned char pk[params.pk_bytes]; + unsigned char sk[params.sk_bytes]; + unsigned char msg[1] = {37}; + unsigned char sm[params.sig_bytes + 1]; + unsigned long long smlen = 0; + + for (int i = 0; i < 3*params.n; i++) { + seed[i] = i; + } + + xmssmt_core_keypair2(¶ms, pk, sk, seed); + + ull_to_bytes(sk, params.index_bytes, 1 << (params.full_height - 1)); + + if (mt) { + xmssmt_core_sign(¶ms, sk, sm, &smlen, msg, 1); + } else { + xmss_core_sign(¶ms, sk, sm, &smlen, msg, 1); + } + + if (mt) { + printf("XMSSMT "); + } else { + printf("XMSS "); + } + printf("%d ", oid); + print_hash(pk, params.pk_bytes); + printf(" "); + print_hash(sm, params.sig_bytes); + printf("\n"); +} + +int vectors_wots(uint32_t oid) { + xmss_params params; + + xmss_parse_oid(¶ms, oid); + + unsigned char sk_seed[params.n]; + unsigned char pub_seed[params.n]; + + unsigned char pk[params.wots_sig_bytes]; + unsigned char leaf[params.n]; + + unsigned char sig[params.wots_sig_bytes]; + unsigned char m[params.n]; + uint32_t addr[8] = {0}; + uint32_t addr2[8] = {0}; + + for (int i = 0; i < 8; i++) { + addr[i] = 500000000*i; + addr2[i] = 400000000*i; + } + + for (int i = 0; i < params.n; i++) { + m[i] = 3*i; + pub_seed[i] = 2*i; + sk_seed[i] = i; + } + + wots_pkgen(¶ms, pk, sk_seed, pub_seed, addr); + wots_sign(¶ms, sig, m, sk_seed, pub_seed, addr); + + printf("WOTS+ %d ", oid); + print_hash(pk, params.wots_sig_bytes); + printf(" "); + print_hash(sig, params.wots_sig_bytes); + printf(" "); + + // Note that this garbles pk + gen_leaf_wots(¶ms, leaf, sk_seed, pub_seed, addr, addr2); + print_hash(leaf, params.n); + + printf("\n"); + + return 0; +} + +int main() { + for (uint32_t oid = 1; oid <= 0x15; oid += 3) { + vectors_wots(oid); + } + for (uint32_t oid = 2; oid <= 56; oid += 8) { + vectors_xmss(oid, 1); + } + for (uint32_t oid = 1; oid <= 0x15; oid += 3) { + vectors_xmss(oid, 0); + } +} + diff --git a/xmss_core.c b/xmss_core.c index 6f159dc..a9a07bf 100644 --- a/xmss_core.c +++ b/xmss_core.c @@ -125,6 +125,41 @@ int xmss_core_sign(const xmss_params *params, return xmssmt_core_sign(params, sk, sm, smlen, m, mlen); } +/* + * Derives a XMSSMT key pair for a given parameter set. + * Seed must be 3*n long. + * Format sk: [(ceil(h/8) bit) index || SK_SEED || SK_PRF || root || PUB_SEED] + * Format pk: [root || PUB_SEED] omitting algorithm OID. + */ +int xmssmt_core_keypair2(const xmss_params *params, + unsigned char *pk, unsigned char *sk, + unsigned char *seed) +{ + /* We do not need the auth path in key generation, but it simplifies the + code to have just one treehash routine that computes both root and path + in one function. */ + unsigned char auth_path[params->tree_height * params->n]; + uint32_t top_tree_addr[8] = {0}; + set_layer_addr(top_tree_addr, params->d - 1); + + /* Initialize index to 0. */ + memset(sk, 0, params->index_bytes); + sk += params->index_bytes; + + /* Initialize SK_SEED and SK_PRF. */ + memcpy(sk, seed, 2 * params->n); + + /* Initialize PUB_SEED. */ + memcpy(sk + 3 * params->n, seed + 2 * params->n, params->n); + memcpy(pk + params->n, sk + 3*params->n, params->n); + + /* Compute root node of the top-most subtree. */ + treehash(params, pk, auth_path, sk, pk + params->n, 0, top_tree_addr); + memcpy(sk + 2*params->n, pk, params->n); + + return 0; +} + /* * Generates a XMSSMT key pair for a given parameter set. * Format sk: [(ceil(h/8) bit) index || SK_SEED || SK_PRF || root || PUB_SEED] diff --git a/xmss_core.h b/xmss_core.h index 52e9cfb..b3a674c 100644 --- a/xmss_core.h +++ b/xmss_core.h @@ -46,6 +46,16 @@ int xmss_core_sign_open(const xmss_params *params, int xmssmt_core_keypair(const xmss_params *params, unsigned char *pk, unsigned char *sk); +/* + * Derives a XMSSMT key pair for a given parameter set. + * Seed must be 3*n long. + * Format sk: [(ceil(h/8) bit) index || SK_SEED || SK_PRF || root || PUB_SEED] + * Format pk: [root || PUB_SEED] omitting algorithm OID. + */ +int xmssmt_core_keypair2(const xmss_params *params, + unsigned char *pk, unsigned char *sk, + unsigned char *seed); + /** * Signs a message. Returns an array containing the signature followed by the * message and an updated secret key.