1 #include <stddef.h>
2 #include <string.h>
3 
4 #include "address.h"
5 #include "hash.h"
6 #include "hash_state.h"
7 #include "params.h"
8 #include "thash.h"
9 #include "utils.h"
10 
11 /**
12  * Converts the value of 'in' to 'outlen' bytes in big-endian byte order.
13  */
PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_ull_to_bytes(unsigned char * out,size_t outlen,unsigned long long in)14 void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_ull_to_bytes(
15     unsigned char *out, size_t outlen, unsigned long long in) {
16 
17     /* Iterate over out in decreasing order, for big-endianness. */
18     for (size_t i = outlen; i > 0; i--) {
19         out[i - 1] = in & 0xff;
20         in = in >> 8;
21     }
22 }
23 
24 /**
25  * Converts the inlen bytes in 'in' from big-endian byte order to an integer.
26  */
PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_bytes_to_ull(const unsigned char * in,size_t inlen)27 unsigned long long PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_bytes_to_ull(
28     const unsigned char *in, size_t inlen) {
29     unsigned long long retval = 0;
30 
31     for (size_t i = 0; i < inlen; i++) {
32         retval |= ((unsigned long long)in[i]) << (8 * (inlen - 1 - i));
33     }
34     return retval;
35 }
36 
37 /**
38  * Computes a root node given a leaf and an auth path.
39  * Expects address to be complete other than the tree_height and tree_index.
40  */
PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_compute_root(unsigned char * root,const unsigned char * leaf,uint32_t leaf_idx,uint32_t idx_offset,const unsigned char * auth_path,uint32_t tree_height,const unsigned char * pub_seed,uint32_t addr[8],const hash_state * hash_state_seeded)41 void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_compute_root(
42     unsigned char *root, const unsigned char *leaf,
43     uint32_t leaf_idx, uint32_t idx_offset,
44     const unsigned char *auth_path, uint32_t tree_height,
45     const unsigned char *pub_seed, uint32_t addr[8],
46     const hash_state *hash_state_seeded) {
47     uint32_t i;
48     unsigned char buffer[2 * PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N];
49 
50     /* If leaf_idx is odd (last bit = 1), current path element is a right child
51        and auth_path has to go left. Otherwise it is the other way around. */
52     if (leaf_idx & 1) {
53         memcpy(buffer + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N, leaf, PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N);
54         memcpy(buffer, auth_path, PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N);
55     } else {
56         memcpy(buffer, leaf, PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N);
57         memcpy(buffer + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N, auth_path, PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N);
58     }
59     auth_path += PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N;
60 
61     for (i = 0; i < tree_height - 1; i++) {
62         leaf_idx >>= 1;
63         idx_offset >>= 1;
64         /* Set the address of the node we're creating. */
65         PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height(addr, i + 1);
66         PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index(
67             addr, leaf_idx + idx_offset);
68 
69         /* Pick the right or left neighbor, depending on parity of the node. */
70         if (leaf_idx & 1) {
71             PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2(
72                 buffer + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N, buffer, pub_seed, addr, hash_state_seeded);
73             memcpy(buffer, auth_path, PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N);
74         } else {
75             PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2(
76                 buffer, buffer, pub_seed, addr, hash_state_seeded);
77             memcpy(buffer + PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N, auth_path, PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N);
78         }
79         auth_path += PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N;
80     }
81 
82     /* The last iteration is exceptional; we do not copy an auth_path node. */
83     leaf_idx >>= 1;
84     idx_offset >>= 1;
85     PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height(addr, tree_height);
86     PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index(
87         addr, leaf_idx + idx_offset);
88     PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2(
89         root, buffer, pub_seed, addr, hash_state_seeded);
90 }
91 
92 /**
93  * For a given leaf index, computes the authentication path and the resulting
94  * root node using Merkle's TreeHash algorithm.
95  * Expects the layer and tree parts of the tree_addr to be set, as well as the
96  * tree type (i.e. PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_ADDR_TYPE_HASHTREE or PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_ADDR_TYPE_FORSTREE).
97  * Applies the offset idx_offset to indices before building addresses, so that
98  * it is possible to continue counting indices across trees.
99  */
PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash(unsigned char * root,unsigned char * auth_path,unsigned char * stack,unsigned int * heights,const unsigned char * sk_seed,const unsigned char * pub_seed,uint32_t leaf_idx,uint32_t idx_offset,uint32_t tree_height,void (* gen_leaf)(unsigned char *,const unsigned char *,const unsigned char *,uint32_t,const uint32_t[8],const hash_state *),uint32_t tree_addr[8],const hash_state * hash_state_seeded)100 static void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash(
101     unsigned char *root, unsigned char *auth_path,
102     unsigned char *stack, unsigned int *heights,
103     const unsigned char *sk_seed, const unsigned char *pub_seed,
104     uint32_t leaf_idx, uint32_t idx_offset, uint32_t tree_height,
105     void (*gen_leaf)(
106         unsigned char * /* leaf */,
107         const unsigned char * /* sk_seed */,
108         const unsigned char * /* pub_seed */,
109         uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
110         const hash_state * /* hash_state_seeded */),
111     uint32_t tree_addr[8],
112     const hash_state *hash_state_seeded) {
113 
114     unsigned int offset = 0;
115     uint32_t idx;
116     uint32_t tree_idx;
117 
118     for (idx = 0; idx < (uint32_t)(1 << tree_height); idx++) {
119         /* Add the next leaf node to the stack. */
120         gen_leaf(stack + offset * PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N,
121                  sk_seed, pub_seed, idx + idx_offset, tree_addr,
122                  hash_state_seeded);
123         offset++;
124         heights[offset - 1] = 0;
125 
126         /* If this is a node we need for the auth path.. */
127         if ((leaf_idx ^ 0x1) == idx) {
128             memcpy(auth_path, stack + (offset - 1)*PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N, PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N);
129         }
130 
131         /* While the top-most nodes are of equal height.. */
132         while (offset >= 2 && heights[offset - 1] == heights[offset - 2]) {
133             /* Compute index of the new node, in the next layer. */
134             tree_idx = (idx >> (heights[offset - 1] + 1));
135 
136             /* Set the address of the node we're creating. */
137             PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_height(
138                 tree_addr, heights[offset - 1] + 1);
139             PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_set_tree_index(
140                 tree_addr, tree_idx + (idx_offset >> (heights[offset - 1] + 1)));
141             /* Hash the top-most nodes from the stack together. */
142             PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_thash_2(
143                 stack + (offset - 2)*PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N, stack + (offset - 2)*PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N,
144                 pub_seed, tree_addr, hash_state_seeded);
145             offset--;
146             /* Note that the top-most node is now one layer higher. */
147             heights[offset - 1]++;
148 
149             /* If this is a node we need for the auth path.. */
150             if (((leaf_idx >> heights[offset - 1]) ^ 0x1) == tree_idx) {
151                 memcpy(auth_path + heights[offset - 1]*PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N,
152                        stack + (offset - 1)*PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N, PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N);
153             }
154         }
155     }
156     memcpy(root, stack, PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N);
157 }
158 
159 /* The wrappers below ensure that we use fixed-size buffers on the stack */
160 
PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash_FORS_HEIGHT(unsigned char * root,unsigned char * auth_path,const unsigned char * sk_seed,const unsigned char * pub_seed,uint32_t leaf_idx,uint32_t idx_offset,void (* gen_leaf)(unsigned char *,const unsigned char *,const unsigned char *,uint32_t,const uint32_t[8],const hash_state *),uint32_t tree_addr[8],const hash_state * hash_state_seeded)161 void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash_FORS_HEIGHT(
162     unsigned char *root, unsigned char *auth_path,
163     const unsigned char *sk_seed, const unsigned char *pub_seed,
164     uint32_t leaf_idx, uint32_t idx_offset,
165     void (*gen_leaf)(
166         unsigned char * /* leaf */,
167         const unsigned char * /* sk_seed */,
168         const unsigned char * /* pub_seed */,
169         uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
170         const hash_state * /* hash_state_seeded */),
171     uint32_t tree_addr[8], const hash_state *hash_state_seeded) {
172 
173     unsigned char stack[(PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_FORS_HEIGHT + 1)*PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N];
174     unsigned int heights[PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_FORS_HEIGHT + 1];
175 
176     PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash(
177         root, auth_path, stack, heights, sk_seed, pub_seed,
178         leaf_idx, idx_offset, PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_FORS_HEIGHT, gen_leaf, tree_addr, hash_state_seeded);
179 }
180 
PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash_TREE_HEIGHT(unsigned char * root,unsigned char * auth_path,const unsigned char * sk_seed,const unsigned char * pub_seed,uint32_t leaf_idx,uint32_t idx_offset,void (* gen_leaf)(unsigned char *,const unsigned char *,const unsigned char *,uint32_t,const uint32_t[8],const hash_state *),uint32_t tree_addr[8],const hash_state * hash_state_seeded)181 void PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash_TREE_HEIGHT(
182     unsigned char *root, unsigned char *auth_path,
183     const unsigned char *sk_seed, const unsigned char *pub_seed,
184     uint32_t leaf_idx, uint32_t idx_offset,
185     void (*gen_leaf)(
186         unsigned char * /* leaf */,
187         const unsigned char * /* sk_seed */,
188         const unsigned char * /* pub_seed */,
189         uint32_t /* addr_idx */, const uint32_t[8] /* tree_addr */,
190         const hash_state * /* hash_state_seeded */),
191     uint32_t tree_addr[8], const hash_state *hash_state_seeded) {
192 
193     unsigned char stack[(PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_TREE_HEIGHT + 1)*PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_N];
194     unsigned int heights[PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_TREE_HEIGHT + 1];
195 
196     PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_treehash(
197         root, auth_path, stack, heights, sk_seed, pub_seed,
198         leaf_idx, idx_offset, PQCLEAN_SPHINCSHARAKA192SSIMPLE_CLEAN_TREE_HEIGHT, gen_leaf, tree_addr, hash_state_seeded);
199 }
200