/src/liboqs/src/sig/falcon/pqclean_falcon-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 | 136 | #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 | | * |
33 | | * message + signature: |
34 | | * signature length (2 bytes, big-endian) |
35 | | * nonce 40 bytes |
36 | | * message |
37 | | * header byte: 0010nnnn |
38 | | * value compressed format |
39 | | * (signature length is 1+len(value), not counting the nonce) |
40 | | */ |
41 | | |
42 | | /* see api.h */ |
43 | | int |
44 | | PQCLEAN_FALCON512_CLEAN_crypto_sign_keypair( |
45 | 0 | uint8_t *pk, uint8_t *sk) { |
46 | 0 | union { |
47 | 0 | uint8_t b[FALCON_KEYGEN_TEMP_9]; |
48 | 0 | uint64_t dummy_u64; |
49 | 0 | fpr dummy_fpr; |
50 | 0 | } tmp; |
51 | 0 | int8_t f[512], g[512], F[512]; |
52 | 0 | uint16_t h[512]; |
53 | 0 | unsigned char seed[48]; |
54 | 0 | inner_shake256_context rng; |
55 | 0 | size_t u, v; |
56 | | |
57 | | /* |
58 | | * Generate key pair. |
59 | | */ |
60 | 0 | randombytes(seed, sizeof seed); |
61 | 0 | inner_shake256_init(&rng); |
62 | 0 | inner_shake256_inject(&rng, seed, sizeof seed); |
63 | 0 | inner_shake256_flip(&rng); |
64 | 0 | PQCLEAN_FALCON512_CLEAN_keygen(&rng, f, g, F, NULL, h, 9, tmp.b); |
65 | 0 | inner_shake256_ctx_release(&rng); |
66 | | |
67 | | /* |
68 | | * Encode private key. |
69 | | */ |
70 | 0 | sk[0] = 0x50 + 9; |
71 | 0 | u = 1; |
72 | 0 | v = PQCLEAN_FALCON512_CLEAN_trim_i8_encode( |
73 | 0 | sk + u, PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES - u, |
74 | 0 | f, 9, PQCLEAN_FALCON512_CLEAN_max_fg_bits[9]); |
75 | 0 | if (v == 0) { |
76 | 0 | return -1; |
77 | 0 | } |
78 | 0 | u += v; |
79 | 0 | v = PQCLEAN_FALCON512_CLEAN_trim_i8_encode( |
80 | 0 | sk + u, PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES - u, |
81 | 0 | g, 9, PQCLEAN_FALCON512_CLEAN_max_fg_bits[9]); |
82 | 0 | if (v == 0) { |
83 | 0 | return -1; |
84 | 0 | } |
85 | 0 | u += v; |
86 | 0 | v = PQCLEAN_FALCON512_CLEAN_trim_i8_encode( |
87 | 0 | sk + u, PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES - u, |
88 | 0 | F, 9, PQCLEAN_FALCON512_CLEAN_max_FG_bits[9]); |
89 | 0 | if (v == 0) { |
90 | 0 | return -1; |
91 | 0 | } |
92 | 0 | u += v; |
93 | 0 | if (u != PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES) { |
94 | 0 | return -1; |
95 | 0 | } |
96 | | |
97 | | /* |
98 | | * Encode public key. |
99 | | */ |
100 | 0 | pk[0] = 0x00 + 9; |
101 | 0 | v = PQCLEAN_FALCON512_CLEAN_modq_encode( |
102 | 0 | pk + 1, PQCLEAN_FALCON512_CLEAN_CRYPTO_PUBLICKEYBYTES - 1, |
103 | 0 | h, 9); |
104 | 0 | if (v != PQCLEAN_FALCON512_CLEAN_CRYPTO_PUBLICKEYBYTES - 1) { |
105 | 0 | return -1; |
106 | 0 | } |
107 | | |
108 | 0 | return 0; |
109 | 0 | } |
110 | | |
111 | | /* |
112 | | * Compute the signature. nonce[] receives the nonce and must have length |
113 | | * NONCELEN bytes. sigbuf[] receives the signature value (without nonce |
114 | | * or header byte), with *sigbuflen providing the maximum value length and |
115 | | * receiving the actual value length. |
116 | | * |
117 | | * If a signature could be computed but not encoded because it would |
118 | | * exceed the output buffer size, then an error is returned. |
119 | | * |
120 | | * Return value: 0 on success, -1 on error. |
121 | | */ |
122 | | static int |
123 | | do_sign(uint8_t *nonce, uint8_t *sigbuf, size_t *sigbuflen, |
124 | 66 | const uint8_t *m, size_t mlen, const uint8_t *sk) { |
125 | 66 | union { |
126 | 66 | uint8_t b[72 * 512]; |
127 | 66 | uint64_t dummy_u64; |
128 | 66 | fpr dummy_fpr; |
129 | 66 | } tmp; |
130 | 66 | int8_t f[512], g[512], F[512], G[512]; |
131 | 66 | struct { |
132 | 66 | int16_t sig[512]; |
133 | 66 | uint16_t hm[512]; |
134 | 66 | } r; |
135 | 66 | unsigned char seed[48]; |
136 | 66 | inner_shake256_context sc; |
137 | 66 | size_t u, v; |
138 | | |
139 | | /* |
140 | | * Decode the private key. |
141 | | */ |
142 | 66 | if (sk[0] != 0x50 + 9) { |
143 | 0 | return -1; |
144 | 0 | } |
145 | 66 | u = 1; |
146 | 66 | v = PQCLEAN_FALCON512_CLEAN_trim_i8_decode( |
147 | 66 | f, 9, PQCLEAN_FALCON512_CLEAN_max_fg_bits[9], |
148 | 66 | sk + u, PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES - u); |
149 | 66 | if (v == 0) { |
150 | 0 | return -1; |
151 | 0 | } |
152 | 66 | u += v; |
153 | 66 | v = PQCLEAN_FALCON512_CLEAN_trim_i8_decode( |
154 | 66 | g, 9, PQCLEAN_FALCON512_CLEAN_max_fg_bits[9], |
155 | 66 | sk + u, PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES - u); |
156 | 66 | if (v == 0) { |
157 | 0 | return -1; |
158 | 0 | } |
159 | 66 | u += v; |
160 | 66 | v = PQCLEAN_FALCON512_CLEAN_trim_i8_decode( |
161 | 66 | F, 9, PQCLEAN_FALCON512_CLEAN_max_FG_bits[9], |
162 | 66 | sk + u, PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES - u); |
163 | 66 | if (v == 0) { |
164 | 0 | return -1; |
165 | 0 | } |
166 | 66 | u += v; |
167 | 66 | if (u != PQCLEAN_FALCON512_CLEAN_CRYPTO_SECRETKEYBYTES) { |
168 | 0 | return -1; |
169 | 0 | } |
170 | 66 | if (!PQCLEAN_FALCON512_CLEAN_complete_private(G, f, g, F, 9, tmp.b)) { |
171 | 0 | return -1; |
172 | 0 | } |
173 | | |
174 | | /* |
175 | | * Create a random nonce (40 bytes). |
176 | | */ |
177 | 66 | randombytes(nonce, NONCELEN); |
178 | | |
179 | | /* |
180 | | * Hash message nonce + message into a vector. |
181 | | */ |
182 | 66 | inner_shake256_init(&sc); |
183 | 66 | inner_shake256_inject(&sc, nonce, NONCELEN); |
184 | 66 | inner_shake256_inject(&sc, m, mlen); |
185 | 66 | inner_shake256_flip(&sc); |
186 | 66 | PQCLEAN_FALCON512_CLEAN_hash_to_point_ct(&sc, r.hm, 9, tmp.b); |
187 | 66 | inner_shake256_ctx_release(&sc); |
188 | | |
189 | | /* |
190 | | * Initialize a RNG. |
191 | | */ |
192 | 66 | randombytes(seed, sizeof seed); |
193 | 66 | inner_shake256_init(&sc); |
194 | 66 | inner_shake256_inject(&sc, seed, sizeof seed); |
195 | 66 | inner_shake256_flip(&sc); |
196 | | |
197 | | /* |
198 | | * Compute and return the signature. |
199 | | */ |
200 | 66 | PQCLEAN_FALCON512_CLEAN_sign_dyn(r.sig, &sc, f, g, F, G, r.hm, 9, tmp.b); |
201 | 66 | v = PQCLEAN_FALCON512_CLEAN_comp_encode(sigbuf, *sigbuflen, r.sig, 9); |
202 | 66 | if (v != 0) { |
203 | 66 | inner_shake256_ctx_release(&sc); |
204 | 66 | *sigbuflen = v; |
205 | 66 | return 0; |
206 | 66 | } |
207 | 0 | return -1; |
208 | 66 | } |
209 | | |
210 | | /* |
211 | | * Verify a sigature. The nonce has size NONCELEN bytes. sigbuf[] |
212 | | * (of size sigbuflen) contains the signature value, not including the |
213 | | * header byte or nonce. Return value is 0 on success, -1 on error. |
214 | | */ |
215 | | static int |
216 | | do_verify( |
217 | | const uint8_t *nonce, const uint8_t *sigbuf, size_t sigbuflen, |
218 | 136 | const uint8_t *m, size_t mlen, const uint8_t *pk) { |
219 | 136 | union { |
220 | 136 | uint8_t b[2 * 512]; |
221 | 136 | uint64_t dummy_u64; |
222 | 136 | fpr dummy_fpr; |
223 | 136 | } tmp; |
224 | 136 | uint16_t h[512], hm[512]; |
225 | 136 | int16_t sig[512]; |
226 | 136 | inner_shake256_context sc; |
227 | 136 | size_t v; |
228 | | |
229 | | /* |
230 | | * Decode public key. |
231 | | */ |
232 | 136 | if (pk[0] != 0x00 + 9) { |
233 | 0 | return -1; |
234 | 0 | } |
235 | 136 | if (PQCLEAN_FALCON512_CLEAN_modq_decode(h, 9, |
236 | 136 | pk + 1, PQCLEAN_FALCON512_CLEAN_CRYPTO_PUBLICKEYBYTES - 1) |
237 | 136 | != PQCLEAN_FALCON512_CLEAN_CRYPTO_PUBLICKEYBYTES - 1) { |
238 | 0 | return -1; |
239 | 0 | } |
240 | 136 | PQCLEAN_FALCON512_CLEAN_to_ntt_monty(h, 9); |
241 | | |
242 | | /* |
243 | | * Decode signature. |
244 | | */ |
245 | 136 | if (sigbuflen == 0) { |
246 | 0 | return -1; |
247 | 0 | } |
248 | | |
249 | 136 | v = PQCLEAN_FALCON512_CLEAN_comp_decode(sig, 9, sigbuf, sigbuflen); |
250 | 136 | if (v == 0) { |
251 | 0 | return -1; |
252 | 0 | } |
253 | 136 | if (v != sigbuflen) { |
254 | 70 | if (sigbuflen == PQCLEAN_FALCONPADDED512_CLEAN_CRYPTO_BYTES - NONCELEN - 1) { |
255 | 742 | while (v < sigbuflen) { |
256 | 672 | if (sigbuf[v++] != 0) { |
257 | 0 | return -1; |
258 | 0 | } |
259 | 672 | } |
260 | 70 | } else { |
261 | 0 | return -1; |
262 | 0 | } |
263 | 70 | } |
264 | | |
265 | | /* |
266 | | * Hash nonce + message into a vector. |
267 | | */ |
268 | 136 | inner_shake256_init(&sc); |
269 | 136 | inner_shake256_inject(&sc, nonce, NONCELEN); |
270 | 136 | inner_shake256_inject(&sc, m, mlen); |
271 | 136 | inner_shake256_flip(&sc); |
272 | 136 | PQCLEAN_FALCON512_CLEAN_hash_to_point_ct(&sc, hm, 9, tmp.b); |
273 | 136 | inner_shake256_ctx_release(&sc); |
274 | | |
275 | | /* |
276 | | * Verify signature. |
277 | | */ |
278 | 136 | if (!PQCLEAN_FALCON512_CLEAN_verify_raw(hm, sig, h, 9, tmp.b)) { |
279 | 0 | return -1; |
280 | 0 | } |
281 | 136 | return 0; |
282 | 136 | } |
283 | | |
284 | | /* see api.h */ |
285 | | int |
286 | | PQCLEAN_FALCON512_CLEAN_crypto_sign_signature( |
287 | | uint8_t *sig, size_t *siglen, |
288 | 0 | const uint8_t *m, size_t mlen, const uint8_t *sk) { |
289 | 0 | size_t vlen; |
290 | |
|
291 | 0 | vlen = PQCLEAN_FALCON512_CLEAN_CRYPTO_BYTES - NONCELEN - 1; |
292 | 0 | if (do_sign(sig + 1, sig + 1 + NONCELEN, &vlen, m, mlen, sk) < 0) { |
293 | 0 | return -1; |
294 | 0 | } |
295 | 0 | sig[0] = 0x30 + 9; |
296 | 0 | *siglen = 1 + NONCELEN + vlen; |
297 | 0 | return 0; |
298 | 0 | } |
299 | | |
300 | | /* see api.h */ |
301 | | int |
302 | | PQCLEAN_FALCON512_CLEAN_crypto_sign_verify( |
303 | | const uint8_t *sig, size_t siglen, |
304 | 0 | const uint8_t *m, size_t mlen, const uint8_t *pk) { |
305 | 0 | if (siglen < 1 + NONCELEN) { |
306 | 0 | return -1; |
307 | 0 | } |
308 | 0 | if (sig[0] != 0x30 + 9) { |
309 | 0 | return -1; |
310 | 0 | } |
311 | 0 | return do_verify(sig + 1, |
312 | 0 | sig + 1 + NONCELEN, siglen - 1 - NONCELEN, m, mlen, pk); |
313 | 0 | } |
314 | | |
315 | | /* see api.h */ |
316 | | int |
317 | | PQCLEAN_FALCON512_CLEAN_crypto_sign( |
318 | | uint8_t *sm, size_t *smlen, |
319 | 0 | const uint8_t *m, size_t mlen, const uint8_t *sk) { |
320 | 0 | uint8_t *pm, *sigbuf; |
321 | 0 | size_t sigbuflen; |
322 | | |
323 | | /* |
324 | | * Move the message to its final location; this is a memmove() so |
325 | | * it handles overlaps properly. |
326 | | */ |
327 | 0 | memmove(sm + 2 + NONCELEN, m, mlen); |
328 | 0 | pm = sm + 2 + NONCELEN; |
329 | 0 | sigbuf = pm + 1 + mlen; |
330 | 0 | sigbuflen = PQCLEAN_FALCON512_CLEAN_CRYPTO_BYTES - NONCELEN - 3; |
331 | 0 | if (do_sign(sm + 2, sigbuf, &sigbuflen, pm, mlen, sk) < 0) { |
332 | 0 | return -1; |
333 | 0 | } |
334 | 0 | pm[mlen] = 0x20 + 9; |
335 | 0 | sigbuflen ++; |
336 | 0 | sm[0] = (uint8_t)(sigbuflen >> 8); |
337 | 0 | sm[1] = (uint8_t)sigbuflen; |
338 | 0 | *smlen = mlen + 2 + NONCELEN + sigbuflen; |
339 | 0 | return 0; |
340 | 0 | } |
341 | | |
342 | | /* see api.h */ |
343 | | int |
344 | | PQCLEAN_FALCON512_CLEAN_crypto_sign_open( |
345 | | uint8_t *m, size_t *mlen, |
346 | 0 | const uint8_t *sm, size_t smlen, const uint8_t *pk) { |
347 | 0 | const uint8_t *sigbuf; |
348 | 0 | size_t pmlen, sigbuflen; |
349 | |
|
350 | 0 | if (smlen < 3 + NONCELEN) { |
351 | 0 | return -1; |
352 | 0 | } |
353 | 0 | sigbuflen = ((size_t)sm[0] << 8) | (size_t)sm[1]; |
354 | 0 | if (sigbuflen < 2 || sigbuflen > (smlen - NONCELEN - 2)) { |
355 | 0 | return -1; |
356 | 0 | } |
357 | 0 | sigbuflen --; |
358 | 0 | pmlen = smlen - NONCELEN - 3 - sigbuflen; |
359 | 0 | if (sm[2 + NONCELEN + pmlen] != 0x20 + 9) { |
360 | 0 | return -1; |
361 | 0 | } |
362 | 0 | sigbuf = sm + 2 + NONCELEN + pmlen + 1; |
363 | | |
364 | | /* |
365 | | * The 2-byte length header and the one-byte signature header |
366 | | * have been verified. Nonce is at sm+2, followed by the message |
367 | | * itself. Message length is in pmlen. sigbuf/sigbuflen point to |
368 | | * the signature value (excluding the header byte). |
369 | | */ |
370 | 0 | if (do_verify(sm + 2, sigbuf, sigbuflen, |
371 | 0 | sm + 2 + NONCELEN, pmlen, pk) < 0) { |
372 | 0 | return -1; |
373 | 0 | } |
374 | | |
375 | | /* |
376 | | * Signature is correct, we just have to copy/move the message |
377 | | * to its final destination. The memmove() properly handles |
378 | | * overlaps. |
379 | | */ |
380 | 0 | memmove(m, sm + 2 + NONCELEN, pmlen); |
381 | 0 | *mlen = pmlen; |
382 | 0 | return 0; |
383 | 0 | } |