34#define MLKEM_QINV 62209U
35#define MLKEM_BARRETT_V 20159
36#define MLKEM_BARRETT_SHIFT 26
37#define MLKEM_MONT_FACTOR 1353
38#define MLKEM_INVNTT_SCALE 1441
44#define MLKEM_COMPRESS_CONST_D1 1290168U
45#define MLKEM_COMPRESS_CONST_D4 1290160U
46#define MLKEM_COMPRESS_CONST_D5 1290176U
47#define MLKEM_COMPRESS_CONST_D10_11 \
55 -1044, -758, -359, -1517, 1493, 1422, 287, 202, -171, 622, 1577, 182, 962,
56 -1202, -1474, 1468, 573, -1325, 264, 383, -829, 1458, -1602, -130, -681, 1017,
57 732, 608, -1542, 411, -205, -1571, 1223, 652, -552, 1015, -1293, 1491, -282,
58 -1544, 516, -8, -320, -666, -1618, -1162, 126, 1469, -853, -90, -271, 830,
59 107, -1421, -247, -951, -398, 961, -1508, -725, 448, -1065, 677, -1275, -1103,
60 430, 555, 843, -1251, 871, 1550, 105, 422, 587, 177, -235, -291, -460,
61 1574, 1653, -246, 778, 1159, -147, -777, 1483, -602, 1119, -1590, 644, -872,
62 349, 418, 329, -156, -75, 817, 1097, 603, 610, 1322, -1285, -1465, 384,
63 -1215, -136, 1218, -1335, -874, 220, -1187, -1659, -1185, -1530, -1278, 794, -1510,
64 -854, -870, 478, -108, -308, 996, 991, 958, -1460, 1522, 1628,
69 uint16_t a_lo = (uint16_t) a;
70 int16_t t = (int16_t) ((uint16_t) (a_lo *
MLKEM_QINV));
71 int32_t r = a - ((int32_t) t *
MLKEM_Q);
72 return (int16_t) (r >> 16);
84 return (int16_t) ((int32_t) a - (t *
MLKEM_Q));
89 int16_t mask = (int16_t) (c >> 15);
90 return (int16_t) (c + (mask &
MLKEM_Q));
95 for (uint32_t i = 0U; i <
MLKEM_N; i++) {
102 for (uint32_t i = 0U; i <
MLKEM_N; i++) {
109 for (uint32_t i = 0U; i <
MLKEM_N; i++) {
116 for (uint32_t i = 0U; i <
MLKEM_N; i++) {
126 for (uint32_t len =
MLKEM_N / 2U; len >= 2U; len >>= 1U) {
127 for (uint32_t start = 0U; start <
MLKEM_N; start += 2U * len) {
128 int16_t zeta =
zetas[k++];
129 for (uint32_t j = start; j < (start + len); j++) {
131 r[j + len] = (int16_t) (r[j] - t);
132 r[j] = (int16_t) (r[j] + t);
141 uint32_t k = (
MLKEM_N / 2U) - 1U;
143 for (uint32_t j = 0U; j <
MLKEM_N; j++) {
147 for (uint32_t len = 2U; len <=
MLKEM_N / 2U; len <<= 1U) {
148 for (uint32_t start = 0U; start <
MLKEM_N; start += 2U * len) {
149 int16_t zeta =
zetas[k--];
150 for (uint32_t j = start; j < (start + len); j++) {
161 for (uint32_t i = 0U; i < (
MLKEM_N / 4U); i++) {
168 int32_t t1 = (int32_t) a->
coeffs[4U * i] * b->
coeffs[(4U * i) + 1U];
169 t1 += (int32_t) a->
coeffs[(4U * i) + 1U] * b->
coeffs[4U * i];
181 int16_t neg_zeta = (int16_t) (-zeta);
182 t0 = (int32_t) a->
coeffs[(4U * i) + 3U]
184 t0 += (int32_t) a->
coeffs[(4U * i) + 2U] * b->
coeffs[(4U * i) + 2U];
186 t1 = (int32_t) a->
coeffs[(4U * i) + 2U] * b->
coeffs[(4U * i) + 3U];
187 t1 += (int32_t) a->
coeffs[(4U * i) + 3U] * b->
coeffs[(4U * i) + 2U];
208 for (uint32_t i = 0U; i < (
MLKEM_N / 2U); i++) {
209 uint16_t t0 = (uint16_t) a->
coeffs[2U * i];
210 uint16_t t1 = (uint16_t) a->
coeffs[(2U * i) + 1U];
211 r[(3U * i) + 0U] = (uint8_t) (t0 & 0xFFU);
212 r[(3U * i) + 1U] = (uint8_t) ((t0 >> 8U) | ((t1 << 4U) & 0xF0U));
213 r[(3U * i) + 2U] = (uint8_t) (t1 >> 4U);
219 for (uint32_t i = 0U; i < (
MLKEM_N / 2U); i++) {
220 uint8_t t0 = a[(3U * i) + 0U];
221 uint8_t t1 = a[(3U * i) + 1U];
222 uint8_t t2 = a[(3U * i) + 2U];
223 r->
coeffs[(2U * i) + 0U] = (int16_t) (t0 | (((uint16_t) t1 << 8U) & 0xFFFU));
224 r->
coeffs[(2U * i) + 1U] = (int16_t) ((t1 >> 4U) | ((uint16_t) t2 << 4U));
235 return (uint8_t) ((d0 + ((uint32_t) 1u << 30)) >> 31);
241 return (uint8_t) ((d0 + ((uint32_t) 1u << 27)) >> 28);
246 return (int16_t) ((((uint32_t) u *
MLKEM_Q) + 8) >> 4);
252 return (uint8_t) ((d0 + ((uint32_t) 1u << 26)) >> 27);
257 return (int16_t) ((((uint32_t) u *
MLKEM_Q) + 16) >> 5);
263 d0 = (d0 + ((uint64_t) 1u << 32)) >> 33;
264 return (uint16_t) (d0 & 0x3FF);
269 return (int16_t) ((((uint32_t) u *
MLKEM_Q) + 512) >> 10);
275 d0 = (d0 + ((uint64_t) 1u << 31)) >> 32;
276 return (uint16_t) (d0 & 0x7FF);
281 return (int16_t) ((((uint32_t) u *
MLKEM_Q) + 1024) >> 11);
287 for (uint32_t i = 0U; i < (
MLKEM_N / 8U); i++) {
289 for (uint32_t j = 0U; j < 8U; j++) {
292 r[(i * 4U) + 0U] = (uint8_t) (t[0] | (uint8_t) (t[1] << 4U));
293 r[(i * 4U) + 1U] = (uint8_t) (t[2] | (uint8_t) (t[3] << 4U));
294 r[(i * 4U) + 2U] = (uint8_t) (t[4] | (uint8_t) (t[5] << 4U));
295 r[(i * 4U) + 3U] = (uint8_t) (t[6] | (uint8_t) (t[7] << 4U));
301 for (uint32_t i = 0U; i < (
MLKEM_N / 2U); i++) {
310 for (uint32_t i = 0U; i < (
MLKEM_N / 8U); i++) {
312 for (uint32_t j = 0U; j < 8U; j++) {
315 r[(5U * i) + 0U] = (uint8_t) ((t[0] >> 0) | (t[1] << 5));
316 r[(5U * i) + 1U] = (uint8_t) ((t[1] >> 3) | (t[2] << 2) | (t[3] << 7));
317 r[(5U * i) + 2U] = (uint8_t) ((t[3] >> 1) | (t[4] << 4));
318 r[(5U * i) + 3U] = (uint8_t) ((t[4] >> 4) | (t[5] << 1) | (t[6] << 6));
319 r[(5U * i) + 4U] = (uint8_t) ((t[6] >> 2) | (t[7] << 3));
325 for (uint32_t i = 0U; i < (
MLKEM_N / 8U); i++) {
327 t[0] = (a[5 * i + 0] >> 0) & 0x1F;
328 t[1] = ((a[5 * i + 0] >> 5) | (a[5 * i + 1] << 3)) & 0x1F;
329 t[2] = (a[5 * i + 1] >> 2) & 0x1F;
330 t[3] = ((a[5 * i + 1] >> 7) | (a[5 * i + 2] << 1)) & 0x1F;
331 t[4] = ((a[5 * i + 2] >> 4) | (a[5 * i + 3] << 4)) & 0x1F;
332 t[5] = (a[5 * i + 3] >> 1) & 0x1F;
333 t[6] = ((a[5 * i + 3] >> 6) | (a[5 * i + 4] << 2)) & 0x1F;
334 t[7] = (a[5 * i + 4] >> 3) & 0x1F;
335 for (uint32_t j = 0; j < 8; j++) {
344 for (uint32_t j = 0U; j < (
MLKEM_N / 4U); j++) {
346 for (uint32_t k = 0U; k < 4U; k++) {
349 r[(5U * j) + 0U] = (uint8_t) ((t[0] >> 0U) & 0xFFU);
350 r[(5U * j) + 1U] = (uint8_t) ((t[0] >> 8U) | ((t[1] << 2U) & 0xFFU));
351 r[(5U * j) + 2U] = (uint8_t) ((t[1] >> 6U) | ((t[2] << 4U) & 0xFFU));
352 r[(5U * j) + 3U] = (uint8_t) ((t[2] >> 4U) | ((t[3] << 6U) & 0xFFU));
353 r[(5U * j) + 4U] = (uint8_t) (t[3] >> 2U);
359 for (uint32_t j = 0U; j < (
MLKEM_N / 4U); j++) {
360 const uint8_t *base = &a[5U * j];
362 t[0] = 0x3FFU & ((base[0] >> 0U) | ((uint16_t) base[1] << 8U));
363 t[1] = 0x3FFU & ((base[1] >> 2U) | ((uint16_t) base[2] << 6U));
364 t[2] = 0x3FFU & ((base[2] >> 4U) | ((uint16_t) base[3] << 4U));
365 t[3] = 0x3FFU & ((base[3] >> 6U) | ((uint16_t) base[4] << 2U));
366 for (uint32_t k = 0U; k < 4U; k++) {
375 for (uint32_t j = 0U; j < (
MLKEM_N / 8U); j++) {
377 for (uint32_t k = 0U; k < 8U; k++) {
380 r[(11U * j) + 0U] = (uint8_t) (t[0] >> 0);
381 r[(11U * j) + 1U] = (uint8_t) ((t[0] >> 8) | (t[1] << 3));
382 r[(11U * j) + 2U] = (uint8_t) ((t[1] >> 5) | (t[2] << 6));
383 r[(11U * j) + 3U] = (uint8_t) (t[2] >> 2);
384 r[(11U * j) + 4U] = (uint8_t) ((t[2] >> 10) | (t[3] << 1));
385 r[(11U * j) + 5U] = (uint8_t) ((t[3] >> 7) | (t[4] << 4));
386 r[(11U * j) + 6U] = (uint8_t) ((t[4] >> 4) | (t[5] << 7));
387 r[(11U * j) + 7U] = (uint8_t) (t[5] >> 1);
388 r[(11U * j) + 8U] = (uint8_t) ((t[5] >> 9) | (t[6] << 2));
389 r[(11U * j) + 9U] = (uint8_t) ((t[6] >> 6) | (t[7] << 5));
390 r[(11U * j) + 10U] = (uint8_t) (t[7] >> 3);
396 for (uint32_t j = 0U; j < (
MLKEM_N / 8U); j++) {
397 const uint8_t *base = &a[11U * j];
399 t[0] = 0x7FFU & ((base[0] >> 0) | ((uint16_t) base[1] << 8));
400 t[1] = 0x7FFU & ((base[1] >> 3) | ((uint16_t) base[2] << 5));
401 t[2] = 0x7FFU & ((base[2] >> 6) | ((uint16_t) base[3] << 2) | ((uint16_t) base[4] << 10));
402 t[3] = 0x7FFU & ((base[4] >> 1) | ((uint16_t) base[5] << 7));
403 t[4] = 0x7FFU & ((base[5] >> 4) | ((uint16_t) base[6] << 4));
404 t[5] = 0x7FFU & ((base[6] >> 7) | ((uint16_t) base[7] << 1) | ((uint16_t) base[8] << 9));
405 t[6] = 0x7FFU & ((base[8] >> 2) | ((uint16_t) base[9] << 6));
406 t[7] = 0x7FFU & ((base[9] >> 5) | ((uint16_t) base[10] << 3));
407 for (uint32_t k = 0U; k < 8U; k++) {
416 for (uint32_t i = 0U; i < (
MLKEM_N / 8U); i++) {
417 for (uint32_t j = 0U; j < 8U; j++) {
418 int16_t bit = (int16_t) ((msg[i] >> j) & 1U);
426 for (uint32_t i = 0U; i < (
MLKEM_N / 8U); i++) {
428 for (uint32_t j = 0U; j < 8U; j++) {
430 msg[i] |= (uint8_t) (t << j);
static const int16_t zetas[MLKEM_N/2U]
int16_t MLKEM_POLY_scalar_decompress_d10(uint16_t u)
Scalar decompression with d=10.
void MLKEM_POLY_sub(poly *r, const poly *b)
Subtracts polynomial b from polynomial r in place.
#define MLKEM_COMPRESS_CONST_D4
int16_t MLKEM_POLY_fqmul(int16_t a, int16_t b)
Multiplication in the NTT domain followed by Montgomery reduction.
int16_t MLKEM_POLY_scalar_decompress_d4(uint8_t u)
Scalar decompression with d=4.
void MLKEM_POLY_decompress_d5(poly *r, const uint8_t *a)
Decompresses a polynomial from bytes with dv=5.
void MLKEM_POLY_decompress_d4(poly *r, const uint8_t *a)
Decompresses a polynomial from bytes with dv=4.
void MLKEM_POLY_basemul_acc_montgomery(poly *r, const poly *a, const poly *b, int32_t first)
Pointwise multiplication of two polynomials in NTT domain with accumulation.
#define MLKEM_INVNTT_SCALE
void MLKEM_POLY_tomont(poly *r)
Converts a polynomial to Montgomery domain.
void MLKEM_POLY_reduce(poly *r)
Applies Barrett reduction to all coefficients and map to [0, q-1].
uint8_t MLKEM_POLY_scalar_compress_d4(int16_t u)
Scalar compression with d=4.
uint8_t MLKEM_POLY_scalar_compress_d5(int16_t u)
Scalar compression with d=5.
void MLKEM_POLY_ntt(poly *p)
Computes the NTT of a polynomial in place.
void MLKEM_POLY_tobytes(uint8_t *r, const poly *a)
Serializes a polynomial to bytes (12 bits per coefficient).
int16_t MLKEM_POLY_signed_to_unsigned_q(int16_t c)
Maps a signed representative to an unsigned one in [0, q-1].
void MLKEM_POLY_compress_d5(uint8_t *r, const poly *a)
Compresses a polynomial with dv=5 and serialize to bytes.
uint8_t MLKEM_POLY_scalar_compress_d1(int16_t u)
Scalar compression with d=1.
#define MLKEM_MONT_FACTOR
int16_t MLKEM_POLY_barrett_reduce(int16_t a)
Barrett reduction of a coefficient modulo q.
void MLKEM_POLY_tomsg(uint8_t *msg, const poly *a)
Encodes a polynomial into a 32-byte message.
#define MLKEM_BARRETT_SHIFT
int16_t MLKEM_POLY_montgomery_reduce(int32_t a)
Montgomery reduction of a 32-bit integer.
void MLKEM_POLY_compress_d11(uint8_t *r, const poly *a)
Compresses a polynomial with du=11 and serialize to bytes.
void MLKEM_POLY_invntt_tomont(poly *p)
Computes the inverse NTT and multiply by Montgomery factor.
void MLKEM_POLY_decompress_d11(poly *r, const uint8_t *a)
Decompresses a polynomial from bytes with du=11.
void MLKEM_POLY_decompress_d10(poly *r, const uint8_t *a)
Decompresses a polynomial from bytes with du=10.
void MLKEM_POLY_frombytes(poly *r, const uint8_t *a)
Deserializes a polynomial from bytes (12 bits per coefficient).
#define MLKEM_COMPRESS_CONST_D10_11
#define MLKEM_COMPRESS_CONST_D1
int16_t MLKEM_POLY_scalar_decompress_d5(uint8_t u)
Scalar decompression with d=5.
uint16_t MLKEM_POLY_scalar_compress_d11(int16_t u)
Scalar compression with d=11.
void MLKEM_POLY_add(poly *r, const poly *b)
Adds polynomial b to polynomial r in place.
uint16_t MLKEM_POLY_scalar_compress_d10(int16_t u)
Scalar compression with d=10.
void MLKEM_POLY_frommsg(poly *r, const uint8_t *msg)
Decodes a 32-byte message into a polynomial.
void MLKEM_POLY_compress_d4(uint8_t *r, const poly *a)
Compresses a polynomial with dv=4 and serialize to bytes.
#define MLKEM_COMPRESS_CONST_D5
int16_t MLKEM_POLY_scalar_decompress_d11(uint16_t u)
Scalar decompression with d=11.
void MLKEM_POLY_compress_d10(uint8_t *r, const poly *a)
Compresses a polynomial with du=10 and serialize to bytes.
ML-KEM (Module-Lattice Key Encapsulation Mechanism) public API.
SHA-3 (Secure Hash Algorithm 3)
Polynomial with MLKEM_N coefficients.