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

345 рядки
12 KiB

  1. #include <stddef.h>
  2. #include <stdint.h>
  3. #include <string.h>
  4. #include "address.h"
  5. #include "api.h"
  6. #include "fors.h"
  7. #include "hash.h"
  8. #include "params.h"
  9. #include "randombytes.h"
  10. #include "thash.h"
  11. #include "utils.h"
  12. #include "wots.h"
  13. /**
  14. * Computes the leaf at a given address. First generates the WOTS key pair,
  15. * then computes leaf by hashing horizontally.
  16. */
  17. static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
  18. const unsigned char *pub_seed,
  19. uint32_t addr_idx, const uint32_t tree_addr[8]) {
  20. unsigned char pk[SPX_WOTS_BYTES];
  21. uint32_t wots_addr[8] = {0};
  22. uint32_t wots_pk_addr[8] = {0};
  23. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
  24. wots_addr, SPX_ADDR_TYPE_WOTS);
  25. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
  26. wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
  27. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_subtree_addr(
  28. wots_addr, tree_addr);
  29. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_keypair_addr(
  30. wots_addr, addr_idx);
  31. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_wots_gen_pk(
  32. pk, sk_seed, pub_seed, wots_addr);
  33. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_keypair_addr(
  34. wots_pk_addr, wots_addr);
  35. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_WOTS_LEN(
  36. leaf, pk, pub_seed, wots_pk_addr);
  37. }
  38. /*
  39. * Returns the length of a secret key, in bytes
  40. */
  41. size_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_secretkeybytes(void) {
  42. return PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES;
  43. }
  44. /*
  45. * Returns the length of a public key, in bytes
  46. */
  47. size_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_publickeybytes(void) {
  48. return PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES;
  49. }
  50. /*
  51. * Returns the length of a signature, in bytes
  52. */
  53. size_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_bytes(void) {
  54. return PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_BYTES;
  55. }
  56. /*
  57. * Returns the length of the seed required to generate a key pair, in bytes
  58. */
  59. size_t PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_seedbytes(void) {
  60. return PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_SEEDBYTES;
  61. }
  62. /*
  63. * Generates an SPX key pair given a seed of length
  64. * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
  65. * Format pk: [PUB_SEED || root]
  66. */
  67. int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_seed_keypair(
  68. uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
  69. /* We do not need the auth path in key generation, but it simplifies the
  70. code to have just one treehash routine that computes both root and path
  71. in one function. */
  72. unsigned char auth_path[SPX_TREE_HEIGHT * SPX_N];
  73. uint32_t top_tree_addr[8] = {0};
  74. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_layer_addr(
  75. top_tree_addr, SPX_D - 1);
  76. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
  77. top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
  78. /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
  79. memcpy(sk, seed, PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_SEEDBYTES);
  80. memcpy(pk, sk + 2 * SPX_N, SPX_N);
  81. /* This hook allows the hash function instantiation to do whatever
  82. preparation or computation it needs, based on the public seed. */
  83. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_initialize_hash_function(pk, sk);
  84. /* Compute root node of the top-most subtree. */
  85. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_treehash_TREE_HEIGHT(
  86. sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
  87. wots_gen_leaf, top_tree_addr);
  88. memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
  89. return 0;
  90. }
  91. /*
  92. * Generates an SPX key pair.
  93. * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
  94. * Format pk: [PUB_SEED || root]
  95. */
  96. int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_keypair(
  97. uint8_t *pk, uint8_t *sk) {
  98. unsigned char seed[PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_SEEDBYTES];
  99. randombytes(seed, PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_CRYPTO_SEEDBYTES);
  100. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_seed_keypair(
  101. pk, sk, seed);
  102. return 0;
  103. }
  104. /**
  105. * Returns an array containing a detached signature.
  106. */
  107. int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_signature(
  108. uint8_t *sig, size_t *siglen,
  109. const uint8_t *m, size_t mlen, const uint8_t *sk) {
  110. const unsigned char *sk_seed = sk;
  111. const unsigned char *sk_prf = sk + SPX_N;
  112. const unsigned char *pk = sk + 2 * SPX_N;
  113. const unsigned char *pub_seed = pk;
  114. unsigned char optrand[SPX_N];
  115. unsigned char mhash[SPX_FORS_MSG_BYTES];
  116. unsigned char root[SPX_N];
  117. uint32_t i;
  118. uint64_t tree;
  119. uint32_t idx_leaf;
  120. uint32_t wots_addr[8] = {0};
  121. uint32_t tree_addr[8] = {0};
  122. /* This hook allows the hash function instantiation to do whatever
  123. preparation or computation it needs, based on the public seed. */
  124. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_initialize_hash_function(
  125. pub_seed, sk_seed);
  126. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
  127. wots_addr, SPX_ADDR_TYPE_WOTS);
  128. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
  129. tree_addr, SPX_ADDR_TYPE_HASHTREE);
  130. /* Optionally, signing can be made non-deterministic using optrand.
  131. This can help counter side-channel attacks that would benefit from
  132. getting a large number of traces when the signer uses the same nodes. */
  133. randombytes(optrand, SPX_N);
  134. /* Compute the digest randomization value. */
  135. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_gen_message_random(
  136. sig, sk_prf, optrand, m, mlen);
  137. /* Derive the message digest and leaf index from R, PK and M. */
  138. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_hash_message(
  139. mhash, &tree, &idx_leaf, sig, pk, m, mlen);
  140. sig += SPX_N;
  141. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_addr(wots_addr, tree);
  142. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_keypair_addr(
  143. wots_addr, idx_leaf);
  144. /* Sign the message hash using FORS. */
  145. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_fors_sign(
  146. sig, root, mhash, sk_seed, pub_seed, wots_addr);
  147. sig += SPX_FORS_BYTES;
  148. for (i = 0; i < SPX_D; i++) {
  149. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_layer_addr(tree_addr, i);
  150. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_addr(tree_addr, tree);
  151. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_subtree_addr(
  152. wots_addr, tree_addr);
  153. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_keypair_addr(
  154. wots_addr, idx_leaf);
  155. /* Compute a WOTS signature. */
  156. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_wots_sign(
  157. sig, root, sk_seed, pub_seed, wots_addr);
  158. sig += SPX_WOTS_BYTES;
  159. /* Compute the authentication path for the used WOTS leaf. */
  160. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_treehash_TREE_HEIGHT(
  161. root, sig, sk_seed, pub_seed, idx_leaf, 0,
  162. wots_gen_leaf, tree_addr);
  163. sig += SPX_TREE_HEIGHT * SPX_N;
  164. /* Update the indices for the next layer. */
  165. idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
  166. tree = tree >> SPX_TREE_HEIGHT;
  167. }
  168. *siglen = SPX_BYTES;
  169. return 0;
  170. }
  171. /**
  172. * Verifies a detached signature and message under a given public key.
  173. */
  174. int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_verify(
  175. const uint8_t *sig, size_t siglen,
  176. const uint8_t *m, size_t mlen, const uint8_t *pk) {
  177. const unsigned char *pub_seed = pk;
  178. const unsigned char *pub_root = pk + SPX_N;
  179. unsigned char mhash[SPX_FORS_MSG_BYTES];
  180. unsigned char wots_pk[SPX_WOTS_BYTES];
  181. unsigned char root[SPX_N];
  182. unsigned char leaf[SPX_N];
  183. unsigned int i;
  184. uint64_t tree;
  185. uint32_t idx_leaf;
  186. uint32_t wots_addr[8] = {0};
  187. uint32_t tree_addr[8] = {0};
  188. uint32_t wots_pk_addr[8] = {0};
  189. if (siglen != SPX_BYTES) {
  190. return -1;
  191. }
  192. /* This hook allows the hash function instantiation to do whatever
  193. preparation or computation it needs, based on the public seed. */
  194. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_initialize_hash_function(
  195. pub_seed, NULL);
  196. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
  197. wots_addr, SPX_ADDR_TYPE_WOTS);
  198. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
  199. tree_addr, SPX_ADDR_TYPE_HASHTREE);
  200. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_type(
  201. wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
  202. /* Derive the message digest and leaf index from R || PK || M. */
  203. /* The additional SPX_N is a result of the hash domain separator. */
  204. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_hash_message(
  205. mhash, &tree, &idx_leaf, sig, pk, m, mlen);
  206. sig += SPX_N;
  207. /* Layer correctly defaults to 0, so no need to set_layer_addr */
  208. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_addr(wots_addr, tree);
  209. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_keypair_addr(
  210. wots_addr, idx_leaf);
  211. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_fors_pk_from_sig(
  212. root, sig, mhash, pub_seed, wots_addr);
  213. sig += SPX_FORS_BYTES;
  214. /* For each subtree.. */
  215. for (i = 0; i < SPX_D; i++) {
  216. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_layer_addr(tree_addr, i);
  217. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_tree_addr(tree_addr, tree);
  218. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_subtree_addr(
  219. wots_addr, tree_addr);
  220. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_set_keypair_addr(
  221. wots_addr, idx_leaf);
  222. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_copy_keypair_addr(
  223. wots_pk_addr, wots_addr);
  224. /* The WOTS public key is only correct if the signature was correct. */
  225. /* Initially, root is the FORS pk, but on subsequent iterations it is
  226. the root of the subtree below the currently processed subtree. */
  227. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_wots_pk_from_sig(
  228. wots_pk, sig, root, pub_seed, wots_addr);
  229. sig += SPX_WOTS_BYTES;
  230. /* Compute the leaf node using the WOTS public key. */
  231. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_thash_WOTS_LEN(
  232. leaf, wots_pk, pub_seed, wots_pk_addr);
  233. /* Compute the root node of this subtree. */
  234. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_compute_root(
  235. root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
  236. pub_seed, tree_addr);
  237. sig += SPX_TREE_HEIGHT * SPX_N;
  238. /* Update the indices for the next layer. */
  239. idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
  240. tree = tree >> SPX_TREE_HEIGHT;
  241. }
  242. /* Check if the root node equals the root node in the public key. */
  243. if (memcmp(root, pub_root, SPX_N) != 0) {
  244. return -1;
  245. }
  246. return 0;
  247. }
  248. /**
  249. * Returns an array containing the signature followed by the message.
  250. */
  251. int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign(
  252. uint8_t *sm, size_t *smlen,
  253. const uint8_t *m, size_t mlen, const uint8_t *sk) {
  254. size_t siglen;
  255. PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_signature(
  256. sm, &siglen, m, mlen, sk);
  257. memmove(sm + SPX_BYTES, m, mlen);
  258. *smlen = siglen + mlen;
  259. return 0;
  260. }
  261. /**
  262. * Verifies a given signature-message pair under a given public key.
  263. */
  264. int PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_open(
  265. uint8_t *m, size_t *mlen,
  266. const uint8_t *sm, size_t smlen, const uint8_t *pk) {
  267. /* The API caller does not necessarily know what size a signature should be
  268. but SPHINCS+ signatures are always exactly SPX_BYTES. */
  269. if (smlen < SPX_BYTES) {
  270. memset(m, 0, smlen);
  271. *mlen = 0;
  272. return -1;
  273. }
  274. *mlen = smlen - SPX_BYTES;
  275. if (PQCLEAN_SPHINCSSHA256128FROBUST_CLEAN_crypto_sign_verify(
  276. sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
  277. memset(m, 0, smlen);
  278. *mlen = 0;
  279. return -1;
  280. }
  281. /* If verification was successful, move the message to the right place. */
  282. memmove(m, sm + SPX_BYTES, *mlen);
  283. return 0;
  284. }