Using global defines for parameters (as seems to be typical in academic crypto code) does not play nice with multithreading at all.master
@@ -2,11 +2,11 @@ CC = /usr/bin/gcc | |||
CFLAGS = -Wall -g -O3 -Wextra | |||
all: test/test_wots \ | |||
test/test_xmss_core_XMSS_SHA2-256_W16_H10 \ | |||
test/test_xmss_core_fast_XMSS_SHA2-256_W16_H10 \ | |||
test/test_xmss_core \ | |||
test/test_xmss_core_fast \ | |||
test/test_xmss \ | |||
test/test_xmssmt_core_fast_XMSSMT_SHA2-256_W16_H20_D4 \ | |||
test/test_xmssmt_core_XMSSMT_SHA2-256_W16_H20_D4 \ | |||
test/test_xmssmt_core_fast \ | |||
test/test_xmssmt_core \ | |||
test/test_xmssmt | |||
.PHONY: clean | |||
@@ -15,41 +15,34 @@ test/test_xmssmt | |||
params_%.h: params.h.py | |||
python3 params.h.py $(patsubst params_%.h,%,$@) > $@ | |||
test/test_wots: params_XMSS_SHA2-256_W16_H10.h hash.c fips202.c hash_address.c randombytes.c wots.c xmss_commons.c test/test_wots.c hash.h fips202.h hash_address.h randombytes.h wots.h xmss_commons.h | |||
ln -sf params_XMSS_SHA2-256_W16_H10.h params.h | |||
$(CC) $(CFLAGS) hash.c fips202.c hash_address.c randombytes.c wots.c xmss_commons.c test/test_wots.c -o $@ -lcrypto -lm | |||
test/test_wots: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_commons.c test/test_wots.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_commons.h | |||
$(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_commons.c test/test_wots.c -o $@ -lcrypto -lm | |||
test/test_xmss_core_XMSS_%: params_XMSS_%.h hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c test/test_xmss_core.c hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core.h xmss_commons.h | |||
ln -sf params_XMSS_$(patsubst test/test_xmss_core_XMSS_%,%,$@).h params.h | |||
$(CC) $(CFLAGS) hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c test/test_xmss_core.c -o $@ -lcrypto -lm | |||
test/test_xmss_core: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c test/test_xmss_core.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core.h xmss_commons.h | |||
$(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c test/test_xmss_core.c -o $@ -lcrypto -lm | |||
test/test_xmss_core_fast_XMSS_%: params_XMSS_%.h hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core_fast.c xmss_commons.c test/test_xmss_core_fast.c hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core_fast.h xmss_commons.h | |||
ln -sf params_XMSS_$(patsubst test/test_xmss_core_fast_XMSS_%,%,$@).h params.h | |||
$(CC) $(CFLAGS) hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core_fast.c xmss_commons.c test/test_xmss_core_fast.c -o $@ -lcrypto -lm | |||
test/test_xmss_core_fast: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core_fast.c xmss_commons.c test/test_xmss_core_fast.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core_fast.h xmss_commons.h | |||
$(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core_fast.c xmss_commons.c test/test_xmss_core_fast.c -o $@ -lcrypto -lm | |||
test/test_xmssmt_core_XMSSMT_%: params_XMSSMT_%.h hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c test/test_xmssmt_core.c hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core.h xmss_commons.h | |||
ln -sf params_XMSSMT_$(patsubst test/test_xmssmt_core_XMSSMT_%,%,$@).h params.h | |||
$(CC) $(CFLAGS) hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c test/test_xmssmt_core.c -o $@ -lcrypto -lm | |||
test/test_xmssmt_core: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c test/test_xmssmt_core.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core.h xmss_commons.h | |||
$(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c test/test_xmssmt_core.c -o $@ -lcrypto -lm | |||
test/test_xmssmt_core_fast_XMSSMT_%: params_XMSSMT_%.h hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core_fast.c xmss_commons.c test/test_xmssmt_core_fast.c hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core_fast.h xmss_commons.h | |||
ln -sf params_XMSSMT_$(patsubst test/test_xmssmt_core_fast_XMSSMT_%,%,$@).h params.h | |||
$(CC) $(CFLAGS) hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core_fast.c xmss_commons.c test/test_xmssmt_core_fast.c -o $@ -lcrypto -lm | |||
test/test_xmssmt_core_fast: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core_fast.c xmss_commons.c test/test_xmssmt_core_fast.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core_fast.h xmss_commons.h | |||
$(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core_fast.c xmss_commons.c test/test_xmssmt_core_fast.c -o $@ -lcrypto -lm | |||
test/test_xmss: params_runtime.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c xmss.c test/test_xmss.c params_runtime.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core.h xmss_commons.h xmss.h | |||
ln -sf params_runtime.h params.h | |||
$(CC) $(CFLAGS) params_runtime.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c xmss.c test/test_xmss.c -o $@ -lcrypto -lm | |||
test/test_xmss: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c xmss.c test/test_xmss.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core.h xmss_commons.h xmss.h | |||
$(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c xmss.c test/test_xmss.c -o $@ -lcrypto -lm | |||
test/test_xmssmt: params_runtime.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c xmss.c test/test_xmssmt.c params_runtime.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core.h xmss_commons.h xmss.h | |||
ln -sf params_runtime.h params.h | |||
$(CC) $(CFLAGS) params_runtime.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c xmss.c test/test_xmssmt.c -o $@ -lcrypto -lm | |||
test/test_xmssmt: params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c xmss.c test/test_xmssmt.c params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss_core.h xmss_commons.h xmss.h | |||
$(CC) $(CFLAGS) params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss_core.c xmss_commons.c xmss.c test/test_xmssmt.c -o $@ -lcrypto -lm | |||
clean: | |||
-rm test/test_wots | |||
-rm test/test_xmss_core_XMSS* | |||
-rm test/test_xmss_core_fast_XMSS* | |||
-rm test/test_xmss_core | |||
-rm test/test_xmss_core_fast | |||
-rm test/test_xmss | |||
-rm test/test_xmssmt_core_XMSS* | |||
-rm test/test_xmssmt_core_fast_XMSS* | |||
-rm test/test_xmssmt_core | |||
-rm test/test_xmssmt_core_fast | |||
-rm test/test_xmssmt | |||
distclean: clean | |||
@@ -2,7 +2,7 @@ | |||
This repository contains the reference implementation that accompanies the Internet Draft _"XMSS: Extended Hash-Based Signatures"_, [`draft-irtf-cfrg-xmss-hash-based-signatures`](https://datatracker.ietf.org/doc/draft-irtf-cfrg-xmss-hash-based-signatures/). | |||
This reference implementation supports all parameter sets as defined in the Draft at run-time (specified by prefixing the public and private keys with a 32-bit `oid`), but also allows for compile-time parameters when directly using the internal `*_core*` functions. | |||
This reference implementation supports all parameter sets as defined in the Draft at run-time (specified by prefixing the public and private keys with a 32-bit `oid`). Implementations that want to use compile-time parameter sets can remove the `struct xmss_params` function parameter. | |||
_While the behavior of the code in this repository is supposed to be stable, the API is not yet fully complete. In particular, the wrapper for run-time parameters does not yet support the back-end functions that make use of BDS traversal (TODO). We will also add more extensive test functionality, making it easier to compare to other XMSS implementations (TODO)._ | |||
@@ -28,7 +28,8 @@ unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]) | |||
return bytes; | |||
} | |||
static int core_hash(unsigned char *out, const unsigned int type, | |||
static int core_hash(const xmss_params *params, | |||
unsigned char *out, const unsigned int type, | |||
const unsigned char *key, unsigned int keylen, | |||
const unsigned char *in, unsigned long long inlen, int n) | |||
{ | |||
@@ -47,16 +48,16 @@ static int core_hash(unsigned char *out, const unsigned int type, | |||
buf[keylen + n + i] = in[i]; | |||
} | |||
if (n == 32 && XMSS_FUNC == XMSS_SHA2) { | |||
if (n == 32 && params->func == XMSS_SHA2) { | |||
SHA256(buf, inlen + keylen + n, out); | |||
} | |||
else if (n == 32 && XMSS_FUNC == XMSS_SHAKE) { | |||
else if (n == 32 && params->func == XMSS_SHAKE) { | |||
shake128(out, 32, buf, inlen + keylen + n); | |||
} | |||
else if (n == 64 && XMSS_FUNC == XMSS_SHA2) { | |||
else if (n == 64 && params->func == XMSS_SHA2) { | |||
SHA512(buf, inlen + keylen + n, out); | |||
} | |||
else if (n == 64 && XMSS_FUNC == XMSS_SHAKE) { | |||
else if (n == 64 && params->func == XMSS_SHAKE) { | |||
shake256(out, 64, buf, inlen + keylen + n); | |||
} | |||
else { | |||
@@ -65,66 +66,70 @@ static int core_hash(unsigned char *out, const unsigned int type, | |||
return 0; | |||
} | |||
int prf(unsigned char *out, const unsigned char *in, | |||
int prf(const xmss_params *params, | |||
unsigned char *out, const unsigned char *in, | |||
const unsigned char *key, unsigned int keylen) | |||
{ | |||
return core_hash(out, 3, key, keylen, in, 32, keylen); | |||
return core_hash(params, out, 3, key, keylen, in, 32, keylen); | |||
} | |||
int h_msg(unsigned char *out, | |||
int h_msg(const xmss_params *params, | |||
unsigned char *out, | |||
const unsigned char *in, unsigned long long inlen, | |||
const unsigned char *key, const unsigned int keylen) | |||
{ | |||
return core_hash(out, 2, key, keylen, in, inlen, XMSS_N); | |||
return core_hash(params, out, 2, key, keylen, in, inlen, params->n); | |||
} | |||
/** | |||
* We assume the left half is in in[0]...in[n-1] | |||
*/ | |||
int hash_h(unsigned char *out, const unsigned char *in, | |||
int hash_h(const xmss_params *params, | |||
unsigned char *out, const unsigned char *in, | |||
const unsigned char *pub_seed, uint32_t addr[8]) | |||
{ | |||
unsigned char buf[2*XMSS_N]; | |||
unsigned char key[XMSS_N]; | |||
unsigned char bitmask[2*XMSS_N]; | |||
unsigned char buf[2*params->n]; | |||
unsigned char key[params->n]; | |||
unsigned char bitmask[2*params->n]; | |||
unsigned char byte_addr[32]; | |||
unsigned int i; | |||
set_key_and_mask(addr, 0); | |||
addr_to_byte(byte_addr, addr); | |||
prf(key, byte_addr, pub_seed, XMSS_N); | |||
prf(params, key, byte_addr, pub_seed, params->n); | |||
// Use MSB order | |||
set_key_and_mask(addr, 1); | |||
addr_to_byte(byte_addr, addr); | |||
prf(bitmask, byte_addr, pub_seed, XMSS_N); | |||
prf(params, bitmask, byte_addr, pub_seed, params->n); | |||
set_key_and_mask(addr, 2); | |||
addr_to_byte(byte_addr, addr); | |||
prf(bitmask+XMSS_N, byte_addr, pub_seed, XMSS_N); | |||
for (i = 0; i < 2*XMSS_N; i++) { | |||
prf(params, bitmask+params->n, byte_addr, pub_seed, params->n); | |||
for (i = 0; i < 2*params->n; i++) { | |||
buf[i] = in[i] ^ bitmask[i]; | |||
} | |||
return core_hash(out, 1, key, XMSS_N, buf, 2*XMSS_N, XMSS_N); | |||
return core_hash(params, out, 1, key, params->n, buf, 2*params->n, params->n); | |||
} | |||
int hash_f(unsigned char *out, const unsigned char *in, | |||
int hash_f(const xmss_params *params, | |||
unsigned char *out, const unsigned char *in, | |||
const unsigned char *pub_seed, uint32_t addr[8]) | |||
{ | |||
unsigned char buf[XMSS_N]; | |||
unsigned char key[XMSS_N]; | |||
unsigned char bitmask[XMSS_N]; | |||
unsigned char buf[params->n]; | |||
unsigned char key[params->n]; | |||
unsigned char bitmask[params->n]; | |||
unsigned char byte_addr[32]; | |||
unsigned int i; | |||
set_key_and_mask(addr, 0); | |||
addr_to_byte(byte_addr, addr); | |||
prf(key, byte_addr, pub_seed, XMSS_N); | |||
prf(params, key, byte_addr, pub_seed, params->n); | |||
set_key_and_mask(addr, 1); | |||
addr_to_byte(byte_addr, addr); | |||
prf(bitmask, byte_addr, pub_seed, XMSS_N); | |||
prf(params, bitmask, byte_addr, pub_seed, params->n); | |||
for (i = 0; i < XMSS_N; i++) { | |||
for (i = 0; i < params->n; i++) { | |||
buf[i] = in[i] ^ bitmask[i]; | |||
} | |||
return core_hash(out, 0, key, XMSS_N, buf, XMSS_N, XMSS_N); | |||
return core_hash(params, out, 0, key, params->n, buf, params->n, params->n); | |||
} |
@@ -8,21 +8,27 @@ Public domain. | |||
#ifndef HASH_H | |||
#define HASH_H | |||
#include "params.h" | |||
#define IS_LITTLE_ENDIAN 1 | |||
unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]); | |||
int prf(unsigned char *out, const unsigned char *in, | |||
int prf(const xmss_params *params, | |||
unsigned char *out, const unsigned char *in, | |||
const unsigned char *key, unsigned int keylen); | |||
int h_msg(unsigned char *out, | |||
int h_msg(const xmss_params *params, | |||
unsigned char *out, | |||
const unsigned char *in, unsigned long long inlen, | |||
const unsigned char *key, const unsigned int keylen); | |||
int hash_h(unsigned char *out, const unsigned char *in, | |||
int hash_h(const xmss_params *params, | |||
unsigned char *out, const unsigned char *in, | |||
const unsigned char *pub_seed, uint32_t addr[8]); | |||
int hash_f(unsigned char *out, const unsigned char *in, | |||
int hash_f(const xmss_params *params, | |||
unsigned char *out, const unsigned char *in, | |||
const unsigned char *pub_seed, uint32_t addr[8]); | |||
#endif |
@@ -1,7 +1,7 @@ | |||
#include <stdint.h> | |||
#include "params_runtime.h" | |||
#include "params.h" | |||
int xmss_parse_oid(uint32_t oid) | |||
int xmss_parse_oid(xmss_params *params, const uint32_t oid) | |||
{ | |||
switch (oid) { | |||
case 0x01000001: | |||
@@ -10,7 +10,7 @@ int xmss_parse_oid(uint32_t oid) | |||
case 0x04000004: | |||
case 0x05000005: | |||
case 0x06000006: | |||
XMSS_FUNC = XMSS_SHA2; | |||
params->func = XMSS_SHA2; | |||
break; | |||
case 0x07000007: | |||
@@ -19,7 +19,7 @@ int xmss_parse_oid(uint32_t oid) | |||
case 0x0a00000a: | |||
case 0x0b00000b: | |||
case 0x0c00000c: | |||
XMSS_FUNC = XMSS_SHAKE; | |||
params->func = XMSS_SHAKE; | |||
break; | |||
default: | |||
@@ -33,7 +33,7 @@ int xmss_parse_oid(uint32_t oid) | |||
case 0x07000007: | |||
case 0x08000008: | |||
case 0x09000009: | |||
XMSS_N = 32; | |||
params->n = 32; | |||
break; | |||
case 0x04000004: | |||
@@ -43,7 +43,7 @@ int xmss_parse_oid(uint32_t oid) | |||
case 0x0a00000a: | |||
case 0x0b00000b: | |||
case 0x0c00000c: | |||
XMSS_N = 64; | |||
params->n = 64; | |||
break; | |||
default: | |||
@@ -54,53 +54,51 @@ int xmss_parse_oid(uint32_t oid) | |||
case 0x04000004: | |||
case 0x07000007: | |||
case 0x0a00000a: | |||
XMSS_FULLHEIGHT = 10; | |||
params->full_height = 10; | |||
break; | |||
case 0x02000002: | |||
case 0x05000005: | |||
case 0x08000008: | |||
case 0x0b00000b: | |||
XMSS_FULLHEIGHT = 16; | |||
params->full_height = 16; | |||
break; | |||
case 0x03000003: | |||
case 0x06000006: | |||
case 0x09000009: | |||
case 0x0c00000c: | |||
XMSS_FULLHEIGHT = 20; | |||
params->full_height = 20; | |||
break; | |||
default: | |||
return 1; | |||
} | |||
XMSS_D = 1; | |||
XMSS_TREEHEIGHT = XMSS_FULLHEIGHT / XMSS_D; | |||
XMSS_WOTS_W = 16; | |||
XMSS_WOTS_LOG_W = 4; | |||
if (XMSS_N == 32) { | |||
XMSS_WOTS_LEN1 = 64; | |||
params->d = 1; | |||
params->tree_height = params->full_height / params->d; | |||
params->wots_w = 16; | |||
params->wots_log_w = 4; | |||
if (params->n == 32) { | |||
params->wots_len1 = 64; | |||
} | |||
else { | |||
XMSS_WOTS_LEN1 = 128; | |||
params->wots_len1 = 128; | |||
} | |||
XMSS_WOTS_LEN2 = 3; | |||
XMSS_WOTS_LEN = XMSS_WOTS_LEN1 + XMSS_WOTS_LEN2; | |||
XMSS_WOTS_KEYSIZE = XMSS_WOTS_LEN * XMSS_N; | |||
XMSS_INDEX_LEN = 4; | |||
XMSS_BYTES = (XMSS_INDEX_LEN + XMSS_N + XMSS_D*XMSS_WOTS_KEYSIZE | |||
+ XMSS_FULLHEIGHT*XMSS_N); | |||
XMSS_PUBLICKEY_BYTES = 2*XMSS_N; | |||
XMSS_PRIVATEKEY_BYTES = 4*XMSS_N + XMSS_INDEX_LEN; | |||
XMSS_OID_LEN = 4; | |||
params->wots_len2 = 3; | |||
params->wots_len = params->wots_len1 + params->wots_len2; | |||
params->wots_keysize = params->wots_len * params->n; | |||
params->index_len = 4; | |||
params->bytes = (params->index_len + params->n + params->d*params->wots_keysize | |||
+ params->full_height *params->n); | |||
params->publickey_bytes = 2*params->n; | |||
params->privatekey_bytes = 4*params->n + params->index_len; | |||
// TODO figure out sensible and legal values for this based on the above | |||
XMSS_BDS_K = 0; | |||
params->bds_k = 0; | |||
return 0; | |||
} | |||
int xmssmt_parse_oid(uint32_t oid) | |||
int xmssmt_parse_oid(xmss_params *params, const uint32_t oid) | |||
{ | |||
switch (oid) { | |||
case 0x01000001: | |||
@@ -119,7 +117,7 @@ int xmssmt_parse_oid(uint32_t oid) | |||
case 0x0e00000e: | |||
case 0x0f00000f: | |||
case 0x01010101: | |||
XMSS_FUNC = XMSS_SHA2; | |||
params->func = XMSS_SHA2; | |||
break; | |||
case 0x02010102: | |||
@@ -138,7 +136,7 @@ int xmssmt_parse_oid(uint32_t oid) | |||
case 0x0f01010f: | |||
case 0x01020201: | |||
case 0x02020202: | |||
XMSS_FUNC = XMSS_SHAKE; | |||
params->func = XMSS_SHAKE; | |||
break; | |||
default: | |||
@@ -162,7 +160,7 @@ int xmssmt_parse_oid(uint32_t oid) | |||
case 0x07010107: | |||
case 0x08010108: | |||
case 0x09010109: | |||
XMSS_N = 32; | |||
params->n = 32; | |||
break; | |||
case 0x09000009: | |||
@@ -182,7 +180,7 @@ int xmssmt_parse_oid(uint32_t oid) | |||
case 0x0f01010f: | |||
case 0x01020201: | |||
case 0x02020202: | |||
XMSS_N = 64; | |||
params->n = 64; | |||
break; | |||
default: | |||
@@ -200,7 +198,7 @@ int xmssmt_parse_oid(uint32_t oid) | |||
case 0x0a01010a: | |||
case 0x0b01010b: | |||
XMSS_FULLHEIGHT = 20; | |||
params->full_height = 20; | |||
break; | |||
case 0x03000003: | |||
@@ -218,7 +216,7 @@ int xmssmt_parse_oid(uint32_t oid) | |||
case 0x0c01010c: | |||
case 0x0d01010d: | |||
case 0x0e01010e: | |||
XMSS_FULLHEIGHT = 40; | |||
params->full_height = 40; | |||
break; | |||
case 0x06000006: | |||
@@ -236,7 +234,7 @@ int xmssmt_parse_oid(uint32_t oid) | |||
case 0x0f01010f: | |||
case 0x01020201: | |||
case 0x02020202: | |||
XMSS_FULLHEIGHT = 60; | |||
params->full_height = 60; | |||
break; | |||
default: | |||
@@ -251,7 +249,7 @@ int xmssmt_parse_oid(uint32_t oid) | |||
case 0x04010104: | |||
case 0x0a01010a: | |||
case 0x0c01010c: | |||
XMSS_D = 2; | |||
params->d = 2; | |||
break; | |||
case 0x02000002: | |||
@@ -262,62 +260,60 @@ int xmssmt_parse_oid(uint32_t oid) | |||
case 0x05010105: | |||
case 0x0b01010b: | |||
case 0x0d01010d: | |||
XMSS_D = 4; | |||
params->d = 4; | |||
break; | |||
case 0x05000005: | |||
case 0x0d00000d: | |||
case 0x06010106: | |||
case 0x0e01010e: | |||
XMSS_D = 8; | |||
params->d = 8; | |||
break; | |||
case 0x06000006: | |||
case 0x0e00000e: | |||
case 0x07010107: | |||
case 0x0f01010f: | |||
XMSS_D = 3; | |||
params->d = 3; | |||
break; | |||
case 0x07000007: | |||
case 0x0f00000f: | |||
case 0x08010108: | |||
case 0x01020201: | |||
XMSS_D = 6; | |||
params->d = 6; | |||
break; | |||
case 0x08000008: | |||
case 0x01010101: | |||
case 0x09010109: | |||
case 0x02020202: | |||
XMSS_D = 12; | |||
params->d = 12; | |||
break; | |||
default: | |||
return 1; | |||
} | |||
XMSS_TREEHEIGHT = XMSS_FULLHEIGHT / XMSS_D; | |||
XMSS_WOTS_W = 16; | |||
XMSS_WOTS_LOG_W = 4; | |||
if (XMSS_N == 32) { | |||
XMSS_WOTS_LEN1 = 64; | |||
params->tree_height = params->full_height / params->d; | |||
params->wots_w = 16; | |||
params->wots_log_w = 4; | |||
if (params->n == 32) { | |||
params->wots_len1 = 64; | |||
} | |||
else { | |||
XMSS_WOTS_LEN1 = 128; | |||
params->wots_len1 = 128; | |||
} | |||
XMSS_WOTS_LEN2 = 3; | |||
XMSS_WOTS_LEN = XMSS_WOTS_LEN1 + XMSS_WOTS_LEN2; | |||
XMSS_WOTS_KEYSIZE = XMSS_WOTS_LEN * XMSS_N; | |||
XMSS_INDEX_LEN = 4; | |||
XMSS_BYTES = (XMSS_INDEX_LEN + XMSS_N + XMSS_D*XMSS_WOTS_KEYSIZE | |||
+ XMSS_FULLHEIGHT*XMSS_N); | |||
XMSS_PUBLICKEY_BYTES = 2*XMSS_N; | |||
XMSS_PRIVATEKEY_BYTES = 4*XMSS_N + XMSS_INDEX_LEN; | |||
XMSS_OID_LEN = 4; | |||
params->wots_len2 = 3; | |||
params->wots_len = params->wots_len1 + params->wots_len2; | |||
params->wots_keysize = params->wots_len * params->n; | |||
params->index_len = 4; | |||
params->bytes = (params->index_len + params->n + params->d*params->wots_keysize | |||
+ params->full_height *params->n); | |||
params->publickey_bytes = 2*params->n; | |||
params->privatekey_bytes = 4*params->n + params->index_len; | |||
// TODO figure out sensible and legal values for this based on the above | |||
XMSS_BDS_K = 0; | |||
params->bds_k = 0; | |||
return 0; | |||
} |
@@ -1,32 +0,0 @@ | |||
#ifndef PARAMS_H | |||
#define PARAMS_H | |||
#include <stdint.h> | |||
// These are simply internal identifiers for the supported hash functions | |||
#define XMSS_SHA2 0 | |||
#define XMSS_SHAKE 1 | |||
// These parameters can be used after calling xmss[mt]_parse_oid(oid). | |||
unsigned int XMSS_FUNC; | |||
unsigned int XMSS_N; | |||
unsigned int XMSS_WOTS_W; | |||
unsigned int XMSS_WOTS_LOG_W; | |||
unsigned int XMSS_WOTS_LEN1; | |||
unsigned int XMSS_WOTS_LEN2; | |||
unsigned int XMSS_WOTS_LEN; | |||
unsigned int XMSS_WOTS_KEYSIZE; | |||
unsigned int XMSS_FULLHEIGHT; | |||
unsigned int XMSS_TREEHEIGHT; | |||
unsigned int XMSS_D; | |||
unsigned int XMSS_INDEX_LEN; | |||
unsigned int XMSS_BYTES; | |||
unsigned int XMSS_PUBLICKEY_BYTES; | |||
unsigned int XMSS_PRIVATEKEY_BYTES; | |||
unsigned int XMSS_OID_LEN; | |||
unsigned int XMSS_BDS_K; | |||
int xmss_parse_oid(uint32_t oid); | |||
int xmssmt_parse_oid(uint32_t oid); | |||
#endif |
@@ -14,27 +14,32 @@ static void hexdump(unsigned char *a, size_t len) | |||
int main() | |||
{ | |||
unsigned char seed[XMSS_N]; | |||
unsigned char pub_seed[XMSS_N]; | |||
xmss_params params; | |||
// TODO test more different OIDs | |||
uint32_t oid = 0x01000001; | |||
xmssmt_parse_oid(¶ms, oid); | |||
int sig_len = XMSS_WOTS_LEN*XMSS_N; | |||
unsigned char seed[params.n]; | |||
unsigned char pub_seed[params.n]; | |||
int sig_len = params.wots_len*params.n; | |||
unsigned char pk1[sig_len]; | |||
unsigned char pk2[sig_len]; | |||
unsigned char sig[sig_len]; | |||
uint32_t addr[8] = {1,2,3,4}; | |||
unsigned char msg[XMSS_N]; | |||
unsigned char msg[params.n]; | |||
int i; | |||
randombytes(seed, XMSS_N); | |||
randombytes(pub_seed, XMSS_N); | |||
randombytes(msg, XMSS_N); | |||
randombytes(seed, params.n); | |||
randombytes(pub_seed, params.n); | |||
randombytes(msg, params.n); | |||
//randombytes(addr, 16); | |||
wots_pkgen(pk1, seed, pub_seed, addr); | |||
wots_sign(sig, msg, seed, pub_seed, addr); | |||
wots_pk_from_sig(pk2, sig, msg, pub_seed, addr); | |||
wots_pkgen(¶ms, pk1, seed, pub_seed, addr); | |||
wots_sign(¶ms, sig, msg, seed, pub_seed, addr); | |||
wots_pk_from_sig(¶ms, pk2, sig, msg, pub_seed, addr); | |||
for (i = 0; i < sig_len; i++) | |||
if (pk1[i] != pk2[i]) { | |||
@@ -15,26 +15,27 @@ unsigned long long mlen; | |||
int main() | |||
{ | |||
xmss_params params; | |||
// TODO test more different OIDs | |||
uint32_t oid = 0x01000001; | |||
xmss_parse_oid(oid); // Parse it to make sure the sizes are set | |||
xmss_parse_oid(¶ms, oid); | |||
int r; | |||
unsigned long long i, j; | |||
unsigned long errors = 0; | |||
unsigned char sk[XMSS_OID_LEN + XMSS_PRIVATEKEY_BYTES]; | |||
unsigned char pk[XMSS_OID_LEN + XMSS_PUBLICKEY_BYTES]; | |||
unsigned char sk[XMSS_OID_LEN + params.privatekey_bytes]; | |||
unsigned char pk[XMSS_OID_LEN + params.publickey_bytes]; | |||
unsigned char mo[MLEN+XMSS_BYTES]; | |||
unsigned char sm[MLEN+XMSS_BYTES]; | |||
unsigned char mo[MLEN+params.bytes]; | |||
unsigned char sm[MLEN+params.bytes]; | |||
printf("keypair\n"); | |||
xmss_keypair(pk, sk, oid); | |||
// check pub_seed in SK | |||
for (i = 0; i < XMSS_N; i++) { | |||
if (pk[XMSS_OID_LEN+XMSS_N+i] != sk[XMSS_OID_LEN+XMSS_INDEX_LEN+2*XMSS_N+i]) printf("pk.pub_seed != sk.pub_seed %llu",i); | |||
if (pk[XMSS_OID_LEN+i] != sk[XMSS_OID_LEN+XMSS_INDEX_LEN+3*XMSS_N+i]) printf("pk.root != sk.root %llu",i); | |||
for (i = 0; i < params.n; i++) { | |||
if (pk[XMSS_OID_LEN+params.n+i] != sk[XMSS_OID_LEN+params.index_len+2*params.n+i]) printf("pk.pub_seed != sk.pub_seed %llu",i); | |||
if (pk[XMSS_OID_LEN+i] != sk[XMSS_OID_LEN+params.index_len+3*params.n+i]) printf("pk.root != sk.root %llu",i); | |||
} | |||
// check index | |||
@@ -54,7 +55,7 @@ int main() | |||
} | |||
printf("\n"); | |||
r = memcmp(mi, sm+XMSS_BYTES,MLEN); | |||
r = memcmp(mi, sm+params.bytes,MLEN); | |||
printf("%d\n", r); | |||
/* Test valid signature */ | |||
@@ -67,7 +68,7 @@ int main() | |||
printf("%llu\n", MLEN-mlen); | |||
/* Test with modified message */ | |||
sm[XMSS_BYTES+10] ^= 1; | |||
sm[params.bytes+10] ^= 1; | |||
r = xmss_sign_open(mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
if (r == 0) errors++; | |||
@@ -77,7 +78,7 @@ int main() | |||
/* Test with modified signature */ | |||
/* Modified index */ | |||
sm[XMSS_BYTES+10] ^= 1; | |||
sm[params.bytes+10] ^= 1; | |||
sm[2] ^= 1; | |||
r = xmss_sign_open(mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
@@ -108,7 +109,7 @@ int main() | |||
/* Modified AUTH */ | |||
sm[240] ^= 1; | |||
sm[XMSS_BYTES - 10] ^= 1; | |||
sm[params.bytes - 10] ^= 1; | |||
r = xmss_sign_open(mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
if (r == 0) errors++; | |||
@@ -14,23 +14,28 @@ unsigned long long mlen; | |||
int main() | |||
{ | |||
xmss_params params; | |||
// TODO test more different OIDs | |||
uint32_t oid = 0x01000001; | |||
xmss_parse_oid(¶ms, oid); | |||
int r; | |||
unsigned long long i, j; | |||
unsigned long errors = 0; | |||
unsigned char sk[4*XMSS_N+4]; | |||
unsigned char pk[2*XMSS_N]; | |||
unsigned char sk[4*params.n+4]; | |||
unsigned char pk[2*params.n]; | |||
unsigned long long signature_length = 4+XMSS_N+XMSS_WOTS_KEYSIZE+XMSS_TREEHEIGHT*XMSS_N; | |||
unsigned long long signature_length = 4+params.n+params.wots_keysize+params.tree_height*params.n; | |||
unsigned char mo[MLEN+signature_length]; | |||
unsigned char sm[MLEN+signature_length]; | |||
printf("keypair\n"); | |||
xmss_core_keypair(pk, sk); | |||
xmss_core_keypair(¶ms, pk, sk); | |||
// check pub_seed in SK | |||
for (i = 0; i < XMSS_N; i++) { | |||
if (pk[XMSS_N+i] != sk[4+2*XMSS_N+i]) printf("pk.pub_seed != sk.pub_seed %llu",i); | |||
if (pk[i] != sk[4+3*XMSS_N+i]) printf("pk.root != sk.root %llu",i); | |||
for (i = 0; i < params.n; i++) { | |||
if (pk[params.n+i] != sk[4+2*params.n+i]) printf("pk.pub_seed != sk.pub_seed %llu",i); | |||
if (pk[i] != sk[4+3*params.n+i]) printf("pk.root != sk.root %llu",i); | |||
} | |||
// check index | |||
@@ -41,7 +46,7 @@ int main() | |||
randombytes(mi, MLEN); | |||
printf("sign\n"); | |||
xmss_core_sign(sk, sm, &smlen, mi, MLEN); | |||
xmss_core_sign(¶ms, sk, sm, &smlen, mi, MLEN); | |||
idx = ((unsigned long)sm[0] << 24) | ((unsigned long)sm[1] << 16) | ((unsigned long)sm[2] << 8) | sm[3]; | |||
printf("\nidx = %lu\n",idx); | |||
@@ -55,7 +60,7 @@ int main() | |||
/* Test valid signature */ | |||
printf("verify\n"); | |||
r = xmss_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmss_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r); | |||
if (r != 0) errors++; | |||
r = memcmp(mi,mo,MLEN); | |||
@@ -64,7 +69,7 @@ int main() | |||
/* Test with modified message */ | |||
sm[signature_length+10] ^= 1; | |||
r = xmss_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmss_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
if (r == 0) errors++; | |||
r = memcmp(mi,mo,MLEN); | |||
@@ -75,7 +80,7 @@ int main() | |||
/* Modified index */ | |||
sm[signature_length+10] ^= 1; | |||
sm[2] ^= 1; | |||
r = xmss_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmss_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
if (r == 0) errors++; | |||
r = memcmp(mi,mo,MLEN); | |||
@@ -85,7 +90,7 @@ int main() | |||
/* Modified R */ | |||
sm[2] ^= 1; | |||
sm[5] ^= 1; | |||
r = xmss_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmss_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
if (r == 0) errors++; | |||
r = memcmp(mi,mo,MLEN); | |||
@@ -95,7 +100,7 @@ int main() | |||
/* Modified OTS sig */ | |||
sm[5] ^= 1; | |||
sm[240] ^= 1; | |||
r = xmss_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmss_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
if (r == 0) errors++; | |||
r = memcmp(mi,mo,MLEN); | |||
@@ -105,7 +110,7 @@ int main() | |||
/* Modified AUTH */ | |||
sm[240] ^= 1; | |||
sm[signature_length - 10] ^= 1; | |||
r = xmss_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmss_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
if (r == 0) errors++; | |||
r = memcmp(mi,mo,MLEN); | |||
@@ -20,31 +20,36 @@ unsigned long long cpucycles(void) | |||
int main() | |||
{ | |||
xmss_params params; | |||
// TODO test more different OIDs | |||
uint32_t oid = 0x01000001; | |||
xmss_parse_oid(¶ms, oid); | |||
int r; | |||
unsigned long long i; | |||
unsigned int k = XMSS_BDS_K; | |||
unsigned int k = params.bds_k; | |||
unsigned long errors = 0; | |||
unsigned char sk[4*XMSS_N+4]; | |||
unsigned char pk[2*XMSS_N]; | |||
unsigned char sk[4*params.n+4]; | |||
unsigned char pk[2*params.n]; | |||
// TODO should we hide this into xmss_fast.c and just allocate a large enough chunk of memory here? | |||
unsigned char stack[(XMSS_TREEHEIGHT+1)*XMSS_N]; | |||
unsigned char stack[(params.tree_height+1)*params.n]; | |||
unsigned int stackoffset = 0; | |||
unsigned char stacklevels[XMSS_TREEHEIGHT+1]; | |||
unsigned char auth[(XMSS_TREEHEIGHT)*XMSS_N]; | |||
unsigned char keep[(XMSS_TREEHEIGHT >> 1)*XMSS_N]; | |||
treehash_inst treehash[XMSS_TREEHEIGHT-k]; | |||
unsigned char th_nodes[(XMSS_TREEHEIGHT-k)*XMSS_N]; | |||
unsigned char retain[((1 << k) - k - 1)*XMSS_N]; | |||
unsigned char stacklevels[params.tree_height+1]; | |||
unsigned char auth[(params.tree_height)*params.n]; | |||
unsigned char keep[(params.tree_height >> 1)*params.n]; | |||
treehash_inst treehash[params.tree_height-k]; | |||
unsigned char th_nodes[(params.tree_height-k)*params.n]; | |||
unsigned char retain[((1 << k) - k - 1)*params.n]; | |||
bds_state s; | |||
bds_state *state = &s; | |||
for (i = 0; i < XMSS_TREEHEIGHT-k; i++) | |||
treehash[i].node = &th_nodes[XMSS_N*i]; | |||
for (i = 0; i < params.tree_height-k; i++) | |||
treehash[i].node = &th_nodes[params.n*i]; | |||
xmss_set_bds_state(state, stack, stackoffset, stacklevels, auth, keep, treehash, retain, 0); | |||
unsigned long long signature_length = 4+XMSS_N+XMSS_WOTS_KEYSIZE+XMSS_TREEHEIGHT*XMSS_N; | |||
unsigned long long signature_length = 4+params.n+params.wots_keysize+params.tree_height*params.n; | |||
unsigned char mi[MLEN]; | |||
unsigned char mo[MLEN+signature_length]; | |||
unsigned char sm[MLEN+signature_length]; | |||
@@ -55,15 +60,15 @@ int main() | |||
printf("keypair\n"); | |||
t1 = cpucycles(); | |||
xmss_core_keypair(pk, sk, state); | |||
xmss_core_keypair(¶ms, pk, sk, state); | |||
t2 = cpucycles(); | |||
printf("cycles = %llu\n", (t2-t1)); | |||
double sec = (t2-t1)/3500000; | |||
printf("ms = %f\n", sec); | |||
// check pub_seed in SK | |||
for (i = 0; i < XMSS_N; i++) { | |||
if (pk[XMSS_N+i] != sk[4+2*XMSS_N+i]) printf("pk.pub_seed != sk.pub_seed %llu",i); | |||
if (pk[i] != sk[4+3*XMSS_N+i]) printf("pk.root != sk.root %llu",i); | |||
for (i = 0; i < params.n; i++) { | |||
if (pk[params.n+i] != sk[4+2*params.n+i]) printf("pk.pub_seed != sk.pub_seed %llu",i); | |||
if (pk[i] != sk[4+3*params.n+i]) printf("pk.root != sk.root %llu",i); | |||
} | |||
// check index | |||
@@ -72,7 +77,7 @@ int main() | |||
for (i = 0; i < SIGNATURES; i++) { | |||
printf("sign\n"); | |||
xmss_core_sign(sk, state, sm, &smlen, mi, MLEN); | |||
xmss_core_sign(¶ms, sk, state, sm, &smlen, mi, MLEN); | |||
idx = ((unsigned long)sm[0] << 24) | ((unsigned long)sm[1] << 16) | ((unsigned long)sm[2] << 8) | sm[3]; | |||
printf("\nidx = %lu\n",idx); | |||
@@ -81,7 +86,7 @@ int main() | |||
/* Test valid signature */ | |||
printf("verify\n"); | |||
r = xmss_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmss_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r); | |||
if (r != 0) errors++; | |||
r = memcmp(mi,mo,MLEN); | |||
@@ -90,7 +95,7 @@ int main() | |||
/* Test with modified message */ | |||
sm[signature_length+10] ^= 1; | |||
r = xmss_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmss_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
if (r == 0) errors++; | |||
r = memcmp(mi,mo,MLEN); | |||
@@ -101,7 +106,7 @@ int main() | |||
/* Modified index */ | |||
sm[signature_length+10] ^= 1; | |||
sm[2] ^= 1; | |||
r = xmss_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmss_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
if (r == 0) errors++; | |||
r = memcmp(mi,mo,MLEN); | |||
@@ -111,7 +116,7 @@ int main() | |||
/* Modified R */ | |||
sm[2] ^= 1; | |||
sm[5] ^= 1; | |||
r = xmss_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmss_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
if (r == 0) errors++; | |||
r = memcmp(mi,mo,MLEN); | |||
@@ -121,7 +126,7 @@ int main() | |||
/* Modified OTS sig */ | |||
sm[5] ^= 1; | |||
sm[240] ^= 1; | |||
r = xmss_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmss_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
if (r == 0) errors++; | |||
r = memcmp(mi,mo,MLEN); | |||
@@ -131,7 +136,7 @@ int main() | |||
/* Modified AUTH */ | |||
sm[240] ^= 1; | |||
sm[signature_length - 10] ^= 1; | |||
r = xmss_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmss_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
if (r == 0) errors++; | |||
r = memcmp(mi,mo,MLEN); | |||
@@ -15,33 +15,34 @@ unsigned long long mlen; | |||
int main() | |||
{ | |||
xmss_params params; | |||
// TODO test more different OIDs | |||
uint32_t oid = 0x01000001; | |||
xmssmt_parse_oid(oid); // Parse it to make sure the sizes are set | |||
xmssmt_parse_oid(¶ms, oid); | |||
int r; | |||
unsigned long long i,j; | |||
unsigned char sk[XMSS_OID_LEN + XMSS_PRIVATEKEY_BYTES]; | |||
unsigned char pk[XMSS_OID_LEN + XMSS_PUBLICKEY_BYTES]; | |||
unsigned char sk[XMSS_OID_LEN + params.privatekey_bytes]; | |||
unsigned char pk[XMSS_OID_LEN + params.publickey_bytes]; | |||
unsigned char mo[MLEN+XMSS_BYTES]; | |||
unsigned char sm[MLEN+XMSS_BYTES]; | |||
unsigned char mo[MLEN+params.bytes]; | |||
unsigned char sm[MLEN+params.bytes]; | |||
printf("keypair\n"); | |||
xmssmt_keypair(pk, sk, oid); | |||
// check pub_seed in SK | |||
for (i = 0; i < XMSS_N; i++) { | |||
if (pk[XMSS_OID_LEN+XMSS_N+i] != sk[XMSS_OID_LEN+XMSS_INDEX_LEN+2*XMSS_N+i]) printf("pk.pub_seed != sk.pub_seed %llu",i); | |||
if (pk[XMSS_OID_LEN+i] != sk[XMSS_OID_LEN+XMSS_INDEX_LEN+3*XMSS_N+i]) printf("pk.root != sk.root %llu",i); | |||
for (i = 0; i < params.n; i++) { | |||
if (pk[XMSS_OID_LEN+params.n+i] != sk[XMSS_OID_LEN+params.index_len+2*params.n+i]) printf("pk.pub_seed != sk.pub_seed %llu",i); | |||
if (pk[XMSS_OID_LEN+i] != sk[XMSS_OID_LEN+params.index_len+3*params.n+i]) printf("pk.root != sk.root %llu",i); | |||
} | |||
printf("pk checked\n"); | |||
// check index | |||
unsigned long long idx = 0; | |||
for (i = 0; i < XMSS_INDEX_LEN; i++) { | |||
idx |= ((unsigned long long)sk[i + XMSS_OID_LEN]) << 8*(XMSS_INDEX_LEN - 1 - i); | |||
for (i = 0; i < params.index_len; i++) { | |||
idx |= ((unsigned long long)sk[i + XMSS_OID_LEN]) << 8*(params.index_len - 1 - i); | |||
} | |||
if (idx) printf("\nidx != 0: %llu\n",idx); | |||
@@ -52,11 +53,11 @@ int main() | |||
printf("sign\n"); | |||
xmssmt_sign(sk, sm, &smlen, mi, MLEN); | |||
idx = 0; | |||
for (j = 0; j < XMSS_INDEX_LEN; j++) { | |||
idx += ((unsigned long long)sm[j]) << 8*(XMSS_INDEX_LEN - 1 - j); | |||
for (j = 0; j < params.index_len; j++) { | |||
idx += ((unsigned long long)sm[j]) << 8*(params.index_len - 1 - j); | |||
} | |||
printf("\nidx = %llu\n",idx); | |||
r = memcmp(mi, sm+XMSS_BYTES,MLEN); | |||
r = memcmp(mi, sm+params.bytes,MLEN); | |||
printf("%d\n", r); | |||
for (j = 0; j < smlen; j++) { | |||
@@ -14,26 +14,31 @@ unsigned long long mlen; | |||
int main() | |||
{ | |||
xmss_params params; | |||
// TODO test more different OIDs | |||
uint32_t oid = 0x01000001; | |||
xmssmt_parse_oid(¶ms, oid); | |||
int r; | |||
unsigned long long i,j; | |||
unsigned char sk[(XMSS_INDEX_LEN+4*XMSS_N)]; | |||
unsigned char pk[2*XMSS_N]; | |||
unsigned char sk[(params.index_len+4*params.n)]; | |||
unsigned char pk[2*params.n]; | |||
unsigned long long signature_length = XMSS_INDEX_LEN + XMSS_N + (XMSS_D*XMSS_WOTS_KEYSIZE) + XMSS_FULLHEIGHT*XMSS_N; | |||
unsigned long long signature_length = params.index_len + params.n + (params.d*params.wots_keysize) + params.full_height*params.n; | |||
unsigned char mo[MLEN+signature_length]; | |||
unsigned char sm[MLEN+signature_length]; | |||
printf("keypair\n"); | |||
xmssmt_core_keypair(pk, sk); | |||
xmssmt_core_keypair(¶ms, pk, sk); | |||
// check pub_seed in SK | |||
for (i = 0; i < XMSS_N; i++) { | |||
if (pk[XMSS_N+i] != sk[XMSS_INDEX_LEN+2*XMSS_N+i]) printf("pk.pub_seed != sk.pub_seed %llu",i); | |||
if (pk[i] != sk[XMSS_INDEX_LEN+3*XMSS_N+i]) printf("pk.root != sk.root %llu",i); | |||
for (i = 0; i < params.n; i++) { | |||
if (pk[params.n+i] != sk[params.index_len+2*params.n+i]) printf("pk.pub_seed != sk.pub_seed %llu",i); | |||
if (pk[i] != sk[params.index_len+3*params.n+i]) printf("pk.root != sk.root %llu",i); | |||
} | |||
printf("pk checked\n"); | |||
unsigned int idx_len = XMSS_INDEX_LEN; | |||
unsigned int idx_len = params.index_len; | |||
// check index | |||
unsigned long long idx = 0; | |||
for (i = 0; i < idx_len; i++) { | |||
@@ -46,7 +51,7 @@ int main() | |||
randombytes(mi, MLEN); | |||
printf("sign\n"); | |||
xmssmt_core_sign(sk, sm, &smlen, mi, MLEN); | |||
xmssmt_core_sign(¶ms, sk, sm, &smlen, mi, MLEN); | |||
idx = 0; | |||
for (j = 0; j < idx_len; j++) { | |||
idx += ((unsigned long long)sm[j]) << 8*(idx_len - 1 - j); | |||
@@ -62,7 +67,7 @@ int main() | |||
/* Test valid signature */ | |||
printf("verify\n"); | |||
r = xmssmt_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmssmt_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r); | |||
r = memcmp(mi,mo,MLEN); | |||
printf("%d\n", r); | |||
@@ -70,7 +75,7 @@ int main() | |||
/* Test with modified message */ | |||
sm[52] ^= 1; | |||
r = xmssmt_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmssmt_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
r = memcmp(mi,mo,MLEN); | |||
printf("%d\n", (r!=0) - 1); | |||
@@ -80,7 +85,7 @@ int main() | |||
sm[260] ^= 1; | |||
sm[52] ^= 1; | |||
sm[2] ^= 1; | |||
r = xmssmt_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmssmt_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
r = memcmp(mi,mo,MLEN); | |||
printf("%d\n", (r!=0) - 1); | |||
@@ -23,12 +23,17 @@ unsigned long long cpucycles(void) | |||
int main() | |||
{ | |||
xmss_params params; | |||
// TODO test more different OIDs | |||
uint32_t oid = 0x01000001; | |||
xmssmt_parse_oid(¶ms, oid); | |||
int r; | |||
unsigned long long i,j; | |||
unsigned int n = XMSS_N; | |||
unsigned int h = XMSS_FULLHEIGHT; | |||
unsigned int d = XMSS_D; | |||
unsigned int k = XMSS_BDS_K; | |||
unsigned int n = params.n; | |||
unsigned int h = params.full_height; | |||
unsigned int d = params.d; | |||
unsigned int k = params.bds_k; | |||
unsigned int tree_h = h / d; | |||
@@ -40,7 +45,7 @@ int main() | |||
treehash_inst treehash[(2*d-1) * (tree_h-k)]; | |||
unsigned char th_nodes[(2*d-1) * (tree_h-k)*n]; | |||
unsigned char retain[(2*d-1) * ((1 << k) - k - 1)*n]; | |||
unsigned char wots_sigs[d * XMSS_WOTS_KEYSIZE]; | |||
unsigned char wots_sigs[d * params.wots_keysize]; | |||
// first d are 'regular' states, second d are 'next'; top tree has no 'next' | |||
bds_state states[2*d-1]; | |||
@@ -57,25 +62,25 @@ int main() | |||
); | |||
} | |||
unsigned char sk[(XMSS_INDEX_LEN+4*n)]; | |||
unsigned char sk[(params.index_len+4*n)]; | |||
unsigned char pk[2*n]; | |||
unsigned long long signature_length = XMSS_INDEX_LEN + n + (d*XMSS_WOTS_KEYSIZE) + h*n; | |||
unsigned long long signature_length = params.index_len + n + (d*params.wots_keysize) + h*n; | |||
unsigned char mo[MLEN+signature_length]; | |||
unsigned char sm[MLEN+signature_length]; | |||
randombytes(mi, MLEN); | |||
printf("keypair\n"); | |||
xmssmt_core_keypair(pk, sk, states, wots_sigs); | |||
xmssmt_core_keypair(¶ms, pk, sk, states, wots_sigs); | |||
// check pub_seed in SK | |||
for (i = 0; i < n; i++) { | |||
if (pk[n+i] != sk[XMSS_INDEX_LEN+2*n+i]) printf("pk.pub_seed != sk.pub_seed %llu",i); | |||
if (pk[i] != sk[XMSS_INDEX_LEN+3*n+i]) printf("pk.root != sk.root %llu",i); | |||
if (pk[n+i] != sk[params.index_len+2*n+i]) printf("pk.pub_seed != sk.pub_seed %llu",i); | |||
if (pk[i] != sk[params.index_len+3*n+i]) printf("pk.root != sk.root %llu",i); | |||
} | |||
printf("pk checked\n"); | |||
unsigned int idx_len = XMSS_INDEX_LEN; | |||
unsigned int idx_len = params.index_len; | |||
// check index | |||
unsigned long long idx = 0; | |||
for (i = 0; i < idx_len; i++) { | |||
@@ -87,7 +92,7 @@ int main() | |||
for (i = 0; i < SIGNATURES; i++) { | |||
printf("sign\n"); | |||
t1 = cpucycles(); | |||
xmssmt_core_sign(sk, states, wots_sigs, sm, &smlen, mi, MLEN); | |||
xmssmt_core_sign(¶ms, sk, states, wots_sigs, sm, &smlen, mi, MLEN); | |||
t2 = cpucycles(); | |||
printf("signing cycles = %llu\n", (t2-t1)); | |||
@@ -102,7 +107,7 @@ int main() | |||
/* Test valid signature */ | |||
printf("verify\n"); | |||
t1 = cpucycles(); | |||
r = xmssmt_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmssmt_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
t2 = cpucycles(); | |||
printf("verification cycles = %llu\n", (t2-t1)); | |||
printf("%d\n", r); | |||
@@ -112,7 +117,7 @@ int main() | |||
/* Test with modified message */ | |||
sm[52] ^= 1; | |||
r = xmssmt_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmssmt_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
r = memcmp(mi,mo,MLEN); | |||
printf("%d\n", (r!=0) - 1); | |||
@@ -122,7 +127,7 @@ int main() | |||
sm[260] ^= 1; | |||
sm[52] ^= 1; | |||
sm[2] ^= 1; | |||
r = xmssmt_core_sign_open(mo, &mlen, sm, smlen, pk); | |||
r = xmssmt_core_sign_open(¶ms, mo, &mlen, sm, smlen, pk); | |||
printf("%d\n", r+1); | |||
r = memcmp(mi,mo,MLEN); | |||
printf("%d\n", (r!=0) - 1); | |||
@@ -17,14 +17,15 @@ Public domain. | |||
* Expands an n-byte array into a len*n byte array | |||
* this is done using PRF | |||
*/ | |||
static void expand_seed(unsigned char *outseeds, const unsigned char *inseed) | |||
static void expand_seed(const xmss_params *params, | |||
unsigned char *outseeds, const unsigned char *inseed) | |||
{ | |||
uint32_t i; | |||
unsigned char ctr[32]; | |||
for (i = 0; i < XMSS_WOTS_LEN; i++) { | |||
for (i = 0; i < params->wots_len; i++) { | |||
to_byte(ctr, i, 32); | |||
prf(outseeds + i*XMSS_N, ctr, inseed, XMSS_N); | |||
prf(params, outseeds + i*params->n, ctr, inseed, params->n); | |||
} | |||
} | |||
@@ -35,26 +36,28 @@ static void expand_seed(unsigned char *outseeds, const unsigned char *inseed) | |||
* interpretes in as start-th value of the chain | |||
* addr has to contain the address of the chain | |||
*/ | |||
static void gen_chain(unsigned char *out, const unsigned char *in, | |||
static void gen_chain(const xmss_params *params, | |||
unsigned char *out, const unsigned char *in, | |||
unsigned int start, unsigned int steps, | |||
const unsigned char *pub_seed, uint32_t addr[8]) | |||
{ | |||
uint32_t i; | |||
for (i = 0; i < XMSS_N; i++) { | |||
for (i = 0; i < params->n; i++) { | |||
out[i] = in[i]; | |||
} | |||
for (i = start; i < (start+steps) && i < XMSS_WOTS_W; i++) { | |||
for (i = start; i < (start+steps) && i < params->wots_w; i++) { | |||
set_hash_addr(addr, i); | |||
hash_f(out, out, pub_seed, addr); | |||
hash_f(params, out, out, pub_seed, addr); | |||
} | |||
} | |||
/** | |||
* base_w algorithm as described in draft. | |||
*/ | |||
static void base_w(int *output, const int out_len, const unsigned char *input) | |||
static void base_w(const xmss_params *params, | |||
int *output, const int out_len, const unsigned char *input) | |||
{ | |||
int in = 0; | |||
int out = 0; | |||
@@ -68,87 +71,89 @@ static void base_w(int *output, const int out_len, const unsigned char *input) | |||
in++; | |||
bits += 8; | |||
} | |||
bits -= XMSS_WOTS_LOG_W; | |||
output[out] = (total >> bits) & (XMSS_WOTS_W - 1); | |||
bits -= params->wots_log_w; | |||
output[out] = (total >> bits) & (params->wots_w - 1); | |||
out++; | |||
} | |||
} | |||
void wots_pkgen(unsigned char *pk, const unsigned char *sk, | |||
void wots_pkgen(const xmss_params *params, | |||
unsigned char *pk, const unsigned char *sk, | |||
const unsigned char *pub_seed, uint32_t addr[8]) | |||
{ | |||
uint32_t i; | |||
expand_seed(pk, sk); | |||
for (i = 0; i < XMSS_WOTS_LEN; i++) { | |||
expand_seed(params, pk, sk); | |||
for (i = 0; i < params->wots_len; i++) { | |||
set_chain_addr(addr, i); | |||
gen_chain(pk + i*XMSS_N, pk + i*XMSS_N, | |||
0, XMSS_WOTS_W-1, pub_seed, addr); | |||
gen_chain(params, pk + i*params->n, pk + i*params->n, | |||
0, params->wots_w-1, pub_seed, addr); | |||
} | |||
} | |||
void wots_sign(unsigned char *sig, const unsigned char *msg, | |||
void wots_sign(const xmss_params *params, | |||
unsigned char *sig, const unsigned char *msg, | |||
const unsigned char *sk, const unsigned char *pub_seed, | |||
uint32_t addr[8]) | |||
{ | |||
int basew[XMSS_WOTS_LEN]; | |||
int basew[params->wots_len]; | |||
int csum = 0; | |||
unsigned char csum_bytes[((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) + 7) / 8]; | |||
int csum_basew[XMSS_WOTS_LEN2]; | |||
unsigned char csum_bytes[((params->wots_len2 * params->wots_log_w) + 7) / 8]; | |||
int csum_basew[params->wots_len2]; | |||
uint32_t i; | |||
base_w(basew, XMSS_WOTS_LEN1, msg); | |||
base_w(params, basew, params->wots_len1, msg); | |||
for (i = 0; i < XMSS_WOTS_LEN1; i++) { | |||
csum += XMSS_WOTS_W - 1 - basew[i]; | |||
for (i = 0; i < params->wots_len1; i++) { | |||
csum += params->wots_w - 1 - basew[i]; | |||
} | |||
csum = csum << (8 - ((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) % 8)); | |||
csum = csum << (8 - ((params->wots_len2 * params->wots_log_w) % 8)); | |||
to_byte(csum_bytes, csum, ((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) + 7) / 8); | |||
base_w(csum_basew, XMSS_WOTS_LEN2, csum_bytes); | |||
to_byte(csum_bytes, csum, ((params->wots_len2 * params->wots_log_w) + 7) / 8); | |||
base_w(params, csum_basew, params->wots_len2, csum_bytes); | |||
for (i = 0; i < XMSS_WOTS_LEN2; i++) { | |||
basew[XMSS_WOTS_LEN1 + i] = csum_basew[i]; | |||
for (i = 0; i < params->wots_len2; i++) { | |||
basew[params->wots_len1 + i] = csum_basew[i]; | |||
} | |||
expand_seed(sig, sk); | |||
expand_seed(params, sig, sk); | |||
for (i = 0; i < XMSS_WOTS_LEN; i++) { | |||
for (i = 0; i < params->wots_len; i++) { | |||
set_chain_addr(addr, i); | |||
gen_chain(sig + i*XMSS_N, sig + i*XMSS_N, | |||
gen_chain(params, sig + i*params->n, sig + i*params->n, | |||
0, basew[i], pub_seed, addr); | |||
} | |||
} | |||
void wots_pk_from_sig(unsigned char *pk, | |||
void wots_pk_from_sig(const xmss_params *params, unsigned char *pk, | |||
const unsigned char *sig, const unsigned char *msg, | |||
const unsigned char *pub_seed, uint32_t addr[8]) | |||
{ | |||
int basew[XMSS_WOTS_LEN]; | |||
int basew[params->wots_len]; | |||
int csum = 0; | |||
unsigned char csum_bytes[((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) + 7) / 8]; | |||
int csum_basew[XMSS_WOTS_LEN2]; | |||
unsigned char csum_bytes[((params->wots_len2 * params->wots_log_w) + 7) / 8]; | |||
int csum_basew[params->wots_len2]; | |||
uint32_t i = 0; | |||
base_w(basew, XMSS_WOTS_LEN1, msg); | |||
base_w(params, basew, params->wots_len1, msg); | |||
for (i=0; i < XMSS_WOTS_LEN1; i++) { | |||
csum += XMSS_WOTS_W - 1 - basew[i]; | |||
for (i=0; i < params->wots_len1; i++) { | |||
csum += params->wots_w - 1 - basew[i]; | |||
} | |||
csum = csum << (8 - ((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) % 8)); | |||
csum = csum << (8 - ((params->wots_len2 * params->wots_log_w) % 8)); | |||
to_byte(csum_bytes, csum, ((XMSS_WOTS_LEN2 * XMSS_WOTS_LOG_W) + 7) / 8); | |||
base_w(csum_basew, XMSS_WOTS_LEN2, csum_bytes); | |||
to_byte(csum_bytes, csum, ((params->wots_len2 * params->wots_log_w) + 7) / 8); | |||
base_w(params, csum_basew, params->wots_len2, csum_bytes); | |||
for (i = 0; i < XMSS_WOTS_LEN2; i++) { | |||
basew[XMSS_WOTS_LEN1 + i] = csum_basew[i]; | |||
for (i = 0; i < params->wots_len2; i++) { | |||
basew[params->wots_len1 + i] = csum_basew[i]; | |||
} | |||
for (i=0; i < XMSS_WOTS_LEN; i++) { | |||
for (i=0; i < params->wots_len; i++) { | |||
set_chain_addr(addr, i); | |||
gen_chain(pk + i*XMSS_N, sig + i*XMSS_N, | |||
basew[i], XMSS_WOTS_W-1-basew[i], pub_seed, addr); | |||
gen_chain(params, pk + i*params->n, sig + i*params->n, | |||
basew[i], params->wots_w-1-basew[i], pub_seed, addr); | |||
} | |||
} |
@@ -9,6 +9,7 @@ Public domain. | |||
#define WOTS_H | |||
#include <stdint.h> | |||
#include "params.h" | |||
/** | |||
* WOTS key generation. Takes a 32byte seed for the secret key, expands it to a full WOTS secret key and computes the corresponding public key. | |||
@@ -16,20 +17,22 @@ Public domain. | |||
* | |||
* Places the computed public key at address pk. | |||
*/ | |||
void wots_pkgen(unsigned char *pk, const unsigned char *sk, | |||
void wots_pkgen(const xmss_params *params, | |||
unsigned char *pk, const unsigned char *sk, | |||
const unsigned char *pub_seed, uint32_t addr[8]); | |||
/** | |||
* Takes a m-byte message and the 32-byte seed for the secret key to compute a signature that is placed at "sig". | |||
*/ | |||
void wots_sign(unsigned char *sig, const unsigned char *msg, | |||
void wots_sign(const xmss_params *params, | |||
unsigned char *sig, const unsigned char *msg, | |||
const unsigned char *sk, const unsigned char *pub_seed, | |||
uint32_t addr[8]); | |||
/** | |||
* Takes a WOTS signature, a m-byte message and computes a WOTS public key that it places at pk. | |||
*/ | |||
void wots_pk_from_sig(unsigned char *pk, | |||
void wots_pk_from_sig(const xmss_params *params, unsigned char *pk, | |||
const unsigned char *sig, const unsigned char *msg, | |||
const unsigned char *pub_seed, uint32_t addr[8]); | |||
@@ -1,6 +1,6 @@ | |||
#include <stdint.h> | |||
#include "params_runtime.h" | |||
#include "params.h" | |||
#include "xmss_core.h" | |||
/* This file provides wrapper functions that take keys that include OIDs to | |||
@@ -9,94 +9,101 @@ it falls back to the regular XMSS core functions. */ | |||
int xmss_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) | |||
{ | |||
xmss_params params; | |||
unsigned int i; | |||
if (xmss_parse_oid(oid)) { | |||
if (xmss_parse_oid(¶ms, oid)) { | |||
return 1; | |||
} | |||
for (i = 0; i < XMSS_OID_LEN; i++) { | |||
pk[i] = (oid >> (8 * i)) & 0xFF; | |||
/* For an implementation that uses runtime parameters, it is crucial | |||
that the OID is part of the secret key as well. */ | |||
that the OID is part of the secret key as well; | |||
i.e. not just for interoperability, but also for internal use. */ | |||
sk[i] = (oid >> (8 * i)) & 0xFF; | |||
} | |||
return xmss_core_keypair(pk + XMSS_OID_LEN, sk + XMSS_OID_LEN); | |||
return xmss_core_keypair(¶ms, pk + XMSS_OID_LEN, sk + XMSS_OID_LEN); | |||
} | |||
int xmss_sign(unsigned char *sk, | |||
unsigned char *sm, unsigned long long *smlen, | |||
const unsigned char *m, unsigned long long mlen) | |||
{ | |||
xmss_params params; | |||
uint32_t oid = 0; | |||
unsigned int i; | |||
for (i = 0; i < XMSS_OID_LEN; i++) { | |||
oid |= sk[i] << (i * 8); | |||
} | |||
if (xmss_parse_oid(oid)) { | |||
if (xmss_parse_oid(¶ms, oid)) { | |||
return 1; | |||
} | |||
return xmss_core_sign(sk + XMSS_OID_LEN, sm, smlen, m, mlen); | |||
return xmss_core_sign(¶ms, sk + XMSS_OID_LEN, sm, smlen, m, mlen); | |||
} | |||
int xmss_sign_open(unsigned char *m, unsigned long long *mlen, | |||
const unsigned char *sm, unsigned long long smlen, | |||
const unsigned char *pk) | |||
{ | |||
xmss_params params; | |||
uint32_t oid = 0; | |||
unsigned int i; | |||
for (i = 0; i < XMSS_OID_LEN; i++) { | |||
oid |= pk[i] << (i * 8); | |||
} | |||
if (xmss_parse_oid(oid)) { | |||
if (xmss_parse_oid(¶ms, oid)) { | |||
return 1; | |||
} | |||
return xmss_core_sign_open(m, mlen, sm, smlen, pk + XMSS_OID_LEN); | |||
return xmss_core_sign_open(¶ms, m, mlen, sm, smlen, pk + XMSS_OID_LEN); | |||
} | |||
int xmssmt_keypair(unsigned char *pk, unsigned char *sk, const uint32_t oid) | |||
{ | |||
xmss_params params; | |||
unsigned int i; | |||
if (xmssmt_parse_oid(oid)) { | |||
if (xmssmt_parse_oid(¶ms, oid)) { | |||
return 1; | |||
} | |||
for (i = 0; i < XMSS_OID_LEN; i++) { | |||
pk[i] = (oid >> (8 * i)) & 0xFF; | |||
sk[i] = (oid >> (8 * i)) & 0xFF; | |||
} | |||
return xmssmt_core_keypair(pk + XMSS_OID_LEN, sk + XMSS_OID_LEN); | |||
return xmssmt_core_keypair(¶ms, pk + XMSS_OID_LEN, sk + XMSS_OID_LEN); | |||
} | |||
int xmssmt_sign(unsigned char *sk, | |||
unsigned char *sm, unsigned long long *smlen, | |||
const unsigned char *m, unsigned long long mlen) | |||
{ | |||
xmss_params params; | |||
uint32_t oid = 0; | |||
unsigned int i; | |||
for (i = 0; i < XMSS_OID_LEN; i++) { | |||
oid |= sk[i] << (i * 8); | |||
} | |||
if (xmssmt_parse_oid(oid)) { | |||
if (xmssmt_parse_oid(¶ms, oid)) { | |||
return 1; | |||
} | |||
return xmssmt_core_sign(sk + XMSS_OID_LEN, sm, smlen, m, mlen); | |||
return xmssmt_core_sign(¶ms, sk + XMSS_OID_LEN, sm, smlen, m, mlen); | |||
} | |||
int xmssmt_sign_open(unsigned char *m, unsigned long long *mlen, | |||
const unsigned char *sm, unsigned long long smlen, | |||
const unsigned char *pk) | |||
{ | |||
xmss_params params; | |||
uint32_t oid = 0; | |||
unsigned int i; | |||
for (i = 0; i < XMSS_OID_LEN; i++) { | |||
oid |= pk[i] << (i * 8); | |||
} | |||
if (xmssmt_parse_oid(oid)) { | |||
if (xmssmt_parse_oid(¶ms, oid)) { | |||
return 1; | |||
} | |||
return xmssmt_core_sign_open(m, mlen, sm, smlen, pk + XMSS_OID_LEN); | |||
return xmssmt_core_sign_open(¶ms, m, mlen, sm, smlen, pk + XMSS_OID_LEN); | |||
} |
@@ -28,26 +28,26 @@ void to_byte(unsigned char *out, unsigned long long in, uint32_t bytes) | |||
/** | |||
* Computes the leaf at a given address. First generates the WOTS key pair, then computes leaf using l_tree. As this happens position independent, we only require that addr encodes the right ltree-address. | |||
*/ | |||
void gen_leaf_wots(unsigned char *leaf, | |||
void gen_leaf_wots(const xmss_params *params, unsigned char *leaf, | |||
const unsigned char *sk_seed, const unsigned char *pub_seed, | |||
uint32_t ltree_addr[8], uint32_t ots_addr[8]) | |||
{ | |||
unsigned char seed[XMSS_N]; | |||
unsigned char pk[XMSS_WOTS_KEYSIZE]; | |||
unsigned char seed[params->n]; | |||
unsigned char pk[params->wots_keysize]; | |||
get_seed(seed, sk_seed, ots_addr); | |||
wots_pkgen(pk, seed, pub_seed, ots_addr); | |||
get_seed(params, seed, sk_seed, ots_addr); | |||
wots_pkgen(params, pk, seed, pub_seed, ots_addr); | |||
l_tree(leaf, pk, pub_seed, ltree_addr); | |||
l_tree(params, leaf, pk, pub_seed, ltree_addr); | |||
} | |||
/** | |||
* Used for pseudorandom keygeneration, | |||
* generates the seed for the WOTS keypair at address addr | |||
* | |||
* takes XMSS_N byte sk_seed and returns XMSS_N byte seed using 32 byte address addr. | |||
* takes params->n byte sk_seed and returns params->n byte seed using 32 byte address addr. | |||
*/ | |||
void get_seed(unsigned char *seed, | |||
void get_seed(const xmss_params *params, unsigned char *seed, | |||
const unsigned char *sk_seed, uint32_t addr[8]) | |||
{ | |||
unsigned char bytes[32]; | |||
@@ -58,16 +58,16 @@ void get_seed(unsigned char *seed, | |||
set_key_and_mask(addr, 0); | |||
// Generate pseudorandom value | |||
addr_to_byte(bytes, addr); | |||
prf(seed, bytes, sk_seed, XMSS_N); | |||
prf(params, seed, bytes, sk_seed, params->n); | |||
} | |||
/** | |||
* Computes a leaf from a WOTS public key using an L-tree. | |||
*/ | |||
void l_tree(unsigned char *leaf, unsigned char *wots_pk, | |||
void l_tree(const xmss_params *params, unsigned char *leaf, unsigned char *wots_pk, | |||
const unsigned char *pub_seed, uint32_t addr[8]) | |||
{ | |||
unsigned int l = XMSS_WOTS_LEN; | |||
unsigned int l = params->wots_len; | |||
uint32_t i = 0; | |||
uint32_t height = 0; | |||
uint32_t bound; | |||
@@ -78,10 +78,10 @@ void l_tree(unsigned char *leaf, unsigned char *wots_pk, | |||
bound = l >> 1; | |||
for (i = 0; i < bound; i++) { | |||
set_tree_index(addr, i); | |||
hash_h(wots_pk + i*XMSS_N, wots_pk + i*2*XMSS_N, pub_seed, addr); | |||
hash_h(params, wots_pk + i*params->n, wots_pk + i*2*params->n, pub_seed, addr); | |||
} | |||
if (l & 1) { | |||
memcpy(wots_pk + (l >> 1)*XMSS_N, wots_pk + (l - 1)*XMSS_N, XMSS_N); | |||
memcpy(wots_pk + (l >> 1)*params->n, wots_pk + (l - 1)*params->n, params->n); | |||
l = (l >> 1) + 1; | |||
} | |||
else { | |||
@@ -90,77 +90,78 @@ void l_tree(unsigned char *leaf, unsigned char *wots_pk, | |||
height++; | |||
set_tree_height(addr, height); | |||
} | |||
memcpy(leaf, wots_pk, XMSS_N); | |||
memcpy(leaf, wots_pk, params->n); | |||
} | |||
/** | |||
* Computes a root node given a leaf and an authapth | |||
*/ | |||
static void validate_authpath(unsigned char *root, | |||
static void validate_authpath(const xmss_params *params, unsigned char *root, | |||
const unsigned char *leaf, unsigned long leafidx, | |||
const unsigned char *authpath, | |||
const unsigned char *pub_seed, uint32_t addr[8]) | |||
{ | |||
uint32_t i, j; | |||
unsigned char buffer[2*XMSS_N]; | |||
unsigned char buffer[2*params->n]; | |||
// If leafidx is odd (last bit = 1), current path element is a right child and authpath has to go to the left. | |||
// Otherwise, it is the other way around | |||
if (leafidx & 1) { | |||
for (j = 0; j < XMSS_N; j++) { | |||
buffer[XMSS_N + j] = leaf[j]; | |||
for (j = 0; j < params->n; j++) { | |||
buffer[params->n + j] = leaf[j]; | |||
buffer[j] = authpath[j]; | |||
} | |||
} | |||
else { | |||
for (j = 0; j < XMSS_N; j++) { | |||
for (j = 0; j < params->n; j++) { | |||
buffer[j] = leaf[j]; | |||
buffer[XMSS_N + j] = authpath[j]; | |||
buffer[params->n + j] = authpath[j]; | |||
} | |||
} | |||
authpath += XMSS_N; | |||
authpath += params->n; | |||
for (i = 0; i < XMSS_TREEHEIGHT-1; i++) { | |||
for (i = 0; i < params->tree_height-1; i++) { | |||
set_tree_height(addr, i); | |||
leafidx >>= 1; | |||
set_tree_index(addr, leafidx); | |||
if (leafidx & 1) { | |||
hash_h(buffer + XMSS_N, buffer, pub_seed, addr); | |||
for (j = 0; j < XMSS_N; j++) { | |||
hash_h(params, buffer + params->n, buffer, pub_seed, addr); | |||
for (j = 0; j < params->n; j++) { | |||
buffer[j] = authpath[j]; | |||
} | |||
} | |||
else { | |||
hash_h(buffer, buffer, pub_seed, addr); | |||
for (j = 0; j < XMSS_N; j++) { | |||
buffer[j + XMSS_N] = authpath[j]; | |||
hash_h(params, buffer, buffer, pub_seed, addr); | |||
for (j = 0; j < params->n; j++) { | |||
buffer[j + params->n] = authpath[j]; | |||
} | |||
} | |||
authpath += XMSS_N; | |||
authpath += params->n; | |||
} | |||
set_tree_height(addr, XMSS_TREEHEIGHT - 1); | |||
set_tree_height(addr, params->tree_height - 1); | |||
leafidx >>= 1; | |||
set_tree_index(addr, leafidx); | |||
hash_h(root, buffer, pub_seed, addr); | |||
hash_h(params, root, buffer, pub_seed, addr); | |||
} | |||
/** | |||
* Verifies a given message signature pair under a given public key. | |||
*/ | |||
int xmss_core_sign_open(unsigned char *m, unsigned long long *mlen, | |||
int xmss_core_sign_open(const xmss_params *params, | |||
unsigned char *m, unsigned long long *mlen, | |||
const unsigned char *sm, unsigned long long smlen, | |||
const unsigned char *pk) | |||
{ | |||
unsigned long long i; | |||
unsigned long idx = 0; | |||
unsigned char wots_pk[XMSS_WOTS_KEYSIZE]; | |||
unsigned char pkhash[XMSS_N]; | |||
unsigned char root[XMSS_N]; | |||
unsigned char msg_h[XMSS_N]; | |||
unsigned char hash_key[3*XMSS_N]; | |||
unsigned char wots_pk[params->wots_keysize]; | |||
unsigned char pkhash[params->n]; | |||
unsigned char root[params->n]; | |||
unsigned char msg_h[params->n]; | |||
unsigned char hash_key[3*params->n]; | |||
unsigned char pub_seed[XMSS_N]; | |||
memcpy(pub_seed, pk + XMSS_N, XMSS_N); | |||
unsigned char pub_seed[params->n]; | |||
memcpy(pub_seed, pk + params->n, params->n); | |||
// Init addresses | |||
uint32_t ots_addr[8] = {0}; | |||
@@ -171,37 +172,37 @@ int xmss_core_sign_open(unsigned char *m, unsigned long long *mlen, | |||
set_type(ltree_addr, 1); | |||
set_type(node_addr, 2); | |||
*mlen = smlen - XMSS_BYTES; | |||
*mlen = smlen - params->bytes; | |||
// Extract index | |||
for (i = 0; i < XMSS_INDEX_LEN; i++) { | |||
idx |= ((unsigned long long)sm[i]) << (8*(XMSS_INDEX_LEN - 1 - i)); | |||
for (i = 0; i < params->index_len; i++) { | |||
idx |= ((unsigned long long)sm[i]) << (8*(params->index_len - 1 - i)); | |||
} | |||
// Generate hash key (R || root || idx) | |||
memcpy(hash_key, sm + XMSS_INDEX_LEN, XMSS_N); | |||
memcpy(hash_key + XMSS_N, pk, XMSS_N); | |||
to_byte(hash_key + 2*XMSS_N, idx, XMSS_N); | |||
memcpy(hash_key, sm + params->index_len, params->n); | |||
memcpy(hash_key + params->n, pk, params->n); | |||
to_byte(hash_key + 2*params->n, idx, params->n); | |||
// hash message | |||
h_msg(msg_h, sm + XMSS_BYTES, *mlen, hash_key, 3*XMSS_N); | |||
sm += XMSS_INDEX_LEN + XMSS_N; | |||
h_msg(params, msg_h, sm + params->bytes, *mlen, hash_key, 3*params->n); | |||
sm += params->index_len + params->n; | |||
// Prepare Address | |||
set_ots_addr(ots_addr, idx); | |||
// Check WOTS signature | |||
wots_pk_from_sig(wots_pk, sm, msg_h, pub_seed, ots_addr); | |||
sm += XMSS_WOTS_KEYSIZE; | |||
wots_pk_from_sig(params, wots_pk, sm, msg_h, pub_seed, ots_addr); | |||
sm += params->wots_keysize; | |||
// Compute Ltree | |||
set_ltree_addr(ltree_addr, idx); | |||
l_tree(pkhash, wots_pk, pub_seed, ltree_addr); | |||
l_tree(params, pkhash, wots_pk, pub_seed, ltree_addr); | |||
// Compute root | |||
validate_authpath(root, pkhash, idx, sm, pub_seed, node_addr); | |||
sm += XMSS_TREEHEIGHT*XMSS_N; | |||
validate_authpath(params, root, pkhash, idx, sm, pub_seed, node_addr); | |||
sm += params->tree_height*params->n; | |||
for (i = 0; i < XMSS_N; i++) { | |||
for (i = 0; i < params->n; i++) { | |||
if (root[i] != pk[i]) { | |||
for (i = 0; i < *mlen; i++) { | |||
m[i] = 0; | |||
@@ -221,19 +222,20 @@ int xmss_core_sign_open(unsigned char *m, unsigned long long *mlen, | |||
/** | |||
* Verifies a given message signature pair under a given public key. | |||
*/ | |||
int xmssmt_core_sign_open(unsigned char *m, unsigned long long *mlen, | |||
int xmssmt_core_sign_open(const xmss_params *params, | |||
unsigned char *m, unsigned long long *mlen, | |||
const unsigned char *sm, unsigned long long smlen, | |||
const unsigned char *pk) | |||
{ | |||
uint32_t idx_leaf; | |||
unsigned long long i; | |||
unsigned long long idx = 0; | |||
unsigned char wots_pk[XMSS_WOTS_KEYSIZE]; | |||
unsigned char pkhash[XMSS_N]; | |||
unsigned char root[XMSS_N]; | |||
unsigned char wots_pk[params->wots_keysize]; | |||
unsigned char pkhash[params->n]; | |||
unsigned char root[params->n]; | |||
unsigned char *msg_h = root; | |||
unsigned char hash_key[3*XMSS_N]; | |||
const unsigned char *pub_seed = pk + XMSS_N; | |||
unsigned char hash_key[3*params->n]; | |||
const unsigned char *pub_seed = pk + params->n; | |||
// Init addresses | |||
uint32_t ots_addr[8] = {0}; | |||
@@ -244,26 +246,26 @@ int xmssmt_core_sign_open(unsigned char *m, unsigned long long *mlen, | |||
set_type(ltree_addr, 1); | |||
set_type(node_addr, 2); | |||
*mlen = smlen - XMSS_BYTES; | |||
*mlen = smlen - params->bytes; | |||
// Extract index | |||
for (i = 0; i < XMSS_INDEX_LEN; i++) { | |||
idx |= ((unsigned long long)sm[i]) << (8*(XMSS_INDEX_LEN - 1 - i)); | |||
for (i = 0; i < params->index_len; i++) { | |||
idx |= ((unsigned long long)sm[i]) << (8*(params->index_len - 1 - i)); | |||
} | |||
// Generate hash key (R || root || idx) | |||
memcpy(hash_key, sm + XMSS_INDEX_LEN, XMSS_N); | |||
memcpy(hash_key + XMSS_N, pk, XMSS_N); | |||
to_byte(hash_key + 2*XMSS_N, idx, XMSS_N); | |||
memcpy(hash_key, sm + params->index_len, params->n); | |||
memcpy(hash_key + params->n, pk, params->n); | |||
to_byte(hash_key + 2*params->n, idx, params->n); | |||
// hash message | |||
h_msg(msg_h, sm + XMSS_BYTES, *mlen, hash_key, 3*XMSS_N); | |||
sm += XMSS_INDEX_LEN + XMSS_N; | |||
h_msg(params, msg_h, sm + params->bytes, *mlen, hash_key, 3*params->n); | |||
sm += params->index_len + params->n; | |||
for (i = 0; i < XMSS_D; i++) { | |||
for (i = 0; i < params->d; i++) { | |||
// Prepare Address | |||
idx_leaf = (idx & ((1 << XMSS_TREEHEIGHT)-1)); | |||
idx = idx >> XMSS_TREEHEIGHT; | |||
idx_leaf = (idx & ((1 << params->tree_height)-1)); | |||
idx = idx >> params->tree_height; | |||
set_layer_addr(ots_addr, i); | |||
set_layer_addr(ltree_addr, i); | |||
@@ -276,19 +278,19 @@ int xmssmt_core_sign_open(unsigned char *m, unsigned long long *mlen, | |||
set_ots_addr(ots_addr, idx_leaf); | |||
// Check WOTS signature | |||
wots_pk_from_sig(wots_pk, sm, root, pub_seed, ots_addr); | |||
sm += XMSS_WOTS_KEYSIZE; | |||
wots_pk_from_sig(params, wots_pk, sm, root, pub_seed, ots_addr); | |||
sm += params->wots_keysize; | |||
// Compute Ltree | |||
set_ltree_addr(ltree_addr, idx_leaf); | |||
l_tree(pkhash, wots_pk, pub_seed, ltree_addr); | |||
l_tree(params, pkhash, wots_pk, pub_seed, ltree_addr); | |||
// Compute root | |||
validate_authpath(root, pkhash, idx_leaf, sm, pub_seed, node_addr); | |||
sm += XMSS_TREEHEIGHT*XMSS_N; | |||
validate_authpath(params, root, pkhash, idx_leaf, sm, pub_seed, node_addr); | |||
sm += params->tree_height*params->n; | |||
} | |||
for (i = 0; i < XMSS_N; i++) { | |||
for (i = 0; i < params->n; i++) { | |||
if (root[i] != pk[i]) { | |||
for (i = 0; i < *mlen; i++) { | |||
m[i] = 0; | |||
@@ -9,26 +9,29 @@ Public domain. | |||
#include <stdlib.h> | |||
#include <stdint.h> | |||
#include "params.h" | |||
void to_byte(unsigned char *output, unsigned long long in, uint32_t bytes); | |||
void hexdump(const unsigned char *a, size_t len); | |||
void gen_leaf_wots(unsigned char *leaf, | |||
void gen_leaf_wots(const xmss_params *params, unsigned char *leaf, | |||
const unsigned char *sk_seed, const unsigned char *pub_seed, | |||
uint32_t ltree_addr[8], uint32_t ots_addr[8]); | |||
void get_seed(unsigned char *seed, | |||
void get_seed(const xmss_params *params, unsigned char *seed, | |||
const unsigned char *sk_seed, uint32_t addr[8]); | |||
void l_tree(unsigned char *leaf, unsigned char *wots_pk, | |||
void l_tree(const xmss_params *params, unsigned char *leaf, unsigned char *wots_pk, | |||
const unsigned char *pub_seed, uint32_t addr[8]); | |||
int xmss_core_sign_open(unsigned char *m, unsigned long long *mlen, | |||
int xmss_core_sign_open(const xmss_params *params, | |||
unsigned char *m, unsigned long long *mlen, | |||
const unsigned char *sm, unsigned long long smlen, | |||
const unsigned char *pk); | |||
int xmssmt_core_sign_open(unsigned char *m, unsigned long long *mlen, | |||
int xmssmt_core_sign_open(const xmss_params *params, | |||
unsigned char *m, unsigned long long *mlen, | |||
const unsigned char *sm, unsigned long long smlen, | |||
const unsigned char *pk); | |||
#endif |
@@ -22,7 +22,7 @@ Public domain. | |||
* Currently only used for key generation. | |||
* | |||
*/ | |||
static void treehash(unsigned char *node, uint32_t index, const unsigned char *sk_seed, const unsigned char *pub_seed, const uint32_t addr[8]) | |||
static void treehash(const xmss_params *params, unsigned char *node, uint32_t index, const unsigned char *sk_seed, const unsigned char *pub_seed, const uint32_t addr[8]) | |||
{ | |||
uint32_t idx = index; | |||
// use three different addresses because at this point we use all three formats in parallel | |||
@@ -39,27 +39,27 @@ static void treehash(unsigned char *node, uint32_t index, const unsigned char *s | |||
set_type(node_addr, 2); | |||
uint32_t lastnode, i; | |||
unsigned char stack[(XMSS_TREEHEIGHT+1)*XMSS_N]; | |||
uint16_t stacklevels[XMSS_TREEHEIGHT+1]; | |||
unsigned char stack[(params->tree_height+1)*params->n]; | |||
uint16_t stacklevels[params->tree_height+1]; | |||
unsigned int stackoffset=0; | |||
lastnode = idx+(1 << XMSS_TREEHEIGHT); | |||
lastnode = idx+(1 << params->tree_height); | |||
for (; idx < lastnode; idx++) { | |||
set_ltree_addr(ltree_addr, idx); | |||
set_ots_addr(ots_addr, idx); | |||
gen_leaf_wots(stack+stackoffset*XMSS_N, sk_seed, pub_seed, ltree_addr, ots_addr); | |||
gen_leaf_wots(params, stack+stackoffset*params->n, sk_seed, pub_seed, ltree_addr, ots_addr); | |||
stacklevels[stackoffset] = 0; | |||
stackoffset++; | |||
while (stackoffset>1 && stacklevels[stackoffset-1] == stacklevels[stackoffset-2]) { | |||
set_tree_height(node_addr, stacklevels[stackoffset-1]); | |||
set_tree_index(node_addr, (idx >> (stacklevels[stackoffset-1]+1))); | |||
hash_h(stack+(stackoffset-2)*XMSS_N, stack+(stackoffset-2)*XMSS_N, pub_seed, node_addr); | |||
hash_h(params, stack+(stackoffset-2)*params->n, stack+(stackoffset-2)*params->n, pub_seed, node_addr); | |||
stacklevels[stackoffset-2]++; | |||
stackoffset--; | |||
} | |||
} | |||
for (i = 0; i < XMSS_N; i++) { | |||
for (i = 0; i < params->n; i++) { | |||
node[i] = stack[i]; | |||
} | |||
} | |||
@@ -69,11 +69,11 @@ static void treehash(unsigned char *node, uint32_t index, const unsigned char *s | |||
* For more efficient algorithms see e.g. the chapter on hash-based signatures in Bernstein, Buchmann, Dahmen. "Post-quantum Cryptography", Springer 2009. | |||
* It returns the authpath in "authpath" with the node on level 0 at index 0. | |||
*/ | |||
static void compute_authpath_wots(unsigned char *root, unsigned char *authpath, unsigned long leaf_idx, const unsigned char *sk_seed, unsigned char *pub_seed, uint32_t addr[8]) | |||
static void compute_authpath_wots(const xmss_params *params, unsigned char *root, unsigned char *authpath, unsigned long leaf_idx, const unsigned char *sk_seed, unsigned char *pub_seed, uint32_t addr[8]) | |||
{ | |||
uint32_t i, j, level; | |||
unsigned char tree[2*(1<<XMSS_TREEHEIGHT)*XMSS_N]; | |||
unsigned char tree[2*(1 << params->tree_height)*params->n]; | |||
uint32_t ots_addr[8]; | |||
uint32_t ltree_addr[8]; | |||
@@ -87,33 +87,33 @@ static void compute_authpath_wots(unsigned char *root, unsigned char *authpath, | |||
set_type(node_addr, 2); | |||
// Compute all leaves | |||
for (i = 0; i < (1U << XMSS_TREEHEIGHT); i++) { | |||
for (i = 0; i < (1U << params->tree_height); i++) { | |||
set_ltree_addr(ltree_addr, i); | |||
set_ots_addr(ots_addr, i); | |||
gen_leaf_wots(tree+((1<<XMSS_TREEHEIGHT)*XMSS_N + i*XMSS_N), sk_seed, pub_seed, ltree_addr, ots_addr); | |||
gen_leaf_wots(params, tree+((1 << params->tree_height)*params->n + i*params->n), sk_seed, pub_seed, ltree_addr, ots_addr); | |||
} | |||
level = 0; | |||
// Compute tree: | |||
// Outer loop: For each inner layer | |||
for (i = (1<<XMSS_TREEHEIGHT); i > 1; i>>=1) { | |||
for (i = (1 << params->tree_height); i > 1; i>>=1) { | |||
set_tree_height(node_addr, level); | |||
// Inner loop: for each pair of sibling nodes | |||
for (j = 0; j < i; j+=2) { | |||
set_tree_index(node_addr, j>>1); | |||
hash_h(tree + (i>>1)*XMSS_N + (j>>1) * XMSS_N, tree + i*XMSS_N + j*XMSS_N, pub_seed, node_addr); | |||
hash_h(params, tree + (i>>1)*params->n + (j>>1) * params->n, tree + i*params->n + j*params->n, pub_seed, node_addr); | |||
} | |||
level++; | |||
} | |||
// copy authpath | |||
for (i = 0; i < XMSS_TREEHEIGHT; i++) { | |||
memcpy(authpath + i*XMSS_N, tree + ((1<<XMSS_TREEHEIGHT)>>i)*XMSS_N + ((leaf_idx >> i) ^ 1) * XMSS_N, XMSS_N); | |||
for (i = 0; i < params->tree_height; i++) { | |||
memcpy(authpath + i*params->n, tree + ((1 << params->tree_height)>>i)*params->n + ((leaf_idx >> i) ^ 1) * params->n, params->n); | |||
} | |||
// copy root | |||
memcpy(root, tree+XMSS_N, XMSS_N); | |||
memcpy(root, tree+params->n, params->n); | |||
} | |||
@@ -122,23 +122,23 @@ memcpy(root, tree+XMSS_N, XMSS_N); | |||
* Format sk: [(32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] | |||
* Format pk: [root || PUB_SEED] omitting algo oid. | |||
*/ | |||
int xmss_core_keypair(unsigned char *pk, unsigned char *sk) | |||
int xmss_core_keypair(const xmss_params *params, unsigned char *pk, unsigned char *sk) | |||
{ | |||
// Set idx = 0 | |||
sk[0] = 0; | |||
sk[1] = 0; | |||
sk[2] = 0; | |||
sk[3] = 0; | |||
// Init SK_SEED (XMSS_N byte), SK_PRF (XMSS_N byte), and PUB_SEED (XMSS_N byte) | |||
randombytes(sk+4, 3*XMSS_N); | |||
// Init SK_SEED (params->n byte), SK_PRF (params->n byte), and PUB_SEED (params->n byte) | |||
randombytes(sk+4, 3*params->n); | |||
// Copy PUB_SEED to public key | |||
memcpy(pk+XMSS_N, sk+4+2*XMSS_N, XMSS_N); | |||
memcpy(pk+params->n, sk+4+2*params->n, params->n); | |||
uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | |||
// Compute root | |||
treehash(pk, 0, sk+4, sk+4+2*XMSS_N, addr); | |||
treehash(params, pk, 0, sk+4, sk+4+2*params->n, addr); | |||
// copy root to sk | |||
memcpy(sk+4+3*XMSS_N, pk, XMSS_N); | |||
memcpy(sk+4+3*params->n, pk, params->n); | |||
return 0; | |||
} | |||
@@ -149,24 +149,24 @@ int xmss_core_keypair(unsigned char *pk, unsigned char *sk) | |||
* 2. an updated secret key! | |||
* | |||
*/ | |||
int xmss_core_sign(unsigned char *sk, unsigned char *sm, unsigned long long *smlen, const unsigned char *m, unsigned long long mlen) | |||
int xmss_core_sign(const xmss_params *params, unsigned char *sk, unsigned char *sm, unsigned long long *smlen, const unsigned char *m, unsigned long long mlen) | |||
{ | |||
uint16_t i = 0; | |||
// Extract SK | |||
uint32_t idx = ((unsigned long)sk[0] << 24) | ((unsigned long)sk[1] << 16) | ((unsigned long)sk[2] << 8) | sk[3]; | |||
unsigned char sk_seed[XMSS_N]; | |||
unsigned char sk_prf[XMSS_N]; | |||
unsigned char pub_seed[XMSS_N]; | |||
unsigned char hash_key[3*XMSS_N]; | |||
unsigned char sk_seed[params->n]; | |||
unsigned char sk_prf[params->n]; | |||
unsigned char pub_seed[params->n]; | |||
unsigned char hash_key[3*params->n]; | |||
// index as 32 bytes string | |||
unsigned char idx_bytes_32[32]; | |||
to_byte(idx_bytes_32, idx, 32); | |||
memcpy(sk_seed, sk+4, XMSS_N); | |||
memcpy(sk_prf, sk+4+XMSS_N, XMSS_N); | |||
memcpy(pub_seed, sk+4+2*XMSS_N, XMSS_N); | |||
memcpy(sk_seed, sk+4, params->n); | |||
memcpy(sk_prf, sk+4+params->n, params->n); | |||
memcpy(pub_seed, sk+4+2*params->n, params->n); | |||
// Update SK | |||
sk[0] = ((idx + 1) >> 24) & 255; | |||
@@ -177,10 +177,10 @@ int xmss_core_sign(unsigned char *sk, unsigned char *sm, unsigned long long *sml | |||
// -- A productive implementation should use a file handle instead and write the updated secret key at this point! | |||
// Init working params | |||
unsigned char R[XMSS_N]; | |||
unsigned char msg_h[XMSS_N]; | |||
unsigned char root[XMSS_N]; | |||
unsigned char ots_seed[XMSS_N]; | |||
unsigned char R[params->n]; | |||
unsigned char msg_h[params->n]; | |||
unsigned char root[params->n]; | |||
unsigned char ots_seed[params->n]; | |||
uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | |||
// --------------------------------- | |||
@@ -189,13 +189,13 @@ int xmss_core_sign(unsigned char *sk, unsigned char *sm, unsigned long long *sml | |||
// Message Hash: | |||
// First compute pseudorandom value | |||
prf(R, idx_bytes_32, sk_prf, XMSS_N); | |||
prf(params, R, idx_bytes_32, sk_prf, params->n); | |||
// Generate hash key (R || root || idx) | |||
memcpy(hash_key, R, XMSS_N); | |||
memcpy(hash_key+XMSS_N, sk+4+3*XMSS_N, XMSS_N); | |||
to_byte(hash_key+2*XMSS_N, idx, XMSS_N); | |||
memcpy(hash_key, R, params->n); | |||
memcpy(hash_key+params->n, sk+4+3*params->n, params->n); | |||
to_byte(hash_key+2*params->n, idx, params->n); | |||
// Then use it for message digest | |||
h_msg(msg_h, m, mlen, hash_key, 3*XMSS_N); | |||
h_msg(params, msg_h, m, mlen, hash_key, 3*params->n); | |||
// Start collecting signature | |||
*smlen = 0; | |||
@@ -210,11 +210,11 @@ int xmss_core_sign(unsigned char *sk, unsigned char *sm, unsigned long long *sml | |||
*smlen += 4; | |||
// Copy R to signature | |||
for (i = 0; i < XMSS_N; i++) | |||
for (i = 0; i < params->n; i++) | |||
sm[i] = R[i]; | |||
sm += XMSS_N; | |||
*smlen += XMSS_N; | |||
sm += params->n; | |||
*smlen += params->n; | |||
// ---------------------------------- | |||
// Now we start to "really sign" | |||
@@ -225,17 +225,17 @@ int xmss_core_sign(unsigned char *sk, unsigned char *sm, unsigned long long *sml | |||
set_ots_addr(ots_addr, idx); | |||
// Compute seed for OTS key pair | |||
get_seed(ots_seed, sk_seed, ots_addr); | |||
get_seed(params, ots_seed, sk_seed, ots_addr); | |||
// Compute WOTS signature | |||
wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); | |||
wots_sign(params, sm, msg_h, ots_seed, pub_seed, ots_addr); | |||
sm += XMSS_WOTS_KEYSIZE; | |||
*smlen += XMSS_WOTS_KEYSIZE; | |||
sm += params->wots_keysize; | |||
*smlen += params->wots_keysize; | |||
compute_authpath_wots(root, sm, idx, sk_seed, pub_seed, ots_addr); | |||
sm += XMSS_TREEHEIGHT*XMSS_N; | |||
*smlen += XMSS_TREEHEIGHT*XMSS_N; | |||
compute_authpath_wots(params, root, sm, idx, sk_seed, pub_seed, ots_addr); | |||
sm += params->tree_height*params->n; | |||
*smlen += params->tree_height*params->n; | |||
memcpy(sm, m, mlen); | |||
*smlen += mlen; | |||
@@ -248,25 +248,25 @@ int xmss_core_sign(unsigned char *sk, unsigned char *sm, unsigned long long *sml | |||
* Format sk: [(ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED] | |||
* Format pk: [root || PUB_SEED] omitting algo oid. | |||
*/ | |||
int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk) | |||
int xmssmt_core_keypair(const xmss_params *params, unsigned char *pk, unsigned char *sk) | |||
{ | |||
uint16_t i; | |||
// Set idx = 0 | |||
for (i = 0; i < XMSS_INDEX_LEN; i++) { | |||
for (i = 0; i < params->index_len; i++) { | |||
sk[i] = 0; | |||
} | |||
// Init SK_SEED (XMSS_N byte), SK_PRF (XMSS_N byte), and PUB_SEED (XMSS_N byte) | |||
randombytes(sk+XMSS_INDEX_LEN, 3*XMSS_N); | |||
// Init SK_SEED (params->n byte), SK_PRF (params->n byte), and PUB_SEED (params->n byte) | |||
randombytes(sk+params->index_len, 3*params->n); | |||
// Copy PUB_SEED to public key | |||
memcpy(pk+XMSS_N, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N); | |||
memcpy(pk+params->n, sk+params->index_len+2*params->n, params->n); | |||
// Set address to point on the single tree on layer d-1 | |||
uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | |||
set_layer_addr(addr, (XMSS_D-1)); | |||
set_layer_addr(addr, (params->d-1)); | |||
// Compute root | |||
treehash(pk, 0, sk+XMSS_INDEX_LEN, pk+XMSS_N, addr); | |||
memcpy(sk+XMSS_INDEX_LEN+3*XMSS_N, pk, XMSS_N); | |||
treehash(params, pk, 0, sk+params->index_len, pk+params->n, addr); | |||
memcpy(sk+params->index_len+3*params->n, pk, params->n); | |||
return 0; | |||
} | |||
@@ -277,37 +277,37 @@ int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk) | |||
* 2. an updated secret key! | |||
* | |||
*/ | |||
int xmssmt_core_sign(unsigned char *sk, unsigned char *sm, unsigned long long *smlen, const unsigned char *m, unsigned long long mlen) | |||
int xmssmt_core_sign(const xmss_params *params, unsigned char *sk, unsigned char *sm, unsigned long long *smlen, const unsigned char *m, unsigned long long mlen) | |||
{ | |||
uint64_t idx_tree; | |||
uint32_t idx_leaf; | |||
uint64_t i; | |||
unsigned char sk_seed[XMSS_N]; | |||
unsigned char sk_prf[XMSS_N]; | |||
unsigned char pub_seed[XMSS_N]; | |||
unsigned char sk_seed[params->n]; | |||
unsigned char sk_prf[params->n]; | |||
unsigned char pub_seed[params->n]; | |||
// Init working params | |||
unsigned char R[XMSS_N]; | |||
unsigned char hash_key[3*XMSS_N]; | |||
unsigned char msg_h[XMSS_N]; | |||
unsigned char root[XMSS_N]; | |||
unsigned char ots_seed[XMSS_N]; | |||
unsigned char R[params->n]; | |||
unsigned char hash_key[3*params->n]; | |||
unsigned char msg_h[params->n]; | |||
unsigned char root[params->n]; | |||
unsigned char ots_seed[params->n]; | |||
uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | |||
unsigned char idx_bytes_32[32]; | |||
// Extract SK | |||
unsigned long long idx = 0; | |||
for (i = 0; i < XMSS_INDEX_LEN; i++) { | |||
idx |= ((unsigned long long)sk[i]) << 8*(XMSS_INDEX_LEN - 1 - i); | |||
for (i = 0; i < params->index_len; i++) { | |||
idx |= ((unsigned long long)sk[i]) << 8*(params->index_len - 1 - i); | |||
} | |||
memcpy(sk_seed, sk+XMSS_INDEX_LEN, XMSS_N); | |||
memcpy(sk_prf, sk+XMSS_INDEX_LEN+XMSS_N, XMSS_N); | |||
memcpy(pub_seed, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N); | |||
memcpy(sk_seed, sk+params->index_len, params->n); | |||
memcpy(sk_prf, sk+params->index_len+params->n, params->n); | |||
memcpy(pub_seed, sk+params->index_len+2*params->n, params->n); | |||
// Update SK | |||
for (i = 0; i < XMSS_INDEX_LEN; i++) { | |||
sk[i] = ((idx + 1) >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; | |||
for (i = 0; i < params->index_len; i++) { | |||
sk[i] = ((idx + 1) >> 8*(params->index_len - 1 - i)) & 255; | |||
} | |||
// -- Secret key for this non-forward-secure version is now updated. | |||
// -- A productive implementation should use a file handle instead and write the updated secret key at this point! | |||
@@ -320,33 +320,33 @@ int xmssmt_core_sign(unsigned char *sk, unsigned char *sm, unsigned long long *s | |||
// Message Hash: | |||
// First compute pseudorandom value | |||
to_byte(idx_bytes_32, idx, 32); | |||
prf(R, idx_bytes_32, sk_prf, XMSS_N); | |||
prf(params, R, idx_bytes_32, sk_prf, params->n); | |||
// Generate hash key (R || root || idx) | |||
memcpy(hash_key, R, XMSS_N); | |||
memcpy(hash_key+XMSS_N, sk+XMSS_INDEX_LEN+3*XMSS_N, XMSS_N); | |||
to_byte(hash_key+2*XMSS_N, idx, XMSS_N); | |||
memcpy(hash_key, R, params->n); | |||
memcpy(hash_key+params->n, sk+params->index_len+3*params->n, params->n); | |||
to_byte(hash_key+2*params->n, idx, params->n); | |||
// Then use it for message digest | |||
h_msg(msg_h, m, mlen, hash_key, 3*XMSS_N); | |||
h_msg(params, msg_h, m, mlen, hash_key, 3*params->n); | |||
// Start collecting signature | |||
*smlen = 0; | |||
// Copy index to signature | |||
for (i = 0; i < XMSS_INDEX_LEN; i++) { | |||
sm[i] = (idx >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; | |||
for (i = 0; i < params->index_len; i++) { | |||
sm[i] = (idx >> 8*(params->index_len - 1 - i)) & 255; | |||
} | |||
sm += XMSS_INDEX_LEN; | |||
*smlen += XMSS_INDEX_LEN; | |||
sm += params->index_len; | |||
*smlen += params->index_len; | |||
// Copy R to signature | |||
for (i = 0; i < XMSS_N; i++) { | |||
for (i = 0; i < params->n; i++) { | |||
sm[i] = R[i]; | |||
} | |||
sm += XMSS_N; | |||
*smlen += XMSS_N; | |||
sm += params->n; | |||
*smlen += params->n; | |||
// ---------------------------------- | |||
// Now we start to "really sign" | |||
@@ -356,47 +356,47 @@ int xmssmt_core_sign(unsigned char *sk, unsigned char *sm, unsigned long long *s | |||
// Prepare Address | |||
set_type(ots_addr, 0); | |||
idx_tree = idx >> XMSS_TREEHEIGHT; | |||
idx_leaf = (idx & ((1 << XMSS_TREEHEIGHT)-1)); | |||
idx_tree = idx >> params->tree_height; | |||
idx_leaf = (idx & ((1 << params->tree_height)-1)); | |||
set_layer_addr(ots_addr, 0); | |||
set_tree_addr(ots_addr, idx_tree); | |||
set_ots_addr(ots_addr, idx_leaf); | |||
// Compute seed for OTS key pair | |||
get_seed(ots_seed, sk_seed, ots_addr); | |||
get_seed(params, ots_seed, sk_seed, ots_addr); | |||
// Compute WOTS signature | |||
wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); | |||
wots_sign(params, sm, msg_h, ots_seed, pub_seed, ots_addr); | |||
sm += XMSS_WOTS_KEYSIZE; | |||
*smlen += XMSS_WOTS_KEYSIZE; | |||
sm += params->wots_keysize; | |||
*smlen += params->wots_keysize; | |||
compute_authpath_wots(root, sm, idx_leaf, sk_seed, pub_seed, ots_addr); | |||
sm += XMSS_TREEHEIGHT*XMSS_N; | |||
*smlen += XMSS_TREEHEIGHT*XMSS_N; | |||
compute_authpath_wots(params, root, sm, idx_leaf, sk_seed, pub_seed, ots_addr); | |||
sm += params->tree_height*params->n; | |||
*smlen += params->tree_height*params->n; | |||
// Now loop over remaining layers... | |||
unsigned int j; | |||
for (j = 1; j < XMSS_D; j++) { | |||
for (j = 1; j < params->d; j++) { | |||
// Prepare Address | |||
idx_leaf = (idx_tree & ((1 << XMSS_TREEHEIGHT)-1)); | |||
idx_tree = idx_tree >> XMSS_TREEHEIGHT; | |||
idx_leaf = (idx_tree & ((1 << params->tree_height)-1)); | |||
idx_tree = idx_tree >> params->tree_height; | |||
set_layer_addr(ots_addr, j); | |||
set_tree_addr(ots_addr, idx_tree); | |||
set_ots_addr(ots_addr, idx_leaf); | |||
// Compute seed for OTS key pair | |||
get_seed(ots_seed, sk_seed, ots_addr); | |||
get_seed(params, ots_seed, sk_seed, ots_addr); | |||
// Compute WOTS signature | |||
wots_sign(sm, root, ots_seed, pub_seed, ots_addr); | |||
wots_sign(params, sm, root, ots_seed, pub_seed, ots_addr); | |||
sm += XMSS_WOTS_KEYSIZE; | |||
*smlen += XMSS_WOTS_KEYSIZE; | |||
sm += params->wots_keysize; | |||
*smlen += params->wots_keysize; | |||
compute_authpath_wots(root, sm, idx_leaf, sk_seed, pub_seed, ots_addr); | |||
sm += XMSS_TREEHEIGHT*XMSS_N; | |||
*smlen += XMSS_TREEHEIGHT*XMSS_N; | |||
compute_authpath_wots(params, root, sm, idx_leaf, sk_seed, pub_seed, ots_addr); | |||
sm += params->tree_height*params->n; | |||
*smlen += params->tree_height*params->n; | |||
} | |||
memcpy(sm, m, mlen); | |||
@@ -15,7 +15,7 @@ Public domain. | |||
* Format sk: [(32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] | |||
* Format pk: [root || PUB_SEED] omitting algo oid. | |||
*/ | |||
int xmss_core_keypair(unsigned char *pk, unsigned char *sk); | |||
int xmss_core_keypair(const xmss_params *params, unsigned char *pk, unsigned char *sk); | |||
/** | |||
* Signs a message. | |||
* Returns | |||
@@ -23,20 +23,20 @@ int xmss_core_keypair(unsigned char *pk, unsigned char *sk); | |||
* 2. an updated secret key! | |||
* | |||
*/ | |||
int xmss_core_sign(unsigned char *sk, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen); | |||
int xmss_core_sign(const xmss_params *params, unsigned char *sk, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen); | |||
/** | |||
* Verifies a given message signature pair under a given public key. | |||
* | |||
* Note: msg and msglen are pure outputs which carry the message in case verification succeeds. The (input) message is assumed to be within sig_msg which has the form (sig||msg). | |||
*/ | |||
int xmss_core_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk); | |||
int xmss_core_sign_open(const xmss_params *params, unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk); | |||
/* | |||
* Generates a XMSSMT key pair for a given parameter set. | |||
* Format sk: [(ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] | |||
* Format pk: [root || PUB_SEED] omitting algo oid. | |||
*/ | |||
int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk); | |||
int xmssmt_core_keypair(const xmss_params *params, unsigned char *pk, unsigned char *sk); | |||
/** | |||
* Signs a message. | |||
* Returns | |||
@@ -44,10 +44,10 @@ int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk); | |||
* 2. an updated secret key! | |||
* | |||
*/ | |||
int xmssmt_core_sign(unsigned char *sk, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen); | |||
int xmssmt_core_sign(const xmss_params *params, unsigned char *sk, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen); | |||
/** | |||
* Verifies a given message signature pair under a given public key. | |||
*/ | |||
int xmssmt_core_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk); | |||
int xmssmt_core_sign_open(const xmss_params *params, unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk); | |||
#endif | |||
@@ -37,10 +37,11 @@ void xmss_set_bds_state(bds_state *state, unsigned char *stack, | |||
state->next_leaf = next_leaf; | |||
} | |||
static int treehash_minheight_on_stack(bds_state* state, | |||
static int treehash_minheight_on_stack(const xmss_params *params, | |||
bds_state* state, | |||
const treehash_inst *treehash) | |||
{ | |||
unsigned int r = XMSS_TREEHEIGHT, i; | |||
unsigned int r = params->tree_height, i; | |||
for (i = 0; i < treehash->stackusage; i++) { | |||
if (state->stacklevels[state->stackoffset - i - 1] < r) { | |||
@@ -55,7 +56,8 @@ static int treehash_minheight_on_stack(bds_state* state, | |||
* Currently only used for key generation. | |||
* | |||
*/ | |||
static void treehash_init(unsigned char *node, int height, int index, | |||
static void treehash_init(const xmss_params *params, | |||
unsigned char *node, int height, int index, | |||
bds_state *state, const unsigned char *sk_seed, | |||
const unsigned char *pub_seed, const uint32_t addr[8]) | |||
{ | |||
@@ -74,14 +76,14 @@ static void treehash_init(unsigned char *node, int height, int index, | |||
set_type(node_addr, 2); | |||
uint32_t lastnode, i; | |||
unsigned char stack[(height+1)*XMSS_N]; | |||
unsigned char stack[(height+1)*params->n]; | |||
unsigned int stacklevels[height+1]; | |||
unsigned int stackoffset=0; | |||
unsigned int nodeh; | |||
lastnode = idx+(1<<height); | |||
for (i = 0; i < XMSS_TREEHEIGHT-XMSS_BDS_K; i++) { | |||
for (i = 0; i < params->tree_height-params->bds_k; i++) { | |||
state->treehash[i].h = i; | |||
state->treehash[i].completed = 1; | |||
state->treehash[i].stackusage = 0; | |||
@@ -91,40 +93,41 @@ static void treehash_init(unsigned char *node, int height, int index, | |||
for (; idx < lastnode; idx++) { | |||
set_ltree_addr(ltree_addr, idx); | |||
set_ots_addr(ots_addr, idx); | |||
gen_leaf_wots(stack+stackoffset*XMSS_N, sk_seed, pub_seed, ltree_addr, ots_addr); | |||
gen_leaf_wots(params, stack+stackoffset*params->n, sk_seed, pub_seed, ltree_addr, ots_addr); | |||
stacklevels[stackoffset] = 0; | |||
stackoffset++; | |||
if (XMSS_TREEHEIGHT - XMSS_BDS_K > 0 && i == 3) { | |||
memcpy(state->treehash[0].node, stack+stackoffset*XMSS_N, XMSS_N); | |||
if (params->tree_height - params->bds_k > 0 && i == 3) { | |||
memcpy(state->treehash[0].node, stack+stackoffset*params->n, params->n); | |||
} | |||
while (stackoffset>1 && stacklevels[stackoffset-1] == stacklevels[stackoffset-2]) { | |||
nodeh = stacklevels[stackoffset-1]; | |||
if (i >> nodeh == 1) { | |||
memcpy(state->auth + nodeh*XMSS_N, stack+(stackoffset-1)*XMSS_N, XMSS_N); | |||
memcpy(state->auth + nodeh*params->n, stack+(stackoffset-1)*params->n, params->n); | |||
} | |||
else { | |||
if (nodeh < XMSS_TREEHEIGHT - XMSS_BDS_K && i >> nodeh == 3) { | |||
memcpy(state->treehash[nodeh].node, stack+(stackoffset-1)*XMSS_N, XMSS_N); | |||
if (nodeh < params->tree_height - params->bds_k && i >> nodeh == 3) { | |||
memcpy(state->treehash[nodeh].node, stack+(stackoffset-1)*params->n, params->n); | |||
} | |||
else if (nodeh >= XMSS_TREEHEIGHT - XMSS_BDS_K) { | |||
memcpy(state->retain + ((1 << (XMSS_TREEHEIGHT - 1 - nodeh)) + nodeh - XMSS_TREEHEIGHT + (((i >> nodeh) - 3) >> 1)) * XMSS_N, stack+(stackoffset-1)*XMSS_N, XMSS_N); | |||
else if (nodeh >= params->tree_height - params->bds_k) { | |||
memcpy(state->retain + ((1 << (params->tree_height - 1 - nodeh)) + nodeh - params->tree_height + (((i >> nodeh) - 3) >> 1)) * params->n, stack+(stackoffset-1)*params->n, params->n); | |||
} | |||
} | |||
set_tree_height(node_addr, stacklevels[stackoffset-1]); | |||
set_tree_index(node_addr, (idx >> (stacklevels[stackoffset-1]+1))); | |||
hash_h(stack+(stackoffset-2)*XMSS_N, stack+(stackoffset-2)*XMSS_N, pub_seed, node_addr); | |||
hash_h(params, stack+(stackoffset-2)*params->n, stack+(stackoffset-2)*params->n, pub_seed, node_addr); | |||
stacklevels[stackoffset-2]++; | |||
stackoffset--; | |||
} | |||
i++; | |||
} | |||
for (i = 0; i < XMSS_N; i++) { | |||
for (i = 0; i < params->n; i++) { | |||
node[i] = stack[i]; | |||
} | |||
} | |||
static void treehash_update(treehash_inst *treehash, bds_state *state, | |||
static void treehash_update(const xmss_params *params, | |||
treehash_inst *treehash, bds_state *state, | |||
const unsigned char *sk_seed, | |||
const unsigned char *pub_seed, | |||
const uint32_t addr[8]) | |||
@@ -144,25 +147,25 @@ static void treehash_update(treehash_inst *treehash, bds_state *state, | |||
set_ltree_addr(ltree_addr, treehash->next_idx); | |||
set_ots_addr(ots_addr, treehash->next_idx); | |||
unsigned char nodebuffer[2 * XMSS_N]; | |||
unsigned char nodebuffer[2 * params->n]; | |||
unsigned int nodeheight = 0; | |||
gen_leaf_wots(nodebuffer, sk_seed, pub_seed, ltree_addr, ots_addr); | |||
gen_leaf_wots(params, nodebuffer, sk_seed, pub_seed, ltree_addr, ots_addr); | |||
while (treehash->stackusage > 0 && state->stacklevels[state->stackoffset-1] == nodeheight) { | |||
memcpy(nodebuffer + XMSS_N, nodebuffer, XMSS_N); | |||
memcpy(nodebuffer, state->stack + (state->stackoffset-1)*XMSS_N, XMSS_N); | |||
memcpy(nodebuffer + params->n, nodebuffer, params->n); | |||
memcpy(nodebuffer, state->stack + (state->stackoffset-1)*params->n, params->n); | |||
set_tree_height(node_addr, nodeheight); | |||
set_tree_index(node_addr, (treehash->next_idx >> (nodeheight+1))); | |||
hash_h(nodebuffer, nodebuffer, pub_seed, node_addr); | |||
hash_h(params, nodebuffer, nodebuffer, pub_seed, node_addr); | |||
nodeheight++; | |||
treehash->stackusage--; | |||
state->stackoffset--; | |||
} | |||
if (nodeheight == treehash->h) { // this also implies stackusage == 0 | |||
memcpy(treehash->node, nodebuffer, XMSS_N); | |||
memcpy(treehash->node, nodebuffer, params->n); | |||
treehash->completed = 1; | |||
} | |||
else { | |||
memcpy(state->stack + state->stackoffset*XMSS_N, nodebuffer, XMSS_N); | |||
memcpy(state->stack + state->stackoffset*params->n, nodebuffer, params->n); | |||
treehash->stackusage++; | |||
state->stacklevels[state->stackoffset] = nodeheight; | |||
state->stackoffset++; | |||
@@ -174,7 +177,8 @@ static void treehash_update(treehash_inst *treehash, bds_state *state, | |||
* Performs one treehash update on the instance that needs it the most. | |||
* Returns 1 if such an instance was not found | |||
**/ | |||
static char bds_treehash_update(bds_state *state, unsigned int updates, | |||
static char bds_treehash_update(const xmss_params *params, | |||
bds_state *state, unsigned int updates, | |||
const unsigned char *sk_seed, | |||
unsigned char *pub_seed, | |||
const uint32_t addr[8]) | |||
@@ -184,27 +188,27 @@ static char bds_treehash_update(bds_state *state, unsigned int updates, | |||
unsigned int used = 0; | |||
for (j = 0; j < updates; j++) { | |||
l_min = XMSS_TREEHEIGHT; | |||
level = XMSS_TREEHEIGHT - XMSS_BDS_K; | |||
for (i = 0; i < XMSS_TREEHEIGHT - XMSS_BDS_K; i++) { | |||
l_min = params->tree_height; | |||
level = params->tree_height - params->bds_k; | |||
for (i = 0; i < params->tree_height - params->bds_k; i++) { | |||
if (state->treehash[i].completed) { | |||
low = XMSS_TREEHEIGHT; | |||
low = params->tree_height; | |||
} | |||
else if (state->treehash[i].stackusage == 0) { | |||
low = i; | |||
} | |||
else { | |||
low = treehash_minheight_on_stack(state, &(state->treehash[i])); | |||
low = treehash_minheight_on_stack(params, state, &(state->treehash[i])); | |||
} | |||
if (low < l_min) { | |||
level = i; | |||
l_min = low; | |||
} | |||
} | |||
if (level == XMSS_TREEHEIGHT - XMSS_BDS_K) { | |||
if (level == params->tree_height - params->bds_k) { | |||
break; | |||
} | |||
treehash_update(&(state->treehash[level]), state, sk_seed, pub_seed, addr); | |||
treehash_update(params, &(state->treehash[level]), state, sk_seed, pub_seed, addr); | |||
used++; | |||
} | |||
return updates - used; | |||
@@ -214,7 +218,8 @@ static char bds_treehash_update(bds_state *state, unsigned int updates, | |||
* Updates the state (typically NEXT_i) by adding a leaf and updating the stack | |||
* Returns 1 if all leaf nodes have already been processed | |||
**/ | |||
static char bds_state_update(bds_state *state, const unsigned char *sk_seed, | |||
static char bds_state_update(const xmss_params *params, | |||
bds_state *state, const unsigned char *sk_seed, | |||
const unsigned char *pub_seed, | |||
const uint32_t addr[8]) | |||
{ | |||
@@ -224,7 +229,7 @@ static char bds_state_update(bds_state *state, const unsigned char *sk_seed, | |||
int nodeh; | |||
int idx = state->next_leaf; | |||
if (idx == 1 << XMSS_TREEHEIGHT) { | |||
if (idx == 1 << params->tree_height) { | |||
return 1; | |||
} | |||
@@ -240,29 +245,29 @@ static char bds_state_update(bds_state *state, const unsigned char *sk_seed, | |||
set_ots_addr(ots_addr, idx); | |||
set_ltree_addr(ltree_addr, idx); | |||
gen_leaf_wots(state->stack+state->stackoffset*XMSS_N, sk_seed, pub_seed, ltree_addr, ots_addr); | |||
gen_leaf_wots(params, state->stack+state->stackoffset*params->n, sk_seed, pub_seed, ltree_addr, ots_addr); | |||
state->stacklevels[state->stackoffset] = 0; | |||
state->stackoffset++; | |||
if (XMSS_TREEHEIGHT - XMSS_BDS_K > 0 && idx == 3) { | |||
memcpy(state->treehash[0].node, state->stack+state->stackoffset*XMSS_N, XMSS_N); | |||
if (params->tree_height - params->bds_k > 0 && idx == 3) { | |||
memcpy(state->treehash[0].node, state->stack+state->stackoffset*params->n, params->n); | |||
} | |||
while (state->stackoffset>1 && state->stacklevels[state->stackoffset-1] == state->stacklevels[state->stackoffset-2]) { | |||
nodeh = state->stacklevels[state->stackoffset-1]; | |||
if (idx >> nodeh == 1) { | |||
memcpy(state->auth + nodeh*XMSS_N, state->stack+(state->stackoffset-1)*XMSS_N, XMSS_N); | |||
memcpy(state->auth + nodeh*params->n, state->stack+(state->stackoffset-1)*params->n, params->n); | |||
} | |||
else { | |||
if (nodeh < XMSS_TREEHEIGHT - XMSS_BDS_K && idx >> nodeh == 3) { | |||
memcpy(state->treehash[nodeh].node, state->stack+(state->stackoffset-1)*XMSS_N, XMSS_N); | |||
if (nodeh < params->tree_height - params->bds_k && idx >> nodeh == 3) { | |||
memcpy(state->treehash[nodeh].node, state->stack+(state->stackoffset-1)*params->n, params->n); | |||
} | |||
else if (nodeh >= XMSS_TREEHEIGHT - XMSS_BDS_K) { | |||
memcpy(state->retain + ((1 << (XMSS_TREEHEIGHT - 1 - nodeh)) + nodeh - XMSS_TREEHEIGHT + (((idx >> nodeh) - 3) >> 1)) * XMSS_N, state->stack+(state->stackoffset-1)*XMSS_N, XMSS_N); | |||
else if (nodeh >= params->tree_height - params->bds_k) { | |||
memcpy(state->retain + ((1 << (params->tree_height - 1 - nodeh)) + nodeh - params->tree_height + (((idx >> nodeh) - 3) >> 1)) * params->n, state->stack+(state->stackoffset-1)*params->n, params->n); | |||
} | |||
} | |||
set_tree_height(node_addr, state->stacklevels[state->stackoffset-1]); | |||
set_tree_index(node_addr, (idx >> (state->stacklevels[state->stackoffset-1]+1))); | |||
hash_h(state->stack+(state->stackoffset-2)*XMSS_N, state->stack+(state->stackoffset-2)*XMSS_N, pub_seed, node_addr); | |||
hash_h(params, state->stack+(state->stackoffset-2)*params->n, state->stack+(state->stackoffset-2)*params->n, pub_seed, node_addr); | |||
state->stacklevels[state->stackoffset-2]++; | |||
state->stackoffset--; | |||
@@ -276,15 +281,16 @@ static char bds_state_update(bds_state *state, const unsigned char *sk_seed, | |||
* next leaf node, using the algorithm described by Buchmann, Dahmen and Szydlo | |||
* in "Post Quantum Cryptography", Springer 2009. | |||
*/ | |||
static void bds_round(bds_state *state, const unsigned long leaf_idx, | |||
static void bds_round(const xmss_params *params, | |||
bds_state *state, const unsigned long leaf_idx, | |||
const unsigned char *sk_seed, | |||
const unsigned char *pub_seed, uint32_t addr[8]) | |||
{ | |||
unsigned int i; | |||
unsigned int tau = XMSS_TREEHEIGHT; | |||
unsigned int tau = params->tree_height; | |||
unsigned int startidx; | |||
unsigned int offset, rowidx; | |||
unsigned char buf[2 * XMSS_N]; | |||
unsigned char buf[2 * params->n]; | |||
uint32_t ots_addr[8]; | |||
uint32_t ltree_addr[8]; | |||
@@ -298,7 +304,7 @@ static void bds_round(bds_state *state, const unsigned long leaf_idx, | |||
memcpy(node_addr, addr, 12); | |||
set_type(node_addr, 2); | |||
for (i = 0; i < XMSS_TREEHEIGHT; i++) { | |||
for (i = 0; i < params->tree_height; i++) { | |||
if (! ((leaf_idx >> i) & 1)) { | |||
tau = i; | |||
break; | |||
@@ -306,36 +312,36 @@ static void bds_round(bds_state *state, const unsigned long leaf_idx, | |||
} | |||
if (tau > 0) { | |||
memcpy(buf, state->auth + (tau-1) * XMSS_N, XMSS_N); | |||
memcpy(buf, state->auth + (tau-1) * params->n, params->n); | |||
// we need to do this before refreshing state->keep to prevent overwriting | |||
memcpy(buf + XMSS_N, state->keep + ((tau-1) >> 1) * XMSS_N, XMSS_N); | |||
memcpy(buf + params->n, state->keep + ((tau-1) >> 1) * params->n, params->n); | |||
} | |||
if (!((leaf_idx >> (tau + 1)) & 1) && (tau < XMSS_TREEHEIGHT - 1)) { | |||
memcpy(state->keep + (tau >> 1)*XMSS_N, state->auth + tau*XMSS_N, XMSS_N); | |||
if (!((leaf_idx >> (tau + 1)) & 1) && (tau < params->tree_height - 1)) { | |||
memcpy(state->keep + (tau >> 1)*params->n, state->auth + tau*params->n, params->n); | |||
} | |||
if (tau == 0) { | |||
set_ltree_addr(ltree_addr, leaf_idx); | |||
set_ots_addr(ots_addr, leaf_idx); | |||
gen_leaf_wots(state->auth, sk_seed, pub_seed, ltree_addr, ots_addr); | |||
gen_leaf_wots(params, state->auth, sk_seed, pub_seed, ltree_addr, ots_addr); | |||
} | |||
else { | |||
set_tree_height(node_addr, (tau-1)); | |||
set_tree_index(node_addr, leaf_idx >> tau); | |||
hash_h(state->auth + tau * XMSS_N, buf, pub_seed, node_addr); | |||
hash_h(params, state->auth + tau * params->n, buf, pub_seed, node_addr); | |||
for (i = 0; i < tau; i++) { | |||
if (i < XMSS_TREEHEIGHT - XMSS_BDS_K) { | |||
memcpy(state->auth + i * XMSS_N, state->treehash[i].node, XMSS_N); | |||
if (i < params->tree_height - params->bds_k) { | |||
memcpy(state->auth + i * params->n, state->treehash[i].node, params->n); | |||
} | |||
else { | |||
offset = (1 << (XMSS_TREEHEIGHT - 1 - i)) + i - XMSS_TREEHEIGHT; | |||
offset = (1 << (params->tree_height - 1 - i)) + i - params->tree_height; | |||
rowidx = ((leaf_idx >> i) - 1) >> 1; | |||
memcpy(state->auth + i * XMSS_N, state->retain + (offset + rowidx) * XMSS_N, XMSS_N); | |||
memcpy(state->auth + i * params->n, state->retain + (offset + rowidx) * params->n, params->n); | |||
} | |||
} | |||
for (i = 0; i < ((tau < XMSS_TREEHEIGHT - XMSS_BDS_K) ? tau : (XMSS_TREEHEIGHT - XMSS_BDS_K)); i++) { | |||
for (i = 0; i < ((tau < params->tree_height - params->bds_k) ? tau : (params->tree_height - params->bds_k)); i++) { | |||
startidx = leaf_idx + 1 + 3 * (1 << i); | |||
if (startidx < 1U << XMSS_TREEHEIGHT) { | |||
if (startidx < 1U << params->tree_height) { | |||
state->treehash[i].h = i; | |||
state->treehash[i].next_idx = startidx; | |||
state->treehash[i].completed = 0; | |||
@@ -350,7 +356,8 @@ static void bds_round(bds_state *state, const unsigned long leaf_idx, | |||
* Format sk: [(32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] | |||
* Format pk: [root || PUB_SEED] omitting algo oid. | |||
*/ | |||
int xmss_core_keypair(unsigned char *pk, unsigned char *sk, bds_state *state) | |||
int xmss_core_keypair(const xmss_params *params, | |||
unsigned char *pk, unsigned char *sk, bds_state *state) | |||
{ | |||
uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | |||
@@ -360,14 +367,14 @@ int xmss_core_keypair(unsigned char *pk, unsigned char *sk, bds_state *state) | |||
sk[2] = 0; | |||
sk[3] = 0; | |||
// Init SK_SEED (n byte), SK_PRF (n byte), and PUB_SEED (n byte) | |||
randombytes(sk + XMSS_INDEX_LEN, 3*XMSS_N); | |||
randombytes(sk + params->index_len, 3*params->n); | |||
// Copy PUB_SEED to public key | |||
memcpy(pk + XMSS_N, sk + XMSS_INDEX_LEN + 2*XMSS_N, XMSS_N); | |||
memcpy(pk + params->n, sk + params->index_len + 2*params->n, params->n); | |||
// Compute root | |||
treehash_init(pk, XMSS_TREEHEIGHT, 0, state, sk + XMSS_INDEX_LEN, sk + XMSS_INDEX_LEN + 2*XMSS_N, addr); | |||
treehash_init(params, pk, params->tree_height, 0, state, sk + params->index_len, sk + params->index_len + 2*params->n, addr); | |||
// copy root o sk | |||
memcpy(sk + XMSS_INDEX_LEN + 3*XMSS_N, pk, XMSS_N); | |||
memcpy(sk + params->index_len + 3*params->n, pk, params->n); | |||
return 0; | |||
} | |||
@@ -378,7 +385,8 @@ int xmss_core_keypair(unsigned char *pk, unsigned char *sk, bds_state *state) | |||
* 2. an updated secret key! | |||
* | |||
*/ | |||
int xmss_core_sign(unsigned char *sk, bds_state *state, | |||
int xmss_core_sign(const xmss_params *params, | |||
unsigned char *sk, bds_state *state, | |||
unsigned char *sm, unsigned long long *smlen, | |||
const unsigned char *m, unsigned long long mlen) | |||
{ | |||
@@ -386,18 +394,18 @@ int xmss_core_sign(unsigned char *sk, bds_state *state, | |||
// Extract SK | |||
unsigned long idx = ((unsigned long)sk[0] << 24) | ((unsigned long)sk[1] << 16) | ((unsigned long)sk[2] << 8) | sk[3]; | |||
unsigned char sk_seed[XMSS_N]; | |||
memcpy(sk_seed, sk + XMSS_INDEX_LEN, XMSS_N); | |||
unsigned char sk_prf[XMSS_N]; | |||
memcpy(sk_prf, sk + XMSS_INDEX_LEN + XMSS_N, XMSS_N); | |||
unsigned char pub_seed[XMSS_N]; | |||
memcpy(pub_seed, sk + XMSS_INDEX_LEN + 2*XMSS_N, XMSS_N); | |||
unsigned char sk_seed[params->n]; | |||
memcpy(sk_seed, sk + params->index_len, params->n); | |||
unsigned char sk_prf[params->n]; | |||
memcpy(sk_prf, sk + params->index_len + params->n, params->n); | |||
unsigned char pub_seed[params->n]; | |||
memcpy(pub_seed, sk + params->index_len + 2*params->n, params->n); | |||
// index as 32 bytes string | |||
unsigned char idx_bytes_32[32]; | |||
to_byte(idx_bytes_32, idx, 32); | |||
unsigned char hash_key[3*XMSS_N]; | |||
unsigned char hash_key[3*params->n]; | |||
// Update SK | |||
sk[0] = ((idx + 1) >> 24) & 255; | |||
@@ -408,9 +416,9 @@ int xmss_core_sign(unsigned char *sk, bds_state *state, | |||
// -- A productive implementation should use a file handle instead and write the updated secret key at this point! | |||
// Init working params | |||
unsigned char R[XMSS_N]; | |||
unsigned char msg_h[XMSS_N]; | |||
unsigned char ots_seed[XMSS_N]; | |||
unsigned char R[params->n]; | |||
unsigned char msg_h[params->n]; | |||
unsigned char ots_seed[params->n]; | |||
uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | |||
// --------------------------------- | |||
@@ -419,13 +427,13 @@ int xmss_core_sign(unsigned char *sk, bds_state *state, | |||
// Message Hash: | |||
// First compute pseudorandom value | |||
prf(R, idx_bytes_32, sk_prf, XMSS_N); | |||
prf(params, R, idx_bytes_32, sk_prf, params->n); | |||
// Generate hash key (R || root || idx) | |||
memcpy(hash_key, R, XMSS_N); | |||
memcpy(hash_key+XMSS_N, sk+4+3*XMSS_N, XMSS_N); | |||
to_byte(hash_key+2*XMSS_N, idx, XMSS_N); | |||
memcpy(hash_key, R, params->n); | |||
memcpy(hash_key+params->n, sk+4+3*params->n, params->n); | |||
to_byte(hash_key+2*params->n, idx, params->n); | |||
// Then use it for message digest | |||
h_msg(msg_h, m, mlen, hash_key, 3*XMSS_N); | |||
h_msg(params, msg_h, m, mlen, hash_key, 3*params->n); | |||
// Start collecting signature | |||
*smlen = 0; | |||
@@ -440,12 +448,12 @@ int xmss_core_sign(unsigned char *sk, bds_state *state, | |||
*smlen += 4; | |||
// Copy R to signature | |||
for (i = 0; i < XMSS_N; i++) { | |||
for (i = 0; i < params->n; i++) { | |||
sm[i] = R[i]; | |||
} | |||
sm += XMSS_N; | |||
*smlen += XMSS_N; | |||
sm += params->n; | |||
*smlen += params->n; | |||
// ---------------------------------- | |||
// Now we start to "really sign" | |||
@@ -456,24 +464,24 @@ int xmss_core_sign(unsigned char *sk, bds_state *state, | |||
set_ots_addr(ots_addr, idx); | |||
// Compute seed for OTS key pair | |||
get_seed(ots_seed, sk_seed, ots_addr); | |||
get_seed(params, ots_seed, sk_seed, ots_addr); | |||
// Compute WOTS signature | |||
wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); | |||
wots_sign(params, sm, msg_h, ots_seed, pub_seed, ots_addr); | |||
sm += XMSS_WOTS_KEYSIZE; | |||
*smlen += XMSS_WOTS_KEYSIZE; | |||
sm += params->wots_keysize; | |||
*smlen += params->wots_keysize; | |||
// the auth path was already computed during the previous round | |||
memcpy(sm, state->auth, XMSS_TREEHEIGHT*XMSS_N); | |||
memcpy(sm, state->auth, params->tree_height*params->n); | |||
if (idx < (1U << XMSS_TREEHEIGHT) - 1) { | |||
bds_round(state, idx, sk_seed, pub_seed, ots_addr); | |||
bds_treehash_update(state, (XMSS_TREEHEIGHT - XMSS_BDS_K) >> 1, sk_seed, pub_seed, ots_addr); | |||
if (idx < (1U << params->tree_height) - 1) { | |||
bds_round(params, state, idx, sk_seed, pub_seed, ots_addr); | |||
bds_treehash_update(params, state, (params->tree_height - params->bds_k) >> 1, sk_seed, pub_seed, ots_addr); | |||
} | |||
sm += XMSS_TREEHEIGHT*XMSS_N; | |||
*smlen += XMSS_TREEHEIGHT*XMSS_N; | |||
sm += params->tree_height*params->n; | |||
*smlen += params->tree_height*params->n; | |||
memcpy(sm, m, mlen); | |||
*smlen += mlen; | |||
@@ -486,35 +494,36 @@ int xmss_core_sign(unsigned char *sk, bds_state *state, | |||
* Format sk: [(ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] | |||
* Format pk: [root || PUB_SEED] omitting algo oid. | |||
*/ | |||
int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk, | |||
int xmssmt_core_keypair(const xmss_params *params, | |||
unsigned char *pk, unsigned char *sk, | |||
bds_state *states, unsigned char *wots_sigs) | |||
{ | |||
unsigned char ots_seed[XMSS_N]; | |||
unsigned char ots_seed[params->n]; | |||
uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | |||
int i; | |||
// Set idx = 0 | |||
for (i = 0; i < XMSS_INDEX_LEN; i++) { | |||
for (i = 0; i < params->index_len; i++) { | |||
sk[i] = 0; | |||
} | |||
// Init SK_SEED (XMSS_N byte), SK_PRF (XMSS_N byte), and PUB_SEED (XMSS_N byte) | |||
randombytes(sk+XMSS_INDEX_LEN, 3*XMSS_N); | |||
// Init SK_SEED (params->n byte), SK_PRF (params->n byte), and PUB_SEED (params->n byte) | |||
randombytes(sk+params->index_len, 3*params->n); | |||
// Copy PUB_SEED to public key | |||
memcpy(pk+XMSS_N, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N); | |||
memcpy(pk+params->n, sk+params->index_len+2*params->n, params->n); | |||
// Start with the bottom-most layer | |||
set_layer_addr(addr, 0); | |||
// Set up state and compute wots signatures for all but topmost tree root | |||
for (i = 0; i < XMSS_D - 1; i++) { | |||
for (i = 0; i < params->d - 1; i++) { | |||
// Compute seed for OTS key pair | |||
treehash_init(pk, XMSS_TREEHEIGHT, 0, states + i, sk+XMSS_INDEX_LEN, pk+XMSS_N, addr); | |||
treehash_init(params, pk, params->tree_height, 0, states + i, sk+params->index_len, pk+params->n, addr); | |||
set_layer_addr(addr, (i+1)); | |||
get_seed(ots_seed, sk + XMSS_INDEX_LEN, addr); | |||
wots_sign(wots_sigs + i*XMSS_WOTS_KEYSIZE, pk, ots_seed, pk+XMSS_N, addr); | |||
get_seed(params, ots_seed, sk + params->index_len, addr); | |||
wots_sign(params, wots_sigs + i*params->wots_keysize, pk, ots_seed, pk+params->n, addr); | |||
} | |||
// Address now points to the single tree on layer d-1 | |||
treehash_init(pk, XMSS_TREEHEIGHT, 0, states + i, sk+XMSS_INDEX_LEN, pk+XMSS_N, addr); | |||
memcpy(sk + XMSS_INDEX_LEN + 3*XMSS_N, pk, XMSS_N); | |||
treehash_init(params, pk, params->tree_height, 0, states + i, sk+params->index_len, pk+params->n, addr); | |||
memcpy(sk + params->index_len + 3*params->n, pk, params->n); | |||
return 0; | |||
} | |||
@@ -525,7 +534,8 @@ int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk, | |||
* 2. an updated secret key! | |||
* | |||
*/ | |||
int xmssmt_core_sign(unsigned char *sk, | |||
int xmssmt_core_sign(const xmss_params *params, | |||
unsigned char *sk, | |||
bds_state *states, unsigned char *wots_sigs, | |||
unsigned char *sm, unsigned long long *smlen, | |||
const unsigned char *m, unsigned long long mlen) | |||
@@ -536,14 +546,14 @@ int xmssmt_core_sign(unsigned char *sk, | |||
int needswap_upto = -1; | |||
unsigned int updates; | |||
unsigned char sk_seed[XMSS_N]; | |||
unsigned char sk_prf[XMSS_N]; | |||
unsigned char pub_seed[XMSS_N]; | |||
unsigned char sk_seed[params->n]; | |||
unsigned char sk_prf[params->n]; | |||
unsigned char pub_seed[params->n]; | |||
// Init working params | |||
unsigned char R[XMSS_N]; | |||
unsigned char msg_h[XMSS_N]; | |||
unsigned char hash_key[3*XMSS_N]; | |||
unsigned char ots_seed[XMSS_N]; | |||
unsigned char R[params->n]; | |||
unsigned char msg_h[params->n]; | |||
unsigned char hash_key[3*params->n]; | |||
unsigned char ots_seed[params->n]; | |||
uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | |||
uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; | |||
unsigned char idx_bytes_32[32]; | |||
@@ -551,17 +561,17 @@ int xmssmt_core_sign(unsigned char *sk, | |||
// Extract SK | |||
unsigned long long idx = 0; | |||
for (i = 0; i < XMSS_INDEX_LEN; i++) { | |||
idx |= ((unsigned long long)sk[i]) << 8*(XMSS_INDEX_LEN - 1 - i); | |||
for (i = 0; i < params->index_len; i++) { | |||
idx |= ((unsigned long long)sk[i]) << 8*(params->index_len - 1 - i); | |||
} | |||
memcpy(sk_seed, sk+XMSS_INDEX_LEN, XMSS_N); | |||
memcpy(sk_prf, sk+XMSS_INDEX_LEN+XMSS_N, XMSS_N); | |||
memcpy(pub_seed, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N); | |||
memcpy(sk_seed, sk+params->index_len, params->n); | |||
memcpy(sk_prf, sk+params->index_len+params->n, params->n); | |||
memcpy(pub_seed, sk+params->index_len+2*params->n, params->n); | |||
// Update SK | |||
for (i = 0; i < XMSS_INDEX_LEN; i++) { | |||
sk[i] = ((idx + 1) >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; | |||
for (i = 0; i < params->index_len; i++) { | |||
sk[i] = ((idx + 1) >> 8*(params->index_len - 1 - i)) & 255; | |||
} | |||
// -- Secret key for this non-forward-secure version is now updated. | |||
// -- A productive implementation should use a file handle instead and write the updated secret key at this point! | |||
@@ -574,33 +584,33 @@ int xmssmt_core_sign(unsigned char *sk, | |||
// Message Hash: | |||
// First compute pseudorandom value | |||
to_byte(idx_bytes_32, idx, 32); | |||
prf(R, idx_bytes_32, sk_prf, XMSS_N); | |||
prf(params, R, idx_bytes_32, sk_prf, params->n); | |||
// Generate hash key (R || root || idx) | |||
memcpy(hash_key, R, XMSS_N); | |||
memcpy(hash_key+XMSS_N, sk+XMSS_INDEX_LEN+3*XMSS_N, XMSS_N); | |||
to_byte(hash_key+2*XMSS_N, idx, XMSS_N); | |||
memcpy(hash_key, R, params->n); | |||
memcpy(hash_key+params->n, sk+params->index_len+3*params->n, params->n); | |||
to_byte(hash_key+2*params->n, idx, params->n); | |||
// Then use it for message digest | |||
h_msg(msg_h, m, mlen, hash_key, 3*XMSS_N); | |||
h_msg(params, msg_h, m, mlen, hash_key, 3*params->n); | |||
// Start collecting signature | |||
*smlen = 0; | |||
// Copy index to signature | |||
for (i = 0; i < XMSS_INDEX_LEN; i++) { | |||
sm[i] = (idx >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255; | |||
for (i = 0; i < params->index_len; i++) { | |||
sm[i] = (idx >> 8*(params->index_len - 1 - i)) & 255; | |||
} | |||
sm += XMSS_INDEX_LEN; | |||
*smlen += XMSS_INDEX_LEN; | |||
sm += params->index_len; | |||
*smlen += params->index_len; | |||
// Copy R to signature | |||
for (i = 0; i < XMSS_N; i++) { | |||
for (i = 0; i < params->n; i++) { | |||
sm[i] = R[i]; | |||
} | |||
sm += XMSS_N; | |||
*smlen += XMSS_N; | |||
sm += params->n; | |||
*smlen += params->n; | |||
// ---------------------------------- | |||
// Now we start to "really sign" | |||
@@ -610,85 +620,85 @@ int xmssmt_core_sign(unsigned char *sk, | |||
// Prepare Address | |||
set_type(ots_addr, 0); | |||
idx_tree = idx >> XMSS_TREEHEIGHT; | |||
idx_leaf = (idx & ((1 << XMSS_TREEHEIGHT)-1)); | |||
idx_tree = idx >> params->tree_height; | |||
idx_leaf = (idx & ((1 << params->tree_height)-1)); | |||
set_layer_addr(ots_addr, 0); | |||
set_tree_addr(ots_addr, idx_tree); | |||
set_ots_addr(ots_addr, idx_leaf); | |||
// Compute seed for OTS key pair | |||
get_seed(ots_seed, sk_seed, ots_addr); | |||
get_seed(params, ots_seed, sk_seed, ots_addr); | |||
// Compute WOTS signature | |||
wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr); | |||
wots_sign(params, sm, msg_h, ots_seed, pub_seed, ots_addr); | |||
sm += XMSS_WOTS_KEYSIZE; | |||
*smlen += XMSS_WOTS_KEYSIZE; | |||
sm += params->wots_keysize; | |||
*smlen += params->wots_keysize; | |||
memcpy(sm, states[0].auth, XMSS_TREEHEIGHT*XMSS_N); | |||
sm += XMSS_TREEHEIGHT*XMSS_N; | |||
*smlen += XMSS_TREEHEIGHT*XMSS_N; | |||
memcpy(sm, states[0].auth, params->tree_height*params->n); | |||
sm += params->tree_height*params->n; | |||
*smlen += params->tree_height*params->n; | |||
// prepare signature of remaining layers | |||
for (i = 1; i < XMSS_D; i++) { | |||
for (i = 1; i < params->d; i++) { | |||
// put WOTS signature in place | |||
memcpy(sm, wots_sigs + (i-1)*XMSS_WOTS_KEYSIZE, XMSS_WOTS_KEYSIZE); | |||
memcpy(sm, wots_sigs + (i-1)*params->wots_keysize, params->wots_keysize); | |||
sm += XMSS_WOTS_KEYSIZE; | |||
*smlen += XMSS_WOTS_KEYSIZE; | |||
sm += params->wots_keysize; | |||
*smlen += params->wots_keysize; | |||
// put AUTH nodes in place | |||
memcpy(sm, states[i].auth, XMSS_TREEHEIGHT*XMSS_N); | |||
sm += XMSS_TREEHEIGHT*XMSS_N; | |||
*smlen += XMSS_TREEHEIGHT*XMSS_N; | |||
memcpy(sm, states[i].auth, params->tree_height*params->n); | |||
sm += params->tree_height*params->n; | |||
*smlen += params->tree_height*params->n; | |||
} | |||
updates = (XMSS_TREEHEIGHT - XMSS_BDS_K) >> 1; | |||
updates = (params->tree_height - params->bds_k) >> 1; | |||
set_tree_addr(addr, (idx_tree + 1)); | |||
// mandatory update for NEXT_0 (does not count towards h-k/2) if NEXT_0 exists | |||
if ((1 + idx_tree) * (1 << XMSS_TREEHEIGHT) + idx_leaf < (1ULL << XMSS_FULLHEIGHT)) { | |||
bds_state_update(&states[XMSS_D], sk_seed, pub_seed, addr); | |||
if ((1 + idx_tree) * (1 << params->tree_height) + idx_leaf < (1ULL << params->full_height)) { | |||
bds_state_update(params, &states[params->d], sk_seed, pub_seed, addr); | |||
} | |||
for (i = 0; i < XMSS_D; i++) { | |||
for (i = 0; i < params->d; i++) { | |||
// check if we're not at the end of a tree | |||
if (! (((idx + 1) & ((1ULL << ((i+1)*XMSS_TREEHEIGHT)) - 1)) == 0)) { | |||
idx_leaf = (idx >> (XMSS_TREEHEIGHT * i)) & ((1 << XMSS_TREEHEIGHT)-1); | |||
idx_tree = (idx >> (XMSS_TREEHEIGHT * (i+1))); | |||
if (! (((idx + 1) & ((1ULL << ((i+1)*params->tree_height)) - 1)) == 0)) { | |||
idx_leaf = (idx >> (params->tree_height * i)) & ((1 << params->tree_height)-1); | |||
idx_tree = (idx >> (params->tree_height * (i+1))); | |||
set_layer_addr(addr, i); | |||
set_tree_addr(addr, idx_tree); | |||
if (i == (unsigned int) (needswap_upto + 1)) { | |||
bds_round(&states[i], idx_leaf, sk_seed, pub_seed, addr); | |||
bds_round(params, &states[i], idx_leaf, sk_seed, pub_seed, addr); | |||
} | |||
updates = bds_treehash_update(&states[i], updates, sk_seed, pub_seed, addr); | |||
updates = bds_treehash_update(params, &states[i], updates, sk_seed, pub_seed, addr); | |||
set_tree_addr(addr, (idx_tree + 1)); | |||
// if a NEXT-tree exists for this level; | |||
if ((1 + idx_tree) * (1 << XMSS_TREEHEIGHT) + idx_leaf < (1ULL << (XMSS_FULLHEIGHT - XMSS_TREEHEIGHT * i))) { | |||
if (i > 0 && updates > 0 && states[XMSS_D + i].next_leaf < (1ULL << XMSS_FULLHEIGHT)) { | |||
bds_state_update(&states[XMSS_D + i], sk_seed, pub_seed, addr); | |||
if ((1 + idx_tree) * (1 << params->tree_height) + idx_leaf < (1ULL << (params->full_height - params->tree_height * i))) { | |||
if (i > 0 && updates > 0 && states[params->d + i].next_leaf < (1ULL << params->full_height)) { | |||
bds_state_update(params, &states[params->d + i], sk_seed, pub_seed, addr); | |||
updates--; | |||
} | |||
} | |||
} | |||
else if (idx < (1ULL << XMSS_FULLHEIGHT) - 1) { | |||
memcpy(&tmp, states+XMSS_D + i, sizeof(bds_state)); | |||
memcpy(states+XMSS_D + i, states + i, sizeof(bds_state)); | |||
else if (idx < (1ULL << params->full_height) - 1) { | |||
memcpy(&tmp, states+params->d + i, sizeof(bds_state)); | |||
memcpy(states+params->d + i, states + i, sizeof(bds_state)); | |||
memcpy(states + i, &tmp, sizeof(bds_state)); | |||
set_layer_addr(ots_addr, (i+1)); | |||
set_tree_addr(ots_addr, ((idx + 1) >> ((i+2) * XMSS_TREEHEIGHT))); | |||
set_ots_addr(ots_addr, (((idx >> ((i+1) * XMSS_TREEHEIGHT)) + 1) & ((1 << XMSS_TREEHEIGHT)-1))); | |||
set_tree_addr(ots_addr, ((idx + 1) >> ((i+2) * params->tree_height))); | |||
set_ots_addr(ots_addr, (((idx >> ((i+1) * params->tree_height)) + 1) & ((1 << params->tree_height)-1))); | |||
get_seed(ots_seed, sk+XMSS_INDEX_LEN, ots_addr); | |||
wots_sign(wots_sigs + i*XMSS_WOTS_KEYSIZE, states[i].stack, ots_seed, pub_seed, ots_addr); | |||
get_seed(params, ots_seed, sk+params->index_len, ots_addr); | |||
wots_sign(params, wots_sigs + i*params->wots_keysize, states[i].stack, ots_seed, pub_seed, ots_addr); | |||
states[XMSS_D + i].stackoffset = 0; | |||
states[XMSS_D + i].next_leaf = 0; | |||
states[params->d + i].stackoffset = 0; | |||
states[params->d + i].next_leaf = 0; | |||
updates--; // WOTS-signing counts as one update | |||
needswap_upto = i; | |||
for (j = 0; j < XMSS_TREEHEIGHT-XMSS_BDS_K; j++) { | |||
for (j = 0; j < params->tree_height-params->bds_k; j++) { | |||
states[i].treehash[j].completed = 1; | |||
} | |||
} | |||
@@ -8,6 +8,8 @@ Public domain. | |||
#ifndef XMSS_CORE_H | |||
#define XMSS_CORE_H | |||
#include "params.h" | |||
typedef struct{ | |||
unsigned int h; | |||
unsigned int next_idx; | |||
@@ -41,14 +43,16 @@ void xmss_set_bds_state(bds_state *state, unsigned char *stack, | |||
* Format sk: [(32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] | |||
* Format pk: [root || PUB_SEED] omitting algo oid. | |||
*/ | |||
int xmss_core_keypair(unsigned char *pk, unsigned char *sk, bds_state *state); | |||
int xmss_core_keypair(const xmss_params *params, | |||
unsigned char *pk, unsigned char *sk, bds_state *state); | |||
/** | |||
* Signs a message. | |||
* Returns | |||
* 1. an array containing the signature followed by the message AND | |||
* 2. an updated secret key! | |||
*/ | |||
int xmss_core_sign(unsigned char *sk, bds_state *state, | |||
int xmss_core_sign(const xmss_params *params, | |||
unsigned char *sk, bds_state *state, | |||
unsigned char *sm, unsigned long long *smlen, | |||
const unsigned char *m, unsigned long long mlen); | |||
/** | |||
@@ -56,7 +60,8 @@ int xmss_core_sign(unsigned char *sk, bds_state *state, | |||
* | |||
* Note: msg and mlen are pure outputs which carry the message in case verification succeeds. The (input) message is assumed to be within sm which has the form (sig||msg). | |||
*/ | |||
int xmss_core_sign_open(unsigned char *m, unsigned long long *mlen, | |||
int xmss_core_sign_open(const xmss_params *params, | |||
unsigned char *m, unsigned long long *mlen, | |||
const unsigned char *sm, unsigned long long smlen, | |||
const unsigned char *pk); | |||
@@ -65,7 +70,8 @@ int xmss_core_sign_open(unsigned char *m, unsigned long long *mlen, | |||
* Format sk: [(ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root] | |||
* Format pk: [root || PUB_SEED] omitting algo oid. | |||
*/ | |||
int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk, | |||
int xmssmt_core_keypair(const xmss_params *params, | |||
unsigned char *pk, unsigned char *sk, | |||
bds_state *states, unsigned char *wots_sigs); | |||
/** | |||
@@ -74,7 +80,8 @@ int xmssmt_core_keypair(unsigned char *pk, unsigned char *sk, | |||
* 1. an array containing the signature followed by the message AND | |||
* 2. an updated secret key! | |||
*/ | |||
int xmssmt_core_sign(unsigned char *sk, | |||
int xmssmt_core_sign(const xmss_params *params, | |||
unsigned char *sk, | |||
bds_state *states, unsigned char *wots_sigs, | |||
unsigned char *sm, unsigned long long *smlen, | |||
const unsigned char *m, unsigned long long mlen); | |||
@@ -82,7 +89,8 @@ int xmssmt_core_sign(unsigned char *sk, | |||
/** | |||
* Verifies a given message signature pair under a given public key. | |||
*/ | |||
int xmssmt_core_sign_open(unsigned char *m, unsigned long long *mlen, | |||
int xmssmt_core_sign_open(const xmss_params *params, | |||
unsigned char *m, unsigned long long *mlen, | |||
const unsigned char *sm, unsigned long long smlen, | |||
const unsigned char *pk); | |||
#endif |