ソースを参照

Revert to using runtime-only parameter struct

Using global defines for parameters (as seems to be typical in
academic crypto code) does not play nice with multithreading at all.
master
Joost Rijneveld 7年前
コミット
6a8571d880
この署名に対応する既知のキーがデータベースに存在しません GPGキーID: A4FE39CF49CBC553
22個のファイルの変更710行の追加677行の削除
  1. +22
    -29
      Makefile
  2. +1
    -1
      README.md
  3. +31
    -26
      hash.c
  4. +10
    -4
      hash.h
  5. +54
    -58
      params.c
  6. +0
    -32
      params_runtime.h
  7. +15
    -10
      test/test_wots.c
  8. +13
    -12
      test/test_xmss.c
  9. +19
    -14
      test/test_xmss_core.c
  10. +29
    -24
      test/test_xmss_core_fast.c
  11. +14
    -13
      test/test_xmssmt.c
  12. +17
    -12
      test/test_xmssmt_core.c
  13. +20
    -15
      test/test_xmssmt_core_fast.c
  14. +50
    -45
      wots.c
  15. +6
    -3
      wots.h
  16. +21
    -14
      xmss.c
  17. +77
    -75
      xmss_commons.c
  18. +8
    -5
      xmss_commons.h
  19. +104
    -104
      xmss_core.c
  20. +6
    -6
      xmss_core.h
  21. +179
    -169
      xmss_core_fast.c
  22. +14
    -6
      xmss_core_fast.h

+ 22
- 29
Makefile ファイルの表示

@@ -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


+ 1
- 1
README.md ファイルの表示

@@ -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)._



+ 31
- 26
hash.c ファイルの表示

@@ -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);
}

+ 10
- 4
hash.h ファイルの表示

@@ -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

params_runtime.c → params.c ファイルの表示

@@ -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;
}

+ 0
- 32
params_runtime.h ファイルの表示

@@ -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

+ 15
- 10
test/test_wots.c ファイルの表示

@@ -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(&params, 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(&params, pk1, seed, pub_seed, addr);
wots_sign(&params, sig, msg, seed, pub_seed, addr);
wots_pk_from_sig(&params, pk2, sig, msg, pub_seed, addr);

for (i = 0; i < sig_len; i++)
if (pk1[i] != pk2[i]) {


+ 13
- 12
test/test_xmss.c ファイルの表示

@@ -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(&params, 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++;


+ 19
- 14
test/test_xmss_core.c ファイルの表示

@@ -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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, mo, &mlen, sm, smlen, pk);
printf("%d\n", r+1);
if (r == 0) errors++;
r = memcmp(mi,mo,MLEN);


+ 29
- 24
test/test_xmss_core_fast.c ファイルの表示

@@ -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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, mo, &mlen, sm, smlen, pk);
printf("%d\n", r+1);
if (r == 0) errors++;
r = memcmp(mi,mo,MLEN);


+ 14
- 13
test/test_xmssmt.c ファイルの表示

@@ -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(&params, 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++) {


+ 17
- 12
test/test_xmssmt_core.c ファイルの表示

@@ -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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, mo, &mlen, sm, smlen, pk);
printf("%d\n", r+1);
r = memcmp(mi,mo,MLEN);
printf("%d\n", (r!=0) - 1);


+ 20
- 15
test/test_xmssmt_core_fast.c ファイルの表示

@@ -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(&params, 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(&params, 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(&params, 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(&params, 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(&params, 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(&params, mo, &mlen, sm, smlen, pk);
printf("%d\n", r+1);
r = memcmp(mi,mo,MLEN);
printf("%d\n", (r!=0) - 1);


+ 50
- 45
wots.c ファイルの表示

@@ -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);
}
}

+ 6
- 3
wots.h ファイルの表示

@@ -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]);



+ 21
- 14
xmss.c ファイルの表示

@@ -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(&params, 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(&params, 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(&params, oid)) {
return 1;
}
return xmss_core_sign(sk + XMSS_OID_LEN, sm, smlen, m, mlen);
return xmss_core_sign(&params, 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(&params, oid)) {
return 1;
}
return xmss_core_sign_open(m, mlen, sm, smlen, pk + XMSS_OID_LEN);
return xmss_core_sign_open(&params, 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(&params, 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(&params, 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(&params, oid)) {
return 1;
}
return xmssmt_core_sign(sk + XMSS_OID_LEN, sm, smlen, m, mlen);
return xmssmt_core_sign(&params, 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(&params, oid)) {
return 1;
}
return xmssmt_core_sign_open(m, mlen, sm, smlen, pk + XMSS_OID_LEN);
return xmssmt_core_sign_open(&params, m, mlen, sm, smlen, pk + XMSS_OID_LEN);
}

+ 77
- 75
xmss_commons.c ファイルの表示

@@ -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;


+ 8
- 5
xmss_commons.h ファイルの表示

@@ -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

+ 104
- 104
xmss_core.c ファイルの表示

@@ -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);


+ 6
- 6
xmss_core.h ファイルの表示

@@ -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


+ 179
- 169
xmss_core_fast.c ファイルの表示

@@ -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;
}
}


+ 14
- 6
xmss_core_fast.h ファイルの表示

@@ -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

読み込み中…
キャンセル
保存