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.
Этот коммит содержится в:
родитель
2e96b03106
Коммит
1cba1e7be8
32
Makefile
32
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)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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(¶ms, 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(¶ms, pk, sk, state);
|
||||
t2 = cpucycles();
|
||||
printf("cycles = %llu\n", (t2-t1));
|
||||
double sec = (t2-t1)/3500000;
|
||||
printf("ms = %f\n", sec);
|
||||
// check pub_seed in SK
|
||||
for (i = 0; i < 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(¶ms, sk, state, sm, &smlen, mi, MLEN);
|
||||
idx = ((unsigned long)sm[0] << 24) | ((unsigned long)sm[1] << 16) | ((unsigned long)sm[2] << 8) | sm[3];
|
||||
printf("\nidx = %lu\n",idx);
|
||||
|
||||
r = memcmp(mi, sm+signature_length,MLEN);
|
||||
printf("%d\n", r);
|
||||
|
||||
/* Test valid signature */
|
||||
printf("verify\n");
|
||||
r = xmss_core_sign_open(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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;
|
||||
}
|
@ -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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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;
|
||||
}
|
285
xmss_core_fast.c
285
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;
|
||||
}
|
||||
|
104
xmss_core_fast.h
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
|
Загрузка…
Ссылка в новой задаче
Block a user