Coverage Report

Created: 2025-08-29 07:11

/src/liboqs/src/kem/frodokem/external/kem.c
Line
Count
Source (jump to first uncovered line)
1
/********************************************************************************************
2
* FrodoKEM: Learning with Errors Key Encapsulation
3
*
4
* Abstract: Key Encapsulation Mechanism (KEM) based on Frodo
5
*********************************************************************************************/
6
7
#include <string.h>
8
9
OQS_STATUS crypto_kem_keypair_derand(unsigned char *pk, unsigned char *sk, const unsigned char *seed)
10
0
{
11
0
    (void)pk;
12
0
    (void)sk;
13
0
    (void)seed;
14
0
    return OQS_ERROR;
15
0
}
Unexecuted instantiation: OQS_KEM_frodokem_640_aes_keypair_derand
Unexecuted instantiation: OQS_KEM_frodokem_640_shake_keypair_derand
Unexecuted instantiation: OQS_KEM_frodokem_976_aes_keypair_derand
Unexecuted instantiation: OQS_KEM_frodokem_976_shake_keypair_derand
Unexecuted instantiation: OQS_KEM_frodokem_1344_aes_keypair_derand
Unexecuted instantiation: OQS_KEM_frodokem_1344_shake_keypair_derand
16
17
18
OQS_STATUS crypto_kem_keypair(unsigned char* pk, unsigned char* sk)
19
0
{ // FrodoKEM's key generation
20
  // Outputs: public key pk (               BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 bytes)
21
  //          secret key sk (CRYPTO_BYTES + BYTES_SEED_A + (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8 + 2*PARAMS_N*PARAMS_NBAR + BYTES_PKHASH bytes)
22
0
    uint8_t *pk_seedA = &pk[0];
23
0
    uint8_t *pk_b = &pk[BYTES_SEED_A];
24
0
    uint8_t *sk_s = &sk[0];
25
0
    uint8_t *sk_pk = &sk[CRYPTO_BYTES];
26
0
    uint8_t *sk_S = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
27
0
    uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR];
28
0
    uint16_t B[PARAMS_N*PARAMS_NBAR] = {0};
29
0
    uint16_t S[2*PARAMS_N*PARAMS_NBAR] = {0};               // contains secret data
30
0
    uint16_t *E = (uint16_t *)&S[PARAMS_N*PARAMS_NBAR];     // contains secret data
31
0
    uint8_t randomness[2*CRYPTO_BYTES + BYTES_SEED_A];      // contains secret data via randomness_s and randomness_seedSE
32
0
    uint8_t *randomness_s = &randomness[0];                 // contains secret data
33
0
    uint8_t *randomness_seedSE = &randomness[CRYPTO_BYTES]; // contains secret data
34
0
    uint8_t *randomness_z = &randomness[2*CRYPTO_BYTES];
35
0
    uint8_t shake_input_seedSE[1 + CRYPTO_BYTES];           // contains secret data
36
37
    // Generate the secret value s, the seed for S and E, and the seed for the seed for A. Add seed_A to the public key
38
0
    randombytes(randomness, CRYPTO_BYTES + CRYPTO_BYTES + BYTES_SEED_A);
39
0
    shake(pk_seedA, BYTES_SEED_A, randomness_z, BYTES_SEED_A);
40
41
    // Generate S and E, and compute B = A*S + E. Generate A on-the-fly
42
0
    shake_input_seedSE[0] = 0x5F;
43
0
    memcpy(&shake_input_seedSE[1], randomness_seedSE, CRYPTO_BYTES);
44
0
    shake((uint8_t*)S, 2*PARAMS_N*PARAMS_NBAR*sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
45
0
    for (size_t i = 0; i < 2 * PARAMS_N * PARAMS_NBAR; i++) {
46
0
        S[i] = LE_TO_UINT16(S[i]);
47
0
    }
48
0
    frodo_sample_n(S, PARAMS_N*PARAMS_NBAR);
49
0
    frodo_sample_n(E, PARAMS_N*PARAMS_NBAR);
50
0
    frodo_mul_add_as_plus_e(B, S, E, pk);
51
52
    // Encode the second part of the public key
53
0
    frodo_pack(pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, B, PARAMS_N*PARAMS_NBAR, PARAMS_LOGQ);
54
55
    // Add s, pk and S to the secret key
56
0
    memcpy(sk_s, randomness_s, CRYPTO_BYTES);
57
0
    memcpy(sk_pk, pk, CRYPTO_PUBLICKEYBYTES);
58
0
    for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
59
0
        S[i] = UINT16_TO_LE(S[i]);
60
0
    }
61
0
    memcpy(sk_S, S, 2*PARAMS_N*PARAMS_NBAR);
62
63
    // Add H(pk) to the secret key
64
0
    shake(sk_pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
65
66
    // Cleanup:
67
0
    clear_bytes((uint8_t *)S, PARAMS_N*PARAMS_NBAR*sizeof(uint16_t));
68
0
    clear_bytes((uint8_t *)E, PARAMS_N*PARAMS_NBAR*sizeof(uint16_t));
69
0
    clear_bytes(randomness, 2*CRYPTO_BYTES);
70
0
    clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
71
0
    return OQS_SUCCESS;
72
0
}
Unexecuted instantiation: OQS_KEM_frodokem_640_aes_keypair
Unexecuted instantiation: OQS_KEM_frodokem_640_shake_keypair
Unexecuted instantiation: OQS_KEM_frodokem_976_aes_keypair
Unexecuted instantiation: OQS_KEM_frodokem_976_shake_keypair
Unexecuted instantiation: OQS_KEM_frodokem_1344_aes_keypair
Unexecuted instantiation: OQS_KEM_frodokem_1344_shake_keypair
73
74
75
OQS_STATUS crypto_kem_enc_derand(unsigned char *ct, unsigned char *ss, const unsigned char *pk, const unsigned char *seed)
76
0
{
77
0
    (void)ct;
78
0
    (void)ss;
79
0
    (void)pk;
80
0
    (void)seed;
81
0
    return OQS_ERROR;
82
0
}
Unexecuted instantiation: OQS_KEM_frodokem_640_aes_encaps_derand
Unexecuted instantiation: OQS_KEM_frodokem_640_shake_encaps_derand
Unexecuted instantiation: OQS_KEM_frodokem_976_aes_encaps_derand
Unexecuted instantiation: OQS_KEM_frodokem_976_shake_encaps_derand
Unexecuted instantiation: OQS_KEM_frodokem_1344_aes_encaps_derand
Unexecuted instantiation: OQS_KEM_frodokem_1344_shake_encaps_derand
83
84
85
OQS_STATUS crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk)
86
0
{ // FrodoKEM's key encapsulation
87
0
    const uint8_t *pk_seedA = &pk[0];
88
0
    const uint8_t *pk_b = &pk[BYTES_SEED_A];
89
0
    uint8_t *ct_c1 = &ct[0];
90
0
    uint8_t *ct_c2 = &ct[(PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8];
91
0
    uint16_t B[PARAMS_N*PARAMS_NBAR] = {0};
92
0
    uint16_t V[PARAMS_NBAR*PARAMS_NBAR]= {0};                 // contains secret data
93
0
    uint16_t C[PARAMS_NBAR*PARAMS_NBAR] = {0};
94
0
    ALIGN_HEADER(32) uint16_t Bp[PARAMS_N*PARAMS_NBAR] ALIGN_FOOTER(32) = {0};
95
0
    ALIGN_HEADER(32) uint16_t Sp[(2*PARAMS_N+PARAMS_NBAR)*PARAMS_NBAR] ALIGN_FOOTER(32) = {0};  // contains secret data
96
0
    uint16_t *Ep = (uint16_t *)&Sp[PARAMS_N*PARAMS_NBAR];     // contains secret data
97
0
    uint16_t *Epp = (uint16_t *)&Sp[2*PARAMS_N*PARAMS_NBAR];  // contains secret data
98
0
    uint8_t G2in[BYTES_PKHASH + BYTES_MU];                    // contains secret data via mu
99
0
    uint8_t *pkh = &G2in[0];
100
0
    uint8_t *mu = &G2in[BYTES_PKHASH];                        // contains secret data
101
0
    uint8_t G2out[2*CRYPTO_BYTES];                            // contains secret data
102
0
    uint8_t *seedSE = &G2out[0];                              // contains secret data
103
0
    uint8_t *k = &G2out[CRYPTO_BYTES];                        // contains secret data
104
0
    uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES];       // contains secret data via Fin_k
105
0
    uint8_t *Fin_ct = &Fin[0];
106
0
    uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES];            // contains secret data
107
0
    uint8_t shake_input_seedSE[1 + CRYPTO_BYTES];             // contains secret data
108
109
    // pkh <- G_1(pk), generate random mu, compute (seedSE || k) = G_2(pkh || mu)
110
0
    shake(pkh, BYTES_PKHASH, pk, CRYPTO_PUBLICKEYBYTES);
111
0
    randombytes(mu, BYTES_MU);
112
0
    shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
113
114
    // Generate Sp and Ep, and compute Bp = Sp*A + Ep. Generate A on-the-fly
115
0
    shake_input_seedSE[0] = 0x96;
116
0
    memcpy(&shake_input_seedSE[1], seedSE, CRYPTO_BYTES);
117
0
    shake((uint8_t*)Sp, (2*PARAMS_N+PARAMS_NBAR)*PARAMS_NBAR*sizeof(uint16_t), shake_input_seedSE, 1 + CRYPTO_BYTES);
118
0
    for (size_t i = 0; i < (2 * PARAMS_N + PARAMS_NBAR) * PARAMS_NBAR; i++) {
119
0
        Sp[i] = LE_TO_UINT16(Sp[i]);
120
0
    }
121
0
    frodo_sample_n(Sp, PARAMS_N*PARAMS_NBAR);
122
0
    frodo_sample_n(Ep, PARAMS_N*PARAMS_NBAR);
123
0
    frodo_mul_add_sa_plus_e(Bp, Sp, Ep, pk_seedA);
124
0
    frodo_pack(ct_c1, (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8, Bp, PARAMS_N*PARAMS_NBAR, PARAMS_LOGQ);
125
126
    // Generate Epp, and compute V = Sp*B + Epp
127
0
    frodo_sample_n(Epp, PARAMS_NBAR*PARAMS_NBAR);
128
0
    frodo_unpack(B, PARAMS_N*PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
129
0
    frodo_mul_add_sb_plus_e(V, B, Sp, Epp);
130
131
    // Encode mu, and compute C = V + enc(mu) (mod q)
132
0
    frodo_key_encode(C, (uint16_t*)mu);
133
0
    frodo_add(C, V, C);
134
0
    frodo_pack(ct_c2, (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8, C, PARAMS_NBAR*PARAMS_NBAR, PARAMS_LOGQ);
135
136
    // Compute ss = F(ct||KK)
137
0
    memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
138
0
    memcpy(Fin_k, k, CRYPTO_BYTES);
139
0
    shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
140
141
    // Cleanup:
142
0
    clear_bytes((uint8_t *)V, PARAMS_NBAR*PARAMS_NBAR*sizeof(uint16_t));
143
0
    clear_bytes((uint8_t *)Sp, PARAMS_N*PARAMS_NBAR*sizeof(uint16_t));
144
0
    clear_bytes((uint8_t *)Ep, PARAMS_N*PARAMS_NBAR*sizeof(uint16_t));
145
0
    clear_bytes((uint8_t *)Epp, PARAMS_NBAR*PARAMS_NBAR*sizeof(uint16_t));
146
0
    clear_bytes(mu, BYTES_MU);
147
0
    clear_bytes(G2out, 2*CRYPTO_BYTES);
148
0
    clear_bytes(Fin_k, CRYPTO_BYTES);
149
0
    clear_bytes(shake_input_seedSE, 1 + CRYPTO_BYTES);
150
0
    return OQS_SUCCESS;
151
0
}
Unexecuted instantiation: OQS_KEM_frodokem_640_aes_encaps
Unexecuted instantiation: OQS_KEM_frodokem_640_shake_encaps
Unexecuted instantiation: OQS_KEM_frodokem_976_aes_encaps
Unexecuted instantiation: OQS_KEM_frodokem_976_shake_encaps
Unexecuted instantiation: OQS_KEM_frodokem_1344_aes_encaps
Unexecuted instantiation: OQS_KEM_frodokem_1344_shake_encaps
152
153
154
OQS_STATUS crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk)
155
0
{ // FrodoKEM's key decapsulation
156
0
    uint16_t B[PARAMS_N*PARAMS_NBAR] = {0};
157
0
    uint16_t Bp[PARAMS_N*PARAMS_NBAR] = {0};
158
0
    uint16_t W[PARAMS_NBAR*PARAMS_NBAR] = {0};                // contains secret data
159
0
    uint16_t C[PARAMS_NBAR*PARAMS_NBAR] = {0};
160
0
    uint16_t CC[PARAMS_NBAR*PARAMS_NBAR] = {0};
161
0
    ALIGN_HEADER(32) uint16_t BBp[PARAMS_N*PARAMS_NBAR] ALIGN_FOOTER(32) = {0};
162
0
    ALIGN_HEADER(32) uint16_t Sp[(2*PARAMS_N+PARAMS_NBAR)*PARAMS_NBAR] ALIGN_FOOTER(32) = {0};  // contains secret data
163
0
    uint16_t *Ep = (uint16_t *)&Sp[PARAMS_N*PARAMS_NBAR];     // contains secret data
164
0
    uint16_t *Epp = (uint16_t *)&Sp[2*PARAMS_N*PARAMS_NBAR];  // contains secret data
165
0
    const uint8_t *ct_c1 = &ct[0];
166
0
    const uint8_t *ct_c2 = &ct[(PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8];
167
0
    const uint8_t *sk_s = &sk[0];
168
0
    const uint8_t *sk_pk = &sk[CRYPTO_BYTES];
169
0
    const uint16_t *sk_S = (uint16_t *) &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES];
170
0
    uint16_t S[PARAMS_N * PARAMS_NBAR];                      // contains secret data
171
0
    const uint8_t *sk_pkh = &sk[CRYPTO_BYTES + CRYPTO_PUBLICKEYBYTES + 2*PARAMS_N*PARAMS_NBAR];
172
0
    const uint8_t *pk_seedA = &sk_pk[0];
173
0
    const uint8_t *pk_b = &sk_pk[BYTES_SEED_A];
174
0
    uint8_t G2in[BYTES_PKHASH + BYTES_MU];                   // contains secret data via muprime
175
0
    uint8_t *pkh = &G2in[0];
176
0
    uint8_t *muprime = &G2in[BYTES_PKHASH];                  // contains secret data
177
0
    uint8_t G2out[2*CRYPTO_BYTES];                           // contains secret data
178
0
    uint8_t *seedSEprime = &G2out[0];                        // contains secret data
179
0
    uint8_t *kprime = &G2out[CRYPTO_BYTES];                  // contains secret data
180
0
    uint8_t Fin[CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES];      // contains secret data via Fin_k
181
0
    uint8_t *Fin_ct = &Fin[0];
182
0
    uint8_t *Fin_k = &Fin[CRYPTO_CIPHERTEXTBYTES];           // contains secret data
183
0
    uint8_t shake_input_seedSEprime[1 + CRYPTO_BYTES];       // contains secret data
184
185
0
    for (size_t i = 0; i < PARAMS_N * PARAMS_NBAR; i++) {
186
0
        S[i] = LE_TO_UINT16(sk_S[i]);
187
0
    }
188
189
    // Compute W = C - Bp*S (mod q), and decode the randomness mu
190
0
    frodo_unpack(Bp, PARAMS_N*PARAMS_NBAR, ct_c1, (PARAMS_LOGQ*PARAMS_N*PARAMS_NBAR)/8, PARAMS_LOGQ);
191
0
    frodo_unpack(C, PARAMS_NBAR*PARAMS_NBAR, ct_c2, (PARAMS_LOGQ*PARAMS_NBAR*PARAMS_NBAR)/8, PARAMS_LOGQ);
192
0
    frodo_mul_bs(W, Bp, S);
193
0
    frodo_sub(W, C, W);
194
0
    frodo_key_decode((uint16_t*)muprime, W);
195
196
    // Generate (seedSE' || k') = G_2(pkh || mu')
197
0
    memcpy(pkh, sk_pkh, BYTES_PKHASH);
198
0
    shake(G2out, CRYPTO_BYTES + CRYPTO_BYTES, G2in, BYTES_PKHASH + BYTES_MU);
199
200
    // Generate Sp and Ep, and compute BBp = Sp*A + Ep. Generate A on-the-fly
201
0
    shake_input_seedSEprime[0] = 0x96;
202
0
    memcpy(&shake_input_seedSEprime[1], seedSEprime, CRYPTO_BYTES);
203
0
    shake((uint8_t*)Sp, (2*PARAMS_N+PARAMS_NBAR)*PARAMS_NBAR*sizeof(uint16_t), shake_input_seedSEprime, 1 + CRYPTO_BYTES);
204
0
    for (size_t i = 0; i < (2*PARAMS_N+PARAMS_NBAR)*PARAMS_NBAR; i++) {
205
0
        Sp[i] = LE_TO_UINT16(Sp[i]);
206
0
    }
207
0
    frodo_sample_n(Sp, PARAMS_N*PARAMS_NBAR);
208
0
    frodo_sample_n(Ep, PARAMS_N*PARAMS_NBAR);
209
0
    frodo_mul_add_sa_plus_e(BBp, Sp, Ep, pk_seedA);
210
211
    // Generate Epp, and compute W = Sp*B + Epp
212
0
    frodo_sample_n(Epp, PARAMS_NBAR*PARAMS_NBAR);
213
0
    frodo_unpack(B, PARAMS_N*PARAMS_NBAR, pk_b, CRYPTO_PUBLICKEYBYTES - BYTES_SEED_A, PARAMS_LOGQ);
214
0
    frodo_mul_add_sb_plus_e(W, B, Sp, Epp);
215
216
    // Encode mu, and compute CC = W + enc(mu') (mod q)
217
0
    frodo_key_encode(CC, (uint16_t*)muprime);
218
0
    frodo_add(CC, W, CC);
219
220
    // Prepare input to F
221
0
    memcpy(Fin_ct, ct, CRYPTO_CIPHERTEXTBYTES);
222
223
    // Reducing BBp modulo q
224
0
    for (int i = 0; i < PARAMS_N*PARAMS_NBAR; i++) BBp[i] = BBp[i] & ((1 << PARAMS_LOGQ)-1);
225
226
    // If (Bp == BBp & C == CC) then ss = F(ct || k'), else ss = F(ct || s)
227
    // Needs to avoid branching on secret data as per:
228
    //     Qian Guo, Thomas Johansson, Alexander Nilsson. A key-recovery timing attack on post-quantum 
229
    //     primitives using the Fujisaki-Okamoto transformation and its application on FrodoKEM. In CRYPTO 2020.
230
0
    int8_t selector = ct_verify(Bp, BBp, PARAMS_N*PARAMS_NBAR) | ct_verify(C, CC, PARAMS_NBAR*PARAMS_NBAR);
231
    // If (selector == 0) then load k' to do ss = F(ct || k'), else if (selector == -1) load s to do ss = F(ct || s)
232
0
    ct_select((uint8_t*)Fin_k, (uint8_t*)kprime, (uint8_t*)sk_s, CRYPTO_BYTES, selector);
233
0
    shake(ss, CRYPTO_BYTES, Fin, CRYPTO_CIPHERTEXTBYTES + CRYPTO_BYTES);
234
235
    // Cleanup:
236
0
    clear_bytes((uint8_t *)W, PARAMS_NBAR*PARAMS_NBAR*sizeof(uint16_t));
237
0
    clear_bytes((uint8_t *)Sp, PARAMS_N*PARAMS_NBAR*sizeof(uint16_t));
238
0
    clear_bytes((uint8_t *)S, PARAMS_N*PARAMS_NBAR*sizeof(uint16_t));
239
0
    clear_bytes((uint8_t *)Ep, PARAMS_N*PARAMS_NBAR*sizeof(uint16_t));
240
0
    clear_bytes((uint8_t *)Epp, PARAMS_NBAR*PARAMS_NBAR*sizeof(uint16_t));
241
0
    clear_bytes(muprime, BYTES_MU);
242
0
    clear_bytes(G2out, 2*CRYPTO_BYTES);
243
0
    clear_bytes(Fin_k, CRYPTO_BYTES);
244
0
    clear_bytes(shake_input_seedSEprime, 1 + CRYPTO_BYTES);
245
0
    return OQS_SUCCESS;
246
0
}
Unexecuted instantiation: OQS_KEM_frodokem_640_aes_decaps
Unexecuted instantiation: OQS_KEM_frodokem_640_shake_decaps
Unexecuted instantiation: OQS_KEM_frodokem_976_aes_decaps
Unexecuted instantiation: OQS_KEM_frodokem_976_shake_decaps
Unexecuted instantiation: OQS_KEM_frodokem_1344_aes_decaps
Unexecuted instantiation: OQS_KEM_frodokem_1344_shake_decaps