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