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

177 рядки
5.4 KiB

  1. #include <stdint.h>
  2. #include <string.h>
  3. #include "utils.h"
  4. #include "hash.h"
  5. #include "wots.h"
  6. #include "hash_address.h"
  7. #include "params.h"
  8. /**
  9. * Helper method for pseudorandom key generation.
  10. * Expands an n-byte array into a len*n byte array using the `prf_keygen` function.
  11. */
  12. static void expand_seed(const xmss_params *params,
  13. unsigned char *outseeds, const unsigned char *inseed,
  14. const unsigned char *pub_seed, uint32_t addr[8])
  15. {
  16. uint32_t i;
  17. unsigned char buf[params->n + 32];
  18. set_hash_addr(addr, 0);
  19. set_key_and_mask(addr, 0);
  20. memcpy(buf, pub_seed, params->n);
  21. for (i = 0; i < params->wots_len; i++) {
  22. set_chain_addr(addr, i);
  23. addr_to_bytes(buf + params->n, addr);
  24. prf_keygen(params, outseeds + i*params->n, buf, inseed);
  25. }
  26. }
  27. /**
  28. * Computes the chaining function.
  29. * out and in have to be n-byte arrays.
  30. *
  31. * Interprets in as start-th value of the chain.
  32. * addr has to contain the address of the chain.
  33. */
  34. static void gen_chain(const xmss_params *params,
  35. unsigned char *out, const unsigned char *in,
  36. unsigned int start, unsigned int steps,
  37. const unsigned char *pub_seed, uint32_t addr[8])
  38. {
  39. uint32_t i;
  40. /* Initialize out with the value at position 'start'. */
  41. memcpy(out, in, params->n);
  42. /* Iterate 'steps' calls to the hash function. */
  43. for (i = start; i < (start+steps) && i < params->wots_w; i++) {
  44. set_hash_addr(addr, i);
  45. thash_f(params, out, out, pub_seed, addr);
  46. }
  47. }
  48. /**
  49. * base_w algorithm as described in draft.
  50. * Interprets an array of bytes as integers in base w.
  51. * This only works when log_w is a divisor of 8.
  52. */
  53. static void base_w(const xmss_params *params,
  54. int *output, const int out_len, const unsigned char *input)
  55. {
  56. int in = 0;
  57. int out = 0;
  58. unsigned char total;
  59. int bits = 0;
  60. int consumed;
  61. for (consumed = 0; consumed < out_len; consumed++) {
  62. if (bits == 0) {
  63. total = input[in];
  64. in++;
  65. bits += 8;
  66. }
  67. bits -= params->wots_log_w;
  68. output[out] = (total >> bits) & (params->wots_w - 1);
  69. out++;
  70. }
  71. }
  72. /* Computes the WOTS+ checksum over a message (in base_w). */
  73. static void wots_checksum(const xmss_params *params,
  74. int *csum_base_w, const int *msg_base_w)
  75. {
  76. int csum = 0;
  77. unsigned char csum_bytes[(params->wots_len2 * params->wots_log_w + 7) / 8];
  78. unsigned int i;
  79. /* Compute checksum. */
  80. for (i = 0; i < params->wots_len1; i++) {
  81. csum += params->wots_w - 1 - msg_base_w[i];
  82. }
  83. /* Convert checksum to base_w. */
  84. /* Make sure expected empty zero bits are the least significant bits. */
  85. csum = csum << (8 - ((params->wots_len2 * params->wots_log_w) % 8));
  86. ull_to_bytes(csum_bytes, sizeof(csum_bytes), csum);
  87. base_w(params, csum_base_w, params->wots_len2, csum_bytes);
  88. }
  89. /* Takes a message and derives the matching chain lengths. */
  90. static void chain_lengths(const xmss_params *params,
  91. int *lengths, const unsigned char *msg)
  92. {
  93. base_w(params, lengths, params->wots_len1, msg);
  94. wots_checksum(params, lengths + params->wots_len1, lengths);
  95. }
  96. /**
  97. * WOTS key generation. Takes a 32 byte seed for the private key, expands it to
  98. * a full WOTS private key and computes the corresponding public key.
  99. * It requires the seed pub_seed (used to generate bitmasks and hash keys)
  100. * and the address of this WOTS key pair.
  101. *
  102. * Writes the computed public key to 'pk'.
  103. */
  104. void wots_pkgen(const xmss_params *params,
  105. unsigned char *pk, const unsigned char *seed,
  106. const unsigned char *pub_seed, uint32_t addr[8])
  107. {
  108. uint32_t i;
  109. /* The WOTS+ private key is derived from the seed. */
  110. expand_seed(params, pk, seed, pub_seed, addr);
  111. for (i = 0; i < params->wots_len; i++) {
  112. set_chain_addr(addr, i);
  113. gen_chain(params, pk + i*params->n, pk + i*params->n,
  114. 0, params->wots_w - 1, pub_seed, addr);
  115. }
  116. }
  117. /**
  118. * Takes a n-byte message and the 32-byte seed for the private key to compute a
  119. * signature that is placed at 'sig'.
  120. */
  121. void wots_sign(const xmss_params *params,
  122. unsigned char *sig, const unsigned char *msg,
  123. const unsigned char *seed, const unsigned char *pub_seed,
  124. uint32_t addr[8])
  125. {
  126. int lengths[params->wots_len];
  127. uint32_t i;
  128. chain_lengths(params, lengths, msg);
  129. /* The WOTS+ private key is derived from the seed. */
  130. expand_seed(params, sig, seed, pub_seed, addr);
  131. for (i = 0; i < params->wots_len; i++) {
  132. set_chain_addr(addr, i);
  133. gen_chain(params, sig + i*params->n, sig + i*params->n,
  134. 0, lengths[i], pub_seed, addr);
  135. }
  136. }
  137. /**
  138. * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
  139. *
  140. * Writes the computed public key to 'pk'.
  141. */
  142. void wots_pk_from_sig(const xmss_params *params, unsigned char *pk,
  143. const unsigned char *sig, const unsigned char *msg,
  144. const unsigned char *pub_seed, uint32_t addr[8])
  145. {
  146. int lengths[params->wots_len];
  147. uint32_t i;
  148. chain_lengths(params, lengths, msg);
  149. for (i = 0; i < params->wots_len; i++) {
  150. set_chain_addr(addr, i);
  151. gen_chain(params, pk + i*params->n, sig + i*params->n,
  152. lengths[i], params->wots_w - 1 - lengths[i], pub_seed, addr);
  153. }
  154. }