blob: 6aff36a0799f65ea5960d75edbbe1e5e22c91f62 [file] [log] [blame]
markus@openbsd.org1b11ea72018-02-23 15:58:37 +00001/*
2xmss_fast.c version 20160722
3Andreas Hülsing
4Joost Rijneveld
5Public domain.
6*/
7
Damien Millerf8854742018-02-26 12:18:14 +11008#include "includes.h"
9
markus@openbsd.org1b11ea72018-02-23 15:58:37 +000010#include "xmss_fast.h"
11#include <stdlib.h>
12#include <string.h>
13#include <stdint.h>
14
15#include "crypto_api.h"
16#include "xmss_wots.h"
17#include "xmss_hash.h"
18
19#include "xmss_commons.h"
20#include "xmss_hash_address.h"
21// For testing
22#include "stdio.h"
23
24
25
26/**
27 * Used for pseudorandom keygeneration,
28 * generates the seed for the WOTS keypair at address addr
29 *
30 * takes n byte sk_seed and returns n byte seed using 32 byte address addr.
31 */
32static void get_seed(unsigned char *seed, const unsigned char *sk_seed, int n, uint32_t addr[8])
33{
34 unsigned char bytes[32];
35 // Make sure that chain addr, hash addr, and key bit are 0!
36 setChainADRS(addr,0);
37 setHashADRS(addr,0);
38 setKeyAndMask(addr,0);
39 // Generate pseudorandom value
40 addr_to_byte(bytes, addr);
41 prf(seed, bytes, sk_seed, n);
42}
43
44/**
45 * Initialize xmss params struct
46 * parameter names are the same as in the draft
47 * parameter k is K as used in the BDS algorithm
48 */
49int xmss_set_params(xmss_params *params, int n, int h, int w, int k)
50{
51 if (k >= h || k < 2 || (h - k) % 2) {
52 fprintf(stderr, "For BDS traversal, H - K must be even, with H > K >= 2!\n");
53 return 1;
54 }
55 params->h = h;
56 params->n = n;
57 params->k = k;
58 wots_params wots_par;
59 wots_set_params(&wots_par, n, w);
60 params->wots_par = wots_par;
61 return 0;
62}
63
64/**
65 * Initialize BDS state struct
66 * parameter names are the same as used in the description of the BDS traversal
67 */
68void 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)
69{
70 state->stack = stack;
71 state->stackoffset = stackoffset;
72 state->stacklevels = stacklevels;
73 state->auth = auth;
74 state->keep = keep;
75 state->treehash = treehash;
76 state->retain = retain;
77 state->next_leaf = next_leaf;
78}
79
80/**
81 * Initialize xmssmt_params struct
82 * parameter names are the same as in the draft
83 *
84 * Especially h is the total tree height, i.e. the XMSS trees have height h/d
85 */
86int xmssmt_set_params(xmssmt_params *params, int n, int h, int d, int w, int k)
87{
88 if (h % d) {
89 fprintf(stderr, "d must divide h without remainder!\n");
90 return 1;
91 }
92 params->h = h;
93 params->d = d;
94 params->n = n;
95 params->index_len = (h + 7) / 8;
96 xmss_params xmss_par;
97 if (xmss_set_params(&xmss_par, n, (h/d), w, k)) {
98 return 1;
99 }
100 params->xmss_par = xmss_par;
101 return 0;
102}
103
104/**
105 * Computes a leaf from a WOTS public key using an L-tree.
106 */
107static void l_tree(unsigned char *leaf, unsigned char *wots_pk, const xmss_params *params, const unsigned char *pub_seed, uint32_t addr[8])
108{
109 unsigned int l = params->wots_par.len;
110 unsigned int n = params->n;
111 uint32_t i = 0;
112 uint32_t height = 0;
113 uint32_t bound;
114
115 //ADRS.setTreeHeight(0);
116 setTreeHeight(addr, height);
117
118 while (l > 1) {
119 bound = l >> 1; //floor(l / 2);
120 for (i = 0; i < bound; i++) {
121 //ADRS.setTreeIndex(i);
122 setTreeIndex(addr, i);
123 //wots_pk[i] = RAND_HASH(pk[2i], pk[2i + 1], SEED, ADRS);
124 hash_h(wots_pk+i*n, wots_pk+i*2*n, pub_seed, addr, n);
125 }
126 //if ( l % 2 == 1 ) {
127 if (l & 1) {
128 //pk[floor(l / 2) + 1] = pk[l];
129 memcpy(wots_pk+(l>>1)*n, wots_pk+(l-1)*n, n);
130 //l = ceil(l / 2);
131 l=(l>>1)+1;
132 }
133 else {
134 //l = ceil(l / 2);
135 l=(l>>1);
136 }
137 //ADRS.setTreeHeight(ADRS.getTreeHeight() + 1);
138 height++;
139 setTreeHeight(addr, height);
140 }
141 //return pk[0];
142 memcpy(leaf, wots_pk, n);
143}
144
145/**
146 * 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.
147 */
148static void gen_leaf_wots(unsigned char *leaf, const unsigned char *sk_seed, const xmss_params *params, const unsigned char *pub_seed, uint32_t ltree_addr[8], uint32_t ots_addr[8])
149{
150 unsigned char seed[params->n];
151 unsigned char pk[params->wots_par.keysize];
152
153 get_seed(seed, sk_seed, params->n, ots_addr);
154 wots_pkgen(pk, seed, &(params->wots_par), pub_seed, ots_addr);
155
156 l_tree(leaf, pk, params, pub_seed, ltree_addr);
157}
158
159static int treehash_minheight_on_stack(bds_state* state, const xmss_params *params, const treehash_inst *treehash) {
160 unsigned int r = params->h, i;
161 for (i = 0; i < treehash->stackusage; i++) {
162 if (state->stacklevels[state->stackoffset - i - 1] < r) {
163 r = state->stacklevels[state->stackoffset - i - 1];
164 }
165 }
166 return r;
167}
168
169/**
170 * Merkle's TreeHash algorithm. The address only needs to initialize the first 78 bits of addr. Everything else will be set by treehash.
171 * Currently only used for key generation.
172 *
173 */
174static void treehash_setup(unsigned char *node, int height, int index, bds_state *state, const unsigned char *sk_seed, const xmss_params *params, const unsigned char *pub_seed, const uint32_t addr[8])
175{
176 unsigned int idx = index;
177 unsigned int n = params->n;
178 unsigned int h = params->h;
179 unsigned int k = params->k;
180 // use three different addresses because at this point we use all three formats in parallel
181 uint32_t ots_addr[8];
182 uint32_t ltree_addr[8];
183 uint32_t node_addr[8];
184 // only copy layer and tree address parts
185 memcpy(ots_addr, addr, 12);
186 // type = ots
187 setType(ots_addr, 0);
188 memcpy(ltree_addr, addr, 12);
189 setType(ltree_addr, 1);
190 memcpy(node_addr, addr, 12);
191 setType(node_addr, 2);
192
193 uint32_t lastnode, i;
194 unsigned char stack[(height+1)*n];
195 unsigned int stacklevels[height+1];
196 unsigned int stackoffset=0;
197 unsigned int nodeh;
198
199 lastnode = idx+(1<<height);
200
201 for (i = 0; i < h-k; i++) {
202 state->treehash[i].h = i;
203 state->treehash[i].completed = 1;
204 state->treehash[i].stackusage = 0;
205 }
206
207 i = 0;
208 for (; idx < lastnode; idx++) {
209 setLtreeADRS(ltree_addr, idx);
210 setOTSADRS(ots_addr, idx);
211 gen_leaf_wots(stack+stackoffset*n, sk_seed, params, pub_seed, ltree_addr, ots_addr);
212 stacklevels[stackoffset] = 0;
213 stackoffset++;
214 if (h - k > 0 && i == 3) {
215 memcpy(state->treehash[0].node, stack+stackoffset*n, n);
216 }
217 while (stackoffset>1 && stacklevels[stackoffset-1] == stacklevels[stackoffset-2])
218 {
219 nodeh = stacklevels[stackoffset-1];
220 if (i >> nodeh == 1) {
221 memcpy(state->auth + nodeh*n, stack+(stackoffset-1)*n, n);
222 }
223 else {
224 if (nodeh < h - k && i >> nodeh == 3) {
225 memcpy(state->treehash[nodeh].node, stack+(stackoffset-1)*n, n);
226 }
227 else if (nodeh >= h - k) {
228 memcpy(state->retain + ((1 << (h - 1 - nodeh)) + nodeh - h + (((i >> nodeh) - 3) >> 1)) * n, stack+(stackoffset-1)*n, n);
229 }
230 }
231 setTreeHeight(node_addr, stacklevels[stackoffset-1]);
232 setTreeIndex(node_addr, (idx >> (stacklevels[stackoffset-1]+1)));
233 hash_h(stack+(stackoffset-2)*n, stack+(stackoffset-2)*n, pub_seed,
234 node_addr, n);
235 stacklevels[stackoffset-2]++;
236 stackoffset--;
237 }
238 i++;
239 }
240
241 for (i = 0; i < n; i++)
242 node[i] = stack[i];
243}
244
245static void treehash_update(treehash_inst *treehash, bds_state *state, const unsigned char *sk_seed, const xmss_params *params, const unsigned char *pub_seed, const uint32_t addr[8]) {
246 int n = params->n;
247
248 uint32_t ots_addr[8];
249 uint32_t ltree_addr[8];
250 uint32_t node_addr[8];
251 // only copy layer and tree address parts
252 memcpy(ots_addr, addr, 12);
253 // type = ots
254 setType(ots_addr, 0);
255 memcpy(ltree_addr, addr, 12);
256 setType(ltree_addr, 1);
257 memcpy(node_addr, addr, 12);
258 setType(node_addr, 2);
259
260 setLtreeADRS(ltree_addr, treehash->next_idx);
261 setOTSADRS(ots_addr, treehash->next_idx);
262
263 unsigned char nodebuffer[2 * n];
264 unsigned int nodeheight = 0;
265 gen_leaf_wots(nodebuffer, sk_seed, params, pub_seed, ltree_addr, ots_addr);
266 while (treehash->stackusage > 0 && state->stacklevels[state->stackoffset-1] == nodeheight) {
267 memcpy(nodebuffer + n, nodebuffer, n);
268 memcpy(nodebuffer, state->stack + (state->stackoffset-1)*n, n);
269 setTreeHeight(node_addr, nodeheight);
270 setTreeIndex(node_addr, (treehash->next_idx >> (nodeheight+1)));
271 hash_h(nodebuffer, nodebuffer, pub_seed, node_addr, n);
272 nodeheight++;
273 treehash->stackusage--;
274 state->stackoffset--;
275 }
276 if (nodeheight == treehash->h) { // this also implies stackusage == 0
277 memcpy(treehash->node, nodebuffer, n);
278 treehash->completed = 1;
279 }
280 else {
281 memcpy(state->stack + state->stackoffset*n, nodebuffer, n);
282 treehash->stackusage++;
283 state->stacklevels[state->stackoffset] = nodeheight;
284 state->stackoffset++;
285 treehash->next_idx++;
286 }
287}
288
289/**
290 * Computes a root node given a leaf and an authapth
291 */
292static void validate_authpath(unsigned char *root, const unsigned char *leaf, unsigned long leafidx, const unsigned char *authpath, const xmss_params *params, const unsigned char *pub_seed, uint32_t addr[8])
293{
294 unsigned int n = params->n;
295
296 uint32_t i, j;
297 unsigned char buffer[2*n];
298
299 // If leafidx is odd (last bit = 1), current path element is a right child and authpath has to go to the left.
300 // Otherwise, it is the other way around
301 if (leafidx & 1) {
302 for (j = 0; j < n; j++)
303 buffer[n+j] = leaf[j];
304 for (j = 0; j < n; j++)
305 buffer[j] = authpath[j];
306 }
307 else {
308 for (j = 0; j < n; j++)
309 buffer[j] = leaf[j];
310 for (j = 0; j < n; j++)
311 buffer[n+j] = authpath[j];
312 }
313 authpath += n;
314
315 for (i=0; i < params->h-1; i++) {
316 setTreeHeight(addr, i);
317 leafidx >>= 1;
318 setTreeIndex(addr, leafidx);
319 if (leafidx&1) {
320 hash_h(buffer+n, buffer, pub_seed, addr, n);
321 for (j = 0; j < n; j++)
322 buffer[j] = authpath[j];
323 }
324 else {
325 hash_h(buffer, buffer, pub_seed, addr, n);
326 for (j = 0; j < n; j++)
327 buffer[j+n] = authpath[j];
328 }
329 authpath += n;
330 }
331 setTreeHeight(addr, (params->h-1));
332 leafidx >>= 1;
333 setTreeIndex(addr, leafidx);
334 hash_h(root, buffer, pub_seed, addr, n);
335}
336
337/**
338 * Performs one treehash update on the instance that needs it the most.
339 * Returns 1 if such an instance was not found
340 **/
341static char bds_treehash_update(bds_state *state, unsigned int updates, const unsigned char *sk_seed, const xmss_params *params, unsigned char *pub_seed, const uint32_t addr[8]) {
342 uint32_t i, j;
343 unsigned int level, l_min, low;
344 unsigned int h = params->h;
345 unsigned int k = params->k;
346 unsigned int used = 0;
347
348 for (j = 0; j < updates; j++) {
349 l_min = h;
350 level = h - k;
351 for (i = 0; i < h - k; i++) {
352 if (state->treehash[i].completed) {
353 low = h;
354 }
355 else if (state->treehash[i].stackusage == 0) {
356 low = i;
357 }
358 else {
359 low = treehash_minheight_on_stack(state, params, &(state->treehash[i]));
360 }
361 if (low < l_min) {
362 level = i;
363 l_min = low;
364 }
365 }
366 if (level == h - k) {
367 break;
368 }
369 treehash_update(&(state->treehash[level]), state, sk_seed, params, pub_seed, addr);
370 used++;
371 }
372 return updates - used;
373}
374
375/**
376 * Updates the state (typically NEXT_i) by adding a leaf and updating the stack
377 * Returns 1 if all leaf nodes have already been processed
378 **/
379static char bds_state_update(bds_state *state, const unsigned char *sk_seed, const xmss_params *params, unsigned char *pub_seed, const uint32_t addr[8]) {
380 uint32_t ltree_addr[8];
381 uint32_t node_addr[8];
382 uint32_t ots_addr[8];
383
384 int n = params->n;
385 int h = params->h;
386 int k = params->k;
387
388 int nodeh;
389 int idx = state->next_leaf;
390 if (idx == 1 << h) {
391 return 1;
392 }
393
394 // only copy layer and tree address parts
395 memcpy(ots_addr, addr, 12);
396 // type = ots
397 setType(ots_addr, 0);
398 memcpy(ltree_addr, addr, 12);
399 setType(ltree_addr, 1);
400 memcpy(node_addr, addr, 12);
401 setType(node_addr, 2);
402
403 setOTSADRS(ots_addr, idx);
404 setLtreeADRS(ltree_addr, idx);
405
406 gen_leaf_wots(state->stack+state->stackoffset*n, sk_seed, params, pub_seed, ltree_addr, ots_addr);
407
408 state->stacklevels[state->stackoffset] = 0;
409 state->stackoffset++;
410 if (h - k > 0 && idx == 3) {
411 memcpy(state->treehash[0].node, state->stack+state->stackoffset*n, n);
412 }
413 while (state->stackoffset>1 && state->stacklevels[state->stackoffset-1] == state->stacklevels[state->stackoffset-2]) {
414 nodeh = state->stacklevels[state->stackoffset-1];
415 if (idx >> nodeh == 1) {
416 memcpy(state->auth + nodeh*n, state->stack+(state->stackoffset-1)*n, n);
417 }
418 else {
419 if (nodeh < h - k && idx >> nodeh == 3) {
420 memcpy(state->treehash[nodeh].node, state->stack+(state->stackoffset-1)*n, n);
421 }
422 else if (nodeh >= h - k) {
423 memcpy(state->retain + ((1 << (h - 1 - nodeh)) + nodeh - h + (((idx >> nodeh) - 3) >> 1)) * n, state->stack+(state->stackoffset-1)*n, n);
424 }
425 }
426 setTreeHeight(node_addr, state->stacklevels[state->stackoffset-1]);
427 setTreeIndex(node_addr, (idx >> (state->stacklevels[state->stackoffset-1]+1)));
428 hash_h(state->stack+(state->stackoffset-2)*n, state->stack+(state->stackoffset-2)*n, pub_seed, node_addr, n);
429
430 state->stacklevels[state->stackoffset-2]++;
431 state->stackoffset--;
432 }
433 state->next_leaf++;
434 return 0;
435}
436
437/**
438 * Returns the auth path for node leaf_idx and computes the auth path for the
439 * next leaf node, using the algorithm described by Buchmann, Dahmen and Szydlo
440 * in "Post Quantum Cryptography", Springer 2009.
441 */
442static void bds_round(bds_state *state, const unsigned long leaf_idx, const unsigned char *sk_seed, const xmss_params *params, unsigned char *pub_seed, uint32_t addr[8])
443{
444 unsigned int i;
445 unsigned int n = params->n;
446 unsigned int h = params->h;
447 unsigned int k = params->k;
448
449 unsigned int tau = h;
450 unsigned int startidx;
451 unsigned int offset, rowidx;
452 unsigned char buf[2 * n];
453
454 uint32_t ots_addr[8];
455 uint32_t ltree_addr[8];
456 uint32_t node_addr[8];
457 // only copy layer and tree address parts
458 memcpy(ots_addr, addr, 12);
459 // type = ots
460 setType(ots_addr, 0);
461 memcpy(ltree_addr, addr, 12);
462 setType(ltree_addr, 1);
463 memcpy(node_addr, addr, 12);
464 setType(node_addr, 2);
465
466 for (i = 0; i < h; i++) {
467 if (! ((leaf_idx >> i) & 1)) {
468 tau = i;
469 break;
470 }
471 }
472
473 if (tau > 0) {
474 memcpy(buf, state->auth + (tau-1) * n, n);
475 // we need to do this before refreshing state->keep to prevent overwriting
476 memcpy(buf + n, state->keep + ((tau-1) >> 1) * n, n);
477 }
478 if (!((leaf_idx >> (tau + 1)) & 1) && (tau < h - 1)) {
479 memcpy(state->keep + (tau >> 1)*n, state->auth + tau*n, n);
480 }
481 if (tau == 0) {
482 setLtreeADRS(ltree_addr, leaf_idx);
483 setOTSADRS(ots_addr, leaf_idx);
484 gen_leaf_wots(state->auth, sk_seed, params, pub_seed, ltree_addr, ots_addr);
485 }
486 else {
487 setTreeHeight(node_addr, (tau-1));
488 setTreeIndex(node_addr, leaf_idx >> tau);
489 hash_h(state->auth + tau * n, buf, pub_seed, node_addr, n);
490 for (i = 0; i < tau; i++) {
491 if (i < h - k) {
492 memcpy(state->auth + i * n, state->treehash[i].node, n);
493 }
494 else {
495 offset = (1 << (h - 1 - i)) + i - h;
496 rowidx = ((leaf_idx >> i) - 1) >> 1;
497 memcpy(state->auth + i * n, state->retain + (offset + rowidx) * n, n);
498 }
499 }
500
501 for (i = 0; i < ((tau < h - k) ? tau : (h - k)); i++) {
502 startidx = leaf_idx + 1 + 3 * (1 << i);
503 if (startidx < 1U << h) {
504 state->treehash[i].h = i;
505 state->treehash[i].next_idx = startidx;
506 state->treehash[i].completed = 0;
507 state->treehash[i].stackusage = 0;
508 }
509 }
510 }
511}
512
513/*
514 * Generates a XMSS key pair for a given parameter set.
515 * Format sk: [(32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root]
516 * Format pk: [root || PUB_SEED] omitting algo oid.
517 */
518int xmss_keypair(unsigned char *pk, unsigned char *sk, bds_state *state, xmss_params *params)
519{
520 unsigned int n = params->n;
521 // Set idx = 0
522 sk[0] = 0;
523 sk[1] = 0;
524 sk[2] = 0;
525 sk[3] = 0;
526 // Init SK_SEED (n byte), SK_PRF (n byte), and PUB_SEED (n byte)
527 randombytes(sk+4, 3*n);
528 // Copy PUB_SEED to public key
529 memcpy(pk+n, sk+4+2*n, n);
530
531 uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
532
533 // Compute root
534 treehash_setup(pk, params->h, 0, state, sk+4, params, sk+4+2*n, addr);
535 // copy root to sk
536 memcpy(sk+4+3*n, pk, n);
537 return 0;
538}
539
540/**
541 * Signs a message.
542 * Returns
543 * 1. an array containing the signature followed by the message AND
544 * 2. an updated secret key!
545 *
546 */
547int xmss_sign(unsigned char *sk, bds_state *state, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen, const xmss_params *params)
548{
549 unsigned int h = params->h;
550 unsigned int n = params->n;
551 unsigned int k = params->k;
552 uint16_t i = 0;
553
554 // Extract SK
555 unsigned long idx = ((unsigned long)sk[0] << 24) | ((unsigned long)sk[1] << 16) | ((unsigned long)sk[2] << 8) | sk[3];
556 unsigned char sk_seed[n];
557 memcpy(sk_seed, sk+4, n);
558 unsigned char sk_prf[n];
559 memcpy(sk_prf, sk+4+n, n);
560 unsigned char pub_seed[n];
561 memcpy(pub_seed, sk+4+2*n, n);
562
563 // index as 32 bytes string
564 unsigned char idx_bytes_32[32];
565 to_byte(idx_bytes_32, idx, 32);
566
567 unsigned char hash_key[3*n];
568
569 // Update SK
570 sk[0] = ((idx + 1) >> 24) & 255;
571 sk[1] = ((idx + 1) >> 16) & 255;
572 sk[2] = ((idx + 1) >> 8) & 255;
573 sk[3] = (idx + 1) & 255;
574 // -- Secret key for this non-forward-secure version is now updated.
575 // -- A productive implementation should use a file handle instead and write the updated secret key at this point!
576
577 // Init working params
578 unsigned char R[n];
579 unsigned char msg_h[n];
580 unsigned char ots_seed[n];
581 uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
582
583 // ---------------------------------
584 // Message Hashing
585 // ---------------------------------
586
587 // Message Hash:
588 // First compute pseudorandom value
589 prf(R, idx_bytes_32, sk_prf, n);
590 // Generate hash key (R || root || idx)
591 memcpy(hash_key, R, n);
592 memcpy(hash_key+n, sk+4+3*n, n);
593 to_byte(hash_key+2*n, idx, n);
594 // Then use it for message digest
595 h_msg(msg_h, msg, msglen, hash_key, 3*n, n);
596
597 // Start collecting signature
598 *sig_msg_len = 0;
599
600 // Copy index to signature
601 sig_msg[0] = (idx >> 24) & 255;
602 sig_msg[1] = (idx >> 16) & 255;
603 sig_msg[2] = (idx >> 8) & 255;
604 sig_msg[3] = idx & 255;
605
606 sig_msg += 4;
607 *sig_msg_len += 4;
608
609 // Copy R to signature
610 for (i = 0; i < n; i++)
611 sig_msg[i] = R[i];
612
613 sig_msg += n;
614 *sig_msg_len += n;
615
616 // ----------------------------------
617 // Now we start to "really sign"
618 // ----------------------------------
619
620 // Prepare Address
621 setType(ots_addr, 0);
622 setOTSADRS(ots_addr, idx);
623
624 // Compute seed for OTS key pair
625 get_seed(ots_seed, sk_seed, n, ots_addr);
626
627 // Compute WOTS signature
628 wots_sign(sig_msg, msg_h, ots_seed, &(params->wots_par), pub_seed, ots_addr);
629
630 sig_msg += params->wots_par.keysize;
631 *sig_msg_len += params->wots_par.keysize;
632
633 // the auth path was already computed during the previous round
634 memcpy(sig_msg, state->auth, h*n);
635
636 if (idx < (1U << h) - 1) {
637 bds_round(state, idx, sk_seed, params, pub_seed, ots_addr);
638 bds_treehash_update(state, (h - k) >> 1, sk_seed, params, pub_seed, ots_addr);
639 }
640
641/* TODO: save key/bds state here! */
642
643 sig_msg += params->h*n;
644 *sig_msg_len += params->h*n;
645
646 //Whipe secret elements?
647 //zerobytes(tsk, CRYPTO_SECRETKEYBYTES);
648
649
650 memcpy(sig_msg, msg, msglen);
651 *sig_msg_len += msglen;
652
653 return 0;
654}
655
656/**
657 * Verifies a given message signature pair under a given public key.
658 */
659int xmss_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk, const xmss_params *params)
660{
661 unsigned int n = params->n;
662
663 unsigned long long i, m_len;
664 unsigned long idx=0;
665 unsigned char wots_pk[params->wots_par.keysize];
666 unsigned char pkhash[n];
667 unsigned char root[n];
668 unsigned char msg_h[n];
669 unsigned char hash_key[3*n];
670
671 unsigned char pub_seed[n];
672 memcpy(pub_seed, pk+n, n);
673
674 // Init addresses
675 uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
676 uint32_t ltree_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
677 uint32_t node_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
678
679 setType(ots_addr, 0);
680 setType(ltree_addr, 1);
681 setType(node_addr, 2);
682
683 // Extract index
684 idx = ((unsigned long)sig_msg[0] << 24) | ((unsigned long)sig_msg[1] << 16) | ((unsigned long)sig_msg[2] << 8) | sig_msg[3];
685 printf("verify:: idx = %lu\n", idx);
686
687 // Generate hash key (R || root || idx)
688 memcpy(hash_key, sig_msg+4,n);
689 memcpy(hash_key+n, pk, n);
690 to_byte(hash_key+2*n, idx, n);
691
692 sig_msg += (n+4);
693 sig_msg_len -= (n+4);
694
695 // hash message
696 unsigned long long tmp_sig_len = params->wots_par.keysize+params->h*n;
697 m_len = sig_msg_len - tmp_sig_len;
698 h_msg(msg_h, sig_msg + tmp_sig_len, m_len, hash_key, 3*n, n);
699
700 //-----------------------
701 // Verify signature
702 //-----------------------
703
704 // Prepare Address
705 setOTSADRS(ots_addr, idx);
706 // Check WOTS signature
707 wots_pkFromSig(wots_pk, sig_msg, msg_h, &(params->wots_par), pub_seed, ots_addr);
708
709 sig_msg += params->wots_par.keysize;
710 sig_msg_len -= params->wots_par.keysize;
711
712 // Compute Ltree
713 setLtreeADRS(ltree_addr, idx);
714 l_tree(pkhash, wots_pk, params, pub_seed, ltree_addr);
715
716 // Compute root
717 validate_authpath(root, pkhash, idx, sig_msg, params, pub_seed, node_addr);
718
719 sig_msg += params->h*n;
720 sig_msg_len -= params->h*n;
721
722 for (i = 0; i < n; i++)
723 if (root[i] != pk[i])
724 goto fail;
725
726 *msglen = sig_msg_len;
727 for (i = 0; i < *msglen; i++)
728 msg[i] = sig_msg[i];
729
730 return 0;
731
732
733fail:
734 *msglen = sig_msg_len;
735 for (i = 0; i < *msglen; i++)
736 msg[i] = 0;
737 *msglen = -1;
738 return -1;
739}
740
741/*
742 * Generates a XMSSMT key pair for a given parameter set.
743 * Format sk: [(ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root]
744 * Format pk: [root || PUB_SEED] omitting algo oid.
745 */
746int xmssmt_keypair(unsigned char *pk, unsigned char *sk, bds_state *states, unsigned char *wots_sigs, xmssmt_params *params)
747{
748 unsigned int n = params->n;
749 unsigned int i;
750 unsigned char ots_seed[params->n];
751 // Set idx = 0
752 for (i = 0; i < params->index_len; i++) {
753 sk[i] = 0;
754 }
755 // Init SK_SEED (n byte), SK_PRF (n byte), and PUB_SEED (n byte)
756 randombytes(sk+params->index_len, 3*n);
757 // Copy PUB_SEED to public key
758 memcpy(pk+n, sk+params->index_len+2*n, n);
759
760 // Set address to point on the single tree on layer d-1
761 uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
762 setLayerADRS(addr, (params->d-1));
763 // Set up state and compute wots signatures for all but topmost tree root
764 for (i = 0; i < params->d - 1; i++) {
765 // Compute seed for OTS key pair
766 treehash_setup(pk, params->xmss_par.h, 0, states + i, sk+params->index_len, &(params->xmss_par), pk+n, addr);
767 setLayerADRS(addr, (i+1));
768 get_seed(ots_seed, sk+params->index_len, n, addr);
769 wots_sign(wots_sigs + i*params->xmss_par.wots_par.keysize, pk, ots_seed, &(params->xmss_par.wots_par), pk+n, addr);
770 }
771 treehash_setup(pk, params->xmss_par.h, 0, states + i, sk+params->index_len, &(params->xmss_par), pk+n, addr);
772 memcpy(sk+params->index_len+3*n, pk, n);
773 return 0;
774}
775
776/**
777 * Signs a message.
778 * Returns
779 * 1. an array containing the signature followed by the message AND
780 * 2. an updated secret key!
781 *
782 */
783int xmssmt_sign(unsigned char *sk, bds_state *states, unsigned char *wots_sigs, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen, const xmssmt_params *params)
784{
785 unsigned int n = params->n;
786
787 unsigned int tree_h = params->xmss_par.h;
788 unsigned int h = params->h;
789 unsigned int k = params->xmss_par.k;
790 unsigned int idx_len = params->index_len;
791 uint64_t idx_tree;
792 uint32_t idx_leaf;
793 uint64_t i, j;
794 int needswap_upto = -1;
795 unsigned int updates;
796
797 unsigned char sk_seed[n];
798 unsigned char sk_prf[n];
799 unsigned char pub_seed[n];
800 // Init working params
801 unsigned char R[n];
802 unsigned char msg_h[n];
803 unsigned char hash_key[3*n];
804 unsigned char ots_seed[n];
805 uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
806 uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
807 unsigned char idx_bytes_32[32];
808 bds_state tmp;
809
810 // Extract SK
811 unsigned long long idx = 0;
812 for (i = 0; i < idx_len; i++) {
813 idx |= ((unsigned long long)sk[i]) << 8*(idx_len - 1 - i);
814 }
815
816 memcpy(sk_seed, sk+idx_len, n);
817 memcpy(sk_prf, sk+idx_len+n, n);
818 memcpy(pub_seed, sk+idx_len+2*n, n);
819
820 // Update SK
821 for (i = 0; i < idx_len; i++) {
822 sk[i] = ((idx + 1) >> 8*(idx_len - 1 - i)) & 255;
823 }
824 // -- Secret key for this non-forward-secure version is now updated.
825 // -- A productive implementation should use a file handle instead and write the updated secret key at this point!
826
827
828 // ---------------------------------
829 // Message Hashing
830 // ---------------------------------
831
832 // Message Hash:
833 // First compute pseudorandom value
834 to_byte(idx_bytes_32, idx, 32);
835 prf(R, idx_bytes_32, sk_prf, n);
836 // Generate hash key (R || root || idx)
837 memcpy(hash_key, R, n);
838 memcpy(hash_key+n, sk+idx_len+3*n, n);
839 to_byte(hash_key+2*n, idx, n);
840
841 // Then use it for message digest
842 h_msg(msg_h, msg, msglen, hash_key, 3*n, n);
843
844 // Start collecting signature
845 *sig_msg_len = 0;
846
847 // Copy index to signature
848 for (i = 0; i < idx_len; i++) {
849 sig_msg[i] = (idx >> 8*(idx_len - 1 - i)) & 255;
850 }
851
852 sig_msg += idx_len;
853 *sig_msg_len += idx_len;
854
855 // Copy R to signature
856 for (i = 0; i < n; i++)
857 sig_msg[i] = R[i];
858
859 sig_msg += n;
860 *sig_msg_len += n;
861
862 // ----------------------------------
863 // Now we start to "really sign"
864 // ----------------------------------
865
866 // Handle lowest layer separately as it is slightly different...
867
868 // Prepare Address
869 setType(ots_addr, 0);
870 idx_tree = idx >> tree_h;
871 idx_leaf = (idx & ((1 << tree_h)-1));
872 setLayerADRS(ots_addr, 0);
873 setTreeADRS(ots_addr, idx_tree);
874 setOTSADRS(ots_addr, idx_leaf);
875
876 // Compute seed for OTS key pair
877 get_seed(ots_seed, sk_seed, n, ots_addr);
878
879 // Compute WOTS signature
880 wots_sign(sig_msg, msg_h, ots_seed, &(params->xmss_par.wots_par), pub_seed, ots_addr);
881
882 sig_msg += params->xmss_par.wots_par.keysize;
883 *sig_msg_len += params->xmss_par.wots_par.keysize;
884
885 memcpy(sig_msg, states[0].auth, tree_h*n);
886 sig_msg += tree_h*n;
887 *sig_msg_len += tree_h*n;
888
889 // prepare signature of remaining layers
890 for (i = 1; i < params->d; i++) {
891 // put WOTS signature in place
892 memcpy(sig_msg, wots_sigs + (i-1)*params->xmss_par.wots_par.keysize, params->xmss_par.wots_par.keysize);
893
894 sig_msg += params->xmss_par.wots_par.keysize;
895 *sig_msg_len += params->xmss_par.wots_par.keysize;
896
897 // put AUTH nodes in place
898 memcpy(sig_msg, states[i].auth, tree_h*n);
899 sig_msg += tree_h*n;
900 *sig_msg_len += tree_h*n;
901 }
902
903 updates = (tree_h - k) >> 1;
904
905 setTreeADRS(addr, (idx_tree + 1));
906 // mandatory update for NEXT_0 (does not count towards h-k/2) if NEXT_0 exists
907 if ((1 + idx_tree) * (1 << tree_h) + idx_leaf < (1ULL << h)) {
908 bds_state_update(&states[params->d], sk_seed, &(params->xmss_par), pub_seed, addr);
909 }
910
911 for (i = 0; i < params->d; i++) {
912 // check if we're not at the end of a tree
913 if (! (((idx + 1) & ((1ULL << ((i+1)*tree_h)) - 1)) == 0)) {
914 idx_leaf = (idx >> (tree_h * i)) & ((1 << tree_h)-1);
915 idx_tree = (idx >> (tree_h * (i+1)));
916 setLayerADRS(addr, i);
917 setTreeADRS(addr, idx_tree);
918 if (i == (unsigned int) (needswap_upto + 1)) {
919 bds_round(&states[i], idx_leaf, sk_seed, &(params->xmss_par), pub_seed, addr);
920 }
921 updates = bds_treehash_update(&states[i], updates, sk_seed, &(params->xmss_par), pub_seed, addr);
922 setTreeADRS(addr, (idx_tree + 1));
923 // if a NEXT-tree exists for this level;
924 if ((1 + idx_tree) * (1 << tree_h) + idx_leaf < (1ULL << (h - tree_h * i))) {
925 if (i > 0 && updates > 0 && states[params->d + i].next_leaf < (1ULL << h)) {
926 bds_state_update(&states[params->d + i], sk_seed, &(params->xmss_par), pub_seed, addr);
927 updates--;
928 }
929 }
930 }
931 else if (idx < (1ULL << h) - 1) {
932 memcpy(&tmp, states+params->d + i, sizeof(bds_state));
933 memcpy(states+params->d + i, states + i, sizeof(bds_state));
934 memcpy(states + i, &tmp, sizeof(bds_state));
935
936 setLayerADRS(ots_addr, (i+1));
937 setTreeADRS(ots_addr, ((idx + 1) >> ((i+2) * tree_h)));
938 setOTSADRS(ots_addr, (((idx >> ((i+1) * tree_h)) + 1) & ((1 << tree_h)-1)));
939
940 get_seed(ots_seed, sk+params->index_len, n, ots_addr);
941 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);
942
943 states[params->d + i].stackoffset = 0;
944 states[params->d + i].next_leaf = 0;
945
946 updates--; // WOTS-signing counts as one update
947 needswap_upto = i;
948 for (j = 0; j < tree_h-k; j++) {
949 states[i].treehash[j].completed = 1;
950 }
951 }
952 }
953
954 //Whipe secret elements?
955 //zerobytes(tsk, CRYPTO_SECRETKEYBYTES);
956
957 memcpy(sig_msg, msg, msglen);
958 *sig_msg_len += msglen;
959
960 return 0;
961}
962
963/**
964 * Verifies a given message signature pair under a given public key.
965 */
966int xmssmt_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk, const xmssmt_params *params)
967{
968 unsigned int n = params->n;
969
970 unsigned int tree_h = params->xmss_par.h;
971 unsigned int idx_len = params->index_len;
972 uint64_t idx_tree;
973 uint32_t idx_leaf;
974
975 unsigned long long i, m_len;
976 unsigned long long idx=0;
977 unsigned char wots_pk[params->xmss_par.wots_par.keysize];
978 unsigned char pkhash[n];
979 unsigned char root[n];
980 unsigned char msg_h[n];
981 unsigned char hash_key[3*n];
982
983 unsigned char pub_seed[n];
984 memcpy(pub_seed, pk+n, n);
985
986 // Init addresses
987 uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
988 uint32_t ltree_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
989 uint32_t node_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
990
991 // Extract index
992 for (i = 0; i < idx_len; i++) {
993 idx |= ((unsigned long long)sig_msg[i]) << (8*(idx_len - 1 - i));
994 }
995 printf("verify:: idx = %llu\n", idx);
996 sig_msg += idx_len;
997 sig_msg_len -= idx_len;
998
999 // Generate hash key (R || root || idx)
1000 memcpy(hash_key, sig_msg,n);
1001 memcpy(hash_key+n, pk, n);
1002 to_byte(hash_key+2*n, idx, n);
1003
1004 sig_msg += n;
1005 sig_msg_len -= n;
1006
1007
1008 // hash message (recall, R is now on pole position at sig_msg
1009 unsigned long long tmp_sig_len = (params->d * params->xmss_par.wots_par.keysize) + (params->h * n);
1010 m_len = sig_msg_len - tmp_sig_len;
1011 h_msg(msg_h, sig_msg + tmp_sig_len, m_len, hash_key, 3*n, n);
1012
1013
1014 //-----------------------
1015 // Verify signature
1016 //-----------------------
1017
1018 // Prepare Address
1019 idx_tree = idx >> tree_h;
1020 idx_leaf = (idx & ((1 << tree_h)-1));
1021 setLayerADRS(ots_addr, 0);
1022 setTreeADRS(ots_addr, idx_tree);
1023 setType(ots_addr, 0);
1024
1025 memcpy(ltree_addr, ots_addr, 12);
1026 setType(ltree_addr, 1);
1027
1028 memcpy(node_addr, ltree_addr, 12);
1029 setType(node_addr, 2);
1030
1031 setOTSADRS(ots_addr, idx_leaf);
1032
1033 // Check WOTS signature
1034 wots_pkFromSig(wots_pk, sig_msg, msg_h, &(params->xmss_par.wots_par), pub_seed, ots_addr);
1035
1036 sig_msg += params->xmss_par.wots_par.keysize;
1037 sig_msg_len -= params->xmss_par.wots_par.keysize;
1038
1039 // Compute Ltree
1040 setLtreeADRS(ltree_addr, idx_leaf);
1041 l_tree(pkhash, wots_pk, &(params->xmss_par), pub_seed, ltree_addr);
1042
1043 // Compute root
1044 validate_authpath(root, pkhash, idx_leaf, sig_msg, &(params->xmss_par), pub_seed, node_addr);
1045
1046 sig_msg += tree_h*n;
1047 sig_msg_len -= tree_h*n;
1048
1049 for (i = 1; i < params->d; i++) {
1050 // Prepare Address
1051 idx_leaf = (idx_tree & ((1 << tree_h)-1));
1052 idx_tree = idx_tree >> tree_h;
1053
1054 setLayerADRS(ots_addr, i);
1055 setTreeADRS(ots_addr, idx_tree);
1056 setType(ots_addr, 0);
1057
1058 memcpy(ltree_addr, ots_addr, 12);
1059 setType(ltree_addr, 1);
1060
1061 memcpy(node_addr, ltree_addr, 12);
1062 setType(node_addr, 2);
1063
1064 setOTSADRS(ots_addr, idx_leaf);
1065
1066 // Check WOTS signature
1067 wots_pkFromSig(wots_pk, sig_msg, root, &(params->xmss_par.wots_par), pub_seed, ots_addr);
1068
1069 sig_msg += params->xmss_par.wots_par.keysize;
1070 sig_msg_len -= params->xmss_par.wots_par.keysize;
1071
1072 // Compute Ltree
1073 setLtreeADRS(ltree_addr, idx_leaf);
1074 l_tree(pkhash, wots_pk, &(params->xmss_par), pub_seed, ltree_addr);
1075
1076 // Compute root
1077 validate_authpath(root, pkhash, idx_leaf, sig_msg, &(params->xmss_par), pub_seed, node_addr);
1078
1079 sig_msg += tree_h*n;
1080 sig_msg_len -= tree_h*n;
1081
1082 }
1083
1084 for (i = 0; i < n; i++)
1085 if (root[i] != pk[i])
1086 goto fail;
1087
1088 *msglen = sig_msg_len;
1089 for (i = 0; i < *msglen; i++)
1090 msg[i] = sig_msg[i];
1091
1092 return 0;
1093
1094
1095fail:
1096 *msglen = sig_msg_len;
1097 for (i = 0; i < *msglen; i++)
1098 msg[i] = 0;
1099 *msglen = -1;
1100 return -1;
1101}