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