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

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