You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

404 lines
11 KiB

  1. /*
  2. xmss.c version 20160722
  3. Andreas Hülsing
  4. Joost Rijneveld
  5. Public domain.
  6. */
  7. #include "xmss.h"
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <stdint.h>
  11. #include "randombytes.h"
  12. #include "wots.h"
  13. #include "hash.h"
  14. #include "xmss_commons.h"
  15. #include "hash_address.h"
  16. #include "params.h"
  17. /**
  18. * Merkle's TreeHash algorithm. The address only needs to initialize the first 78 bits of addr. Everything else will be set by treehash.
  19. * Currently only used for key generation.
  20. *
  21. */
  22. static void treehash(unsigned char *node, uint32_t index, const unsigned char *sk_seed, const unsigned char *pub_seed, const uint32_t addr[8])
  23. {
  24. uint32_t idx = index;
  25. // use three different addresses because at this point we use all three formats in parallel
  26. uint32_t ots_addr[8];
  27. uint32_t ltree_addr[8];
  28. uint32_t node_addr[8];
  29. // only copy layer and tree address parts
  30. memcpy(ots_addr, addr, 12);
  31. // type = ots
  32. setType(ots_addr, 0);
  33. memcpy(ltree_addr, addr, 12);
  34. setType(ltree_addr, 1);
  35. memcpy(node_addr, addr, 12);
  36. setType(node_addr, 2);
  37. uint32_t lastnode, i;
  38. unsigned char stack[(XMSS_TREEHEIGHT+1)*XMSS_N];
  39. uint16_t stacklevels[XMSS_TREEHEIGHT+1];
  40. unsigned int stackoffset=0;
  41. lastnode = idx+(1 << XMSS_TREEHEIGHT);
  42. for (; idx < lastnode; idx++) {
  43. setLtreeADRS(ltree_addr, idx);
  44. setOTSADRS(ots_addr, idx);
  45. gen_leaf_wots(stack+stackoffset*XMSS_N, sk_seed, pub_seed, ltree_addr, ots_addr);
  46. stacklevels[stackoffset] = 0;
  47. stackoffset++;
  48. while (stackoffset>1 && stacklevels[stackoffset-1] == stacklevels[stackoffset-2]) {
  49. setTreeHeight(node_addr, stacklevels[stackoffset-1]);
  50. setTreeIndex(node_addr, (idx >> (stacklevels[stackoffset-1]+1)));
  51. hash_h(stack+(stackoffset-2)*XMSS_N, stack+(stackoffset-2)*XMSS_N, pub_seed, node_addr);
  52. stacklevels[stackoffset-2]++;
  53. stackoffset--;
  54. }
  55. }
  56. for (i = 0; i < XMSS_N; i++)
  57. node[i] = stack[i];
  58. }
  59. /**
  60. * Computes the authpath and the root. This method is using a lot of space as we build the whole tree and then select the authpath nodes.
  61. * For more efficient algorithms see e.g. the chapter on hash-based signatures in Bernstein, Buchmann, Dahmen. "Post-quantum Cryptography", Springer 2009.
  62. * It returns the authpath in "authpath" with the node on level 0 at index 0.
  63. */
  64. static void compute_authpath_wots(unsigned char *root, unsigned char *authpath, unsigned long leaf_idx, const unsigned char *sk_seed, unsigned char *pub_seed, uint32_t addr[8])
  65. {
  66. uint32_t i, j, level;
  67. unsigned char tree[2*(1<<XMSS_TREEHEIGHT)*XMSS_N];
  68. uint32_t ots_addr[8];
  69. uint32_t ltree_addr[8];
  70. uint32_t node_addr[8];
  71. memcpy(ots_addr, addr, 12);
  72. setType(ots_addr, 0);
  73. memcpy(ltree_addr, addr, 12);
  74. setType(ltree_addr, 1);
  75. memcpy(node_addr, addr, 12);
  76. setType(node_addr, 2);
  77. // Compute all leaves
  78. for (i = 0; i < (1U << XMSS_TREEHEIGHT); i++) {
  79. setLtreeADRS(ltree_addr, i);
  80. setOTSADRS(ots_addr, i);
  81. gen_leaf_wots(tree+((1<<XMSS_TREEHEIGHT)*XMSS_N + i*XMSS_N), sk_seed, pub_seed, ltree_addr, ots_addr);
  82. }
  83. level = 0;
  84. // Compute tree:
  85. // Outer loop: For each inner layer
  86. for (i = (1<<XMSS_TREEHEIGHT); i > 1; i>>=1) {
  87. setTreeHeight(node_addr, level);
  88. // Inner loop: for each pair of sibling nodes
  89. for (j = 0; j < i; j+=2) {
  90. setTreeIndex(node_addr, j>>1);
  91. hash_h(tree + (i>>1)*XMSS_N + (j>>1) * XMSS_N, tree + i*XMSS_N + j*XMSS_N, pub_seed, node_addr);
  92. }
  93. level++;
  94. }
  95. // copy authpath
  96. for (i = 0; i < XMSS_TREEHEIGHT; i++)
  97. memcpy(authpath + i*XMSS_N, tree + ((1<<XMSS_TREEHEIGHT)>>i)*XMSS_N + ((leaf_idx >> i) ^ 1) * XMSS_N, XMSS_N);
  98. // copy root
  99. memcpy(root, tree+XMSS_N, XMSS_N);
  100. }
  101. /*
  102. * Generates a XMSS key pair for a given parameter set.
  103. * Format sk: [(32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root]
  104. * Format pk: [root || PUB_SEED] omitting algo oid.
  105. */
  106. int xmss_keypair(unsigned char *pk, unsigned char *sk)
  107. {
  108. // Set idx = 0
  109. sk[0] = 0;
  110. sk[1] = 0;
  111. sk[2] = 0;
  112. sk[3] = 0;
  113. // Init SK_SEED (XMSS_N byte), SK_PRF (XMSS_N byte), and PUB_SEED (XMSS_N byte)
  114. randombytes(sk+4, 3*XMSS_N);
  115. // Copy PUB_SEED to public key
  116. memcpy(pk+XMSS_N, sk+4+2*XMSS_N, XMSS_N);
  117. uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  118. // Compute root
  119. treehash(pk, 0, sk+4, sk+4+2*XMSS_N, addr);
  120. // copy root to sk
  121. memcpy(sk+4+3*XMSS_N, pk, XMSS_N);
  122. return 0;
  123. }
  124. /**
  125. * Signs a message.
  126. * Returns
  127. * 1. an array containing the signature followed by the message AND
  128. * 2. an updated secret key!
  129. *
  130. */
  131. int xmss_sign(unsigned char *sk, unsigned char *sm, unsigned long long *smlen, const unsigned char *m, unsigned long long mlen)
  132. {
  133. uint16_t i = 0;
  134. // Extract SK
  135. uint32_t idx = ((unsigned long)sk[0] << 24) | ((unsigned long)sk[1] << 16) | ((unsigned long)sk[2] << 8) | sk[3];
  136. unsigned char sk_seed[XMSS_N];
  137. unsigned char sk_prf[XMSS_N];
  138. unsigned char pub_seed[XMSS_N];
  139. unsigned char hash_key[3*XMSS_N];
  140. // index as 32 bytes string
  141. unsigned char idx_bytes_32[32];
  142. to_byte(idx_bytes_32, idx, 32);
  143. memcpy(sk_seed, sk+4, XMSS_N);
  144. memcpy(sk_prf, sk+4+XMSS_N, XMSS_N);
  145. memcpy(pub_seed, sk+4+2*XMSS_N, XMSS_N);
  146. // Update SK
  147. sk[0] = ((idx + 1) >> 24) & 255;
  148. sk[1] = ((idx + 1) >> 16) & 255;
  149. sk[2] = ((idx + 1) >> 8) & 255;
  150. sk[3] = (idx + 1) & 255;
  151. // -- Secret key for this non-forward-secure version is now updated.
  152. // -- A productive implementation should use a file handle instead and write the updated secret key at this point!
  153. // Init working params
  154. unsigned char R[XMSS_N];
  155. unsigned char msg_h[XMSS_N];
  156. unsigned char root[XMSS_N];
  157. unsigned char ots_seed[XMSS_N];
  158. uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  159. // ---------------------------------
  160. // Message Hashing
  161. // ---------------------------------
  162. // Message Hash:
  163. // First compute pseudorandom value
  164. prf(R, idx_bytes_32, sk_prf, XMSS_N);
  165. // Generate hash key (R || root || idx)
  166. memcpy(hash_key, R, XMSS_N);
  167. memcpy(hash_key+XMSS_N, sk+4+3*XMSS_N, XMSS_N);
  168. to_byte(hash_key+2*XMSS_N, idx, XMSS_N);
  169. // Then use it for message digest
  170. h_msg(msg_h, m, mlen, hash_key, 3*XMSS_N);
  171. // Start collecting signature
  172. *smlen = 0;
  173. // Copy index to signature
  174. sm[0] = (idx >> 24) & 255;
  175. sm[1] = (idx >> 16) & 255;
  176. sm[2] = (idx >> 8) & 255;
  177. sm[3] = idx & 255;
  178. sm += 4;
  179. *smlen += 4;
  180. // Copy R to signature
  181. for (i = 0; i < XMSS_N; i++)
  182. sm[i] = R[i];
  183. sm += XMSS_N;
  184. *smlen += XMSS_N;
  185. // ----------------------------------
  186. // Now we start to "really sign"
  187. // ----------------------------------
  188. // Prepare Address
  189. setType(ots_addr, 0);
  190. setOTSADRS(ots_addr, idx);
  191. // Compute seed for OTS key pair
  192. get_seed(ots_seed, sk_seed, ots_addr);
  193. // Compute WOTS signature
  194. wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr);
  195. sm += XMSS_WOTS_KEYSIZE;
  196. *smlen += XMSS_WOTS_KEYSIZE;
  197. compute_authpath_wots(root, sm, idx, sk_seed, pub_seed, ots_addr);
  198. sm += XMSS_TREEHEIGHT*XMSS_N;
  199. *smlen += XMSS_TREEHEIGHT*XMSS_N;
  200. memcpy(sm, m, mlen);
  201. *smlen += mlen;
  202. return 0;
  203. }
  204. /*
  205. * Generates a XMSSMT key pair for a given parameter set.
  206. * Format sk: [(ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED]
  207. * Format pk: [root || PUB_SEED] omitting algo oid.
  208. */
  209. int xmssmt_keypair(unsigned char *pk, unsigned char *sk)
  210. {
  211. uint16_t i;
  212. // Set idx = 0
  213. for (i = 0; i < XMSS_INDEX_LEN; i++) {
  214. sk[i] = 0;
  215. }
  216. // Init SK_SEED (XMSS_N byte), SK_PRF (XMSS_N byte), and PUB_SEED (XMSS_N byte)
  217. randombytes(sk+XMSS_INDEX_LEN, 3*XMSS_N);
  218. // Copy PUB_SEED to public key
  219. memcpy(pk+XMSS_N, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N);
  220. // Set address to point on the single tree on layer d-1
  221. uint32_t addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  222. setLayerADRS(addr, (XMSS_D-1));
  223. // Compute root
  224. treehash(pk, 0, sk+XMSS_INDEX_LEN, pk+XMSS_N, addr);
  225. memcpy(sk+XMSS_INDEX_LEN+3*XMSS_N, pk, XMSS_N);
  226. return 0;
  227. }
  228. /**
  229. * Signs a message.
  230. * Returns
  231. * 1. an array containing the signature followed by the message AND
  232. * 2. an updated secret key!
  233. *
  234. */
  235. int xmssmt_sign(unsigned char *sk, unsigned char *sm, unsigned long long *smlen, const unsigned char *m, unsigned long long mlen)
  236. {
  237. uint64_t idx_tree;
  238. uint32_t idx_leaf;
  239. uint64_t i;
  240. unsigned char sk_seed[XMSS_N];
  241. unsigned char sk_prf[XMSS_N];
  242. unsigned char pub_seed[XMSS_N];
  243. // Init working params
  244. unsigned char R[XMSS_N];
  245. unsigned char hash_key[3*XMSS_N];
  246. unsigned char msg_h[XMSS_N];
  247. unsigned char root[XMSS_N];
  248. unsigned char ots_seed[XMSS_N];
  249. uint32_t ots_addr[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  250. unsigned char idx_bytes_32[32];
  251. // Extract SK
  252. unsigned long long idx = 0;
  253. for (i = 0; i < XMSS_INDEX_LEN; i++) {
  254. idx |= ((unsigned long long)sk[i]) << 8*(XMSS_INDEX_LEN - 1 - i);
  255. }
  256. memcpy(sk_seed, sk+XMSS_INDEX_LEN, XMSS_N);
  257. memcpy(sk_prf, sk+XMSS_INDEX_LEN+XMSS_N, XMSS_N);
  258. memcpy(pub_seed, sk+XMSS_INDEX_LEN+2*XMSS_N, XMSS_N);
  259. // Update SK
  260. for (i = 0; i < XMSS_INDEX_LEN; i++) {
  261. sk[i] = ((idx + 1) >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255;
  262. }
  263. // -- Secret key for this non-forward-secure version is now updated.
  264. // -- A productive implementation should use a file handle instead and write the updated secret key at this point!
  265. // ---------------------------------
  266. // Message Hashing
  267. // ---------------------------------
  268. // Message Hash:
  269. // First compute pseudorandom value
  270. to_byte(idx_bytes_32, idx, 32);
  271. prf(R, idx_bytes_32, sk_prf, XMSS_N);
  272. // Generate hash key (R || root || idx)
  273. memcpy(hash_key, R, XMSS_N);
  274. memcpy(hash_key+XMSS_N, sk+XMSS_INDEX_LEN+3*XMSS_N, XMSS_N);
  275. to_byte(hash_key+2*XMSS_N, idx, XMSS_N);
  276. // Then use it for message digest
  277. h_msg(msg_h, m, mlen, hash_key, 3*XMSS_N);
  278. // Start collecting signature
  279. *smlen = 0;
  280. // Copy index to signature
  281. for (i = 0; i < XMSS_INDEX_LEN; i++) {
  282. sm[i] = (idx >> 8*(XMSS_INDEX_LEN - 1 - i)) & 255;
  283. }
  284. sm += XMSS_INDEX_LEN;
  285. *smlen += XMSS_INDEX_LEN;
  286. // Copy R to signature
  287. for (i = 0; i < XMSS_N; i++)
  288. sm[i] = R[i];
  289. sm += XMSS_N;
  290. *smlen += XMSS_N;
  291. // ----------------------------------
  292. // Now we start to "really sign"
  293. // ----------------------------------
  294. // Handle lowest layer separately as it is slightly different...
  295. // Prepare Address
  296. setType(ots_addr, 0);
  297. idx_tree = idx >> XMSS_TREEHEIGHT;
  298. idx_leaf = (idx & ((1 << XMSS_TREEHEIGHT)-1));
  299. setLayerADRS(ots_addr, 0);
  300. setTreeADRS(ots_addr, idx_tree);
  301. setOTSADRS(ots_addr, idx_leaf);
  302. // Compute seed for OTS key pair
  303. get_seed(ots_seed, sk_seed, ots_addr);
  304. // Compute WOTS signature
  305. wots_sign(sm, msg_h, ots_seed, pub_seed, ots_addr);
  306. sm += XMSS_WOTS_KEYSIZE;
  307. *smlen += XMSS_WOTS_KEYSIZE;
  308. compute_authpath_wots(root, sm, idx_leaf, sk_seed, pub_seed, ots_addr);
  309. sm += XMSS_TREEHEIGHT*XMSS_N;
  310. *smlen += XMSS_TREEHEIGHT*XMSS_N;
  311. // Now loop over remaining layers...
  312. unsigned int j;
  313. for (j = 1; j < XMSS_D; j++) {
  314. // Prepare Address
  315. idx_leaf = (idx_tree & ((1 << XMSS_TREEHEIGHT)-1));
  316. idx_tree = idx_tree >> XMSS_TREEHEIGHT;
  317. setLayerADRS(ots_addr, j);
  318. setTreeADRS(ots_addr, idx_tree);
  319. setOTSADRS(ots_addr, idx_leaf);
  320. // Compute seed for OTS key pair
  321. get_seed(ots_seed, sk_seed, ots_addr);
  322. // Compute WOTS signature
  323. wots_sign(sm, root, ots_seed, pub_seed, ots_addr);
  324. sm += XMSS_WOTS_KEYSIZE;
  325. *smlen += XMSS_WOTS_KEYSIZE;
  326. compute_authpath_wots(root, sm, idx_leaf, sk_seed, pub_seed, ots_addr);
  327. sm += XMSS_TREEHEIGHT*XMSS_N;
  328. *smlen += XMSS_TREEHEIGHT*XMSS_N;
  329. }
  330. memcpy(sm, m, mlen);
  331. *smlen += mlen;
  332. return 0;
  333. }