6#if DETWS_ENABLE_PQC_KEX
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++)
93 r[j] = fqmul(r[j], f);
97static void basemul(int16_t r[2],
const int16_t a[2],
const int16_t b[2], int16_t zeta)
99 r[0] = fqmul(a[1], b[1]);
100 r[0] = fqmul(r[0], zeta);
101 r[0] = (int16_t)(r[0] + fqmul(a[0], b[0]));
102 r[1] = fqmul(a[0], b[1]);
103 r[1] = (int16_t)(r[1] + fqmul(a[1], b[0]));
106static void poly_basemul(int16_t r[MK_N],
const int16_t a[MK_N],
const int16_t b[MK_N])
108 for (
unsigned i = 0; i < MK_N / 4; i++)
110 basemul(&r[4 * i], &a[4 * i], &b[4 * i], mk_zetas[64 + i]);
111 basemul(&r[4 * i + 2], &a[4 * i + 2], &b[4 * i + 2], (int16_t)(-mk_zetas[64 + i]));
116static 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])
119 poly_basemul(r, a[0], b[0]);
120 for (
unsigned i = 1; i < MK_K; i++)
122 poly_basemul(t, a[i], b[i]);
123 for (
unsigned j = 0; j < MK_N; j++)
124 r[j] = (int16_t)(r[j] + t[j]);
126 for (
unsigned j = 0; j < MK_N; j++)
127 r[j] = barrett_reduce(r[j]);
131static void poly_frombytes(int16_t r[MK_N],
const uint8_t a[MK_POLYBYTES])
133 for (
unsigned i = 0; i < MK_N / 2; i++)
135 r[2 * i] = (int16_t)(((a[3 * i + 0] >> 0) | ((uint16_t)a[3 * i + 1] << 8)) & 0xFFF);
136 r[2 * i + 1] = (int16_t)(((a[3 * i + 1] >> 4) | ((uint16_t)a[3 * i + 2] << 4)) & 0xFFF);
141static void poly_frommsg(int16_t r[MK_N],
const uint8_t msg[32])
143 for (
unsigned i = 0; i < 32; i++)
144 for (
unsigned j = 0; j < 8; j++)
146 int16_t mask = (int16_t)(-(int16_t)((msg[i] >> j) & 1));
147 r[8 * i + j] = (int16_t)(mask & ((MK_Q + 1) / 2));
151static inline uint32_t load32_le(
const uint8_t *x)
153 return (uint32_t)x[0] | ((uint32_t)x[1] << 8) | ((uint32_t)x[2] << 16) | ((uint32_t)x[3] << 24);
157static void cbd2(int16_t r[MK_N],
const uint8_t buf[128])
159 for (
unsigned i = 0; i < MK_N / 8; i++)
161 uint32_t t = load32_le(buf + 4 * i);
162 uint32_t d = t & 0x55555555u;
163 d += (t >> 1) & 0x55555555u;
164 for (
unsigned j = 0; j < 8; j++)
166 int16_t a = (int16_t)((d >> (4 * j)) & 0x3);
167 int16_t b = (int16_t)((d >> (4 * j + 2)) & 0x3);
168 r[8 * i + j] = (int16_t)(a - b);
174static void poly_getnoise(int16_t r[MK_N],
const uint8_t seed[32], uint8_t nonce)
177 memcpy(extseed, seed, 32);
179 uint8_t buf[MK_ETA * MK_N / 4];
180 shake256(buf,
sizeof(buf), extseed,
sizeof(extseed));
185static void gen_matrix_entry(int16_t out[MK_N],
const uint8_t rho[32], uint8_t i, uint8_t j)
188 memcpy(seed, rho, 32);
192 shake128_absorb(&ctx, seed,
sizeof(seed));
197 uint8_t buf[KECCAK_RATE_SHAKE128];
198 keccak_squeeze(&ctx, buf,
sizeof(buf));
199 for (
unsigned p = 0; p + 3 <=
sizeof(buf) && count < MK_N; p += 3)
201 uint16_t d1 = (uint16_t)(buf[p] | ((uint16_t)(buf[p + 1] & 0xF) << 8));
202 uint16_t d2 = (uint16_t)((buf[p + 1] >> 4) | ((uint16_t)buf[p + 2] << 4));
204 out[count++] = (int16_t)d1;
205 if (count < MK_N && d2 < MK_Q)
206 out[count++] = (int16_t)d2;
212static void poly_compress10(uint8_t r[320],
const int16_t a[MK_N])
215 for (
unsigned i = 0; i < MK_N / 4; i++)
218 for (
unsigned j = 0; j < 4; j++)
220 int16_t u = a[4 * i + j];
221 u = (int16_t)(u + ((u >> 15) & MK_Q));
222 t[j] = (uint16_t)(((((uint32_t)u << 10) + MK_Q / 2) / MK_Q) & 0x3FF);
224 r[k + 0] = (uint8_t)(t[0]);
225 r[k + 1] = (uint8_t)((t[0] >> 8) | (t[1] << 2));
226 r[k + 2] = (uint8_t)((t[1] >> 6) | (t[2] << 4));
227 r[k + 3] = (uint8_t)((t[2] >> 4) | (t[3] << 6));
228 r[k + 4] = (uint8_t)(t[3] >> 2);
234static void poly_compress4(uint8_t r[128],
const int16_t a[MK_N])
236 for (
unsigned i = 0; i < MK_N / 8; i++)
239 for (
unsigned j = 0; j < 8; j++)
241 int16_t u = a[8 * i + j];
242 u = (int16_t)(u + ((u >> 15) & MK_Q));
243 t[j] = (uint8_t)(((((uint16_t)u << 4) + MK_Q / 2) / MK_Q) & 15);
245 r[4 * i + 0] = (uint8_t)(t[0] | (t[1] << 4));
246 r[4 * i + 1] = (uint8_t)(t[2] | (t[3] << 4));
247 r[4 * i + 2] = (uint8_t)(t[4] | (t[5] << 4));
248 r[4 * i + 3] = (uint8_t)(t[6] | (t[7] << 4));
253static bool check_ek(
const uint8_t ek[MLKEM768_EK_BYTES])
255 for (
unsigned i = 0; i < MK_K; i++)
258 poly_frombytes(p, ek + i * MK_POLYBYTES);
259 for (
unsigned j = 0; j < MK_N; j++)
260 if ((uint16_t)p[j] >= MK_Q)
267static void k_pke_encrypt(uint8_t ct[MLKEM768_CT_BYTES],
const uint8_t ek[MLKEM768_EK_BYTES],
const uint8_t m[32],
268 const uint8_t coins[32])
270 int16_t that[MK_K][MK_N];
271 for (
unsigned i = 0; i < MK_K; i++)
272 poly_frombytes(that[i], ek + i * MK_POLYBYTES);
273 const uint8_t *rho = ek + MK_K * MK_POLYBYTES;
275 int16_t sp[MK_K][MK_N];
276 for (
unsigned i = 0; i < MK_K; i++)
278 poly_getnoise(sp[i], coins, (uint8_t)i);
283 for (
unsigned i = 0; i < MK_K; i++)
285 int16_t at_row[MK_K][MK_N];
286 for (
unsigned j = 0; j < MK_K; j++)
287 gen_matrix_entry(at_row[j], rho, (uint8_t)i, (uint8_t)j);
289 polyvec_basemul_acc(u_row, at_row, sp);
292 poly_getnoise(e1, coins, (uint8_t)(MK_K + i));
293 for (
unsigned x = 0; x < MK_N; x++)
294 u_row[x] = barrett_reduce((int16_t)(u_row[x] + e1[x]));
295 poly_compress10(ct + i * 320, u_row);
300 polyvec_basemul_acc(v, that, sp);
303 poly_getnoise(e2, coins, (uint8_t)(2 * MK_K));
306 for (
unsigned x = 0; x < MK_N; x++)
307 v[x] = barrett_reduce((int16_t)(v[x] + e2[x] + mu[x]));
308 poly_compress4(ct + MK_K * 320, v);
311bool mlkem768_encaps(
const uint8_t ek[MLKEM768_EK_BYTES],
const uint8_t m[MLKEM768_MSG_BYTES],
312 uint8_t ct[MLKEM768_CT_BYTES], uint8_t ss[MLKEM768_SS_BYTES])
320 sha3_256(g_in + 32, ek, MLKEM768_EK_BYTES);
322 sha3_512(g_out, g_in,
sizeof(g_in));
323 memcpy(ss, g_out, 32);
325 k_pke_encrypt(ct, ek, m, g_out + 32);
ML-KEM-768 encapsulation (FIPS 203), responder side only.
Keccak-f[1600] sponge: SHA3-256, SHA3-512, SHAKE128, SHAKE256 (FIPS 202).