Fix update bug (partially re-implement BDS)
The bug occured for cases where d=3 and indicated a lack of updates. Re-implementing the higher-level structure of BDS resolved this.
This commit is contained in:
parent
17c5b2842f
commit
97331f09c0
156
xmss_fast.c
156
xmss_fast.c
@ -401,34 +401,39 @@ static void validate_authpath(unsigned char *root, const unsigned char *leaf, un
|
|||||||
* Performs one treehash update on the instance that needs it the most.
|
* Performs one treehash update on the instance that needs it the most.
|
||||||
* Returns 1 if such an instance was not found
|
* Returns 1 if such an instance was not found
|
||||||
**/
|
**/
|
||||||
static char bds_treehash_update(bds_state *state, const unsigned char *sk_seed, const xmss_params *params, unsigned char *pub_seed, const unsigned char addr[16]) {
|
static char bds_treehash_update(bds_state *state, unsigned int updates, const unsigned char *sk_seed, const xmss_params *params, unsigned char *pub_seed, const unsigned char addr[16]) {
|
||||||
unsigned int i;
|
unsigned int i, j;
|
||||||
int level, l_min, low;
|
int level, l_min, low;
|
||||||
int h = params->h;
|
int h = params->h;
|
||||||
int k = params->k;
|
int k = params->k;
|
||||||
|
int used = 0;
|
||||||
|
|
||||||
l_min = h;
|
for (j = 0; j < updates; j++) {
|
||||||
level = h - k;
|
l_min = h;
|
||||||
for (i = 0; i < h - k; i++) {
|
level = h - k;
|
||||||
if (state->treehash[i].completed) {
|
for (i = 0; i < h - k; i++) {
|
||||||
low = h;
|
if (state->treehash[i].completed) {
|
||||||
|
low = h;
|
||||||
|
}
|
||||||
|
else if (state->treehash[i].stackusage == 0) {
|
||||||
|
low = i;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
low = treehash_minheight_on_stack(state, params, &(state->treehash[i]));
|
||||||
|
}
|
||||||
|
if (low < l_min) {
|
||||||
|
level = i;
|
||||||
|
l_min = low;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (state->treehash[i].stackusage == 0) {
|
if (level == h - k) {
|
||||||
low = i;
|
break;
|
||||||
}
|
|
||||||
else {
|
|
||||||
low = treehash_minheight_on_stack(state, params, &(state->treehash[i]));
|
|
||||||
}
|
|
||||||
if (low < l_min) {
|
|
||||||
level = i;
|
|
||||||
l_min = low;
|
|
||||||
}
|
}
|
||||||
|
// printf("Updated treehash instance on level %d\n", level);
|
||||||
|
treehash_update(&(state->treehash[level]), state, sk_seed, params, pub_seed, addr);
|
||||||
|
used++;
|
||||||
}
|
}
|
||||||
if (level == h - k) {
|
return updates - used;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
treehash_update(&(state->treehash[level]), state, sk_seed, params, pub_seed, addr);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -501,8 +506,9 @@ static char bds_state_update(bds_state *state, const unsigned char *sk_seed, con
|
|||||||
* next leaf node, using the algorithm described by Buchmann, Dahmen and Szydlo
|
* next leaf node, using the algorithm described by Buchmann, Dahmen and Szydlo
|
||||||
* in "Post Quantum Cryptography", Springer 2009.
|
* in "Post Quantum Cryptography", Springer 2009.
|
||||||
*/
|
*/
|
||||||
static int bds_round(bds_state *state, const unsigned long leaf_idx, const unsigned char *sk_seed, const xmss_params *params, const int updates, unsigned char *pub_seed, unsigned char addr[16])
|
static void bds_round(bds_state *state, const unsigned long leaf_idx, const unsigned char *sk_seed, const xmss_params *params, unsigned char *pub_seed, unsigned char addr[16])
|
||||||
{
|
{
|
||||||
|
// printf("COMPUTING %llu\n", leaf_idx);
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int n = params->n;
|
int n = params->n;
|
||||||
int h = params->h;
|
int h = params->h;
|
||||||
@ -571,13 +577,6 @@ static int bds_round(bds_state *state, const unsigned long leaf_idx, const unsig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int remaining = 0;
|
|
||||||
for (i = 0; i < updates; i++) {
|
|
||||||
if (bds_treehash_update(state, sk_seed, params, pub_seed, addr)) {
|
|
||||||
remaining++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return remaining;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -693,7 +692,8 @@ int xmss_sign(unsigned char *sk, bds_state *state, unsigned char *sig_msg, unsig
|
|||||||
memcpy(sig_msg, state->auth, h*n);
|
memcpy(sig_msg, state->auth, h*n);
|
||||||
|
|
||||||
if (idx < (1 << h) - 1) {
|
if (idx < (1 << h) - 1) {
|
||||||
bds_round(state, idx, sk_seed, params, (h - k) >> 1, pub_seed, ots_addr);
|
bds_round(state, idx, sk_seed, params, pub_seed, ots_addr);
|
||||||
|
bds_treehash_update(state, (h - k) >> 1, sk_seed, params, pub_seed, ots_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
sig_msg += params->h*n;
|
sig_msg += params->h*n;
|
||||||
@ -855,8 +855,8 @@ int xmssmt_sign(unsigned char *sk, bds_state *states, unsigned char *wots_sigs,
|
|||||||
unsigned long long idx_tree;
|
unsigned long long idx_tree;
|
||||||
unsigned long long idx_leaf;
|
unsigned long long idx_leaf;
|
||||||
unsigned long long i, j;
|
unsigned long long i, j;
|
||||||
|
int needswap_upto = -1;
|
||||||
unsigned int updates;
|
unsigned int updates;
|
||||||
unsigned int first_nonwots;
|
|
||||||
|
|
||||||
unsigned char sk_seed[n];
|
unsigned char sk_seed[n];
|
||||||
unsigned char sk_prf[m];
|
unsigned char sk_prf[m];
|
||||||
@ -865,6 +865,7 @@ int xmssmt_sign(unsigned char *sk, bds_state *states, unsigned char *wots_sigs,
|
|||||||
unsigned char R[m];
|
unsigned char R[m];
|
||||||
unsigned char msg_h[m];
|
unsigned char msg_h[m];
|
||||||
unsigned char ots_seed[n];
|
unsigned char ots_seed[n];
|
||||||
|
unsigned char addr[16] = {0,0,0,0};
|
||||||
unsigned char ots_addr[16] = {0,0,0,0};
|
unsigned char ots_addr[16] = {0,0,0,0};
|
||||||
bds_state tmp;
|
bds_state tmp;
|
||||||
|
|
||||||
@ -955,71 +956,52 @@ int xmssmt_sign(unsigned char *sk, bds_state *states, unsigned char *wots_sigs,
|
|||||||
*sig_msg_len += tree_h*n;
|
*sig_msg_len += tree_h*n;
|
||||||
}
|
}
|
||||||
|
|
||||||
SET_LAYER_ADDRESS(ots_addr, 0);
|
updates = (tree_h - k) >> 1;
|
||||||
SET_TREE_ADDRESS(ots_addr, (idx_tree + 1));
|
|
||||||
|
|
||||||
updates = tree_h - k;
|
SET_LAYER_ADDRESS(addr, 0);
|
||||||
|
SET_TREE_ADDRESS(addr, (idx_tree + 1));
|
||||||
|
// mandatory update for NEXT_0 (does not count towards h-k/2)
|
||||||
|
bds_state_update(&states[params->d], sk_seed, &(params->xmss_par), pub_seed, addr);
|
||||||
|
|
||||||
// if a NEXT-tree exists within the hypertree
|
for (i = 0; i < params->d; i++) {
|
||||||
if ((1 + idx_tree) * (1 << tree_h) + idx_leaf < (1 << h)) {
|
// check if we're not at the end of a tree
|
||||||
// mandatory update for NEXT_0 (does not count towards h-k)
|
if (! (((idx + 1) & ((1 << ((i+1)*tree_h)) - 1)) == 0)) {
|
||||||
bds_state_update(&states[params->d], sk_seed, &(params->xmss_par), pub_seed, ots_addr);
|
idx_leaf = (idx >> (tree_h * i)) & ((1 << tree_h)-1);
|
||||||
|
idx_tree = (idx >> (tree_h * (i+1)));
|
||||||
// check if we're at the end of a tree
|
SET_LAYER_ADDRESS(addr, i);
|
||||||
for (i = 0; i < params->d; i++) {
|
SET_TREE_ADDRESS(addr, idx_tree);
|
||||||
if (((idx + 1) & ((1 << ((i+1)*tree_h)) - 1)) == 0) {
|
if (i == needswap_upto+1) {
|
||||||
memcpy(&tmp, states+params->d + i, sizeof(bds_state));
|
bds_round(&states[i], idx_leaf, sk_seed, &(params->xmss_par), pub_seed, addr);
|
||||||
memcpy(states+params->d + i, states + i, sizeof(bds_state));
|
}
|
||||||
memcpy(states + i, &tmp, sizeof(bds_state));
|
updates = bds_treehash_update(&states[i], updates, sk_seed, &(params->xmss_par), pub_seed, addr);
|
||||||
|
SET_TREE_ADDRESS(addr, (idx_tree + 1));
|
||||||
SET_TREE_ADDRESS(ots_addr, ((idx + 1) >> ((i+2) * tree_h)));
|
// if a NEXT-tree exists for this level;
|
||||||
SET_OTS_ADDRESS(ots_addr, (((idx >> ((i+1) * tree_h)) + 1) & ((1 << tree_h)-1)));
|
if ((1 + idx_tree) * (1 << tree_h) + idx_leaf < (1 << (h - tree_h * i))) {
|
||||||
SET_LAYER_ADDRESS(ots_addr, (i+1));
|
if (i > 0 && updates > 0 && states[params->d + i].next_leaf < 1 << h) {
|
||||||
|
bds_state_update(&states[params->d + i], sk_seed, &(params->xmss_par), pub_seed, addr);
|
||||||
get_seed(ots_seed, sk+params->index_len, n, ots_addr);
|
updates--;
|
||||||
wots_sign(wots_sigs + i*params->xmss_par.wots_par.keysize, states[i].stack, ots_seed, &(params->xmss_par.wots_par), pub_seed, ots_addr);
|
|
||||||
|
|
||||||
states[params->d + i].stackoffset = 0;
|
|
||||||
states[params->d + i].next_leaf = 0;
|
|
||||||
|
|
||||||
updates--; // WOTS-signing counts as one update
|
|
||||||
|
|
||||||
// this bds_round is needed to initialise the state, but should not perform updates
|
|
||||||
// note that one should still pass the (reduced) current idx, as bds_round sets up for idx+1
|
|
||||||
bds_round(&states[i+1], ((idx >> ((i+1)*tree_h))) & ((1 << tree_h)-1), sk_seed, &(params->xmss_par), 0, pub_seed, ots_addr);
|
|
||||||
for (j = 0; j < tree_h-k; j++) {
|
|
||||||
states[i].treehash[j].completed = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
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_ADDRESS(ots_addr, 0);
|
SET_LAYER_ADDRESS(ots_addr, (i+1));
|
||||||
SET_TREE_ADDRESS(ots_addr, idx_tree);
|
SET_TREE_ADDRESS(ots_addr, ((idx + 1) >> ((i+2) * tree_h)));
|
||||||
|
SET_OTS_ADDRESS(ots_addr, (((idx >> ((i+1) * tree_h)) + 1) & ((1 << tree_h)-1)));
|
||||||
|
|
||||||
first_nonwots = (tree_h - k) - updates;
|
get_seed(ots_seed, sk+params->index_len, n, ots_addr);
|
||||||
|
wots_sign(wots_sigs + i*params->xmss_par.wots_par.keysize, states[i].stack, ots_seed, &(params->xmss_par.wots_par), pub_seed, ots_addr);
|
||||||
|
|
||||||
if (first_nonwots == 0) {
|
states[params->d + i].stackoffset = 0;
|
||||||
updates = bds_round(&states[0], idx_leaf, sk_seed, &(params->xmss_par), (tree_h - k) >> 1, pub_seed, ots_addr);
|
states[params->d + i].next_leaf = 0;
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 1; updates > 0 && i < params->d; i++) {
|
updates--; // WOTS-signing counts as one update
|
||||||
idx_leaf = (idx_tree & ((1 << tree_h)-1));
|
needswap_upto = i;
|
||||||
idx_tree = idx_tree >> tree_h;
|
for (j = 0; j < tree_h-k; j++) {
|
||||||
if (first_nonwots > i) {
|
states[i].treehash[j].completed = 1;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
SET_LAYER_ADDRESS(ots_addr, i);
|
|
||||||
SET_TREE_ADDRESS(ots_addr, idx_tree);
|
|
||||||
SET_OTS_ADDRESS(ots_addr, idx_leaf);
|
|
||||||
while (updates > 0 && !bds_treehash_update(&states[i], sk_seed, &(params->xmss_par), pub_seed, ots_addr)) {
|
|
||||||
updates--;
|
|
||||||
}
|
|
||||||
SET_TREE_ADDRESS(ots_addr, (idx_tree + 1));
|
|
||||||
// if a NEXT-tree exists for this level;
|
|
||||||
if ((1 + idx_tree) * (1 << tree_h) + idx_leaf < (1 << (h - tree_h * i))) {
|
|
||||||
while (updates > 0 && !bds_state_update(&states[params->d + i], sk_seed, &(params->xmss_par), pub_seed, ots_addr)) {
|
|
||||||
updates--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user