You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

173 lines
12 KiB

  1. #include <string.h>
  2. #include "address.h"
  3. #include "params.h"
  4. #include "thashx8.h"
  5. #include "utils.h"
  6. #include "utilsx8.h"
  7. /**
  8. * For a given leaf index, computes the authentication path and the resulting
  9. * root node using Merkle's TreeHash algorithm.
  10. * Expects the layer and tree parts of the tree_addr to be set, as well as the
  11. * tree type (i.e. PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_ADDR_TYPE_HASHTREE or PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_ADDR_TYPE_FORSTREE).
  12. * Applies the offset idx_offset to indices before building addresses, so that
  13. * it is possible to continue counting indices across trees.
  14. */
  15. static void treehashx8(unsigned char *rootx8, unsigned char *auth_pathx8,
  16. unsigned char *stackx8, unsigned int *heights,
  17. const unsigned char *sk_seed, const unsigned char *pub_seed,
  18. const uint32_t leaf_idx[8], uint32_t idx_offset[8],
  19. uint32_t tree_height,
  20. void (*gen_leafx8)(
  21. unsigned char * /* leaf0 */,
  22. unsigned char * /* leaf1 */,
  23. unsigned char * /* leaf2 */,
  24. unsigned char * /* leaf3 */,
  25. unsigned char * /* leaf4 */,
  26. unsigned char * /* leaf5 */,
  27. unsigned char * /* leaf6 */,
  28. unsigned char * /* leaf7 */,
  29. const unsigned char * /* sk_seed */,
  30. const unsigned char * /* pub_seed */,
  31. uint32_t /* addr_idx0 */,
  32. uint32_t /* addr_idx1 */,
  33. uint32_t /* addr_idx2 */,
  34. uint32_t /* addr_idx3 */,
  35. uint32_t /* addr_idx4 */,
  36. uint32_t /* addr_idx5 */,
  37. uint32_t /* addr_idx6 */,
  38. uint32_t /* addr_idx7 */,
  39. const uint32_t[8] /* tree_addr */,
  40. const hash_state * /* state_seeded */),
  41. uint32_t tree_addrx8[8 * 8],
  42. const hash_state *state_seeded) {
  43. unsigned int offset = 0;
  44. uint32_t idx;
  45. uint32_t tree_idx;
  46. unsigned int j;
  47. for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
  48. /* Add the next leaf node to the stack. */
  49. gen_leafx8(stackx8 + 0 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + offset * PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  50. stackx8 + 1 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + offset * PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  51. stackx8 + 2 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + offset * PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  52. stackx8 + 3 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + offset * PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  53. stackx8 + 4 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + offset * PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  54. stackx8 + 5 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + offset * PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  55. stackx8 + 6 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + offset * PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  56. stackx8 + 7 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + offset * PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  57. sk_seed, pub_seed,
  58. idx + idx_offset[0],
  59. idx + idx_offset[1],
  60. idx + idx_offset[2],
  61. idx + idx_offset[3],
  62. idx + idx_offset[4],
  63. idx + idx_offset[5],
  64. idx + idx_offset[6],
  65. idx + idx_offset[7],
  66. tree_addrx8,
  67. state_seeded);
  68. offset++;
  69. heights[offset - 1] = 0;
  70. /* If this is a node we need for the auth path.. */
  71. for (j = 0; j < 8; j++) {
  72. if ((leaf_idx[j] ^ 0x1) == idx) {
  73. memcpy(auth_pathx8 + j * tree_height * PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  74. stackx8 + j * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N, PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N);
  75. }
  76. }
  77. /* While the top-most nodes are of equal height.. */
  78. while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
  79. /* Compute index of the new node, in the next layer. */
  80. tree_idx = (idx >> (heights[offset - 1] + 1));
  81. /* Set the address of the node we're creating. */
  82. for (j = 0; j < 8; j++) {
  83. PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_set_tree_height(tree_addrx8 + j * 8, heights[offset - 1] + 1);
  84. PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_set_tree_index(tree_addrx8 + j * 8,
  85. tree_idx + (idx_offset[j] >> (heights[offset - 1] + 1)));
  86. }
  87. /* Hash the top-most nodes from the stack together. */
  88. PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_thashx8_2(stackx8 + 0 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  89. stackx8 + 1 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  90. stackx8 + 2 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  91. stackx8 + 3 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  92. stackx8 + 4 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  93. stackx8 + 5 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  94. stackx8 + 6 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  95. stackx8 + 7 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  96. stackx8 + 0 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  97. stackx8 + 1 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  98. stackx8 + 2 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  99. stackx8 + 3 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  100. stackx8 + 4 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  101. stackx8 + 5 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  102. stackx8 + 6 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  103. stackx8 + 7 * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 2)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  104. pub_seed, tree_addrx8, state_seeded);
  105. offset--;
  106. /* Note that the top-most node is now one layer higher. */
  107. heights[offset - 1]++;
  108. /* If this is a node we need for the auth path.. */
  109. for (j = 0; j < 8; j++) {
  110. if (((leaf_idx[j] >> heights[offset - 1]) ^ 0x1) == tree_idx) {
  111. memcpy(auth_pathx8 + j * tree_height * PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + heights[offset - 1]*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N,
  112. stackx8 + j * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N + (offset - 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N, PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N);
  113. }
  114. }
  115. }
  116. }
  117. for (j = 0; j < 8; j++) {
  118. memcpy(rootx8 + j * PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N, stackx8 + j * (tree_height + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N, PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N);
  119. }
  120. }
  121. /* The wrappers below ensure we used fixed-size buffers on the stack (no VLAs) */
  122. #define treehashx8_variant(name, size) \
  123. void PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_treehashx8_##name( \
  124. unsigned char *rootx8, unsigned char *auth_pathx8, \
  125. const unsigned char *sk_seed, const unsigned char *pub_seed, \
  126. const uint32_t leaf_idx[8], uint32_t idx_offset[8], \
  127. void (*gen_leafx8)( \
  128. unsigned char* /* leaf0 */, \
  129. unsigned char* /* leaf1 */, \
  130. unsigned char* /* leaf2 */, \
  131. unsigned char* /* leaf3 */, \
  132. unsigned char* /* leaf4 */, \
  133. unsigned char* /* leaf5 */, \
  134. unsigned char* /* leaf6 */, \
  135. unsigned char* /* leaf7 */, \
  136. const unsigned char* /* sk_seed */, \
  137. const unsigned char* /* pub_seed */, \
  138. uint32_t /* addr_idx0 */, \
  139. uint32_t /* addr_idx1 */, \
  140. uint32_t /* addr_idx2 */, \
  141. uint32_t /* addr_idx3 */, \
  142. uint32_t /* addr_idx4 */, \
  143. uint32_t /* addr_idx5 */, \
  144. uint32_t /* addr_idx6 */, \
  145. uint32_t /* addr_idx7 */, \
  146. const uint32_t[8] /* tree_addr */, \
  147. const hash_state* /* state_seeded */), \
  148. uint32_t tree_addrx8[8*8], \
  149. const hash_state *state_seeded) \
  150. { \
  151. const uint32_t tree_height = (size); \
  152. unsigned char stackx8[8*((size) + 1)*PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_N]; \
  153. unsigned int heights[(size) + 1]; \
  154. treehashx8(rootx8, auth_pathx8, stackx8, heights, sk_seed, pub_seed, \
  155. leaf_idx, idx_offset, tree_height, gen_leafx8, tree_addrx8, state_seeded); \
  156. }
  157. treehashx8_variant(FORS_HEIGHT, PQCLEAN_SPHINCSSHA256256SROBUST_AVX2_FORS_HEIGHT)
  158. #undef treehashx8_variant