/src/liboqs/src/sig/falcon/pqclean_falcon-padded-512_clean/pqclean.c
Line | Count | Source |
1 | | /* |
2 | | * Wrapper for implementing the PQClean API. |
3 | | */ |
4 | | |
5 | | #include <stddef.h> |
6 | | #include <string.h> |
7 | | |
8 | | #include "api.h" |
9 | | #include "inner.h" |
10 | | |
11 | 0 | #define NONCELEN 40 |
12 | | |
13 | | #include "randombytes.h" |
14 | | |
15 | | /* |
16 | | * Encoding formats (nnnn = log of degree, 9 for Falcon-512, 10 for Falcon-1024) |
17 | | * |
18 | | * private key: |
19 | | * header byte: 0101nnnn |
20 | | * private f (6 or 5 bits by element, depending on degree) |
21 | | * private g (6 or 5 bits by element, depending on degree) |
22 | | * private F (8 bits by element) |
23 | | * |
24 | | * public key: |
25 | | * header byte: 0000nnnn |
26 | | * public h (14 bits by element) |
27 | | * |
28 | | * signature: |
29 | | * header byte: 0011nnnn |
30 | | * nonce (r) 40 bytes |
31 | | * value (s) compressed format |
32 | | * padding to 666 bytes |
33 | | * |
34 | | * message + signature: |
35 | | * signature 666 bytes |
36 | | * message |
37 | | */ |
38 | | |
39 | | /* see api.h */ |
40 | | int |
41 | | PQCLEAN_FALCONPADDED512_CLEAN_crypto_sign_keypair( |
42 | 0 | uint8_t *pk, uint8_t *sk) { |
43 | 0 | union { |
44 | 0 | uint8_t b[FALCON_KEYGEN_TEMP_9]; |
45 | 0 | uint64_t dummy_u64; |
46 | 0 | fpr dummy_fpr; |
47 | 0 | } tmp; |
48 | 0 | int8_t f[512], g[512], F[512]; |
49 | 0 | uint16_t h[512]; |
50 | 0 | unsigned char seed[48]; |
51 | 0 | inner_shake256_context rng; |
52 | 0 | size_t u, v; |
53 | | |
54 | | /* |
55 | | * Generate key pair. |
56 | | */ |
57 | 0 | randombytes(seed, sizeof seed); |
58 | 0 | inner_shake256_init(&rng); |
59 | 0 | inner_shake256_inject(&rng, seed, sizeof seed); |
60 | 0 | inner_shake256_flip(&rng); |
61 | 0 | PQCLEAN_FALCONPADDED512_CLEAN_keygen(&rng, f, g, F, NULL, h, 9, tmp.b); |
62 | 0 | inner_shake256_ctx_release(&rng); |
63 | | |
64 | | /* |
65 | | * Encode private key. |
66 | | */ |
67 | 0 | sk[0] = 0x50 + 9; |
68 | 0 | u = 1; |
69 | 0 | v = PQCLEAN_FALCONPADDED512_CLEAN_trim_i8_encode( |
70 | 0 | sk + u, PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_SECRETKEYBYTES - u, |
71 | 0 | f, 9, PQCLEAN_FALCONPADDED512_CLEAN_max_fg_bits[9]); |
72 | 0 | if (v == 0) { |
73 | 0 | return -1; |
74 | 0 | } |
75 | 0 | u += v; |
76 | 0 | v = PQCLEAN_FALCONPADDED512_CLEAN_trim_i8_encode( |
77 | 0 | sk + u, PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_SECRETKEYBYTES - u, |
78 | 0 | g, 9, PQCLEAN_FALCONPADDED512_CLEAN_max_fg_bits[9]); |
79 | 0 | if (v == 0) { |
80 | 0 | return -1; |
81 | 0 | } |
82 | 0 | u += v; |
83 | 0 | v = PQCLEAN_FALCONPADDED512_CLEAN_trim_i8_encode( |
84 | 0 | sk + u, PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_SECRETKEYBYTES - u, |
85 | 0 | F, 9, PQCLEAN_FALCONPADDED512_CLEAN_max_FG_bits[9]); |
86 | 0 | if (v == 0) { |
87 | 0 | return -1; |
88 | 0 | } |
89 | 0 | u += v; |
90 | 0 | if (u != PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_SECRETKEYBYTES) { |
91 | 0 | return -1; |
92 | 0 | } |
93 | | |
94 | | /* |
95 | | * Encode public key. |
96 | | */ |
97 | 0 | pk[0] = 0x00 + 9; |
98 | 0 | v = PQCLEAN_FALCONPADDED512_CLEAN_modq_encode( |
99 | 0 | pk + 1, PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_PUBLICKEYBYTES - 1, |
100 | 0 | h, 9); |
101 | 0 | if (v != PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_PUBLICKEYBYTES - 1) { |
102 | 0 | return -1; |
103 | 0 | } |
104 | | |
105 | 0 | return 0; |
106 | 0 | } |
107 | | |
108 | | /* |
109 | | * Compute the signature. nonce[] receives the nonce and must have length |
110 | | * NONCELEN bytes. sigbuf[] receives the signature value (without nonce |
111 | | * or header byte), with sigbuflen providing the maximum value length. |
112 | | * |
113 | | * If a signature could be computed but not encoded because it would |
114 | | * exceed the output buffer size, then a new signature is computed. If |
115 | | * the provided buffer size is too low, this could loop indefinitely, so |
116 | | * the caller must provide a size that can accommodate signatures with a |
117 | | * large enough probability. |
118 | | * |
119 | | * Return value: 0 on success, -1 on error. |
120 | | */ |
121 | | static int |
122 | | do_sign(uint8_t *nonce, uint8_t *sigbuf, size_t sigbuflen, |
123 | | const uint8_t *m, size_t mlen, const uint8_t *sk) { |
124 | | union { |
125 | | uint8_t b[72 * 512]; |
126 | | uint64_t dummy_u64; |
127 | | fpr dummy_fpr; |
128 | | } tmp; |
129 | | int8_t f[512], g[512], F[512], G[512]; |
130 | | struct { |
131 | | int16_t sig[512]; |
132 | | uint16_t hm[512]; |
133 | | } r; |
134 | | unsigned char seed[48]; |
135 | | inner_shake256_context sc; |
136 | | size_t u, v; |
137 | | |
138 | | /* |
139 | | * Decode the private key. |
140 | | */ |
141 | | if (sk[0] != 0x50 + 9) { |
142 | | return -1; |
143 | | } |
144 | | u = 1; |
145 | | v = PQCLEAN_FALCONPADDED512_CLEAN_trim_i8_decode( |
146 | | f, 9, PQCLEAN_FALCONPADDED512_CLEAN_max_fg_bits[9], |
147 | | sk + u, PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_SECRETKEYBYTES - u); |
148 | | if (v == 0) { |
149 | | return -1; |
150 | | } |
151 | | u += v; |
152 | | v = PQCLEAN_FALCONPADDED512_CLEAN_trim_i8_decode( |
153 | | g, 9, PQCLEAN_FALCONPADDED512_CLEAN_max_fg_bits[9], |
154 | | sk + u, PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_SECRETKEYBYTES - u); |
155 | | if (v == 0) { |
156 | | return -1; |
157 | | } |
158 | | u += v; |
159 | | v = PQCLEAN_FALCONPADDED512_CLEAN_trim_i8_decode( |
160 | | F, 9, PQCLEAN_FALCONPADDED512_CLEAN_max_FG_bits[9], |
161 | | sk + u, PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_SECRETKEYBYTES - u); |
162 | | if (v == 0) { |
163 | | return -1; |
164 | | } |
165 | | u += v; |
166 | | if (u != PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_SECRETKEYBYTES) { |
167 | | return -1; |
168 | | } |
169 | | if (!PQCLEAN_FALCONPADDED512_CLEAN_complete_private(G, f, g, F, 9, tmp.b)) { |
170 | | return -1; |
171 | | } |
172 | | |
173 | | /* |
174 | | * Create a random nonce (40 bytes). |
175 | | */ |
176 | | randombytes(nonce, NONCELEN); |
177 | | |
178 | | /* |
179 | | * Hash message nonce + message into a vector. |
180 | | */ |
181 | | inner_shake256_init(&sc); |
182 | | inner_shake256_inject(&sc, nonce, NONCELEN); |
183 | | inner_shake256_inject(&sc, m, mlen); |
184 | | inner_shake256_flip(&sc); |
185 | | PQCLEAN_FALCONPADDED512_CLEAN_hash_to_point_ct(&sc, r.hm, 9, tmp.b); |
186 | | inner_shake256_ctx_release(&sc); |
187 | | |
188 | | /* |
189 | | * Initialize a RNG. |
190 | | */ |
191 | | randombytes(seed, sizeof seed); |
192 | | inner_shake256_init(&sc); |
193 | | inner_shake256_inject(&sc, seed, sizeof seed); |
194 | | inner_shake256_flip(&sc); |
195 | | |
196 | | /* |
197 | | * Compute and return the signature. This loops until a signature |
198 | | * value is found that fits in the provided buffer. |
199 | | */ |
200 | | for (;;) { |
201 | | PQCLEAN_FALCONPADDED512_CLEAN_sign_dyn(r.sig, &sc, f, g, F, G, r.hm, 9, tmp.b); |
202 | | v = PQCLEAN_FALCONPADDED512_CLEAN_comp_encode(sigbuf, sigbuflen, r.sig, 9); |
203 | | if (v != 0) { |
204 | | inner_shake256_ctx_release(&sc); |
205 | | memset(sigbuf + v, 0, sigbuflen - v); |
206 | | return 0; |
207 | | } |
208 | | } |
209 | | } |
210 | | |
211 | | /* |
212 | | * Verify a sigature. The nonce has size NONCELEN bytes. sigbuf[] |
213 | | * (of size sigbuflen) contains the signature value, not including the |
214 | | * header byte or nonce. Return value is 0 on success, -1 on error. |
215 | | */ |
216 | | static int |
217 | | do_verify( |
218 | | const uint8_t *nonce, const uint8_t *sigbuf, size_t sigbuflen, |
219 | | const uint8_t *m, size_t mlen, const uint8_t *pk) { |
220 | | union { |
221 | | uint8_t b[2 * 512]; |
222 | | uint64_t dummy_u64; |
223 | | fpr dummy_fpr; |
224 | | } tmp; |
225 | | uint16_t h[512], hm[512]; |
226 | | int16_t sig[512]; |
227 | | inner_shake256_context sc; |
228 | | size_t v; |
229 | | |
230 | | /* |
231 | | * Decode public key. |
232 | | */ |
233 | | if (pk[0] != 0x00 + 9) { |
234 | | return -1; |
235 | | } |
236 | | if (PQCLEAN_FALCONPADDED512_CLEAN_modq_decode(h, 9, |
237 | | pk + 1, PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_PUBLICKEYBYTES - 1) |
238 | | != PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_PUBLICKEYBYTES - 1) { |
239 | | return -1; |
240 | | } |
241 | | PQCLEAN_FALCONPADDED512_CLEAN_to_ntt_monty(h, 9); |
242 | | |
243 | | /* |
244 | | * Decode signature. |
245 | | */ |
246 | | if (sigbuflen == 0) { |
247 | | return -1; |
248 | | } |
249 | | |
250 | | v = PQCLEAN_FALCONPADDED512_CLEAN_comp_decode(sig, 9, sigbuf, sigbuflen); |
251 | | if (v == 0) { |
252 | | return -1; |
253 | | } |
254 | | if (v != sigbuflen) { |
255 | | if (sigbuflen == PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_BYTES - NONCELEN - 1) { |
256 | | while (v < sigbuflen) { |
257 | | if (sigbuf[v++] != 0) { |
258 | | return -1; |
259 | | } |
260 | | } |
261 | | } else { |
262 | | return -1; |
263 | | } |
264 | | } |
265 | | |
266 | | /* |
267 | | * Hash nonce + message into a vector. |
268 | | */ |
269 | | inner_shake256_init(&sc); |
270 | | inner_shake256_inject(&sc, nonce, NONCELEN); |
271 | | inner_shake256_inject(&sc, m, mlen); |
272 | | inner_shake256_flip(&sc); |
273 | | PQCLEAN_FALCONPADDED512_CLEAN_hash_to_point_ct(&sc, hm, 9, tmp.b); |
274 | | inner_shake256_ctx_release(&sc); |
275 | | |
276 | | /* |
277 | | * Verify signature. |
278 | | */ |
279 | | if (!PQCLEAN_FALCONPADDED512_CLEAN_verify_raw(hm, sig, h, 9, tmp.b)) { |
280 | | return -1; |
281 | | } |
282 | | return 0; |
283 | | } |
284 | | |
285 | | /* see api.h */ |
286 | | int |
287 | | PQCLEAN_FALCONPADDED512_CLEAN_crypto_sign_signature( |
288 | | uint8_t *sig, size_t *siglen, |
289 | 0 | const uint8_t *m, size_t mlen, const uint8_t *sk) { |
290 | 0 | size_t vlen; |
291 | |
|
292 | 0 | vlen = PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_BYTES - NONCELEN - 1; |
293 | 0 | if (do_sign(sig + 1, sig + 1 + NONCELEN, vlen, m, mlen, sk) < 0) { |
294 | 0 | return -1; |
295 | 0 | } |
296 | 0 | sig[0] = 0x30 + 9; |
297 | 0 | *siglen = 1 + NONCELEN + vlen; |
298 | 0 | return 0; |
299 | 0 | } |
300 | | |
301 | | /* see api.h */ |
302 | | int |
303 | | PQCLEAN_FALCONPADDED512_CLEAN_crypto_sign_verify( |
304 | | const uint8_t *sig, size_t siglen, |
305 | 0 | const uint8_t *m, size_t mlen, const uint8_t *pk) { |
306 | 0 | if (siglen < 1 + NONCELEN) { |
307 | 0 | return -1; |
308 | 0 | } |
309 | 0 | if (sig[0] != 0x30 + 9) { |
310 | 0 | return -1; |
311 | 0 | } |
312 | 0 | return do_verify(sig + 1, |
313 | 0 | sig + 1 + NONCELEN, siglen - 1 - NONCELEN, m, mlen, pk); |
314 | 0 | } |
315 | | |
316 | | /* see api.h */ |
317 | | int |
318 | | PQCLEAN_FALCONPADDED512_CLEAN_crypto_sign( |
319 | | uint8_t *sm, size_t *smlen, |
320 | 0 | const uint8_t *m, size_t mlen, const uint8_t *sk) { |
321 | 0 | uint8_t *sigbuf; |
322 | 0 | size_t sigbuflen; |
323 | | |
324 | | /* |
325 | | * Move the message to its final location; this is a memmove() so |
326 | | * it handles overlaps properly. |
327 | | */ |
328 | 0 | memmove(sm + PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_BYTES, m, mlen); |
329 | 0 | sigbuf = sm + 1 + NONCELEN; |
330 | 0 | sigbuflen = PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_BYTES - NONCELEN - 1; |
331 | 0 | if (do_sign(sm + 1, sigbuf, sigbuflen, m, mlen, sk) < 0) { |
332 | 0 | return -1; |
333 | 0 | } |
334 | 0 | sm[0] = 0x30 + 9; |
335 | 0 | sigbuflen ++; |
336 | 0 | *smlen = mlen + NONCELEN + sigbuflen; |
337 | 0 | return 0; |
338 | 0 | } |
339 | | |
340 | | /* see api.h */ |
341 | | int |
342 | | PQCLEAN_FALCONPADDED512_CLEAN_crypto_sign_open( |
343 | | uint8_t *m, size_t *mlen, |
344 | 0 | const uint8_t *sm, size_t smlen, const uint8_t *pk) { |
345 | 0 | const uint8_t *sigbuf; |
346 | 0 | size_t pmlen, sigbuflen; |
347 | |
|
348 | 0 | if (smlen < PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_BYTES) { |
349 | 0 | return -1; |
350 | 0 | } |
351 | 0 | sigbuflen = PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_BYTES - NONCELEN - 1; |
352 | 0 | pmlen = smlen - PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_BYTES; |
353 | 0 | if (sm[0] != 0x30 + 9) { |
354 | 0 | return -1; |
355 | 0 | } |
356 | 0 | sigbuf = sm + 1 + NONCELEN; |
357 | | |
358 | | /* |
359 | | * The one-byte signature header has been verified. Nonce is at sm+1 |
360 | | * followed by the signature (pointed to by sigbuf). The message |
361 | | * follows the signature value. |
362 | | */ |
363 | 0 | if (do_verify(sm + 1, sigbuf, sigbuflen, |
364 | 0 | sm + PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_BYTES, pmlen, pk) < 0) { |
365 | 0 | return -1; |
366 | 0 | } |
367 | | |
368 | | /* |
369 | | * Signature is correct, we just have to copy/move the message |
370 | | * to its final destination. The memmove() properly handles |
371 | | * overlaps. |
372 | | */ |
373 | 0 | memmove(m, sm + PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_BYTES, pmlen); |
374 | 0 | *mlen = pmlen; |
375 | 0 | return 0; |
376 | 0 | } |