Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
8 роки тому
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. /*
  2. xmss_fast.c version 20160722
  3. Andreas Hülsing
  4. Joost Rijneveld
  5. Public domain.
  6. */
  7. #include "xmss_fast.h"
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <stdint.h>
  11. #include <math.h>
  12. #include "randombytes.h"
  13. #include "wots.h"
  14. #include "hash.h"
  15. #include "xmss_commons.h"
  16. #include "hash_address.h"
  17. #include "params.h"
  18. /**
  19. * Used for pseudorandom keygeneration,
  20. * generates the seed for the WOTS keypair at address addr
  21. *
  22. * takes n byte sk_seed and returns n byte seed using 32 byte address addr.
  23. */
  24. static void get_seed(unsigned char *seed, const unsigned char *sk_seed, int n, uint32_t addr[8])
  25. {
  26. unsigned char bytes[32];
  27. // Make sure that chain addr, hash addr, and key bit are 0!
  28. setChainADRS(addr,0);
  29. setHashADRS(addr,0);
  30. setKeyAndMask(addr,0);
  31. // Generate pseudorandom value
  32. addr_to_byte(bytes, addr);
  33. prf(seed, bytes, sk_seed, n);
  34. }
  35. /**
  36. * Initialize BDS state struct
  37. * parameter names are the same as used in the description of the BDS traversal
  38. */
  39. 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)
  40. {
  41. state->stack = stack;
  42. state->stackoffset = stackoffset;
  43. state->stacklevels = stacklevels;
  44. state->auth = auth;
  45. state->keep = keep;
  46. state->treehash = treehash;
  47. state->retain = retain;
  48. state->next_leaf = next_leaf;
  49. }
  50. /**
  51. * Computes a leaf from a WOTS public key using an L-tree.
  52. */
  53. static void l_tree(unsigned char *leaf, unsigned char *wots_pk, const unsigned char *pub_seed, uint32_t addr[8])
  54. {
  55. unsigned int l = XMSS_WOTS_LEN;
  56. unsigned int n = XMSS_N;
  57. uint32_t i = 0;
  58. uint32_t height = 0;
  59. uint32_t bound;
  60. //ADRS.setTreeHeight(0);
  61. setTreeHeight(addr, height);
  62. while (l > 1) {
  63. bound = l >> 1; //floor(l / 2);
  64. for (i = 0; i < bound; i++) {
  65. //ADRS.setTreeIndex(i);
  66. setTreeIndex(addr, i);
  67. //wots_pk[i] = RAND_HASH(pk[2i], pk[2i + 1], SEED, ADRS);
  68. hash_h(wots_pk+i*n, wots_pk+i*2*n, pub_seed, addr, n);
  69. }
  70. //if ( l % 2 == 1 ) {
  71. if (l & 1) {
  72. //pk[floor(l / 2) + 1] = pk[l];
  73. memcpy(wots_pk+(l>>1)*n, wots_pk+(l-1)*n, n);
  74. //l = ceil(l / 2);
  75. l=(l>>1)+1;
  76. }
  77. else {
  78. //l = ceil(l / 2);
  79. l=(l>>1);
  80. }
  81. //ADRS.setTreeHeight(ADRS.getTreeHeight() + 1);
  82. height++;
  83. setTreeHeight(addr, height);
  84. }
  85. //return pk[0];
  86. memcpy(leaf, wots_pk, n);
  87. }
  88. /**
  89. * 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.
  90. */
  91. static void gen_leaf_wots(unsigned char *leaf, const unsigned char *sk_seed, const unsigned char *pub_seed, uint32_t ltree_addr[8], uint32_t ots_addr[8])
  92. {
  93. unsigned char seed[XMSS_N];
  94. unsigned char pk[XMSS_WOTS_KEYSIZE];
  95. get_seed(seed, sk_seed, XMSS_N, ots_addr);
  96. wots_pkgen(pk, seed, pub_seed, ots_addr);
  97. l_tree(leaf, pk, pub_seed, ltree_addr);
  98. }
  99. static int treehash_minheight_on_stack(bds_state* state, const treehash_inst *treehash) {
  100. unsigned int r = XMSS_TREEHEIGHT, i;
  101. for (i = 0; i < treehash->stackusage; i++) {
  102. if (state->stacklevels[state->stackoffset - i - 1] < r) {
  103. r = state->stacklevels[state->stackoffset - i - 1];
  104. }
  105. }
  106. return r;
  107. }
  108. /**
  109. * Merkle's TreeHash algorithm. The address only needs to initialize the first 78 bits of addr. Everything else will be set by treehash.
  110. * Currently only used for key generation.
  111. *
  112. */
  113. static void treehash_setup(unsigned char *node, int height, int index, bds_state *state, const unsigned char *sk_seed, const unsigned char *pub_seed, const uint32_t addr[8])
  114. {
  115. unsigned int idx = index;
  116. // use three different addresses because at this point we use all three formats in parallel
  117. uint32_t ots_addr[8];
  118. uint32_t ltree_addr[8];
  119. uint32_t node_addr[8];
  120. // only copy layer and tree address parts
  121. memcpy(ots_addr, addr, 12);
  122. // type = ots
  123. setType(ots_addr, 0);
  124. memcpy(ltree_addr, addr, 12);
  125. setType(ltree_addr, 1);
  126. memcpy(node_addr, addr, 12);
  127. setType(node_addr, 2);
  128. uint32_t lastnode, i;
  129. unsigned char stack[(height+1)*XMSS_N];
  130. unsigned int stacklevels[height+1];
  131. unsigned int stackoffset=0;
  132. unsigned int nodeh;
  133. lastnode = idx+(1<<height);
  134. for (i = 0; i < XMSS_TREEHEIGHT-XMSS_BDS_K; i++) {
  135. state->treehash[i].h = i;
  136. state->treehash[i].completed = 1;
  137. state->treehash[i].stackusage = 0;
  138. }
  139. i = 0;
  140. for (; idx < lastnode; idx++) {
  141. setLtreeADRS(ltree_addr, idx);
  142. setOTSADRS(ots_addr, idx);
  143. gen_leaf_wots(stack+stackoffset*XMSS_N, sk_seed, pub_seed, ltree_addr, ots_addr);
  144. stacklevels[stackoffset] = 0;
  145. stackoffset++;
  146. if (XMSS_TREEHEIGHT - XMSS_BDS_K > 0 && i == 3) {
  147. memcpy(state->treehash[0].node, stack+stackoffset*XMSS_N, XMSS_N);
  148. }
  149. while (stackoffset>1 && stacklevels[stackoffset-1] == stacklevels[stackoffset-2])
  150. {
  151. nodeh = stacklevels[stackoffset-1];
  152. if (i >> nodeh == 1) {
  153. memcpy(state->auth + nodeh*XMSS_N, stack+(stackoffset-1)*XMSS_N, XMSS_N);
  154. }
  155. else {
  156. if (nodeh < XMSS_TREEHEIGHT - XMSS_BDS_K && i >> nodeh == 3) {
  157. memcpy(state->treehash[nodeh].node, stack+(stackoffset-1)*XMSS_N, XMSS_N);
  158. }
  159. else if (nodeh >= XMSS_TREEHEIGHT - XMSS_BDS_K) {
  160. memcpy(state->retain + ((1 << (XMSS_TREEHEIGHT - 1 - nodeh)) + nodeh - XMSS_TREEHEIGHT + (((i >> nodeh) - 3) >> 1)) * XMSS_N, stack+(stackoffset-1)*XMSS_N, XMSS_N);
  161. }
  162. }
  163. setTreeHeight(node_addr, stacklevels[stackoffset-1]);
  164. setTreeIndex(node_addr, (idx >> (stacklevels[stackoffset-1]+1)));
  165. hash_h(stack+(stackoffset-2)*XMSS_N, stack+(stackoffset-2)*XMSS_N, pub_seed,
  166. node_addr, XMSS_N);
  167. stacklevels[stackoffset-2]++;
  168. stackoffset--;
  169. }
  170. i++;
  171. }
  172. for (i = 0; i < XMSS_N; i++)
  173. node[i] = stack[i];
  174. }
  175. static void treehash_update(treehash_inst *treehash, bds_state *state, const unsigned char *sk_seed, const unsigned char *pub_seed, const uint32_t addr[8]) {
  176. uint32_t ots_addr[8];
  177. uint32_t ltree_addr[8];
  178. uint32_t node_addr[8];
  179. // only copy layer and tree address parts
  180. memcpy(ots_addr, addr, 12);
  181. // type = ots
  182. setType(ots_addr, 0);
  183. memcpy(ltree_addr, addr, 12);
  184. setType(ltree_addr, 1);
  185. memcpy(node_addr, addr, 12);
  186. setType(node_addr, 2);
  187. setLtreeADRS(ltree_addr, treehash->next_idx);
  188. setOTSADRS(ots_addr, treehash->next_idx);
  189. unsigned char nodebuffer[2 * XMSS_N];
  190. unsigned int nodeheight = 0;
  191. gen_leaf_wots(nodebuffer, sk_seed, pub_seed, ltree_addr, ots_addr);
  192. while (treehash->stackusage > 0 && state->stacklevels[state->stackoffset-1] == nodeheight) {
  193. memcpy(nodebuffer + XMSS_N, nodebuffer, XMSS_N);
  194. memcpy(nodebuffer, state->stack + (state->stackoffset-1)*XMSS_N, XMSS_N);
  195. setTreeHeight(node_addr, nodeheight);
  196. setTreeIndex(node_addr, (treehash->next_idx >> (nodeheight+1)));
  197. hash_h(nodebuffer, nodebuffer, pub_seed, node_addr, XMSS_N);
  198. nodeheight++;
  199. treehash->stackusage--;
  200. state->stackoffset--;
  201. }
  202. if (nodeheight == treehash->h) { // this also implies stackusage == 0
  203. memcpy(treehash->node, nodebuffer, XMSS_N);
  204. treehash->completed = 1;
  205. }
  206. else {
  207. memcpy(state->stack + state->stackoffset*XMSS_N, nodebuffer, XMSS_N);
  208. treehash->stackusage++;
  209. state->stacklevels[state->stackoffset] = nodeheight;
  210. state->stackoffset++;
  211. treehash->next_idx++;
  212. }
  213. }
  214. /**
  215. * Computes a root node given a leaf and an authapth
  216. */
  217. static void validate_authpath(unsigned char *root, const unsigned char *leaf, unsigned long leafidx, const unsigned char *authpath, const unsigned char *pub_seed, uint32_t addr[8])
  218. {
  219. uint32_t i, j;
  220. unsigned char buffer[2*XMSS_N];
  221. // If leafidx is odd (last bit = 1), current path element is a right child and authpath has to go to the left.
  222. // Otherwise, it is the other way around
  223. if (leafidx & 1) {
  224. for (j = 0; j < XMSS_N; j++)
  225. buffer[XMSS_N+j] = leaf[j];
  226. for (j = 0; j < XMSS_N; j++)
  227. buffer[j] = authpath[j];
  228. }
  229. else {
  230. for (j = 0; j < XMSS_N; j++)
  231. buffer[j] = leaf[j];
  232. for (j = 0; j < XMSS_N; j++)
  233. buffer[XMSS_N+j] = authpath[j];
  234. }
  235. authpath += XMSS_N;
  236. for (i=0; i < XMSS_TREEHEIGHT-1; i++) {
  237. setTreeHeight(addr, i);
  238. leafidx >>= 1;
  239. setTreeIndex(addr, leafidx);
  240. if (leafidx&1) {
  241. hash_h(buffer+XMSS_N, buffer, pub_seed, addr, XMSS_N);
  242. for (j = 0; j < XMSS_N; j++)
  243. buffer[j] = authpath[j];
  244. }
  245. else {
  246. hash_h(buffer, buffer, pub_seed, addr, XMSS_N);
  247. for (j = 0; j < XMSS_N; j++)
  248. buffer[j+XMSS_N] = authpath[j];
  249. }
  250. authpath += XMSS_N;
  251. }
  252. setTreeHeight(addr, (XMSS_TREEHEIGHT-1));
  253. leafidx >>= 1;
  254. setTreeIndex(addr, leafidx);
  255. hash_h(root, buffer, pub_seed, addr, XMSS_N);
  256. }
  257. /**
  258. * Performs one treehash update on the instance that needs it the most.
  259. * Returns 1 if such an instance was not found
  260. **/
  261. static char bds_treehash_update(bds_state *state, unsigned int updates, const unsigned char *sk_seed, unsigned char *pub_seed, const uint32_t addr[8]) {
  262. uint32_t i, j;
  263. unsigned int level, l_min, low;
  264. unsigned int used = 0;
  265. for (j = 0; j < updates; j++) {
  266. l_min = XMSS_TREEHEIGHT;
  267. level = XMSS_TREEHEIGHT - XMSS_BDS_K;
  268. for (i = 0; i < XMSS_TREEHEIGHT - XMSS_BDS_K; i++) {
  269. if (state->treehash[i].completed) {
  270. low = XMSS_TREEHEIGHT;
  271. }
  272. else if (state->treehash[i].stackusage == 0) {
  273. low = i;
  274. }
  275. else {
  276. low = treehash_minheight_on_stack(state, &(state->treehash[i]));
  277. }
  278. if (low < l_min) {
  279. level = i;
  280. l_min = low;
  281. }
  282. }
  283. if (level == XMSS_TREEHEIGHT - XMSS_BDS_K) {
  284. break;
  285. }
  286. treehash_update(&(state->treehash[level]), state, sk_seed, pub_seed, addr);
  287. used++;
  288. }
  289. return updates - used;
  290. }
  291. /**
  292. * Updates the state (typically NEXT_i) by adding a leaf and updating the stack
  293. * Returns 1 if all leaf nodes have already been processed
  294. **/
  295. static char bds_state_update(bds_state *state, const unsigned char *sk_seed, unsigned char *pub_seed, const uint32_t addr[8]) {
  296. uint32_t ltree_addr[8];
  297. uint32_t node_addr[8];
  298. uint32_t ots_addr[8];
  299. int nodeh;
  300. int idx = state->next_leaf;
  301. if (idx == 1 << XMSS_TREEHEIGHT) {
  302. return 1;
  303. }
  304. // only copy layer and tree address parts
  305. memcpy(ots_addr, addr, 12);
  306. // type = ots
  307. setType(ots_addr, 0);
  308. memcpy(ltree_addr, addr, 12);
  309. setType(ltree_addr, 1);
  310. memcpy(node_addr, addr, 12);
  311. setType(node_addr, 2);
  312. setOTSADRS(ots_addr, idx);
  313. setLtreeADRS(ltree_addr, idx);
  314. gen_leaf_wots(state->stack+state->stackoffset*XMSS_N, sk_seed, pub_seed, ltree_addr, ots_addr);
  315. state->stacklevels[state->stackoffset] = 0;
  316. state->stackoffset++;
  317. if (XMSS_TREEHEIGHT - XMSS_BDS_K > 0 && idx == 3) {
  318. memcpy(state->treehash[0].node, state->stack+state->stackoffset*XMSS_N, XMSS_N);
  319. }
  320. while (state->stackoffset>1 && state->stacklevels[state->stackoffset-1] == state->stacklevels[state->stackoffset-2]) {
  321. nodeh = state->stacklevels[state->stackoffset-1];
  322. if (idx >> nodeh == 1) {
  323. memcpy(state->auth + nodeh*XMSS_N, state->stack+(state->stackoffset-1)*XMSS_N, XMSS_N);
  324. }
  325. else {
  326. if (nodeh < XMSS_TREEHEIGHT - XMSS_BDS_K && idx >> nodeh == 3) {
  327. memcpy(state->treehash[nodeh].node, state->stack+(state->stackoffset-1)*XMSS_N, XMSS_N);
  328. }
  329. else if (nodeh >= XMSS_TREEHEIGHT - XMSS_BDS_K) {
  330. memcpy(state->retain + ((1 << (XMSS_TREEHEIGHT - 1 - nodeh)) + nodeh - XMSS_TREEHEIGHT + (((idx >> nodeh) - 3) >> 1)) * XMSS_N, state->stack+(state->stackoffset-1)*XMSS_N, XMSS_N);
  331. }
  332. }
  333. setTreeHeight(node_addr, state->stacklevels[state->stackoffset-1]);
  334. setTreeIndex(node_addr, (idx >> (state->stacklevels[state->stackoffset-1]+1)));
  335. hash_h(state->stack+(state->stackoffset-2)*XMSS_N, state->stack+(state->stackoffset-2)*XMSS_N, pub_seed, node_addr, XMSS_N);
  336. state->stacklevels[state->stackoffset-2]++;
  337. state->stackoffset--;
  338. }
  339. state->next_leaf++;
  340. return 0;
  341. }
  342. /**
  343. * Returns the auth path for node leaf_idx and computes the auth path for the
  344. * next leaf node, using the algorithm described by Buchmann, Dahmen and Szydlo
  345. * in "Post Quantum Cryptography", Springer 2009.
  346. */
  347. static void bds_round(bds_state *state, const unsigned long leaf_idx, const unsigned char *sk_seed, unsigned char *pub_seed, uint32_t addr[8])
  348. {
  349. unsigned int i;
  350. unsigned int tau = XMSS_TREEHEIGHT;
  351. unsigned int startidx;
  352. unsigned int offset, rowidx;
  353. unsigned char buf[2 * XMSS_N];
  354. uint32_t ots_addr[8];
  355. uint32_t ltree_addr[8];
  356. uint32_t node_addr[8];
  357. // only copy layer and tree address parts
  358. memcpy(ots_addr, addr, 12);
  359. // type = ots
  360. setType(ots_addr, 0);
  361. memcpy(ltree_addr, addr, 12);
  362. setType(ltree_addr, 1);
  363. memcpy(node_addr, addr, 12);
  364. setType(node_addr, 2);
  365. for (i = 0; i < XMSS_TREEHEIGHT; i++) {
  366. if (! ((leaf_idx >> i) & 1)) {
  367. tau = i;
  368. break;
  369. }
  370. }
  371. if (tau > 0) {
  372. memcpy(buf, state->auth + (tau-1) * XMSS_N, XMSS_N);
  373. // we need to do this before refreshing state->keep to prevent overwriting
  374. memcpy(buf + XMSS_N, state->keep + ((tau-1) >> 1) * XMSS_N, XMSS_N);
  375. }
  376. if (!((leaf_idx >> (tau + 1)) & 1) && (tau < XMSS_TREEHEIGHT - 1)) {
  377. memcpy(state->keep + (tau >> 1)*XMSS_N, state->auth + tau*XMSS_N, XMSS_N);
  378. }
  379. if (tau == 0) {
  380. setLtreeADRS(ltree_addr, leaf_idx);
  381. setOTSADRS(ots_addr, leaf_idx);
  382. gen_leaf_wots(state->auth, sk_seed, pub_seed, ltree_addr, ots_addr);
  383. }
  384. else {
  385. setTreeHeight(node_addr, (tau-1));
  386. setTreeIndex(node_addr, leaf_idx >> tau);
  387. hash_h(state->auth + tau * XMSS_N, buf, pub_seed, node_addr, XMSS_N);
  388. for (i = 0; i < tau; i++) {
  389. if (i < XMSS_TREEHEIGHT - XMSS_BDS_K) {
  390. memcpy(state->auth + i * XMSS_N, state->treehash[i].node, XMSS_N);
  391. }
  392. else {
  393. offset = (1 << (XMSS_TREEHEIGHT - 1 - i)) + i - XMSS_TREEHEIGHT;
  394. rowidx = ((leaf_idx >> i) - 1) >> 1;
  395. memcpy(state->auth + i * XMSS_N, state->retain + (offset + rowidx) * XMSS_N, XMSS_N);
  396. }
  397. }
  398. for (i = 0; i < ((tau < XMSS_TREEHEIGHT - XMSS_BDS_K) ? tau : (XMSS_TREEHEIGHT - XMSS_BDS_K)); i++) {
  399. startidx = leaf_idx + 1 + 3 * (1 << i);
  400. if (startidx < 1U << XMSS_TREEHEIGHT) {
  401. state->treehash[i].h = i;
  402. state->treehash[i].next_idx = startidx;
  403. state->treehash[i].completed = 0;
  404. state->treehash[i].stackusage = 0;
  405. }
  406. }
  407. }
  408. }
  409. /*
  410. * Generates a XMSS key pair for a given parameter set.
  411. * Format sk: [(32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root]
  412. * Format pk: [root || PUB_SEED] omitting algo oid.
  413. */
  414. int xmss_keypair(unsigned char *pk, unsigned char *sk, bds_state *state)
  415. {
  416. // Set idx = 0
  417. sk[0] = 0;
  418. sk[1] = 0;
  419. sk[2] = 0;
  420. sk[3] = 0;
  421. // Init SK_SEED (n byte), SK_PRF (n byte), and PUB_SEED (n byte)
  422. randombytes(sk+4, 3*XMSS_N);
  423. // Copy PUB_SEED to public key
  424. memcpy(pk+XMSS_N, sk+4+2*XMSS_N, XMSS_N);
  425. uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  426. // Compute root
  427. treehash_setup(pk, XMSS_TREEHEIGHT, 0, state, sk+4, sk+4+2*XMSS_N, addr);
  428. // copy root to sk
  429. memcpy(sk+4+3*XMSS_N, pk, XMSS_N);
  430. return 0;
  431. }
  432. /**
  433. * Signs a message.
  434. * Returns
  435. * 1. an array containing the signature followed by the message AND
  436. * 2. an updated secret key!
  437. *
  438. */
  439. int 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)
  440. {
  441. uint16_t i = 0;
  442. // Extract SK
  443. unsigned long idx = ((unsigned long)sk[0] << 24) | ((unsigned long)sk[1] << 16) | ((unsigned long)sk[2] << 8) | sk[3];
  444. unsigned char sk_seed[XMSS_N];
  445. memcpy(sk_seed, sk+4, XMSS_N);
  446. unsigned char sk_prf[XMSS_N];
  447. memcpy(sk_prf, sk+4+XMSS_N, XMSS_N);
  448. unsigned char pub_seed[XMSS_N];
  449. memcpy(pub_seed, sk+4+2*XMSS_N, XMSS_N);
  450. // index as 32 bytes string
  451. unsigned char idx_bytes_32[32];
  452. to_byte(idx_bytes_32, idx, 32);
  453. unsigned char hash_key[3*XMSS_N];
  454. // Update SK
  455. sk[0] = ((idx + 1) >> 24) & 255;
  456. sk[1] = ((idx + 1) >> 16) & 255;
  457. sk[2] = ((idx + 1) >> 8) & 255;
  458. sk[3] = (idx + 1) & 255;
  459. // -- Secret key for this non-forward-secure version is now updated.
  460. // -- A productive implementation should use a file handle instead and write the updated secret key at this point!
  461. // Init working params
  462. unsigned char R[XMSS_N];
  463. unsigned char msg_h[XMSS_N];
  464. unsigned char ots_seed[XMSS_N];
  465. uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  466. // ---------------------------------
  467. // Message Hashing
  468. // ---------------------------------
  469. // Message Hash:
  470. // First compute pseudorandom value
  471. prf(R, idx_bytes_32, sk_prf, XMSS_N);
  472. // Generate hash key (R || root || idx)
  473. memcpy(hash_key, R, XMSS_N);
  474. memcpy(hash_key+XMSS_N, sk+4+3*XMSS_N, XMSS_N);
  475. to_byte(hash_key+2*XMSS_N, idx, XMSS_N);
  476. // Then use it for message digest
  477. h_msg(msg_h, msg, msglen, hash_key, 3*XMSS_N, XMSS_N);
  478. // Start collecting signature
  479. *sig_msg_len = 0;
  480. // Copy index to signature
  481. sig_msg[0] = (idx >> 24) & 255;
  482. sig_msg[1] = (idx >> 16) & 255;
  483. sig_msg[2] = (idx >> 8) & 255;
  484. sig_msg[3] = idx & 255;
  485. sig_msg += 4;
  486. *sig_msg_len += 4;
  487. // Copy R to signature
  488. for (i = 0; i < XMSS_N; i++)
  489. sig_msg[i] = R[i];
  490. sig_msg += XMSS_N;
  491. *sig_msg_len += XMSS_N;
  492. // ----------------------------------
  493. // Now we start to "really sign"
  494. // ----------------------------------
  495. // Prepare Address
  496. setType(ots_addr, 0);
  497. setOTSADRS(ots_addr, idx);
  498. // Compute seed for OTS key pair
  499. get_seed(ots_seed, sk_seed, XMSS_N, ots_addr);
  500. // Compute WOTS signature
  501. wots_sign(sig_msg, msg_h, ots_seed, pub_seed, ots_addr);
  502. sig_msg += XMSS_WOTS_KEYSIZE;
  503. *sig_msg_len += XMSS_WOTS_KEYSIZE;
  504. // the auth path was already computed during the previous round
  505. memcpy(sig_msg, state->auth, XMSS_TREEHEIGHT*XMSS_N);
  506. if (idx < (1U << XMSS_TREEHEIGHT) - 1) {
  507. bds_round(state, idx, sk_seed, pub_seed, ots_addr);
  508. bds_treehash_update(state, (XMSS_TREEHEIGHT - XMSS_BDS_K) >> 1, sk_seed, pub_seed, ots_addr);
  509. }
  510. sig_msg += XMSS_TREEHEIGHT*XMSS_N;
  511. *sig_msg_len += XMSS_TREEHEIGHT*XMSS_N;
  512. memcpy(sig_msg, msg, msglen);
  513. *sig_msg_len += msglen;
  514. return 0;
  515. }
  516. /**
  517. * Verifies a given message signature pair under a given public key.
  518. */
  519. int 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)
  520. {
  521. unsigned long long i, m_len;
  522. unsigned long idx=0;
  523. unsigned char wots_pk[XMSS_WOTS_KEYSIZE];
  524. unsigned char pkhash[XMSS_N];
  525. unsigned char root[XMSS_N];
  526. unsigned char msg_h[XMSS_N];
  527. unsigned char hash_key[3*XMSS_N];
  528. unsigned char pub_seed[XMSS_N];
  529. memcpy(pub_seed, pk+XMSS_N, XMSS_N);
  530. // Init addresses
  531. uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  532. uint32_t ltree_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  533. uint32_t node_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  534. setType(ots_addr, 0);
  535. setType(ltree_addr, 1);
  536. setType(node_addr, 2);
  537. // Extract index
  538. idx = ((unsigned long)sig_msg[0] << 24) | ((unsigned long)sig_msg[1] << 16) | ((unsigned long)sig_msg[2] << 8) | sig_msg[3];
  539. // Generate hash key (R || root || idx)
  540. memcpy(hash_key, sig_msg+4,XMSS_N);
  541. memcpy(hash_key+XMSS_N, pk, XMSS_N);
  542. to_byte(hash_key+2*XMSS_N, idx, XMSS_N);
  543. sig_msg += (XMSS_N+4);
  544. sig_msg_len -= (XMSS_N+4);
  545. // hash message
  546. unsigned long long tmp_sig_len = XMSS_WOTS_KEYSIZE+XMSS_TREEHEIGHT*XMSS_N;
  547. m_len = sig_msg_len - tmp_sig_len;
  548. h_msg(msg_h, sig_msg + tmp_sig_len, m_len, hash_key, 3*XMSS_N, XMSS_N);
  549. //-----------------------
  550. // Verify signature
  551. //-----------------------
  552. // Prepare Address
  553. setOTSADRS(ots_addr, idx);
  554. // Check WOTS signature
  555. wots_pkFromSig(wots_pk, sig_msg, msg_h, pub_seed, ots_addr);
  556. sig_msg += XMSS_WOTS_KEYSIZE;
  557. sig_msg_len -= XMSS_WOTS_KEYSIZE;
  558. // Compute Ltree
  559. setLtreeADRS(ltree_addr, idx);
  560. l_tree(pkhash, wots_pk, pub_seed, ltree_addr);
  561. // Compute root
  562. validate_authpath(root, pkhash, idx, sig_msg, pub_seed, node_addr);
  563. sig_msg += XMSS_TREEHEIGHT*XMSS_N;
  564. sig_msg_len -= XMSS_TREEHEIGHT*XMSS_N;
  565. for (i = 0; i < XMSS_N; i++)
  566. if (root[i] != pk[i])
  567. goto fail;
  568. *msglen = sig_msg_len;
  569. for (i = 0; i < *msglen; i++)
  570. msg[i] = sig_msg[i];
  571. return 0;
  572. fail:
  573. *msglen = sig_msg_len;
  574. for (i = 0; i < *msglen; i++)
  575. msg[i] = 0;
  576. *msglen = -1;
  577. return -1;
  578. }
  579. /*
  580. * Generates a XMSSMT key pair for a given parameter set.
  581. * Format sk: [(ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root]
  582. * Format pk: [root || PUB_SEED] omitting algo oid.
  583. */
  584. int xmssmt_keypair(unsigned char *pk, unsigned char *sk, bds_state *states, unsigned char *wots_sigs)
  585. {
  586. unsigned char ots_seed[XMSS_N];
  587. int i;
  588. // Set idx = 0
  589. for (i = 0; i < XMSS_INDEX_LEN; i++) {
  590. sk[i] = 0;
  591. }
  592. // Init SK_SEED (XMSS_N byte), SK_PRF (XMSS_N byte), and PUB_SEED (XMSS_N byte)
  593. randombytes(sk+XMSS_INDEX_LEN, 3*XMSS_N);
  594. // Copy PUB_SEED to public key
  595. memcpy(pk+XMSS_N, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N);
  596. uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  597. // Start with the bottom-most layer
  598. setLayerADRS(addr, 0);
  599. // Set up state and compute wots signatures for all but topmost tree root
  600. for (i = 0; i < XMSS_D - 1; i++) {
  601. // Compute seed for OTS key pair
  602. treehash_setup(pk, XMSS_TREEHEIGHT, 0, states + i, sk+XMSS_INDEX_LEN, pk+XMSS_N, addr);
  603. setLayerADRS(addr, (i+1));
  604. get_seed(ots_seed, sk+XMSS_INDEX_LEN, XMSS_N, addr);
  605. wots_sign(wots_sigs + i*XMSS_WOTS_KEYSIZE, pk, ots_seed, pk+XMSS_N, addr);
  606. }
  607. // Address now points to the single tree on layer d-1
  608. treehash_setup(pk, XMSS_TREEHEIGHT, 0, states + i, sk+XMSS_INDEX_LEN, pk+XMSS_N, addr);
  609. memcpy(sk+XMSS_INDEX_LEN+3*XMSS_N, pk, XMSS_N);
  610. return 0;
  611. }
  612. /**
  613. * Signs a message.
  614. * Returns
  615. * 1. an array containing the signature followed by the message AND
  616. * 2. an updated secret key!
  617. *
  618. */
  619. int 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)
  620. {
  621. uint64_t idx_tree;
  622. uint32_t idx_leaf;
  623. uint64_t i, j;
  624. int needswap_upto = -1;
  625. unsigned int updates;
  626. unsigned char sk_seed[XMSS_N];
  627. unsigned char sk_prf[XMSS_N];
  628. unsigned char pub_seed[XMSS_N];
  629. // Init working params
  630. unsigned char R[XMSS_N];
  631. unsigned char msg_h[XMSS_N];
  632. unsigned char hash_key[3*XMSS_N];
  633. unsigned char ots_seed[XMSS_N];
  634. uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  635. uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  636. unsigned char idx_bytes_32[32];
  637. bds_state tmp;
  638. // Extract SK
  639. unsigned long long idx = 0;
  640. for (i = 0; i < XMSS_INDEX_LEN; i++) {
  641. idx |= ((unsigned long long)sk[i]) << 8*(XMSS_INDEX_LEN - 1 - i);
  642. }
  643. memcpy(sk_seed, sk+XMSS_INDEX_LEN, XMSS_N);
  644. memcpy(sk_prf, sk+XMSS_INDEX_LEN+XMSS_N, XMSS_N);
  645. memcpy(pub_seed, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N);
  646. // Update SK
  647. for (i = 0; i < XMSS_INDEX_LEN; i++) {
  648. sk[i] = ((idx + 1) >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255;
  649. }
  650. // -- Secret key for this non-forward-secure version is now updated.
  651. // -- A productive implementation should use a file handle instead and write the updated secret key at this point!
  652. // ---------------------------------
  653. // Message Hashing
  654. // ---------------------------------
  655. // Message Hash:
  656. // First compute pseudorandom value
  657. to_byte(idx_bytes_32, idx, 32);
  658. prf(R, idx_bytes_32, sk_prf, XMSS_N);
  659. // Generate hash key (R || root || idx)
  660. memcpy(hash_key, R, XMSS_N);
  661. memcpy(hash_key+XMSS_N, sk+XMSS_INDEX_LEN+3*XMSS_N, XMSS_N);
  662. to_byte(hash_key+2*XMSS_N, idx, XMSS_N);
  663. // Then use it for message digest
  664. h_msg(msg_h, msg, msglen, hash_key, 3*XMSS_N, XMSS_N);
  665. // Start collecting signature
  666. *sig_msg_len = 0;
  667. // Copy index to signature
  668. for (i = 0; i < XMSS_INDEX_LEN; i++) {
  669. sig_msg[i] = (idx >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255;
  670. }
  671. sig_msg += XMSS_INDEX_LEN;
  672. *sig_msg_len += XMSS_INDEX_LEN;
  673. // Copy R to signature
  674. for (i = 0; i < XMSS_N; i++)
  675. sig_msg[i] = R[i];
  676. sig_msg += XMSS_N;
  677. *sig_msg_len += XMSS_N;
  678. // ----------------------------------
  679. // Now we start to "really sign"
  680. // ----------------------------------
  681. // Handle lowest layer separately as it is slightly different...
  682. // Prepare Address
  683. setType(ots_addr, 0);
  684. idx_tree = idx >> XMSS_TREEHEIGHT;
  685. idx_leaf = (idx & ((1 << XMSS_TREEHEIGHT)-1));
  686. setLayerADRS(ots_addr, 0);
  687. setTreeADRS(ots_addr, idx_tree);
  688. setOTSADRS(ots_addr, idx_leaf);
  689. // Compute seed for OTS key pair
  690. get_seed(ots_seed, sk_seed, XMSS_N, ots_addr);
  691. // Compute WOTS signature
  692. wots_sign(sig_msg, msg_h, ots_seed, pub_seed, ots_addr);
  693. sig_msg += XMSS_WOTS_KEYSIZE;
  694. *sig_msg_len += XMSS_WOTS_KEYSIZE;
  695. memcpy(sig_msg, states[0].auth, XMSS_TREEHEIGHT*XMSS_N);
  696. sig_msg += XMSS_TREEHEIGHT*XMSS_N;
  697. *sig_msg_len += XMSS_TREEHEIGHT*XMSS_N;
  698. // prepare signature of remaining layers
  699. for (i = 1; i < XMSS_D; i++) {
  700. // put WOTS signature in place
  701. memcpy(sig_msg, wots_sigs + (i-1)*XMSS_WOTS_KEYSIZE, XMSS_WOTS_KEYSIZE);
  702. sig_msg += XMSS_WOTS_KEYSIZE;
  703. *sig_msg_len += XMSS_WOTS_KEYSIZE;
  704. // put AUTH nodes in place
  705. memcpy(sig_msg, states[i].auth, XMSS_TREEHEIGHT*XMSS_N);
  706. sig_msg += XMSS_TREEHEIGHT*XMSS_N;
  707. *sig_msg_len += XMSS_TREEHEIGHT*XMSS_N;
  708. }
  709. updates = (XMSS_TREEHEIGHT - XMSS_BDS_K) >> 1;
  710. setTreeADRS(addr, (idx_tree + 1));
  711. // mandatory update for NEXT_0 (does not count towards h-k/2) if NEXT_0 exists
  712. if ((1 + idx_tree) * (1 << XMSS_TREEHEIGHT) + idx_leaf < (1ULL << XMSS_FULLHEIGHT)) {
  713. bds_state_update(&states[XMSS_D], sk_seed, pub_seed, addr);
  714. }
  715. for (i = 0; i < XMSS_D; i++) {
  716. // check if we're not at the end of a tree
  717. if (! (((idx + 1) & ((1ULL << ((i+1)*XMSS_TREEHEIGHT)) - 1)) == 0)) {
  718. idx_leaf = (idx >> (XMSS_TREEHEIGHT * i)) & ((1 << XMSS_TREEHEIGHT)-1);
  719. idx_tree = (idx >> (XMSS_TREEHEIGHT * (i+1)));
  720. setLayerADRS(addr, i);
  721. setTreeADRS(addr, idx_tree);
  722. if (i == (unsigned int) (needswap_upto + 1)) {
  723. bds_round(&states[i], idx_leaf, sk_seed, pub_seed, addr);
  724. }
  725. updates = bds_treehash_update(&states[i], updates, sk_seed, pub_seed, addr);
  726. setTreeADRS(addr, (idx_tree + 1));
  727. // if a NEXT-tree exists for this level;
  728. if ((1 + idx_tree) * (1 << XMSS_TREEHEIGHT) + idx_leaf < (1ULL << (XMSS_FULLHEIGHT - XMSS_TREEHEIGHT * i))) {
  729. if (i > 0 && updates > 0 && states[XMSS_D + i].next_leaf < (1ULL << XMSS_FULLHEIGHT)) {
  730. bds_state_update(&states[XMSS_D + i], sk_seed, pub_seed, addr);
  731. updates--;
  732. }
  733. }
  734. }
  735. else if (idx < (1ULL << XMSS_FULLHEIGHT) - 1) {
  736. memcpy(&tmp, states+XMSS_D + i, sizeof(bds_state));
  737. memcpy(states+XMSS_D + i, states + i, sizeof(bds_state));
  738. memcpy(states + i, &tmp, sizeof(bds_state));
  739. setLayerADRS(ots_addr, (i+1));
  740. setTreeADRS(ots_addr, ((idx + 1) >> ((i+2) * XMSS_TREEHEIGHT)));
  741. setOTSADRS(ots_addr, (((idx >> ((i+1) * XMSS_TREEHEIGHT)) + 1) & ((1 << XMSS_TREEHEIGHT)-1)));
  742. get_seed(ots_seed, sk+XMSS_INDEX_LEN, XMSS_N, ots_addr);
  743. wots_sign(wots_sigs + i*XMSS_WOTS_KEYSIZE, states[i].stack, ots_seed, pub_seed, ots_addr);
  744. states[XMSS_D + i].stackoffset = 0;
  745. states[XMSS_D + i].next_leaf = 0;
  746. updates--; // WOTS-signing counts as one update
  747. needswap_upto = i;
  748. for (j = 0; j < XMSS_TREEHEIGHT-XMSS_BDS_K; j++) {
  749. states[i].treehash[j].completed = 1;
  750. }
  751. }
  752. }
  753. memcpy(sig_msg, msg, msglen);
  754. *sig_msg_len += msglen;
  755. return 0;
  756. }
  757. /**
  758. * Verifies a given message signature pair under a given public key.
  759. */
  760. int 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)
  761. {
  762. uint64_t idx_tree;
  763. uint32_t idx_leaf;
  764. unsigned long long i, m_len;
  765. unsigned long long idx=0;
  766. unsigned char wots_pk[XMSS_WOTS_KEYSIZE];
  767. unsigned char pkhash[XMSS_N];
  768. unsigned char root[XMSS_N];
  769. unsigned char msg_h[XMSS_N];
  770. unsigned char hash_key[3*XMSS_N];
  771. unsigned char pub_seed[XMSS_N];
  772. memcpy(pub_seed, pk+XMSS_N, XMSS_N);
  773. // Init addresses
  774. uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  775. uint32_t ltree_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  776. uint32_t node_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  777. // Extract index
  778. for (i = 0; i < XMSS_INDEX_LEN; i++) {
  779. idx |= ((unsigned long long)sig_msg[i]) << (8*(XMSS_INDEX_LEN - 1 - i));
  780. }
  781. sig_msg += XMSS_INDEX_LEN;
  782. sig_msg_len -= XMSS_INDEX_LEN;
  783. // Generate hash key (R || root || idx)
  784. memcpy(hash_key, sig_msg,XMSS_N);
  785. memcpy(hash_key+XMSS_N, pk, XMSS_N);
  786. to_byte(hash_key+2*XMSS_N, idx, XMSS_N);
  787. sig_msg += XMSS_N;
  788. sig_msg_len -= XMSS_N;
  789. // hash message (recall, R is now on pole position at sig_msg
  790. unsigned long long tmp_sig_len = (XMSS_D * XMSS_WOTS_KEYSIZE) + (XMSS_FULLHEIGHT * XMSS_N);
  791. m_len = sig_msg_len - tmp_sig_len;
  792. h_msg(msg_h, sig_msg + tmp_sig_len, m_len, hash_key, 3*XMSS_N, XMSS_N);
  793. //-----------------------
  794. // Verify signature
  795. //-----------------------
  796. // Prepare Address
  797. idx_tree = idx >> XMSS_TREEHEIGHT;
  798. idx_leaf = (idx & ((1 << XMSS_TREEHEIGHT)-1));
  799. setLayerADRS(ots_addr, 0);
  800. setTreeADRS(ots_addr, idx_tree);
  801. setType(ots_addr, 0);
  802. memcpy(ltree_addr, ots_addr, 12);
  803. setType(ltree_addr, 1);
  804. memcpy(node_addr, ltree_addr, 12);
  805. setType(node_addr, 2);
  806. setOTSADRS(ots_addr, idx_leaf);
  807. // Check WOTS signature
  808. wots_pkFromSig(wots_pk, sig_msg, msg_h, pub_seed, ots_addr);
  809. sig_msg += XMSS_WOTS_KEYSIZE;
  810. sig_msg_len -= XMSS_WOTS_KEYSIZE;
  811. // Compute Ltree
  812. setLtreeADRS(ltree_addr, idx_leaf);
  813. l_tree(pkhash, wots_pk, pub_seed, ltree_addr);
  814. // Compute root
  815. validate_authpath(root, pkhash, idx_leaf, sig_msg, pub_seed, node_addr);
  816. sig_msg += XMSS_TREEHEIGHT*XMSS_N;
  817. sig_msg_len -= XMSS_TREEHEIGHT*XMSS_N;
  818. for (i = 1; i < XMSS_D; i++) {
  819. // Prepare Address
  820. idx_leaf = (idx_tree & ((1 << XMSS_TREEHEIGHT)-1));
  821. idx_tree = idx_tree >> XMSS_TREEHEIGHT;
  822. setLayerADRS(ots_addr, i);
  823. setTreeADRS(ots_addr, idx_tree);
  824. setType(ots_addr, 0);
  825. memcpy(ltree_addr, ots_addr, 12);
  826. setType(ltree_addr, 1);
  827. memcpy(node_addr, ltree_addr, 12);
  828. setType(node_addr, 2);
  829. setOTSADRS(ots_addr, idx_leaf);
  830. // Check WOTS signature
  831. wots_pkFromSig(wots_pk, sig_msg, root, pub_seed, ots_addr);
  832. sig_msg += XMSS_WOTS_KEYSIZE;
  833. sig_msg_len -= XMSS_WOTS_KEYSIZE;
  834. // Compute Ltree
  835. setLtreeADRS(ltree_addr, idx_leaf);
  836. l_tree(pkhash, wots_pk, pub_seed, ltree_addr);
  837. // Compute root
  838. validate_authpath(root, pkhash, idx_leaf, sig_msg, pub_seed, node_addr);
  839. sig_msg += XMSS_TREEHEIGHT*XMSS_N;
  840. sig_msg_len -= XMSS_TREEHEIGHT*XMSS_N;
  841. }
  842. for (i = 0; i < XMSS_N; i++)
  843. if (root[i] != pk[i])
  844. goto fail;
  845. *msglen = sig_msg_len;
  846. for (i = 0; i < *msglen; i++)
  847. msg[i] = sig_msg[i];
  848. return 0;
  849. fail:
  850. *msglen = sig_msg_len;
  851. for (i = 0; i < *msglen; i++)
  852. msg[i] = 0;
  853. *msglen = -1;
  854. return -1;
  855. }