Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

241 строка
10 KiB

  1. #include <stdint.h>
  2. #include <string.h>
  3. #include "address.h"
  4. #include "hash.h"
  5. #include "hash_state.h"
  6. #include "hashx8.h"
  7. #include "params.h"
  8. #include "thash.h"
  9. #include "thashx8.h"
  10. #include "utils.h"
  11. #include "wots.h"
  12. // TODO clarify address expectations, and make them more uniform.
  13. // TODO i.e. do we expect types to be set already?
  14. // TODO and do we expect modifications or copies?
  15. /**
  16. * Computes the starting value for a chain, i.e. the secret key.
  17. * Expects the address to be complete up to the chain address.
  18. */
  19. static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
  20. uint32_t wots_addr[8], const hash_state *state_seeded) {
  21. /* Make sure that the hash address is actually zeroed. */
  22. PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_set_hash_addr(wots_addr, 0);
  23. /* Generate sk element. */
  24. PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_prf_addr(sk, sk_seed, wots_addr, state_seeded);
  25. }
  26. /**
  27. * 8-way parallel version of wots_gen_sk; expects 8x as much space in sk
  28. */
  29. static void wots_gen_skx8(unsigned char *skx8, const unsigned char *sk_seed,
  30. uint32_t wots_addrx8[8 * 8]) {
  31. unsigned int j;
  32. /* Make sure that the hash address is actually zeroed. */
  33. for (j = 0; j < 8; j++) {
  34. PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_set_hash_addr(wots_addrx8 + j * 8, 0);
  35. }
  36. /* Generate sk element. */
  37. PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_prf_addrx8(skx8 + 0 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  38. skx8 + 1 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  39. skx8 + 2 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  40. skx8 + 3 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  41. skx8 + 4 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  42. skx8 + 5 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  43. skx8 + 6 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  44. skx8 + 7 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  45. sk_seed, wots_addrx8);
  46. }
  47. /**
  48. * Computes the chaining function.
  49. * out and in have to be n-byte arrays.
  50. *
  51. * Interprets in as start-th value of the chain.
  52. * addr has to contain the address of the chain.
  53. */
  54. static void gen_chain(unsigned char *out, const unsigned char *in,
  55. unsigned int start, unsigned int steps,
  56. const unsigned char *pub_seed, uint32_t addr[8],
  57. const hash_state *state_seeded) {
  58. uint32_t i;
  59. /* Initialize out with the value at position 'start'. */
  60. memcpy(out, in, PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N);
  61. /* Iterate 'steps' calls to the hash function. */
  62. for (i = start; i < (start + steps) && i < PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_W; i++) {
  63. PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_set_hash_addr(addr, i);
  64. PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_thash_1(out, out, pub_seed, addr, state_seeded);
  65. }
  66. }
  67. /**
  68. * 8-way parallel version of gen_chain; expects 8x as much space in out, and
  69. * 8x as much space in inx8. Assumes start and step identical across chains.
  70. */
  71. static void gen_chainx8(unsigned char *outx8, const unsigned char *inx8,
  72. unsigned int start, unsigned int steps,
  73. const unsigned char *pub_seed, uint32_t addrx8[8 * 8],
  74. const hash_state *state_seeded) {
  75. uint32_t i;
  76. unsigned int j;
  77. /* Initialize outx8 with the value at position 'start'. */
  78. memcpy(outx8, inx8, 8 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N);
  79. /* Iterate 'steps' calls to the hash function. */
  80. for (i = start; i < (start + steps) && i < PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_W; i++) {
  81. for (j = 0; j < 8; j++) {
  82. PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_set_hash_addr(addrx8 + j * 8, i);
  83. }
  84. PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_thashx8_1(outx8 + 0 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  85. outx8 + 1 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  86. outx8 + 2 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  87. outx8 + 3 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  88. outx8 + 4 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  89. outx8 + 5 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  90. outx8 + 6 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  91. outx8 + 7 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  92. outx8 + 0 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  93. outx8 + 1 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  94. outx8 + 2 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  95. outx8 + 3 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  96. outx8 + 4 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  97. outx8 + 5 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  98. outx8 + 6 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  99. outx8 + 7 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  100. pub_seed, addrx8, state_seeded);
  101. }
  102. }
  103. /**
  104. * base_w algorithm as described in draft.
  105. * Interprets an array of bytes as integers in base w.
  106. * This only works when log_w is a divisor of 8.
  107. */
  108. static void base_w(unsigned int *output, const int out_len, const unsigned char *input) {
  109. int in = 0;
  110. int out = 0;
  111. unsigned char total = 0;
  112. int bits = 0;
  113. int consumed;
  114. for (consumed = 0; consumed < out_len; consumed++) {
  115. if (bits == 0) {
  116. total = input[in];
  117. in++;
  118. bits += 8;
  119. }
  120. bits -= PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LOGW;
  121. output[out] = (unsigned int)(total >> bits) & (PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_W - 1);
  122. out++;
  123. }
  124. }
  125. /* Computes the WOTS+ checksum over a message (in base_w). */
  126. static void wots_checksum(unsigned int *csum_base_w, const unsigned int *msg_base_w) {
  127. unsigned int csum = 0;
  128. unsigned char csum_bytes[(PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LEN2 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LOGW + 7) / 8];
  129. unsigned int i;
  130. /* Compute checksum. */
  131. for (i = 0; i < PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LEN1; i++) {
  132. csum += PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_W - 1 - msg_base_w[i];
  133. }
  134. /* Convert checksum to base_w. */
  135. /* Make sure expected empty zero bits are the least significant bits. */
  136. csum = csum << (8 - ((PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LEN2 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LOGW) % 8));
  137. PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_ull_to_bytes(csum_bytes, sizeof(csum_bytes), csum);
  138. base_w(csum_base_w, PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LEN2, csum_bytes);
  139. }
  140. /* Takes a message and derives the matching chain lengths. */
  141. static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
  142. base_w(lengths, PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LEN1, msg);
  143. wots_checksum(lengths + PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LEN1, lengths);
  144. }
  145. /**
  146. * WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
  147. * elements and computes the corresponding public key.
  148. * It requires the seed pub_seed (used to generate bitmasks and hash keys)
  149. * and the address of this WOTS key pair.
  150. *
  151. * Writes the computed public key to 'pk'.
  152. */
  153. void PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_wots_gen_pk(unsigned char *pk, const unsigned char *sk_seed,
  154. const unsigned char *pub_seed, uint32_t addr[8],
  155. const hash_state *state_seeded) {
  156. uint32_t i;
  157. unsigned int j;
  158. uint32_t addrx8[8 * 8];
  159. unsigned char pkbuf[8 * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N];
  160. for (j = 0; j < 8; j++) {
  161. memcpy(addrx8 + j * 8, addr, sizeof(uint32_t) * 8);
  162. }
  163. /* The last iteration typically does not have complete set of 4 chains,
  164. but because we use pkbuf, this is not an issue -- we still do as many
  165. in parallel as possible. */
  166. for (i = 0; i < ((PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LEN + 7) & ~0x7); i += 8) {
  167. for (j = 0; j < 8; j++) {
  168. PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_set_chain_addr(addrx8 + j * 8, i + j);
  169. }
  170. wots_gen_skx8(pkbuf, sk_seed, addrx8);
  171. gen_chainx8(pkbuf, pkbuf, 0, PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_W - 1, pub_seed, addrx8, state_seeded);
  172. for (j = 0; j < 8; j++) {
  173. if (i + j < PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LEN) {
  174. memcpy(pk + (i + j)*PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N, pkbuf + j * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N, PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N);
  175. }
  176. }
  177. }
  178. }
  179. /**
  180. * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
  181. */
  182. void PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_wots_sign(unsigned char *sig, const unsigned char *msg,
  183. const unsigned char *sk_seed, const unsigned char *pub_seed,
  184. uint32_t addr[8], const hash_state *state_seeded) {
  185. unsigned int lengths[PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LEN];
  186. uint32_t i;
  187. chain_lengths(lengths, msg);
  188. for (i = 0; i < PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LEN; i++) {
  189. PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_set_chain_addr(addr, i);
  190. wots_gen_sk(sig + i * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N, sk_seed, addr, state_seeded);
  191. gen_chain(sig + i * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N, sig + i * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N, 0, lengths[i], pub_seed, addr, state_seeded);
  192. }
  193. }
  194. /**
  195. * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
  196. *
  197. * Writes the computed public key to 'pk'.
  198. */
  199. void PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_wots_pk_from_sig(unsigned char *pk,
  200. const unsigned char *sig, const unsigned char *msg,
  201. const unsigned char *pub_seed, uint32_t addr[8],
  202. const hash_state *state_seeded) {
  203. unsigned int lengths[PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LEN];
  204. uint32_t i;
  205. chain_lengths(lengths, msg);
  206. for (i = 0; i < PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_LEN; i++) {
  207. PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_set_chain_addr(addr, i);
  208. gen_chain(pk + i * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N, sig + i * PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_N,
  209. lengths[i], PQCLEAN_SPHINCSSHA256192FSIMPLE_AVX2_WOTS_W - 1 - lengths[i], pub_seed, addr, state_seeded);
  210. }
  211. }