1 #include <immintrin.h>
2 #include <stddef.h>
3 #include <stdint.h>
4 #include <string.h>
5
6 #include "address.h"
7 #include "api.h"
8 #include "fors.h"
9 #include "hash.h"
10 #include "hash_state.h"
11 #include "params.h"
12 #include "randombytes.h"
13 #include "thash.h"
14 #include "utils.h"
15 #include "wots.h"
16
17
18 /**
19 * Computes the leaf at a given address. First generates the WOTS key pair,
20 * then computes leaf by hashing horizontally.
21 */
wots_gen_leaf(unsigned char * leaf,const unsigned char * sk_seed,const unsigned char * pub_seed,uint32_t addr_idx,const uint32_t tree_addr[8],const hash_state * hash_state_seeded)22 static void wots_gen_leaf(unsigned char *leaf, const unsigned char *sk_seed,
23 const unsigned char *pub_seed,
24 uint32_t addr_idx, const uint32_t tree_addr[8],
25 const hash_state *hash_state_seeded) {
26 unsigned char pk[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_WOTS_BYTES];
27 uint32_t wots_addr[8] = {0};
28 uint32_t wots_pk_addr[8] = {0};
29
30 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_type(
31 wots_addr, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_ADDR_TYPE_WOTS);
32 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_type(
33 wots_pk_addr, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_ADDR_TYPE_WOTSPK);
34
35 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_copy_subtree_addr(
36 wots_addr, tree_addr);
37 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_keypair_addr(
38 wots_addr, addr_idx);
39 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_wots_gen_pk(
40 pk, sk_seed, pub_seed, wots_addr, hash_state_seeded);
41
42 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_copy_keypair_addr(
43 wots_pk_addr, wots_addr);
44 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_thash_WOTS_LEN(
45 leaf, pk, pub_seed, wots_pk_addr, hash_state_seeded);
46 }
47
48 /*
49 * Returns the length of a secret key, in bytes
50 */
PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_secretkeybytes(void)51 size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_secretkeybytes(void) {
52 return PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_SECRETKEYBYTES;
53 }
54
55 /*
56 * Returns the length of a public key, in bytes
57 */
PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_publickeybytes(void)58 size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_publickeybytes(void) {
59 return PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_PUBLICKEYBYTES;
60 }
61
62 /*
63 * Returns the length of a signature, in bytes
64 */
PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_bytes(void)65 size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_bytes(void) {
66 return PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_BYTES;
67 }
68
69 /*
70 * Returns the length of the seed required to generate a key pair, in bytes
71 */
PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_seedbytes(void)72 size_t PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_seedbytes(void) {
73 return PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_SEEDBYTES;
74 }
75
76 /*
77 * Generates an SPX key pair given a seed of length
78 * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
79 * Format pk: [PUB_SEED || root]
80 */
PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_seed_keypair(uint8_t * pk,uint8_t * sk,const uint8_t * seed)81 int PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_seed_keypair(
82 uint8_t *pk, uint8_t *sk, const uint8_t *seed) {
83 /* We do not need the auth path in key generation, but it simplifies the
84 code to have just one treehash routine that computes both root and path
85 in one function. */
86 unsigned char auth_path[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_TREE_HEIGHT * PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N];
87 uint32_t top_tree_addr[8] = {0};
88 hash_state hash_state_seeded;
89
90 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_layer_addr(
91 top_tree_addr, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_D - 1);
92 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_type(
93 top_tree_addr, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_ADDR_TYPE_HASHTREE);
94
95 /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
96 memcpy(sk, seed, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_SEEDBYTES);
97
98 memcpy(pk, sk + 2 * PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N);
99
100 /* This hook allows the hash function instantiation to do whatever
101 preparation or computation it needs, based on the public seed. */
102 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_initialize_hash_function(&hash_state_seeded, pk, sk);
103
104 /* Compute root node of the top-most subtree. */
105 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_treehash_TREE_HEIGHT(
106 sk + 3 * PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N, auth_path, sk, sk + 2 * PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N, 0, 0,
107 wots_gen_leaf, top_tree_addr, &hash_state_seeded);
108
109 memcpy(pk + PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N, sk + 3 * PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N);
110
111 return 0;
112 }
113
114 /*
115 * Generates an SPX key pair.
116 * Format sk: [SK_SEED || SK_PRF || PUB_SEED || root]
117 * Format pk: [PUB_SEED || root]
118 */
PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_keypair(uint8_t * pk,uint8_t * sk)119 int PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_keypair(
120 uint8_t *pk, uint8_t *sk) {
121
122 // guarantee alignment of pk
123 union {
124 __m128 _x[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_PUBLICKEYBYTES / 16];
125 uint8_t pk[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_PUBLICKEYBYTES];
126 } aligned_pk;
127
128 // guarantee alignment of sk
129 union {
130 __m128 _x[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_SECRETKEYBYTES / 16];
131 uint8_t sk[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_SECRETKEYBYTES];
132 } aligned_sk;
133
134 union {
135 __m128 _x[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_SEEDBYTES / 16];
136 uint8_t seed[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_SEEDBYTES];
137 } aligned_seed;
138 randombytes(aligned_seed.seed, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_SEEDBYTES);
139
140 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_seed_keypair(
141 aligned_pk.pk, aligned_sk.sk, aligned_seed.seed);
142 memcpy(pk, aligned_pk.pk, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_PUBLICKEYBYTES);
143 memcpy(sk, aligned_sk.sk, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_SECRETKEYBYTES);
144
145 return 0;
146 }
147
148 /**
149 * Returns an array containing a detached signature.
150 */
PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_signature(uint8_t * sig,size_t * siglen,const uint8_t * m,size_t mlen,const uint8_t * sk)151 int PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_signature(
152 uint8_t *sig, size_t *siglen,
153 const uint8_t *m, size_t mlen, const uint8_t *sk) {
154 // guarantee alignment of sk
155 union {
156 __m128 *_x;
157 uint8_t sk[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_SECRETKEYBYTES];
158 } aligned_sk;
159 memcpy(aligned_sk.sk, sk, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_SECRETKEYBYTES);
160 sk = aligned_sk.sk;
161
162 // guarantee alignment of sig
163 union {
164 __m128 *_x;
165 uint8_t sig[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_BYTES];
166 } aligned_sig;
167 uint8_t *orig_sig = sig;
168 sig = (uint8_t *)aligned_sig.sig;
169
170 const unsigned char *sk_seed = sk;
171 const unsigned char *sk_prf = sk + PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N;
172 const unsigned char *pk = sk + 2 * PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N;
173 const unsigned char *pub_seed = pk;
174
175 unsigned char optrand[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N];
176 unsigned char mhash[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_FORS_MSG_BYTES];
177 unsigned char root[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N];
178 uint32_t i;
179 uint64_t tree;
180 uint32_t idx_leaf;
181 uint32_t wots_addr[8] = {0};
182 uint32_t tree_addr[8] = {0};
183
184 hash_state hash_state_seeded;
185
186 /* This hook allows the hash function instantiation to do whatever
187 preparation or computation it needs, based on the public seed. */
188 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_initialize_hash_function(
189 &hash_state_seeded,
190 pub_seed, sk_seed);
191
192 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_type(
193 wots_addr, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_ADDR_TYPE_WOTS);
194 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_type(
195 tree_addr, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_ADDR_TYPE_HASHTREE);
196
197 /* Optionally, signing can be made non-deterministic using optrand.
198 This can help counter side-channel attacks that would benefit from
199 getting a large number of traces when the signer uses the same nodes. */
200 randombytes(optrand, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N);
201 /* Compute the digest randomization value. */
202 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_gen_message_random(
203 sig, sk_prf, optrand, m, mlen, &hash_state_seeded);
204
205 /* Derive the message digest and leaf index from R, PK and M. */
206 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_hash_message(
207 mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded);
208 sig += PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N;
209
210 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_tree_addr(wots_addr, tree);
211 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_keypair_addr(
212 wots_addr, idx_leaf);
213
214 /* Sign the message hash using FORS. */
215 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_fors_sign(
216 sig, root, mhash, sk_seed, pub_seed, wots_addr, &hash_state_seeded);
217 sig += PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_FORS_BYTES;
218
219 for (i = 0; i < PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_D; i++) {
220 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_layer_addr(tree_addr, i);
221 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_tree_addr(tree_addr, tree);
222
223 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_copy_subtree_addr(
224 wots_addr, tree_addr);
225 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_keypair_addr(
226 wots_addr, idx_leaf);
227
228 /* Compute a WOTS signature. */
229 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_wots_sign(
230 sig, root, sk_seed, pub_seed, wots_addr, &hash_state_seeded);
231 sig += PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_WOTS_BYTES;
232
233 /* Compute the authentication path for the used WOTS leaf. */
234 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_treehash_TREE_HEIGHT(
235 root, sig, sk_seed, pub_seed, idx_leaf, 0,
236 wots_gen_leaf, tree_addr, &hash_state_seeded);
237 sig += PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_TREE_HEIGHT * PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N;
238
239 /* Update the indices for the next layer. */
240 idx_leaf = (tree & ((1 << PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_TREE_HEIGHT) - 1));
241 tree = tree >> PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_TREE_HEIGHT;
242 }
243
244 memcpy(orig_sig, aligned_sig.sig, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_BYTES);
245 *siglen = PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_BYTES;
246
247 return 0;
248 }
249
250 /**
251 * Verifies a detached signature and message under a given public key.
252 */
PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_verify(const uint8_t * sig,size_t siglen,const uint8_t * m,size_t mlen,const uint8_t * pk)253 int PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_verify(
254 const uint8_t *sig, size_t siglen,
255 const uint8_t *m, size_t mlen, const uint8_t *pk) {
256 // guarantee alignment of pk
257 union {
258 __m128 *_x;
259 uint8_t pk[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_PUBLICKEYBYTES];
260 } aligned_pk;
261 memcpy(aligned_pk.pk, pk, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_PUBLICKEYBYTES);
262 pk = aligned_pk.pk;
263
264 const unsigned char *pub_seed = pk;
265 const unsigned char *pub_root = pk + PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N;
266 unsigned char mhash[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_FORS_MSG_BYTES];
267 unsigned char wots_pk[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_WOTS_BYTES];
268 unsigned char root[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N];
269 unsigned char leaf[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N];
270 unsigned int i;
271 uint64_t tree;
272 uint32_t idx_leaf;
273 uint32_t wots_addr[8] = {0};
274 uint32_t tree_addr[8] = {0};
275 uint32_t wots_pk_addr[8] = {0};
276
277 hash_state hash_state_seeded;
278
279 if (siglen != PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_BYTES) {
280 return -1;
281 }
282
283 /* This hook allows the hash function instantiation to do whatever
284 preparation or computation it needs, based on the public seed. */
285 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_initialize_hash_function(
286 &hash_state_seeded,
287 pub_seed, NULL);
288
289 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_type(
290 wots_addr, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_ADDR_TYPE_WOTS);
291 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_type(
292 tree_addr, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_ADDR_TYPE_HASHTREE);
293 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_type(
294 wots_pk_addr, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_ADDR_TYPE_WOTSPK);
295
296 /* Derive the message digest and leaf index from R || PK || M. */
297 /* The additional PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N is a result of the hash domain separator. */
298 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_hash_message(
299 mhash, &tree, &idx_leaf, sig, pk, m, mlen, &hash_state_seeded);
300 sig += PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N;
301
302 /* Layer correctly defaults to 0, so no need to set_layer_addr */
303 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_tree_addr(wots_addr, tree);
304 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_keypair_addr(
305 wots_addr, idx_leaf);
306
307 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_fors_pk_from_sig(
308 root, sig, mhash, pub_seed, wots_addr, &hash_state_seeded);
309 sig += PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_FORS_BYTES;
310
311 /* For each subtree.. */
312 for (i = 0; i < PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_D; i++) {
313 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_layer_addr(tree_addr, i);
314 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_tree_addr(tree_addr, tree);
315
316 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_copy_subtree_addr(
317 wots_addr, tree_addr);
318 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_set_keypair_addr(
319 wots_addr, idx_leaf);
320
321 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_copy_keypair_addr(
322 wots_pk_addr, wots_addr);
323
324 /* The WOTS public key is only correct if the signature was correct. */
325 /* Initially, root is the FORS pk, but on subsequent iterations it is
326 the root of the subtree below the currently processed subtree. */
327 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_wots_pk_from_sig(
328 wots_pk, sig, root, pub_seed, wots_addr, &hash_state_seeded);
329 sig += PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_WOTS_BYTES;
330
331 /* Compute the leaf node using the WOTS public key. */
332 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_thash_WOTS_LEN(
333 leaf, wots_pk, pub_seed, wots_pk_addr, &hash_state_seeded);
334
335 /* Compute the root node of this subtree. */
336 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_compute_root(
337 root, leaf, idx_leaf, 0, sig, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_TREE_HEIGHT,
338 pub_seed, tree_addr, &hash_state_seeded);
339 sig += PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_TREE_HEIGHT * PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N;
340
341 /* Update the indices for the next layer. */
342 idx_leaf = (tree & ((1 << PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_TREE_HEIGHT) - 1));
343 tree = tree >> PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_TREE_HEIGHT;
344 }
345
346 /* Check if the root node equals the root node in the public key. */
347 if (memcmp(root, pub_root, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_N) != 0) {
348 return -1;
349 }
350
351 return 0;
352 }
353
354
355 /**
356 * Returns an array containing the signature followed by the message.
357 */
PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign(uint8_t * sm,size_t * smlen,const uint8_t * m,size_t mlen,const uint8_t * sk)358 int PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign(
359 uint8_t *sm, size_t *smlen,
360 const uint8_t *m, size_t mlen, const uint8_t *sk) {
361 size_t siglen;
362
363 PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_signature(
364 sm, &siglen, m, mlen, sk);
365
366 memmove(sm + PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_BYTES, m, mlen);
367 *smlen = siglen + mlen;
368
369 return 0;
370 }
371
372 /**
373 * Verifies a given signature-message pair under a given public key.
374 */
PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_open(uint8_t * m,size_t * mlen,const uint8_t * sm,size_t smlen,const uint8_t * pk)375 int PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_open(
376 uint8_t *m, size_t *mlen,
377 const uint8_t *sm, size_t smlen, const uint8_t *pk) {
378
379 // guarantee alignment of pk
380 union {
381 __m128 *_x;
382 uint8_t pk[PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_PUBLICKEYBYTES];
383 } aligned_pk;
384 memcpy(aligned_pk.pk, pk, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_CRYPTO_PUBLICKEYBYTES);
385 pk = aligned_pk.pk;
386
387
388 /* The API caller does not necessarily know what size a signature should be
389 but SPHINCS+ signatures are always exactly PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_BYTES. */
390 if (smlen < PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_BYTES) {
391 memset(m, 0, smlen);
392 *mlen = 0;
393 return -1;
394 }
395
396 *mlen = smlen - PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_BYTES;
397
398 if (PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_crypto_sign_verify(
399 sm, PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_BYTES, sm + PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_BYTES, *mlen, pk)) {
400 memset(m, 0, smlen);
401 *mlen = 0;
402 return -1;
403 }
404
405 /* If verification was successful, move the message to the right place. */
406 memmove(m, sm + PQCLEAN_SPHINCSHARAKA192FSIMPLE_AESNI_BYTES, *mlen);
407
408 return 0;
409 }
410