No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 

168 líneas
6.5 KiB

  1. #include <stdint.h>
  2. #include <string.h>
  3. #include "address.h"
  4. #include "hash.h"
  5. #include "hash_state.h"
  6. #include "params.h"
  7. #include "thash.h"
  8. #include "utils.h"
  9. #include "wots.h"
  10. // TODO clarify address expectations, and make them more uniform.
  11. // TODO i.e. do we expect types to be set already?
  12. // TODO and do we expect modifications or copies?
  13. /**
  14. * Computes the starting value for a chain, i.e. the secret key.
  15. * Expects the address to be complete up to the chain address.
  16. */
  17. static void wots_gen_sk(unsigned char *sk, const unsigned char *sk_seed,
  18. uint32_t wots_addr[8],
  19. const hash_state *hash_state_seeded) {
  20. /* Make sure that the hash address is actually zeroed. */
  21. PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_hash_addr(wots_addr, 0);
  22. /* Generate sk element. */
  23. PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_prf_addr(sk, sk_seed, wots_addr, hash_state_seeded);
  24. }
  25. /**
  26. * Computes the chaining function.
  27. * out and in have to be n-byte arrays.
  28. *
  29. * Interprets in as start-th value of the chain.
  30. * addr has to contain the address of the chain.
  31. */
  32. static void gen_chain(unsigned char *out, const unsigned char *in,
  33. unsigned int start, unsigned int steps,
  34. const unsigned char *pub_seed, uint32_t addr[8],
  35. const hash_state *hash_state_seeded) {
  36. uint32_t i;
  37. /* Initialize out with the value at position 'start'. */
  38. memcpy(out, in, PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_N);
  39. /* Iterate 'steps' calls to the hash function. */
  40. for (i = start; i < (start + steps) && i < PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_W; i++) {
  41. PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_hash_addr(addr, i);
  42. PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_thash_1(
  43. out, out, pub_seed, addr, hash_state_seeded);
  44. }
  45. }
  46. /**
  47. * base_w algorithm as described in draft.
  48. * Interprets an array of bytes as integers in base w.
  49. * This only works when log_w is a divisor of 8.
  50. */
  51. static void base_w(unsigned int *output, const size_t out_len,
  52. const unsigned char *input) {
  53. size_t in = 0;
  54. size_t out = 0;
  55. unsigned char total = 0;
  56. unsigned int bits = 0;
  57. size_t consumed;
  58. for (consumed = 0; consumed < out_len; consumed++) {
  59. if (bits == 0) {
  60. total = input[in];
  61. in++;
  62. bits += 8;
  63. }
  64. bits -= PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_LOGW;
  65. output[out] = (unsigned int)((total >> bits) & (PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_W - 1));
  66. out++;
  67. }
  68. }
  69. /* Computes the WOTS+ checksum over a message (in base_w). */
  70. static void wots_checksum(unsigned int *csum_base_w,
  71. const unsigned int *msg_base_w) {
  72. unsigned int csum = 0;
  73. unsigned char csum_bytes[(PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_LEN2 * PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_LOGW + 7) / 8];
  74. unsigned int i;
  75. /* Compute checksum. */
  76. for (i = 0; i < PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_LEN1; i++) {
  77. csum += PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_W - 1 - msg_base_w[i];
  78. }
  79. /* Convert checksum to base_w. */
  80. /* Make sure expected empty zero bits are the least significant bits. */
  81. csum = csum << (8 - ((PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_LEN2 * PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_LOGW) % 8));
  82. PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_ull_to_bytes(
  83. csum_bytes, sizeof(csum_bytes), csum);
  84. base_w(csum_base_w, PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_LEN2, csum_bytes);
  85. }
  86. /* Takes a message and derives the matching chain lengths. */
  87. static void chain_lengths(unsigned int *lengths, const unsigned char *msg) {
  88. base_w(lengths, PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_LEN1, msg);
  89. wots_checksum(lengths + PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_LEN1, lengths);
  90. }
  91. /**
  92. * WOTS key generation. Takes a 32 byte sk_seed, expands it to WOTS private key
  93. * elements and computes the corresponding public key.
  94. * It requires the seed pub_seed (used to generate bitmasks and hash keys)
  95. * and the address of this WOTS key pair.
  96. *
  97. * Writes the computed public key to 'pk'.
  98. */
  99. void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_gen_pk(
  100. unsigned char *pk, const unsigned char *sk_seed,
  101. const unsigned char *pub_seed, uint32_t addr[8],
  102. const hash_state *hash_state_seeded) {
  103. uint32_t i;
  104. for (i = 0; i < PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_LEN; i++) {
  105. PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_chain_addr(addr, i);
  106. wots_gen_sk(pk + i * PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_N, sk_seed, addr, hash_state_seeded);
  107. gen_chain(pk + i * PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_N, pk + i * PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_N,
  108. 0, PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_W - 1, pub_seed, addr, hash_state_seeded);
  109. }
  110. }
  111. /**
  112. * Takes a n-byte message and the 32-byte sk_see to compute a signature 'sig'.
  113. */
  114. void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_sign(
  115. unsigned char *sig, const unsigned char *msg,
  116. const unsigned char *sk_seed, const unsigned char *pub_seed,
  117. uint32_t addr[8], const hash_state *hash_state_seeded) {
  118. unsigned int lengths[PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_LEN];
  119. uint32_t i;
  120. chain_lengths(lengths, msg);
  121. for (i = 0; i < PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_LEN; i++) {
  122. PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_chain_addr(addr, i);
  123. wots_gen_sk(sig + i * PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_N, sk_seed, addr, hash_state_seeded);
  124. gen_chain(sig + i * PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_N, sig + i * PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_N, 0, lengths[i], pub_seed, addr, hash_state_seeded);
  125. }
  126. }
  127. /**
  128. * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
  129. *
  130. * Writes the computed public key to 'pk'.
  131. */
  132. void PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_wots_pk_from_sig(
  133. unsigned char *pk,
  134. const unsigned char *sig, const unsigned char *msg,
  135. const unsigned char *pub_seed, uint32_t addr[8],
  136. const hash_state *hash_state_seeded) {
  137. unsigned int lengths[PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_LEN];
  138. uint32_t i;
  139. chain_lengths(lengths, msg);
  140. for (i = 0; i < PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_LEN; i++) {
  141. PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_set_chain_addr(addr, i);
  142. gen_chain(pk + i * PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_N, sig + i * PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_N,
  143. lengths[i], PQCLEAN_SPHINCSHARAKA192SROBUST_CLEAN_WOTS_W - 1 - lengths[i], pub_seed, addr,
  144. hash_state_seeded);
  145. }
  146. }