Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 

162 righe
5.2 KiB

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