Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
cx_mlkem_poly.c
Go to the documentation of this file.
1/*****************************************************************************
2 * (c) 2026 Ledger SAS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
25#include "lcx_mlkem.h"
26#include "lcx_sha3.h"
27#include "cx_mlkem_poly.h"
28#include "cx_mlkem_util.h"
29
30/* ========================================================================
31 * ML-KEM Arithmetic Constants
32 * ====================================================================== */
33
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
40/* ========================================================================
41 * ML-KEM Scalar Compression Constants
42 * ====================================================================== */
43
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 \
48 2642263040ULL
50/* ========================================================================
51 * Polynomial Arithmetic
52 * ====================================================================== */
53
54static const int16_t zetas[MLKEM_N / 2U] = {
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,
65};
66
68{
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);
73}
74
75int16_t MLKEM_POLY_fqmul(int16_t a, int16_t b)
76{
77 return MLKEM_POLY_montgomery_reduce((int32_t) a * (int32_t) b);
78}
79
80int16_t MLKEM_POLY_barrett_reduce(int16_t a)
81{
82 int32_t t = ((MLKEM_BARRETT_V * (int32_t) a) + (1 << (MLKEM_BARRETT_SHIFT - 1)))
84 return (int16_t) ((int32_t) a - (t * MLKEM_Q));
85}
86
88{
89 int16_t mask = (int16_t) (c >> 15);
90 return (int16_t) (c + (mask & MLKEM_Q));
91}
92
94{
95 for (uint32_t i = 0U; i < MLKEM_N; i++) {
97 }
98}
99
101{
102 for (uint32_t i = 0U; i < MLKEM_N; i++) {
104 }
105}
106
107void MLKEM_POLY_add(poly *r, const poly *b)
108{
109 for (uint32_t i = 0U; i < MLKEM_N; i++) {
110 r->coeffs[i] = (int16_t) (r->coeffs[i] + b->coeffs[i]);
111 }
112}
113
114void MLKEM_POLY_sub(poly *r, const poly *b)
115{
116 for (uint32_t i = 0U; i < MLKEM_N; i++) {
117 r->coeffs[i] = (int16_t) (r->coeffs[i] - b->coeffs[i]);
118 }
119}
120
122{
123 int16_t *r = p->coeffs;
124 uint32_t k = 1U;
125
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++) {
130 int16_t t = MLKEM_POLY_fqmul(r[j + len], zeta);
131 r[j + len] = (int16_t) (r[j] - t);
132 r[j] = (int16_t) (r[j] + t);
133 }
134 }
135 }
136}
137
139{
140 int16_t *r = p->coeffs;
141 uint32_t k = (MLKEM_N / 2U) - 1U;
142
143 for (uint32_t j = 0U; j < MLKEM_N; j++) {
145 }
146
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++) {
151 int16_t t = r[j];
152 r[j] = MLKEM_POLY_barrett_reduce((int16_t) (t + r[j + len]));
153 r[j + len] = MLKEM_POLY_fqmul((int16_t) (r[j + len] - t), zeta);
154 }
155 }
156 }
157}
158
159void MLKEM_POLY_basemul_acc_montgomery(poly *r, const poly *a, const poly *b, int32_t first)
160{
161 for (uint32_t i = 0U; i < (MLKEM_N / 4U); i++) {
162 int16_t zeta = zetas[(MLKEM_N / 4U) + i];
163
164 int32_t t0
165 = (int32_t) a->coeffs[(4U * i) + 1U] * MLKEM_POLY_fqmul(b->coeffs[(4U * i) + 1U], zeta);
166 t0 += (int32_t) a->coeffs[4U * i] * b->coeffs[4U * i];
167
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];
170
171 if (first != 0) {
172 r->coeffs[4U * i] = MLKEM_POLY_montgomery_reduce(t0);
173 r->coeffs[(4U * i) + 1U] = MLKEM_POLY_montgomery_reduce(t1);
174 }
175 else {
176 r->coeffs[4U * i] = (int16_t) (r->coeffs[4U * i] + MLKEM_POLY_montgomery_reduce(t0));
177 r->coeffs[(4U * i) + 1U]
178 = (int16_t) (r->coeffs[(4U * i) + 1U] + MLKEM_POLY_montgomery_reduce(t1));
179 }
180
181 int16_t neg_zeta = (int16_t) (-zeta);
182 t0 = (int32_t) a->coeffs[(4U * i) + 3U]
183 * MLKEM_POLY_fqmul(b->coeffs[(4U * i) + 3U], neg_zeta);
184 t0 += (int32_t) a->coeffs[(4U * i) + 2U] * b->coeffs[(4U * i) + 2U];
185
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];
188
189 if (first != 0) {
190 r->coeffs[(4U * i) + 2U] = MLKEM_POLY_montgomery_reduce(t0);
191 r->coeffs[(4U * i) + 3U] = MLKEM_POLY_montgomery_reduce(t1);
192 }
193 else {
194 r->coeffs[(4U * i) + 2U]
195 = (int16_t) (r->coeffs[(4U * i) + 2U] + MLKEM_POLY_montgomery_reduce(t0));
196 r->coeffs[(4U * i) + 3U]
197 = (int16_t) (r->coeffs[(4U * i) + 3U] + MLKEM_POLY_montgomery_reduce(t1));
198 }
199 }
200}
201
202/* ========================================================================
203 * Polynomial Serialization
204 * ====================================================================== */
205
206void MLKEM_POLY_tobytes(uint8_t *r, const poly *a)
207{
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);
214 }
215}
216
217void MLKEM_POLY_frombytes(poly *r, const uint8_t *a)
218{
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));
225 }
226}
227
228/* ========================================================================
229 * Compression Functions
230 * ====================================================================== */
231
233{
234 uint32_t d0 = (uint32_t) u * MLKEM_COMPRESS_CONST_D1;
235 return (uint8_t) ((d0 + ((uint32_t) 1u << 30)) >> 31);
236}
237
239{
240 uint32_t d0 = (uint32_t) u * MLKEM_COMPRESS_CONST_D4;
241 return (uint8_t) ((d0 + ((uint32_t) 1u << 27)) >> 28);
242}
243
245{
246 return (int16_t) ((((uint32_t) u * MLKEM_Q) + 8) >> 4);
247}
248
250{
251 uint32_t d0 = (uint32_t) u * MLKEM_COMPRESS_CONST_D5;
252 return (uint8_t) ((d0 + ((uint32_t) 1u << 26)) >> 27);
253}
254
256{
257 return (int16_t) ((((uint32_t) u * MLKEM_Q) + 16) >> 5);
258}
259
261{
262 uint64_t d0 = (uint64_t) u * MLKEM_COMPRESS_CONST_D10_11;
263 d0 = (d0 + ((uint64_t) 1u << 32)) >> 33;
264 return (uint16_t) (d0 & 0x3FF);
265}
266
268{
269 return (int16_t) ((((uint32_t) u * MLKEM_Q) + 512) >> 10);
270}
271
273{
274 uint64_t d0 = (uint64_t) u * MLKEM_COMPRESS_CONST_D10_11;
275 d0 = (d0 + ((uint64_t) 1u << 31)) >> 32;
276 return (uint16_t) (d0 & 0x7FF);
277}
278
280{
281 return (int16_t) ((((uint32_t) u * MLKEM_Q) + 1024) >> 11);
282}
283
284/* Compress dv=4 */
285void MLKEM_POLY_compress_d4(uint8_t *r, const poly *a)
286{
287 for (uint32_t i = 0U; i < (MLKEM_N / 8U); i++) {
288 uint8_t t[8] = {0};
289 for (uint32_t j = 0U; j < 8U; j++) {
290 t[j] = MLKEM_POLY_scalar_compress_d4(a->coeffs[(8U * i) + j]);
291 }
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));
296 }
297}
298
299void MLKEM_POLY_decompress_d4(poly *r, const uint8_t *a)
300{
301 for (uint32_t i = 0U; i < (MLKEM_N / 2U); i++) {
302 r->coeffs[(2U * i) + 0U] = MLKEM_POLY_scalar_decompress_d4((a[i] >> 0U) & 0xFU);
303 r->coeffs[(2U * i) + 1U] = MLKEM_POLY_scalar_decompress_d4((a[i] >> 4U) & 0xFU);
304 }
305}
306
307/* Compress dv=5 */
308void MLKEM_POLY_compress_d5(uint8_t *r, const poly *a)
309{
310 for (uint32_t i = 0U; i < (MLKEM_N / 8U); i++) {
311 uint8_t t[8] = {0};
312 for (uint32_t j = 0U; j < 8U; j++) {
313 t[j] = MLKEM_POLY_scalar_compress_d5(a->coeffs[(8U * i) + j]);
314 }
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));
320 }
321}
322
323void MLKEM_POLY_decompress_d5(poly *r, const uint8_t *a)
324{
325 for (uint32_t i = 0U; i < (MLKEM_N / 8U); i++) {
326 uint8_t t[8] = {0};
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++) {
336 r->coeffs[8 * i + j] = MLKEM_POLY_scalar_decompress_d5(t[j]);
337 }
338 }
339}
340
341/* Compress du=10 */
342void MLKEM_POLY_compress_d10(uint8_t *r, const poly *a)
343{
344 for (uint32_t j = 0U; j < (MLKEM_N / 4U); j++) {
345 uint16_t t[4] = {0};
346 for (uint32_t k = 0U; k < 4U; k++) {
347 t[k] = MLKEM_POLY_scalar_compress_d10(a->coeffs[(4U * j) + k]);
348 }
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);
354 }
355}
356
357void MLKEM_POLY_decompress_d10(poly *r, const uint8_t *a)
358{
359 for (uint32_t j = 0U; j < (MLKEM_N / 4U); j++) {
360 const uint8_t *base = &a[5U * j];
361 uint16_t t[4] = {0};
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++) {
367 r->coeffs[(4U * j) + k] = MLKEM_POLY_scalar_decompress_d10(t[k]);
368 }
369 }
370}
371
372/* Compress du=11 */
373void MLKEM_POLY_compress_d11(uint8_t *r, const poly *a)
374{
375 for (uint32_t j = 0U; j < (MLKEM_N / 8U); j++) {
376 uint16_t t[8] = {0};
377 for (uint32_t k = 0U; k < 8U; k++) {
378 t[k] = MLKEM_POLY_scalar_compress_d11(a->coeffs[(8U * j) + k]);
379 }
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);
391 }
392}
393
394void MLKEM_POLY_decompress_d11(poly *r, const uint8_t *a)
395{
396 for (uint32_t j = 0U; j < (MLKEM_N / 8U); j++) {
397 const uint8_t *base = &a[11U * j];
398 uint16_t t[8] = {0};
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++) {
408 r->coeffs[(8U * j) + k] = MLKEM_POLY_scalar_decompress_d11(t[k]);
409 }
410 }
411}
412
413/* Message encoding/decoding */
414void MLKEM_POLY_frommsg(poly *r, const uint8_t *msg)
415{
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);
419 r->coeffs[(8U * i) + j] = (int16_t) ((-bit) & MLKEM_Q_HALF);
420 }
421 }
422}
423
424void MLKEM_POLY_tomsg(uint8_t *msg, const poly *a)
425{
426 for (uint32_t i = 0U; i < (MLKEM_N / 8U); i++) {
427 msg[i] = 0U;
428 for (uint32_t j = 0U; j < 8U; j++) {
429 uint32_t t = MLKEM_POLY_scalar_compress_d1(a->coeffs[(8U * i) + j]);
430 msg[i] |= (uint8_t) (t << j);
431 }
432 }
433}
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.
#define MLKEM_QINV
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).
#define MLKEM_BARRETT_V
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.
#define MLKEM_Q_HALF
Definition lcx_mlkem.h:37
#define MLKEM_Q
Definition lcx_mlkem.h:36
#define MLKEM_N
Definition lcx_mlkem.h:35
ML-KEM (Module-Lattice Key Encapsulation Mechanism) public API.
SHA-3 (Secure Hash Algorithm 3)
Polynomial with MLKEM_N coefficients.
int16_t coeffs[MLKEM_N]