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.

172 righe
5.2 KiB

  1. #include <stdint.h>
  2. #include <string.h>
  3. #include "xmss_commons.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` function.
  11. */
  12. static void expand_seed(const xmss_params *params,
  13. unsigned char *outseeds, const unsigned char *inseed)
  14. {
  15. uint32_t i;
  16. unsigned char ctr[32];
  17. for (i = 0; i < params->wots_len; i++) {
  18. ull_to_bytes(ctr, 32, i);
  19. prf(params, outseeds + i*params->n, ctr, inseed);
  20. }
  21. }
  22. /**
  23. * Computes the chaining function.
  24. * out and in have to be n-byte arrays.
  25. *
  26. * Interprets in as start-th value of the chain.
  27. * addr has to contain the address of the chain.
  28. */
  29. static void gen_chain(const xmss_params *params,
  30. 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. {
  34. uint32_t i;
  35. /* Initialize out with the value at position 'start'. */
  36. memcpy(out, in, params->n);
  37. /* Iterate 'steps' calls to the hash function. */
  38. for (i = start; i < (start+steps) && i < params->wots_w; i++) {
  39. set_hash_addr(addr, i);
  40. hash_f(params, 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(const xmss_params *params,
  49. int *output, const int out_len, const unsigned char *input)
  50. {
  51. int in = 0;
  52. int out = 0;
  53. unsigned char total;
  54. int bits = 0;
  55. int consumed;
  56. for (consumed = 0; consumed < out_len; consumed++) {
  57. if (bits == 0) {
  58. total = input[in];
  59. in++;
  60. bits += 8;
  61. }
  62. bits -= params->wots_log_w;
  63. output[out] = (total >> bits) & (params->wots_w - 1);
  64. out++;
  65. }
  66. }
  67. /* Computes the WOTS+ checksum over a message (in base_w). */
  68. static void wots_checksum(const xmss_params *params,
  69. int *csum_base_w, const int *msg_base_w)
  70. {
  71. int csum = 0;
  72. unsigned char csum_bytes[(params->wots_len2 * params->wots_log_w + 7) / 8];
  73. unsigned int i;
  74. /* Compute checksum. */
  75. for (i = 0; i < params->wots_len1; i++) {
  76. csum += params->wots_w - 1 - msg_base_w[i];
  77. }
  78. /* Convert checksum to base_w. */
  79. /* Make sure expected empty zero bits are the least significant bits. */
  80. csum = csum << (8 - ((params->wots_len2 * params->wots_log_w) % 8));
  81. ull_to_bytes(csum_bytes, sizeof(csum_bytes), csum);
  82. base_w(params, csum_base_w, params->wots_len2, csum_bytes);
  83. }
  84. /* Takes a message and derives the matching chain lengths. */
  85. static void chain_lengths(const xmss_params *params,
  86. int *lengths, const unsigned char *msg)
  87. {
  88. base_w(params, lengths, params->wots_len1, msg);
  89. wots_checksum(params, lengths + params->wots_len1, lengths);
  90. }
  91. /**
  92. * WOTS key generation. Takes a 32 byte seed for the private key, expands it to
  93. * a full WOTS private key 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 wots_pkgen(const xmss_params *params,
  100. unsigned char *pk, const unsigned char *seed,
  101. const unsigned char *pub_seed, uint32_t addr[8])
  102. {
  103. uint32_t i;
  104. /* The WOTS+ private key is derived from the seed. */
  105. expand_seed(params, pk, seed);
  106. for (i = 0; i < params->wots_len; i++) {
  107. set_chain_addr(addr, i);
  108. gen_chain(params, pk + i*params->n, pk + i*params->n,
  109. 0, params->wots_w - 1, pub_seed, addr);
  110. }
  111. }
  112. /**
  113. * Takes a m-byte message and the 32-byte seed for the private key to compute a
  114. * signature that is placed at 'sig'.
  115. */
  116. void wots_sign(const xmss_params *params,
  117. unsigned char *sig, const unsigned char *msg,
  118. const unsigned char *seed, const unsigned char *pub_seed,
  119. uint32_t addr[8])
  120. {
  121. int lengths[params->wots_len];
  122. uint32_t i;
  123. chain_lengths(params, lengths, msg);
  124. /* The WOTS+ private key is derived from the seed. */
  125. expand_seed(params, sig, seed);
  126. for (i = 0; i < params->wots_len; i++) {
  127. set_chain_addr(addr, i);
  128. gen_chain(params, sig + i*params->n, sig + i*params->n,
  129. 0, lengths[i], pub_seed, addr);
  130. }
  131. }
  132. /**
  133. * Takes a WOTS signature and an m-byte message, computes a WOTS public key.
  134. *
  135. * Writes the computed public key to 'pk'.
  136. */
  137. void wots_pk_from_sig(const xmss_params *params, unsigned char *pk,
  138. const unsigned char *sig, const unsigned char *msg,
  139. const unsigned char *pub_seed, uint32_t addr[8])
  140. {
  141. int lengths[params->wots_len];
  142. uint32_t i;
  143. chain_lengths(params, lengths, msg);
  144. for (i = 0; i < params->wots_len; i++) {
  145. set_chain_addr(addr, i);
  146. gen_chain(params, pk + i*params->n, sig + i*params->n,
  147. lengths[i], params->wots_w - 1 - lengths[i], pub_seed, addr);
  148. }
  149. }