Переглянути джерело

Make core_fast use the secret key for the state

This ensures that xmss_core and xmss_core_fast offer the same API.
Note that xmss_core_fast still needs a major refactor, and this
wrapper is not exactly very clean. There is a considerable chance
this refactor will change the format of the state in the secret key.
master
Joost Rijneveld 7 роки тому
джерело
коміт
1cba1e7be8
Не вдалося знайти GPG ключ що відповідає даному підпису Ідентифікатор GPG ключа: A4FE39CF49CBC553
6 змінених файлів з 265 додано та 448 видалено
  1. +10
    -22
      Makefile
  2. +1
    -3
      README.md
  3. +0
    -150
      test/xmss_core_fast.c
  4. +0
    -138
      test/xmssmt_core_fast.c
  5. +254
    -31
      xmss_core_fast.c
  6. +0
    -104
      xmss_core_fast.h

+ 10
- 22
Makefile Переглянути файл

@@ -5,19 +5,15 @@ LDLIBS = -lcrypto
SOURCES = params.c hash.c fips202.c hash_address.c randombytes.c wots.c xmss.c xmss_core.c xmss_commons.c
HEADERS = params.h hash.h fips202.h hash_address.h randombytes.h wots.h xmss.h xmss_core.h xmss_commons.h

SOURCES_FAST = $(subst core,core_fast,$(SOURCES))
HEADERS_FAST = $(subst core,core_fast,$(HEADERS))
SOURCES_FAST = $(subst xmss_core.c,xmss_core_fast.c,$(SOURCES))
HEADERS_FAST = $(subst xmss_core.c,xmss_core_fast.c,$(HEADERS))

TESTS = test/wots \
test/xmss_determinism \
test/xmss \
test/xmss_fast \
test/xmssmt \
test/xmss_core_fast \
test/xmssmt_core_fast \

# These currently do not work, as xmss_core_fast does not match the xmss_core.h API
# test/xmss_fast \
# test/xmssmt_fast \
test/xmssmt_fast \

UI = ui/xmss_keypair \
ui/xmss_sign \
@@ -25,14 +21,12 @@ UI = ui/xmss_keypair \
ui/xmssmt_keypair \
ui/xmssmt_sign \
ui/xmssmt_open \

# These currently do not work, as xmss_core_fast does not match the xmss_core.h API
# ui/xmss_keypair_fast \
# ui/xmss_sign_fast \
# ui/xmss_open_fast \
# ui/xmssmt_keypair_fast \
# ui/xmssmt_sign_fast \
# ui/xmssmt_open_fast \
ui/xmss_keypair_fast \
ui/xmss_sign_fast \
ui/xmss_open_fast \
ui/xmssmt_keypair_fast \
ui/xmssmt_sign_fast \
ui/xmssmt_open_fast \

all: tests ui

@@ -58,12 +52,6 @@ test/xmssmt_fast: test/xmss.c $(SOURCES_FAST) $(OBJS) $(HEADERS_FAST)
test/xmssmt: test/xmss.c $(SOURCES) $(OBJS) $(HEADERS)
$(CC) -DXMSSMT $(CFLAGS) -o $@ $(SOURCES) $< $(LDLIBS)

test/xmss_core_fast: test/xmss_core_fast.c $(SOURCES_FAST) $(OBJS) $(HEADERS_FAST)
$(CC) $(CFLAGS) -o $@ $(SOURCES_FAST) $< $(LDLIBS)

test/xmssmt_core_fast: test/xmss_core_fast.c $(SOURCES_FAST) $(OBJS) $(HEADERS_FAST)
$(CC) $(CFLAGS) -o $@ $(SOURCES_FAST) $< $(LDLIBS)

test/%: test/%.c $(SOURCES) $(OBJS) $(HEADERS)
$(CC) $(CFLAGS) -o $@ $(SOURCES) $< $(LDLIBS)



+ 1
- 3
README.md Переглянути файл

@@ -4,9 +4,7 @@ This repository contains the reference implementation that accompanies the Inter

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. This means that the `xmss_core_fast.c` back-end is somewhat hard to use. This is the most immediate open TODO, and will be resolved soon.**_

_When using the current code base, please be careful, expect changes and watch this document for further documentation._
_When using the current code base, please be careful, expect changes and watch this document for further documentation. In particular, `xmss_core_fast.c` is long due for a serious clean-up. While this will not change its public API or output, it may affect the storage format of the BDS state (i.e. part of the secret key)._

### Dependencies



+ 0
- 150
test/xmss_core_fast.c Переглянути файл

@@ -1,150 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "../xmss_core_fast.h"
#include "../params.h"
#include "../randombytes.h"

#define MLEN 3491
#define SIGNATURES 256

unsigned long long t1, t2;

unsigned long long cpucycles(void)
{
unsigned long long result;
asm volatile(".byte 15;.byte 49;shlq $32,%%rdx;orq %%rdx,%%rax" : "=a" (result) :: "%rdx");
return result;
}

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 = params.bds_k;

unsigned long errors = 0;

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[(params.tree_height+1)*params.n];
unsigned int stackoffset = 0;
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 < 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+params.n+params.wots_sig_bytes+params.tree_height*params.n;
unsigned char mi[MLEN];
unsigned char mo[MLEN+signature_length];
unsigned char sm[MLEN+signature_length];
unsigned long long smlen;
unsigned long long mlen;

randombytes(mi, MLEN);

printf("keypair\n");
t1 = cpucycles();
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 < 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
unsigned long idx = ((unsigned long)sk[0] << 24) | ((unsigned long)sk[1] << 16) | ((unsigned long)sk[2] << 8) | sk[3];
if (idx) printf("\nidx != 0 %lu\n",idx);

for (i = 0; i < SIGNATURES; i++) {
printf("sign\n");
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);

r = memcmp(mi, sm+signature_length,MLEN);
printf("%d\n", r);

/* Test valid signature */
printf("verify\n");
r = xmss_core_sign_open(&params, mo, &mlen, sm, smlen, pk);
printf("%d\n", r);
if (r != 0) errors++;
r = memcmp(mi,mo,MLEN);
printf("%d\n", r);
printf("%llu\n", MLEN-mlen);

/* Test with modified message */
sm[signature_length+10] ^= 1;
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);
printf("%d\n", (r!=0) - 1);
printf("%llu\n", mlen+1);

/* Test with modified signature */
/* Modified index */
sm[signature_length+10] ^= 1;
sm[2] ^= 1;
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);
printf("%d\n", (r!=0) - 1);
printf("%llu\n", mlen+1);

/* Modified R */
sm[2] ^= 1;
sm[5] ^= 1;
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);
printf("%d\n", (r!=0) - 1);
printf("%llu\n", mlen+1);

/* Modified OTS sig */
sm[5] ^= 1;
sm[240] ^= 1;
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);
printf("%d\n", (r!=0) - 1);
printf("%llu\n", mlen+1);

/* Modified AUTH */
sm[240] ^= 1;
sm[signature_length - 10] ^= 1;
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);
printf("%d\n", (r!=0) - 1);
printf("%llu\n", mlen+1);
}

printf("#errors = %lu\n", errors);
printf("finished loop\n");
return 0;
}

+ 0
- 138
test/xmssmt_core_fast.c Переглянути файл

@@ -1,138 +0,0 @@
#include <stdio.h>
#include <string.h>

#include "../xmss_core_fast.h"
#include "../params.h"
#include "../randombytes.h"

#define MLEN 3491
#define SIGNATURES 128

unsigned char mi[MLEN];
unsigned long long smlen;
unsigned long long mlen;

unsigned long long t1, t2;

unsigned long long cpucycles(void)
{
unsigned long long result;
asm volatile(".byte 15;.byte 49;shlq $32,%%rdx;orq %%rdx,%%rax" : "=a" (result) :: "%rdx");
return result;
}

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

// stack needs to be larger than regular (H-K-1), since we re-use for 'next'
unsigned char stack[(2*d-1) * (tree_h + 1)*n];
unsigned char stacklevels[(2*d-1) * (tree_h + 1)*n];
unsigned char auth[(2*d-1) * tree_h*n];
unsigned char keep[(2*d-1) * (tree_h >> 1)*n];
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-1) * params.wots_sig_bytes];
// first d are 'regular' states, second d are 'next'; top tree has no 'next'
bds_state states[2*d-1];

for (i = 0; i < 2*d-1; i++) {
for (j = 0; j < tree_h-k; j++)
treehash[i*(tree_h-k) + j].node = th_nodes + (i*(tree_h-k) + j) * n;
xmss_set_bds_state(states + i,
stack + i*(tree_h + 1)*n, 0, stacklevels + i*(tree_h + 1),
auth + i*tree_h*n,
keep + i*(tree_h >> 1)*n,
treehash + i*(tree_h-k),
retain + i*((1 << k) - k - 1)*n,
0
);
}

unsigned char sk[(params.index_bytes+4*n)];
unsigned char pk[2*n];

unsigned long long signature_length = params.index_bytes + n + (d*params.wots_sig_bytes) + h*n;
unsigned char mo[MLEN+signature_length];
unsigned char sm[MLEN+signature_length];

randombytes(mi, MLEN);

printf("keypair\n");
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[params.index_bytes+2*n+i]) printf("pk.pub_seed != sk.pub_seed %llu",i);
if (pk[i] != sk[params.index_bytes+3*n+i]) printf("pk.root != sk.root %llu",i);
}
printf("pk checked\n");

unsigned int idx_len = params.index_bytes;
// check index
unsigned long long idx = 0;
for (i = 0; i < idx_len; i++) {
idx |= ((unsigned long long)sk[i]) << 8*(idx_len - 1 - i);
}

if (idx) printf("\nidx != 0: %llu\n",idx);

for (i = 0; i < SIGNATURES; i++) {
printf("sign\n");
t1 = cpucycles();
xmssmt_core_sign(&params, sk, states, wots_sigs, sm, &smlen, mi, MLEN);
t2 = cpucycles();
printf("signing cycles = %llu\n", (t2-t1));

idx = 0;
for (j = 0; j < idx_len; j++) {
idx += ((unsigned long long)sm[j]) << 8*(idx_len - 1 - j);
}
printf("\nidx = %llu\n",idx);
r = memcmp(mi, sm+signature_length,MLEN);
printf("%d\n", r);

/* Test valid signature */
printf("verify\n");
t1 = cpucycles();
r = xmssmt_core_sign_open(&params, mo, &mlen, sm, smlen, pk);
t2 = cpucycles();
printf("verification cycles = %llu\n", (t2-t1));
printf("%d\n", r);
r = memcmp(mi,mo,MLEN);
printf("%d\n", r);
printf("%llu\n", MLEN-mlen);

/* Test with modified message */
sm[52] ^= 1;
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);
printf("%llu\n", mlen+1);

/* Test with modified signature */
sm[260] ^= 1;
sm[52] ^= 1;
sm[2] ^= 1;
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);
printf("%llu\n", mlen+1);

}
return 0;
}

+ 254
- 31
xmss_core_fast.c Переглянути файл

@@ -8,26 +8,187 @@
#include "randombytes.h"
#include "wots.h"
#include "xmss_commons.h"
#include "xmss_core_fast.h"
#include "xmss_core.h"

typedef struct{
unsigned char h;
unsigned long next_idx;
unsigned char stackusage;
unsigned char completed;
unsigned char *node;
} treehash_inst;

typedef struct {
unsigned char *stack;
unsigned int stackoffset;
unsigned char *stacklevels;
unsigned char *auth;
unsigned char *keep;
treehash_inst *treehash;
unsigned char *retain;
unsigned int next_leaf;
} bds_state;

/* These serialization functions provide a transition between the current
way of storing the state in an exposed struct, and storing it as part of the
byte array that is the secret key.
They will probably be refactored in a non-backwards-compatible way, soon. */

static void xmssmt_serialize_state(const xmss_params *params,
unsigned char *sk, bds_state *states)
{
unsigned int i, j;

/* Skip past the 'regular' sk */
sk += params->index_bytes + 4*params->n;

for (i = 0; i < 2*params->d - 1; i++) {
sk += (params->tree_height + 1) * params->n; /* stack */

ull_to_bytes(sk, 4, states[i].stackoffset);
sk += 4;

sk += params->tree_height + 1; /* stacklevels */
sk += params->tree_height * params->n; /* auth */
sk += (params->tree_height >> 1) * params->n; /* keep */

for (j = 0; j < params->tree_height - params->bds_k; j++) {
ull_to_bytes(sk, 1, states[i].treehash[j].h);
sk += 1;

ull_to_bytes(sk, 4, states[i].treehash[j].next_idx);
sk += 4;

ull_to_bytes(sk, 1, states[i].treehash[j].stackusage);
sk += 1;

ull_to_bytes(sk, 1, states[i].treehash[j].completed);
sk += 1;

sk += params->n; /* node */
}

/* retain */
sk += ((1 << params->bds_k) - params->bds_k - 1) * params->n;

ull_to_bytes(sk, 4, states[i].next_leaf);
sk += 4;
}
}

static void xmssmt_deserialize_state(const xmss_params *params,
bds_state *states,
unsigned char **wots_sigs,
unsigned char *sk)
{
unsigned int i, j;

/* Skip past the 'regular' sk */
sk += params->index_bytes + 4*params->n;

// TODO These data sizes follow from the (former) test xmss_core_fast.c
// TODO They should be reconsidered / motivated more explicitly

for (i = 0; i < 2*params->d - 1; i++) {
states[i].stack = sk;
sk += (params->tree_height + 1) * params->n;

states[i].stackoffset = bytes_to_ull(sk, 4);
sk += 4;

states[i].stacklevels = sk;
sk += params->tree_height + 1;

states[i].auth = sk;
sk += params->tree_height * params->n;

states[i].keep = sk;
sk += (params->tree_height >> 1) * params->n;

for (j = 0; j < params->tree_height - params->bds_k; j++) {
states[i].treehash[j].h = bytes_to_ull(sk, 1);
sk += 1;

states[i].treehash[j].next_idx = bytes_to_ull(sk, 4);
sk += 4;

states[i].treehash[j].stackusage = bytes_to_ull(sk, 1);
sk += 1;

states[i].treehash[j].completed = bytes_to_ull(sk, 1);
sk += 1;

states[i].treehash[j].node = sk;
sk += params->n;
}

states[i].retain = sk;
sk += ((1 << params->bds_k) - params->bds_k - 1) * params->n;

states[i].next_leaf = bytes_to_ull(sk, 4);
sk += 4;
}

if (params->d > 1) {
*wots_sigs = sk;
}
}

static void xmss_serialize_state(const xmss_params *params,
unsigned char *sk, bds_state *state)
{
xmssmt_serialize_state(params, sk, state);
}

static void xmss_deserialize_state(const xmss_params *params,
bds_state *state, unsigned char *sk)
{
xmssmt_deserialize_state(params, state, NULL, sk);
}

static void memswap(void *a, void *b, void *t, unsigned long long len)
{
memcpy(t, a, len);
memcpy(a, b, len);
memcpy(b, t, len);
}

/**
* Initialize BDS state struct
* parameter names are the same as used in the description of the BDS traversal
* Swaps the content of two bds_state objects, swapping actual memory rather
* than pointers.
* As we're mapping memory chunks in the secret key to bds state objects,
* it is now necessary to make swaps 'real swaps'. This could be done in the
* serialization function as well, but that causes more overhead
*/
void xmss_set_bds_state(bds_state *state, unsigned char *stack,
int stackoffset, unsigned char *stacklevels,
unsigned char *auth, unsigned char *keep,
treehash_inst *treehash, unsigned char *retain,
int next_leaf)
// TODO this should not be necessary if we keep better track of the states
static void deep_state_swap(const xmss_params *params,
bds_state *a, bds_state *b)
{
state->stack = stack;
state->stackoffset = stackoffset;
state->stacklevels = stacklevels;
state->auth = auth;
state->keep = keep;
state->treehash = treehash;
state->retain = retain;
state->next_leaf = next_leaf;
// TODO this is extremely ugly and should be refactored
// TODO right now, this ensures that both 'stack' and 'retain' fit
unsigned char t[
((params->tree_height + 1) > ((1 << params->bds_k) - params->bds_k - 1)
? (params->tree_height + 1)
: ((1 << params->bds_k) - params->bds_k - 1))
* params->n];
unsigned int i;

memswap(a->stack, b->stack, t, (params->tree_height + 1) * params->n);
memswap(&a->stackoffset, &b->stackoffset, t, sizeof(a->stackoffset));
memswap(a->stacklevels, b->stacklevels, t, params->tree_height + 1);
memswap(a->auth, b->auth, t, params->tree_height * params->n);
memswap(a->keep, b->keep, t, (params->tree_height >> 1) * params->n);

for (i = 0; i < params->tree_height - params->bds_k; i++) {
memswap(&a->treehash[i].h, &b->treehash[i].h, t, sizeof(a->treehash[i].h));
memswap(&a->treehash[i].next_idx, &b->treehash[i].next_idx, t, sizeof(a->treehash[i].next_idx));
memswap(&a->treehash[i].stackusage, &b->treehash[i].stackusage, t, sizeof(a->treehash[i].stackusage));
memswap(&a->treehash[i].completed, &b->treehash[i].completed, t, sizeof(a->treehash[i].completed));
memswap(a->treehash[i].node, b->treehash[i].node, t, params->n);
}

memswap(a->retain, b->retain, t, ((1 << params->bds_k) - params->bds_k - 1) * params->n);
memswap(&a->next_leaf, &b->next_leaf, t, sizeof(a->next_leaf));
}

static int treehash_minheight_on_stack(const xmss_params *params,
@@ -351,7 +512,7 @@ static void bds_round(const xmss_params *params,
*/
unsigned long long xmss_core_sk_bytes(const xmss_params *params)
{
return params->index_bytes + 4 * params->n;
return xmssmt_core_sk_bytes(params);
}

/*
@@ -360,10 +521,20 @@ unsigned long long xmss_core_sk_bytes(const xmss_params *params)
* Format pk: [root || PUB_SEED] omitting algo oid.
*/
int xmss_core_keypair(const xmss_params *params,
unsigned char *pk, unsigned char *sk, bds_state *state)
unsigned char *pk, unsigned char *sk)
{
uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};

// TODO refactor BDS state not to need separate treehash instances
bds_state state;
treehash_inst treehash[params->tree_height - params->bds_k];
state.treehash = treehash;

xmss_deserialize_state(params, &state, sk);

state.stackoffset = 0;
state.next_leaf = 0;

// Set idx = 0
sk[0] = 0;
sk[1] = 0;
@@ -375,9 +546,13 @@ int xmss_core_keypair(const xmss_params *params,
memcpy(pk + params->n, sk + params->index_bytes + 2*params->n, params->n);

// Compute root
treehash_init(params, pk, params->tree_height, 0, state, sk + params->index_bytes, sk + params->index_bytes + 2*params->n, addr);
treehash_init(params, pk, params->tree_height, 0, &state, sk + params->index_bytes, sk + params->index_bytes + 2*params->n, addr);
// copy root o sk
memcpy(sk + params->index_bytes + 3*params->n, pk, params->n);

/* Write the BDS state into sk. */
xmss_serialize_state(params, sk, &state);

return 0;
}

@@ -389,7 +564,7 @@ int xmss_core_keypair(const xmss_params *params,
*
*/
int xmss_core_sign(const xmss_params *params,
unsigned char *sk, bds_state *state,
unsigned char *sk,
unsigned char *sm, unsigned long long *smlen,
const unsigned char *m, unsigned long long mlen)
{
@@ -397,6 +572,14 @@ int xmss_core_sign(const xmss_params *params,

uint16_t i = 0;

// TODO refactor BDS state not to need separate treehash instances
bds_state state;
treehash_inst treehash[params->tree_height - params->bds_k];
state.treehash = treehash;

/* Load the BDS state from sk. */
xmss_deserialize_state(params, &state, sk);

// 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[params->n];
@@ -479,11 +662,11 @@ int xmss_core_sign(const xmss_params *params,
*smlen += params->wots_sig_bytes;

// the auth path was already computed during the previous round
memcpy(sm, state->auth, params->tree_height*params->n);
memcpy(sm, state.auth, params->tree_height*params->n);

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);
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 += params->tree_height*params->n;
@@ -492,6 +675,9 @@ int xmss_core_sign(const xmss_params *params,
memcpy(sm, m, mlen);
*smlen += mlen;

/* Write the updated BDS state back into sk. */
xmss_serialize_state(params, sk, &state);

return 0;
}

@@ -502,7 +688,18 @@ int xmss_core_sign(const xmss_params *params,
*/
unsigned long long xmssmt_core_sk_bytes(const xmss_params *params)
{
return params->index_bytes + 4 * params->n;
return params->index_bytes + 4 * params->n
+ (2 * params->d - 1) * (
(params->tree_height + 1) * params->n
+ 4
+ params->tree_height + 1
+ params->tree_height * params->n
+ (params->tree_height >> 1) * params->n
+ (params->tree_height - params->bds_k) * (7 + params->n)
+ ((1 << params->bds_k) - params->bds_k - 1) * params->n
+ 4
)
+ (params->d - 1) * params->wots_sig_bytes;
}

/*
@@ -511,12 +708,26 @@ unsigned long long xmssmt_core_sk_bytes(const xmss_params *params)
* Format pk: [root || PUB_SEED] omitting algo oid.
*/
int xmssmt_core_keypair(const xmss_params *params,
unsigned char *pk, unsigned char *sk,
bds_state *states, unsigned char *wots_sigs)
unsigned char *pk, unsigned char *sk)
{
unsigned char ots_seed[params->n];
uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
unsigned int i;
unsigned char *wots_sigs;

// TODO refactor BDS state not to need separate treehash instances
bds_state states[2*params->d - 1];
treehash_inst treehash[(2*params->d - 1) * (params->tree_height - params->bds_k)];
for (i = 0; i < 2*params->d - 1; i++) {
states[i].treehash = treehash + i * (params->tree_height - params->bds_k);
}

xmssmt_deserialize_state(params, states, &wots_sigs, sk);

for (i = 0; i < 2 * params->d - 1; i++) {
states[i].stackoffset = 0;
states[i].next_leaf = 0;
}

// Set idx = 0
for (i = 0; i < params->index_bytes; i++) {
@@ -540,6 +751,9 @@ int xmssmt_core_keypair(const xmss_params *params,
// Address now points to the single tree on layer d-1
treehash_init(params, pk, params->tree_height, 0, states + i, sk+params->index_bytes, pk+params->n, addr);
memcpy(sk + params->index_bytes + 3*params->n, pk, params->n);

xmssmt_serialize_state(params, sk, states);

return 0;
}

@@ -552,7 +766,6 @@ int xmssmt_core_keypair(const xmss_params *params,
*/
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)
{
@@ -574,7 +787,17 @@ int xmssmt_core_sign(const xmss_params *params,
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];
bds_state tmp;

unsigned char *wots_sigs;

// TODO refactor BDS state not to need separate treehash instances
bds_state states[2*params->d - 1];
treehash_inst treehash[(2*params->d - 1) * (params->tree_height - params->bds_k)];
for (i = 0; i < 2*params->d - 1; i++) {
states[i].treehash = treehash + i * (params->tree_height - params->bds_k);
}

xmssmt_deserialize_state(params, states, &wots_sigs, sk);

// Extract SK
unsigned long long idx = 0;
@@ -700,9 +923,7 @@ int xmssmt_core_sign(const xmss_params *params,
}
}
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));
deep_state_swap(params, states+params->d + i, states + i);

set_layer_addr(ots_addr, (i+1));
set_tree_addr(ots_addr, ((idx + 1) >> ((i+2) * params->tree_height)));
@@ -725,5 +946,7 @@ int xmssmt_core_sign(const xmss_params *params,
memcpy(sm, m, mlen);
*smlen += mlen;

xmssmt_serialize_state(params, sk, states);

return 0;
}

+ 0
- 104
xmss_core_fast.h Переглянути файл

@@ -1,104 +0,0 @@
#ifndef XMSS_CORE_H
#define XMSS_CORE_H

#include "params.h"

typedef struct{
unsigned int h;
unsigned int next_idx;
unsigned int stackusage;
unsigned char completed;
unsigned char *node;
} treehash_inst;

typedef struct {
unsigned char *stack;
unsigned int stackoffset;
unsigned char *stacklevels;
unsigned char *auth;
unsigned char *keep;
treehash_inst *treehash;
unsigned char *retain;
unsigned int next_leaf;
} bds_state;

/**
* Initialize BDS state struct
* parameter names are the same as used in the description of the BDS traversal
*/
void xmss_set_bds_state(bds_state *state, unsigned char *stack,
int stackoffset, unsigned char *stacklevels,
unsigned char *auth, unsigned char *keep,
treehash_inst *treehash, unsigned char *retain,
int next_leaf);

/**
* Given a set of parameters, this function returns the size of the secret key.
* This is implementation specific, as varying choices in tree traversal will
* result in varying requirements for state storage.
*/
unsigned long long xmss_core_sk_bytes(const xmss_params *params);

/**
* Generates a XMSS key pair for a given parameter set.
* Format sk: [(32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root]
* Format pk: [root || PUB_SEED] omitting algo oid.
*/
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(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);
/**
* Verifies a given message signature pair under a given public key.
*
* 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(const xmss_params *params,
unsigned char *m, unsigned long long *mlen,
const unsigned char *sm, unsigned long long smlen,
const unsigned char *pk);

/**
* Given a set of parameters, this function returns the size of the secret key.
* This is implementation specific, as varying choices in tree traversal will
* result in varying requirements for state storage.
*/
unsigned long long xmssmt_core_sk_bytes(const xmss_params *params);

/*
* 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(const xmss_params *params,
unsigned char *pk, unsigned char *sk,
bds_state *states, unsigned char *wots_sigs);

/**
* Signs a message.
* Returns
* 1. an array containing the signature followed by the message AND
* 2. an updated secret key!
*/
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);

/**
* Verifies a given message signature pair under a given public key.
*/
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

Завантаження…
Відмінити
Зберегти