選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

354 行
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 "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[SPX_WOTS_BYTES];
  23. uint32_t wots_addr[8] = {0};
  24. uint32_t wots_pk_addr[8] = {0};
  25. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
  26. wots_addr, SPX_ADDR_TYPE_WOTS);
  27. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
  28. wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
  29. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_subtree_addr(
  30. wots_addr, tree_addr);
  31. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr(
  32. wots_addr, addr_idx);
  33. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_gen_pk(
  34. pk, sk_seed, pub_seed, wots_addr, hash_state_seeded);
  35. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr(
  36. wots_pk_addr, wots_addr);
  37. PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_secretkeybytes(void) {
  44. return PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SECRETKEYBYTES;
  45. }
  46. /*
  47. * Returns the length of a public key, in bytes
  48. */
  49. size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_publickeybytes(void) {
  50. return PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_PUBLICKEYBYTES;
  51. }
  52. /*
  53. * Returns the length of a signature, in bytes
  54. */
  55. size_t PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_bytes(void) {
  56. return PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_seedbytes(void) {
  62. return PQCLEAN_SPHINCSHARAKA256FROBUST_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_SPHINCSHARAKA256FROBUST_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[SPX_TREE_HEIGHT * SPX_N];
  75. uint32_t top_tree_addr[8] = {0};
  76. hash_state hash_state_seeded;
  77. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_layer_addr(
  78. top_tree_addr, SPX_D - 1);
  79. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
  80. top_tree_addr, SPX_ADDR_TYPE_HASHTREE);
  81. /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
  82. memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SEEDBYTES);
  83. memcpy(pk, sk + 2 * SPX_N, SPX_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_SPHINCSHARAKA256FROBUST_CLEAN_initialize_hash_function(&hash_state_seeded, pk, sk);
  87. /* Compute root node of the top-most subtree. */
  88. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash_TREE_HEIGHT(
  89. sk + 3 * SPX_N, auth_path, sk, sk + 2 * SPX_N, 0, 0,
  90. wots_gen_leaf, top_tree_addr, &hash_state_seeded);
  91. memcpy(pk + SPX_N, sk + 3 * SPX_N, SPX_N);
  92. return 0;
  93. }
  94. /*
  95. * Generates an SPX key pair.
  96. * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
  97. * Format pk: [PUB_SEED || root]
  98. */
  99. int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_keypair(
  100. uint8_t *pk, uint8_t *sk) {
  101. unsigned char seed[PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SEEDBYTES];
  102. randombytes(seed, PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_CRYPTO_SEEDBYTES);
  103. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_seed_keypair(
  104. pk, sk, seed);
  105. return 0;
  106. }
  107. /**
  108. * Returns an array containing a detached signature.
  109. */
  110. int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_signature(
  111. uint8_t *sig, size_t *siglen,
  112. const uint8_t *m, size_t mlen, const uint8_t *sk) {
  113. const unsigned char *sk_seed = sk;
  114. const unsigned char *sk_prf = sk + SPX_N;
  115. const unsigned char *pk = sk + 2 * SPX_N;
  116. const unsigned char *pub_seed = pk;
  117. unsigned char optrand[SPX_N];
  118. unsigned char mhash[SPX_FORS_MSG_BYTES];
  119. unsigned char root[SPX_N];
  120. uint32_t i;
  121. uint64_t tree;
  122. uint32_t idx_leaf;
  123. uint32_t wots_addr[8] = {0};
  124. uint32_t tree_addr[8] = {0};
  125. hash_state hash_state_seeded;
  126. /* This hook allows the hash function instantiation to do whatever
  127. preparation or computation it needs, based on the public seed. */
  128. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_initialize_hash_function(
  129. &hash_state_seeded,
  130. pub_seed, sk_seed);
  131. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
  132. wots_addr, SPX_ADDR_TYPE_WOTS);
  133. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
  134. tree_addr, SPX_ADDR_TYPE_HASHTREE);
  135. /* Optionally, signing can be made non-deterministic using optrand.
  136. This can help counter side-channel attacks that would benefit from
  137. getting a large number of traces when the signer uses the same nodes. */
  138. randombytes(optrand, SPX_N);
  139. /* Compute the digest randomization value. */
  140. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_gen_message_random(
  141. sig, sk_prf, optrand, m, mlen, &hash_state_seeded);
  142. /* Derive the message digest and leaf index from R, PK and M. */
  143. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_hash_message(
  144. mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded);
  145. sig += SPX_N;
  146. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr(wots_addr, tree);
  147. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr(
  148. wots_addr, idx_leaf);
  149. /* Sign the message hash using FORS. */
  150. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_fors_sign(
  151. sig, root, mhash, sk_seed, pub_seed, wots_addr, &hash_state_seeded);
  152. sig += SPX_FORS_BYTES;
  153. for (i = 0; i < SPX_D; i++) {
  154. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_layer_addr(tree_addr, i);
  155. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr(tree_addr, tree);
  156. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_subtree_addr(
  157. wots_addr, tree_addr);
  158. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr(
  159. wots_addr, idx_leaf);
  160. /* Compute a WOTS signature. */
  161. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_sign(
  162. sig, root, sk_seed, pub_seed, wots_addr, &hash_state_seeded);
  163. sig += SPX_WOTS_BYTES;
  164. /* Compute the authentication path for the used WOTS leaf. */
  165. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_treehash_TREE_HEIGHT(
  166. root, sig, sk_seed, pub_seed, idx_leaf, 0,
  167. wots_gen_leaf, tree_addr, &hash_state_seeded);
  168. sig += SPX_TREE_HEIGHT * SPX_N;
  169. /* Update the indices for the next layer. */
  170. idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
  171. tree = tree >> SPX_TREE_HEIGHT;
  172. }
  173. *siglen = SPX_BYTES;
  174. return 0;
  175. }
  176. /**
  177. * Verifies a detached signature and message under a given public key.
  178. */
  179. int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_verify(
  180. const uint8_t *sig, size_t siglen,
  181. const uint8_t *m, size_t mlen, const uint8_t *pk) {
  182. const unsigned char *pub_seed = pk;
  183. const unsigned char *pub_root = pk + SPX_N;
  184. unsigned char mhash[SPX_FORS_MSG_BYTES];
  185. unsigned char wots_pk[SPX_WOTS_BYTES];
  186. unsigned char root[SPX_N];
  187. unsigned char leaf[SPX_N];
  188. unsigned int i;
  189. uint64_t tree;
  190. uint32_t idx_leaf;
  191. uint32_t wots_addr[8] = {0};
  192. uint32_t tree_addr[8] = {0};
  193. uint32_t wots_pk_addr[8] = {0};
  194. hash_state hash_state_seeded;
  195. if (siglen != SPX_BYTES) {
  196. return -1;
  197. }
  198. /* This hook allows the hash function instantiation to do whatever
  199. preparation or computation it needs, based on the public seed. */
  200. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_initialize_hash_function(
  201. &hash_state_seeded,
  202. pub_seed, NULL);
  203. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
  204. wots_addr, SPX_ADDR_TYPE_WOTS);
  205. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
  206. tree_addr, SPX_ADDR_TYPE_HASHTREE);
  207. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_type(
  208. wots_pk_addr, SPX_ADDR_TYPE_WOTSPK);
  209. /* Derive the message digest and leaf index from R || PK || M. */
  210. /* The additional SPX_N is a result of the hash domain separator. */
  211. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_hash_message(
  212. mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded);
  213. sig += SPX_N;
  214. /* Layer correctly defaults to 0, so no need to set_layer_addr */
  215. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr(wots_addr, tree);
  216. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr(
  217. wots_addr, idx_leaf);
  218. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_fors_pk_from_sig(
  219. root, sig, mhash, pub_seed, wots_addr, &hash_state_seeded);
  220. sig += SPX_FORS_BYTES;
  221. /* For each subtree.. */
  222. for (i = 0; i < SPX_D; i++) {
  223. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_layer_addr(tree_addr, i);
  224. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_tree_addr(tree_addr, tree);
  225. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_subtree_addr(
  226. wots_addr, tree_addr);
  227. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_set_keypair_addr(
  228. wots_addr, idx_leaf);
  229. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_copy_keypair_addr(
  230. wots_pk_addr, wots_addr);
  231. /* The WOTS public key is only correct if the signature was correct. */
  232. /* Initially, root is the FORS pk, but on subsequent iterations it is
  233. the root of the subtree below the currently processed subtree. */
  234. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_wots_pk_from_sig(
  235. wots_pk, sig, root, pub_seed, wots_addr, &hash_state_seeded);
  236. sig += SPX_WOTS_BYTES;
  237. /* Compute the leaf node using the WOTS public key. */
  238. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_thash_WOTS_LEN(
  239. leaf, wots_pk, pub_seed, wots_pk_addr, &hash_state_seeded);
  240. /* Compute the root node of this subtree. */
  241. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_compute_root(
  242. root, leaf, idx_leaf, 0, sig, SPX_TREE_HEIGHT,
  243. pub_seed, tree_addr, &hash_state_seeded);
  244. sig += SPX_TREE_HEIGHT * SPX_N;
  245. /* Update the indices for the next layer. */
  246. idx_leaf = (tree & ((1 << SPX_TREE_HEIGHT) - 1));
  247. tree = tree >> SPX_TREE_HEIGHT;
  248. }
  249. /* Check if the root node equals the root node in the public key. */
  250. if (memcmp(root, pub_root, SPX_N) != 0) {
  251. return -1;
  252. }
  253. return 0;
  254. }
  255. /**
  256. * Returns an array containing the signature followed by the message.
  257. */
  258. int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign(
  259. uint8_t *sm, size_t *smlen,
  260. const uint8_t *m, size_t mlen, const uint8_t *sk) {
  261. size_t siglen;
  262. PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_signature(
  263. sm, &siglen, m, mlen, sk);
  264. memmove(sm + SPX_BYTES, m, mlen);
  265. *smlen = siglen + mlen;
  266. return 0;
  267. }
  268. /**
  269. * Verifies a given signature-message pair under a given public key.
  270. */
  271. int PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_open(
  272. uint8_t *m, size_t *mlen,
  273. const uint8_t *sm, size_t smlen, const uint8_t *pk) {
  274. /* The API caller does not necessarily know what size a signature should be
  275. but SPHINCS+ signatures are always exactly SPX_BYTES. */
  276. if (smlen < SPX_BYTES) {
  277. memset(m, 0, smlen);
  278. *mlen = 0;
  279. return -1;
  280. }
  281. *mlen = smlen - SPX_BYTES;
  282. if (PQCLEAN_SPHINCSHARAKA256FROBUST_CLEAN_crypto_sign_verify(
  283. sm, SPX_BYTES, sm + SPX_BYTES, *mlen, pk)) {
  284. memset(m, 0, smlen);
  285. *mlen = 0;
  286. return -1;
  287. }
  288. /* If verification was successful, move the message to the right place. */
  289. memmove(m, sm + SPX_BYTES, *mlen);
  290. return 0;
  291. }