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.

237 line
8.0 KiB

  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdint.h>
  4. #include "hash.h"
  5. #include "hash_address.h"
  6. #include "params.h"
  7. #include "wots.h"
  8. #include "utils.h"
  9. #include "xmss_commons.h"
  10. /**
  11. * Computes a leaf node from a WOTS public key using an L-tree.
  12. * Note that this destroys the used WOTS public key.
  13. */
  14. static void l_tree(const xmss_params *params,
  15. unsigned char *leaf, unsigned char *wots_pk,
  16. const unsigned char *pub_seed, uint32_t addr[8])
  17. {
  18. unsigned int l = params->wots_len;
  19. unsigned int parent_nodes;
  20. uint32_t i;
  21. uint32_t height = 0;
  22. set_tree_height(addr, height);
  23. while (l > 1) {
  24. parent_nodes = l >> 1;
  25. for (i = 0; i < parent_nodes; i++) {
  26. set_tree_index(addr, i);
  27. /* Hashes the nodes at (i*2)*params->n and (i*2)*params->n + 1 */
  28. thash_h(params, wots_pk + i*params->n,
  29. wots_pk + (i*2)*params->n, pub_seed, addr);
  30. }
  31. /* If the row contained an odd number of nodes, the last node was not
  32. hashed. Instead, we pull it up to the next layer. */
  33. if (l & 1) {
  34. memcpy(wots_pk + (l >> 1)*params->n,
  35. wots_pk + (l - 1)*params->n, params->n);
  36. l = (l >> 1) + 1;
  37. }
  38. else {
  39. l = l >> 1;
  40. }
  41. height++;
  42. set_tree_height(addr, height);
  43. }
  44. memcpy(leaf, wots_pk, params->n);
  45. }
  46. /**
  47. * Computes a root node given a leaf and an auth path
  48. */
  49. static void compute_root(const xmss_params *params, unsigned char *root,
  50. const unsigned char *leaf, unsigned long leafidx,
  51. const unsigned char *auth_path,
  52. const unsigned char *pub_seed, uint32_t addr[8])
  53. {
  54. uint32_t i;
  55. unsigned char buffer[2*params->n];
  56. /* If leafidx is odd (last bit = 1), current path element is a right child
  57. and auth_path has to go left. Otherwise it is the other way around. */
  58. if (leafidx & 1) {
  59. memcpy(buffer + params->n, leaf, params->n);
  60. memcpy(buffer, auth_path, params->n);
  61. }
  62. else {
  63. memcpy(buffer, leaf, params->n);
  64. memcpy(buffer + params->n, auth_path, params->n);
  65. }
  66. auth_path += params->n;
  67. for (i = 0; i < params->tree_height - 1; i++) {
  68. set_tree_height(addr, i);
  69. leafidx >>= 1;
  70. set_tree_index(addr, leafidx);
  71. /* Pick the right or left neighbor, depending on parity of the node. */
  72. if (leafidx & 1) {
  73. thash_h(params, buffer + params->n, buffer, pub_seed, addr);
  74. memcpy(buffer, auth_path, params->n);
  75. }
  76. else {
  77. thash_h(params, buffer, buffer, pub_seed, addr);
  78. memcpy(buffer + params->n, auth_path, params->n);
  79. }
  80. auth_path += params->n;
  81. }
  82. /* The last iteration is exceptional; we do not copy an auth_path node. */
  83. set_tree_height(addr, params->tree_height - 1);
  84. leafidx >>= 1;
  85. set_tree_index(addr, leafidx);
  86. thash_h(params, root, buffer, pub_seed, addr);
  87. }
  88. /**
  89. * Computes the leaf at a given address. First generates the WOTS key pair,
  90. * then computes leaf using l_tree. As this happens position independent, we
  91. * only require that addr encodes the right ltree-address.
  92. */
  93. void gen_leaf_wots(const xmss_params *params, unsigned char *leaf,
  94. const unsigned char *sk_seed, const unsigned char *pub_seed,
  95. uint32_t ltree_addr[8], uint32_t ots_addr[8])
  96. {
  97. unsigned char seed[params->n];
  98. unsigned char pk[params->wots_sig_bytes];
  99. get_seed(params, seed, sk_seed, ots_addr);
  100. wots_pkgen(params, pk, seed, pub_seed, ots_addr);
  101. l_tree(params, leaf, pk, pub_seed, ltree_addr);
  102. }
  103. /**
  104. * Used for pseudo-random key generation.
  105. * Generates the seed for the WOTS key pair at address 'addr'.
  106. *
  107. * Takes n-byte sk_seed and returns n-byte seed using 32 byte address 'addr'.
  108. */
  109. void get_seed(const xmss_params *params, unsigned char *seed,
  110. const unsigned char *sk_seed, uint32_t addr[8])
  111. {
  112. unsigned char bytes[32];
  113. /* Make sure that chain addr, hash addr, and key bit are zeroed. */
  114. set_chain_addr(addr, 0);
  115. set_hash_addr(addr, 0);
  116. set_key_and_mask(addr, 0);
  117. /* Generate seed. */
  118. addr_to_bytes(bytes, addr);
  119. prf(params, seed, bytes, sk_seed);
  120. }
  121. /**
  122. * Verifies a given message signature pair under a given public key.
  123. * Note that this assumes a pk without an OID, i.e. [root || PUB_SEED]
  124. */
  125. int xmss_core_sign_open(const xmss_params *params,
  126. unsigned char *m, unsigned long long *mlen,
  127. const unsigned char *sm, unsigned long long smlen,
  128. const unsigned char *pk)
  129. {
  130. /* XMSS signatures are fundamentally an instance of XMSSMT signatures.
  131. For d=1, as is the case with XMSS, some of the calls in the XMSSMT
  132. routine become vacuous (i.e. the loop only iterates once, and address
  133. management can be simplified a bit).*/
  134. return xmssmt_core_sign_open(params, m, mlen, sm, smlen, pk);
  135. }
  136. /**
  137. * Verifies a given message signature pair under a given public key.
  138. * Note that this assumes a pk without an OID, i.e. [root || PUB_SEED]
  139. */
  140. int xmssmt_core_sign_open(const xmss_params *params,
  141. unsigned char *m, unsigned long long *mlen,
  142. const unsigned char *sm, unsigned long long smlen,
  143. const unsigned char *pk)
  144. {
  145. const unsigned char *pub_root = pk;
  146. const unsigned char *pub_seed = pk + params->n;
  147. unsigned char wots_pk[params->wots_sig_bytes];
  148. unsigned char leaf[params->n];
  149. unsigned char root[params->n];
  150. unsigned char *mhash = root;
  151. unsigned long long idx = 0;
  152. unsigned int i;
  153. uint32_t idx_leaf;
  154. uint32_t ots_addr[8] = {0};
  155. uint32_t ltree_addr[8] = {0};
  156. uint32_t node_addr[8] = {0};
  157. set_type(ots_addr, XMSS_ADDR_TYPE_OTS);
  158. set_type(ltree_addr, XMSS_ADDR_TYPE_LTREE);
  159. set_type(node_addr, XMSS_ADDR_TYPE_HASHTREE);
  160. *mlen = smlen - params->sig_bytes;
  161. /* Convert the index bytes from the signature to an integer. */
  162. idx = bytes_to_ull(sm, params->index_bytes);
  163. /* Put the message all the way at the end of the m buffer, so that we can
  164. * prepend the required other inputs for the hash function. */
  165. memcpy(m + params->sig_bytes, sm + params->sig_bytes, *mlen);
  166. /* Compute the message hash. */
  167. hash_message(params, mhash, sm + params->index_bytes, pk, idx,
  168. m + params->sig_bytes - 4*params->n, *mlen);
  169. sm += params->index_bytes + params->n;
  170. /* For each subtree.. */
  171. for (i = 0; i < params->d; i++) {
  172. idx_leaf = (idx & ((1 << params->tree_height)-1));
  173. idx = idx >> params->tree_height;
  174. set_layer_addr(ots_addr, i);
  175. set_layer_addr(ltree_addr, i);
  176. set_layer_addr(node_addr, i);
  177. set_tree_addr(ltree_addr, idx);
  178. set_tree_addr(ots_addr, idx);
  179. set_tree_addr(node_addr, idx);
  180. /* The WOTS public key is only correct if the signature was correct. */
  181. set_ots_addr(ots_addr, idx_leaf);
  182. /* Initially, root = mhash, but on subsequent iterations it is the root
  183. of the subtree below the currently processed subtree. */
  184. wots_pk_from_sig(params, wots_pk, sm, root, pub_seed, ots_addr);
  185. sm += params->wots_sig_bytes;
  186. /* Compute the leaf node using the WOTS public key. */
  187. set_ltree_addr(ltree_addr, idx_leaf);
  188. l_tree(params, leaf, wots_pk, pub_seed, ltree_addr);
  189. /* Compute the root node of this subtree. */
  190. compute_root(params, root, leaf, idx_leaf, sm, pub_seed, node_addr);
  191. sm += params->tree_height*params->n;
  192. }
  193. /* Check if the root node equals the root node in the public key. */
  194. if (memcmp(root, pub_root, params->n)) {
  195. /* If not, zero the message */
  196. memset(m, 0, *mlen);
  197. *mlen = 0;
  198. return -1;
  199. }
  200. /* If verification was successful, copy the message from the signature. */
  201. memcpy(m, sm, *mlen);
  202. return 0;
  203. }