18#define MK_POLYBYTES 384
19#define MK_QINV (-3327)
22static const int16_t mk_zetas[128] = {
23 -1044, -758, -359, -1517, 1493, 1422, 287, 202, -171, 622, 1577, 182, 962, -1202, -1474, 1468,
24 573, -1325, 264, 383, -829, 1458, -1602, -130, -681, 1017, 732, 608, -1542, 411, -205, -1571,
25 1223, 652, -552, 1015, -1293, 1491, -282, -1544, 516, -8, -320, -666, -1618, -1162, 126, 1469,
26 -853, -90, -271, 830, 107, -1421, -247, -951, -398, 961, -1508, -725, 448, -1065, 677, -1275,
27 -1103, 430, 555, 843, -1251, 871, 1550, 105, 422, 587, 177, -235, -291, -460, 1574, 1653,
28 -246, 778, 1159, -147, -777, 1483, -602, 1119, -1590, 644, -872, 349, 418, 329, -156, -75,
29 817, 1097, 603, 610, 1322, -1285, -1465, 384, -1215, -136, 1218, -1335, -874, 220, -1187, -1659,
30 -1185, -1530, -1278, 794, -1510, -854, -870, 478, -108, -308, 996, 991, 958, -1460, 1522, 1628};
33static int16_t mont_reduce(int32_t a)
35 int16_t t = (int16_t)((int16_t)a * (int16_t)MK_QINV);
36 t = (int16_t)((a - (int32_t)t * MK_Q) >> 16);
40static inline int16_t fqmul(int16_t a, int16_t b)
42 return mont_reduce((int32_t)a * b);
46static int16_t barrett_reduce(int16_t a)
48 const int16_t v = 20159;
49 int16_t t = (int16_t)(((int32_t)v * a + (1 << 25)) >> 26);
50 t = (int16_t)(t * MK_Q);
51 return (int16_t)(a - t);
55static void ntt(int16_t r[MK_N])
58 for (
unsigned len = 128; len >= 2; len >>= 1)
60 for (
unsigned start = 0; start < MK_N; start += (len << 1))
62 int16_t zeta = mk_zetas[k++];
63 for (
unsigned j = start; j < start + len; j++)
65 int16_t t = fqmul(zeta, r[j + len]);
66 r[j + len] = (int16_t)(r[j] - t);
67 r[j] = (int16_t)(r[j] + t);
74static void invntt(int16_t r[MK_N])
76 const int16_t f = 1441;
78 for (
unsigned len = 2; len <= 128; len <<= 1)
80 for (
unsigned start = 0; start < MK_N; start += (len << 1))
82 int16_t zeta = mk_zetas[k--];
83 for (
unsigned j = start; j < start + len; j++)
86 r[j] = barrett_reduce((int16_t)(t + r[j + len]));
87 r[j + len] = (int16_t)(r[j + len] - t);
88 r[j + len] = fqmul(zeta, r[j + len]);
92 for (
unsigned j = 0; j < MK_N; j++)
94 r[j] = fqmul(r[j], f);
99static void basemul(int16_t r[2],
const int16_t a[2],
const int16_t b[2], int16_t zeta)
101 r[0] = fqmul(a[1], b[1]);
102 r[0] = fqmul(r[0], zeta);
103 r[0] = (int16_t)(r[0] + fqmul(a[0], b[0]));
104 r[1] = fqmul(a[0], b[1]);
105 r[1] = (int16_t)(r[1] + fqmul(a[1], b[0]));
108static void poly_basemul(int16_t r[MK_N],
const int16_t a[MK_N],
const int16_t b[MK_N])
110 for (
unsigned i = 0; i < MK_N / 4; i++)
112 basemul(&r[4 * i], &a[4 * i], &b[4 * i], mk_zetas[64 + i]);
113 basemul(&r[4 * i + 2], &a[4 * i + 2], &b[4 * i + 2], (int16_t)(-mk_zetas[64 + i]));
118static void polyvec_basemul_acc(int16_t r[MK_N],
const int16_t a[MK_K][MK_N],
const int16_t b[MK_K][MK_N])
121 poly_basemul(r, a[0], b[0]);
122 for (
unsigned i = 1; i < MK_K; i++)
124 poly_basemul(t, a[i], b[i]);
125 for (
unsigned j = 0; j < MK_N; j++)
127 r[j] = (int16_t)(r[j] + t[j]);
130 for (
unsigned j = 0; j < MK_N; j++)
132 r[j] = barrett_reduce(r[j]);
137static void poly_frombytes(int16_t r[MK_N],
const uint8_t a[MK_POLYBYTES])
139 for (
unsigned i = 0; i < MK_N / 2; i++)
141 r[2 * i] = (int16_t)(((a[3 * i + 0] >> 0) | ((uint16_t)a[3 * i + 1] << 8)) & 0xFFF);
142 r[2 * i + 1] = (int16_t)(((a[3 * i + 1] >> 4) | ((uint16_t)a[3 * i + 2] << 4)) & 0xFFF);
147static void poly_frommsg(int16_t r[MK_N],
const uint8_t msg[32])
149 for (
unsigned i = 0; i < 32; i++)
151 for (
unsigned j = 0; j < 8; j++)
153 int16_t
mask = (int16_t)(-(int16_t)((msg[i] >> j) & 1));
154 r[8 * i + j] = (int16_t)(mask & ((MK_Q + 1) / 2));
159static inline uint32_t load32_le(
const uint8_t *x)
161 return (uint32_t)x[0] | ((uint32_t)x[1] << 8) | ((uint32_t)x[2] << 16) | ((uint32_t)x[3] << 24);
165static void cbd2(int16_t r[MK_N],
const uint8_t buf[128])
167 for (
unsigned i = 0; i < MK_N / 8; i++)
169 uint32_t t = load32_le(buf + 4 * i);
170 uint32_t d = t & 0x55555555u;
171 d += (t >> 1) & 0x55555555u;
172 for (
unsigned j = 0; j < 8; j++)
174 int16_t a = (int16_t)((d >> (4 * j)) & 0x3);
175 int16_t b = (int16_t)((d >> (4 * j + 2)) & 0x3);
176 r[8 * i + j] = (int16_t)(a - b);
182static void poly_getnoise(int16_t r[MK_N],
const uint8_t seed[32], uint8_t nonce)
185 memcpy(extseed, seed, 32);
187 uint8_t buf[MK_ETA * MK_N / 4];
188 shake256(buf,
sizeof(buf), extseed,
sizeof(extseed));
193static void gen_matrix_entry(int16_t out[MK_N],
const uint8_t rho[32], uint8_t i, uint8_t j)
196 memcpy(seed, rho, 32);
200 pc_shake128_absorb(&ctx, seed,
sizeof(seed));
205 uint8_t buf[KECCAK_RATE_SHAKE128];
206 pc_keccak_squeeze(&ctx, buf,
sizeof(buf));
207 for (
unsigned p = 0; p + 3 <=
sizeof(buf) && count < MK_N; p += 3)
209 uint16_t d1 = (uint16_t)(buf[p] | ((uint16_t)(buf[p + 1] & 0xF) << 8));
210 uint16_t d2 = (uint16_t)((buf[p + 1] >> 4) | ((uint16_t)buf[p + 2] << 4));
213 out[count++] = (int16_t)d1;
215 if (count < MK_N && d2 < MK_Q)
217 out[count++] = (int16_t)d2;
224static void poly_compress10(uint8_t r[320],
const int16_t a[MK_N])
227 for (
unsigned i = 0; i < MK_N / 4; i++)
230 for (
unsigned j = 0; j < 4; j++)
232 int16_t u = a[4 * i + j];
233 u = (int16_t)(u + ((u >> 15) & MK_Q));
234 t[j] = (uint16_t)(((((uint32_t)u << 10) + MK_Q / 2) / MK_Q) & 0x3FF);
236 r[k + 0] = (uint8_t)(t[0]);
237 r[k + 1] = (uint8_t)((t[0] >> 8) | (t[1] << 2));
238 r[k + 2] = (uint8_t)((t[1] >> 6) | (t[2] << 4));
239 r[k + 3] = (uint8_t)((t[2] >> 4) | (t[3] << 6));
240 r[k + 4] = (uint8_t)(t[3] >> 2);
246static void poly_compress4(uint8_t r[128],
const int16_t a[MK_N])
248 for (
unsigned i = 0; i < MK_N / 8; i++)
251 for (
unsigned j = 0; j < 8; j++)
253 int16_t u = a[8 * i + j];
254 u = (int16_t)(u + ((u >> 15) & MK_Q));
255 t[j] = (uint8_t)(((((uint16_t)u << 4) + MK_Q / 2) / MK_Q) & 15);
257 r[4 * i + 0] = (uint8_t)(t[0] | (t[1] << 4));
258 r[4 * i + 1] = (uint8_t)(t[2] | (t[3] << 4));
259 r[4 * i + 2] = (uint8_t)(t[4] | (t[5] << 4));
260 r[4 * i + 3] = (uint8_t)(t[6] | (t[7] << 4));
265static bool check_ek(
const uint8_t ek[MLKEM768_EK_BYTES])
267 for (
unsigned i = 0; i < MK_K; i++)
270 poly_frombytes(p, ek + i * MK_POLYBYTES);
271 for (
unsigned j = 0; j < MK_N; j++)
273 if ((uint16_t)p[j] >= MK_Q)
283static void k_pke_encrypt(uint8_t ct[MLKEM768_CT_BYTES],
const uint8_t ek[MLKEM768_EK_BYTES],
const uint8_t m[32],
284 const uint8_t coins[32])
286 int16_t that[MK_K][MK_N];
287 for (
unsigned i = 0; i < MK_K; i++)
289 poly_frombytes(that[i], ek + i * MK_POLYBYTES);
291 const uint8_t *rho = ek + MK_K * MK_POLYBYTES;
293 int16_t sp[MK_K][MK_N];
294 for (
unsigned i = 0; i < MK_K; i++)
296 poly_getnoise(sp[i], coins, (uint8_t)i);
301 for (
unsigned i = 0; i < MK_K; i++)
303 int16_t at_row[MK_K][MK_N];
304 for (
unsigned j = 0; j < MK_K; j++)
306 gen_matrix_entry(at_row[j], rho, (uint8_t)i, (uint8_t)j);
309 polyvec_basemul_acc(u_row, at_row, sp);
312 poly_getnoise(e1, coins, (uint8_t)(MK_K + i));
313 for (
unsigned x = 0; x < MK_N; x++)
315 u_row[x] = barrett_reduce((int16_t)(u_row[x] + e1[x]));
317 poly_compress10(ct + i * 320, u_row);
322 polyvec_basemul_acc(v, that, sp);
325 poly_getnoise(e2, coins, (uint8_t)(2 * MK_K));
328 for (
unsigned x = 0; x < MK_N; x++)
330 v[x] = barrett_reduce((int16_t)(v[x] + e2[x] + mu[x]));
332 poly_compress4(ct + MK_K * 320, v);
335bool pc_mlkem768_encaps(
const uint8_t ek[MLKEM768_EK_BYTES],
const uint8_t m[MLKEM768_MSG_BYTES],
336 uint8_t ct[MLKEM768_CT_BYTES], uint8_t ss[MLKEM768_SS_BYTES])
346 sha3_256(g_in + 32, ek, MLKEM768_EK_BYTES);
348 sha3_512(g_out, g_in,
sizeof(g_in));
349 memcpy(ss, g_out, 32);
351 k_pke_encrypt(ct, ek, m, g_out + 32);
362static void poly_tobytes(uint8_t r[MK_POLYBYTES],
const int16_t a[MK_N])
364 for (
unsigned i = 0; i < MK_N / 2; i++)
366 uint16_t t0 = (uint16_t)(a[2 * i] + ((a[2 * i] >> 15) & MK_Q));
367 uint16_t t1 = (uint16_t)(a[2 * i + 1] + ((a[2 * i + 1] >> 15) & MK_Q));
368 r[3 * i + 0] = (uint8_t)(t0);
369 r[3 * i + 1] = (uint8_t)((t0 >> 8) | (t1 << 4));
370 r[3 * i + 2] = (uint8_t)(t1 >> 4);
375static void poly_decompress10(int16_t r[MK_N],
const uint8_t a[320])
378 for (
unsigned i = 0; i < MK_N / 4; i++)
381 t[0] = (uint16_t)((a[k + 0] | ((uint16_t)a[k + 1] << 8)) & 0x3FF);
382 t[1] = (uint16_t)(((a[k + 1] >> 2) | ((uint16_t)a[k + 2] << 6)) & 0x3FF);
383 t[2] = (uint16_t)(((a[k + 2] >> 4) | ((uint16_t)a[k + 3] << 4)) & 0x3FF);
384 t[3] = (uint16_t)(((a[k + 3] >> 6) | ((uint16_t)a[k + 4] << 2)) & 0x3FF);
386 for (
unsigned j = 0; j < 4; j++)
388 r[4 * i + j] = (int16_t)(((uint32_t)t[j] * MK_Q + 512) >> 10);
394static void poly_decompress4(int16_t r[MK_N],
const uint8_t a[128])
396 for (
unsigned i = 0; i < MK_N / 2; i++)
399 r[2 * i + 0] = (int16_t)(((uint32_t)(
byte & 0x0F) * MK_Q + 8) >> 4);
400 r[2 * i + 1] = (int16_t)(((uint32_t)(
byte >> 4) * MK_Q + 8) >> 4);
406static void poly_tomsg(uint8_t msg[32],
const int16_t a[MK_N])
408 for (
unsigned i = 0; i < 32; i++)
411 for (
unsigned j = 0; j < 8; j++)
413 int16_t t = a[8 * i + j];
414 t = (int16_t)(t + ((t >> 15) & MK_Q));
415 uint16_t bit = (uint16_t)(((((uint32_t)t << 1) + MK_Q / 2) / MK_Q) & 1);
416 msg[i] |= (uint8_t)(bit << j);
425static void poly_tomont(int16_t r[MK_N])
427 const int16_t f = 1353;
428 for (
unsigned i = 0; i < MK_N; i++)
430 r[i] = mont_reduce((int32_t)r[i] * f);
436static uint8_t ct_diff_mask(
const uint8_t *a,
const uint8_t *b,
size_t n)
439 for (
size_t i = 0; i < n; i++)
441 acc |= (uint32_t)((uint8_t)(a[i] ^ b[i]));
443 uint8_t equal = (uint8_t)(((acc - 1) >> 31) & 1);
444 return (uint8_t)(equal - 1);
450static void k_pke_keygen(uint8_t ek[MLKEM768_EK_BYTES], uint8_t dk_pke[MK_K * MK_POLYBYTES],
const uint8_t d[32])
457 sha3_512(g_out, g_in,
sizeof(g_in));
458 const uint8_t *rho = g_out;
459 const uint8_t *sigma = g_out + 32;
461 int16_t s[MK_K][MK_N];
462 int16_t e[MK_K][MK_N];
464 for (
unsigned i = 0; i < MK_K; i++)
466 poly_getnoise(s[i], sigma, nonce++);
468 for (
unsigned i = 0; i < MK_K; i++)
470 poly_getnoise(e[i], sigma, nonce++);
472 for (
unsigned i = 0; i < MK_K; i++)
476 for (
unsigned x = 0; x < MK_N; x++)
478 s[i][x] = barrett_reduce(s[i][x]);
479 e[i][x] = barrett_reduce(e[i][x]);
483 for (
unsigned i = 0; i < MK_K; i++)
485 int16_t a_row[MK_K][MK_N];
486 for (
unsigned j = 0; j < MK_K; j++)
488 gen_matrix_entry(a_row[j], rho, (uint8_t)j, (uint8_t)i);
491 polyvec_basemul_acc(t_row, a_row, s);
493 for (
unsigned x = 0; x < MK_N; x++)
495 t_row[x] = barrett_reduce((int16_t)(t_row[x] + e[i][x]));
497 poly_tobytes(ek + i * MK_POLYBYTES, t_row);
499 memcpy(ek + MK_K * MK_POLYBYTES, rho, 32);
501 for (
unsigned i = 0; i < MK_K; i++)
503 poly_tobytes(dk_pke + i * MK_POLYBYTES, s[i]);
508static void k_pke_decrypt(uint8_t m[32],
const uint8_t dk_pke[MK_K * MK_POLYBYTES],
const uint8_t ct[MLKEM768_CT_BYTES])
510 int16_t u[MK_K][MK_N];
511 for (
unsigned i = 0; i < MK_K; i++)
513 poly_decompress10(u[i], ct + i * 320);
516 int16_t shat[MK_K][MK_N];
517 for (
unsigned i = 0; i < MK_K; i++)
519 poly_frombytes(shat[i], dk_pke + i * MK_POLYBYTES);
523 polyvec_basemul_acc(w, shat, u);
527 poly_decompress4(v, ct + MK_K * 320);
528 for (
unsigned x = 0; x < MK_N; x++)
530 w[x] = barrett_reduce((int16_t)(v[x] - w[x]));
535void pc_mlkem768_keygen(
const uint8_t d[MLKEM768_D_BYTES],
const uint8_t z[MLKEM768_Z_BYTES],
536 uint8_t ek[MLKEM768_EK_BYTES], uint8_t dk[MLKEM768_DK_BYTES])
539 k_pke_keygen(ek, dk, d);
540 memcpy(dk + MK_K * MK_POLYBYTES, ek, MLKEM768_EK_BYTES);
541 sha3_256(dk + MK_K * MK_POLYBYTES + MLKEM768_EK_BYTES, ek, MLKEM768_EK_BYTES);
542 memcpy(dk + MK_K * MK_POLYBYTES + MLKEM768_EK_BYTES + 32, z, 32);
545void pc_mlkem768_decaps(
const uint8_t dk[MLKEM768_DK_BYTES],
const uint8_t ct[MLKEM768_CT_BYTES],
546 uint8_t ss[MLKEM768_SS_BYTES])
548 const uint8_t *dk_pke = dk;
549 const uint8_t *ek_pke = dk + MK_K * MK_POLYBYTES;
550 const uint8_t *h = ek_pke + MLKEM768_EK_BYTES;
551 const uint8_t *z = h + 32;
555 k_pke_decrypt(mprime, dk_pke, ct);
557 memcpy(g_in, mprime, 32);
558 memcpy(g_in + 32, h, 32);
560 sha3_512(g_out, g_in,
sizeof(g_in));
563 uint8_t jbuf[32 + MLKEM768_CT_BYTES];
565 memcpy(jbuf + 32, ct, MLKEM768_CT_BYTES);
567 shake256(kbar,
sizeof(kbar), jbuf,
sizeof(jbuf));
570 uint8_t ctprime[MLKEM768_CT_BYTES];
571 k_pke_encrypt(ctprime, ek_pke, mprime, g_out + 32);
572 uint8_t diff = ct_diff_mask(ct, ctprime, MLKEM768_CT_BYTES);
573 for (
unsigned i = 0; i < 32; i++)
575 ss[i] = (uint8_t)((g_out[i] & (uint8_t)~diff) | (kbar[i] & diff));
ML-KEM-768 (FIPS 203): Encaps (responder) + KeyGen and Decaps (initiator).
uint32_t mask(uint8_t width)
Mask of width low bits (width 32 handled without a 32-bit shift, which is UB).
Keccak-f[1600] sponge: SHA3-256, SHA3-512, SHAKE128, SHAKE256 (FIPS 202).