Coverage Report

Created: 2026-01-16 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}