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-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
}