Coverage Report

Created: 2026-07-16 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wolfssl/wolfcrypt/src/wc_mlkem_poly.c
Line
Count
Source
1
/* wc_mlkem_poly.c
2
 *
3
 * Copyright (C) 2006-2026 wolfSSL Inc.
4
 *
5
 * This file is part of wolfSSL.
6
 *
7
 * wolfSSL is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * wolfSSL is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20
 */
21
22
/* Implementation based on FIPS 203:
23
 *   https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf
24
 *
25
 * Original implementation based on NIST 3rd Round submission package.
26
 * See link at:
27
 *   https://csrc.nist.gov/Projects/post-quantum-cryptography/
28
 *   post-quantum-cryptography-standardization/round-3-submissions
29
 */
30
31
/* Implementation of the functions that operate on polynomials or vectors of
32
 * polynomials.
33
 */
34
35
/* Possible ML-KEM options:
36
 *
37
 * WOLFSSL_HAVE_MLKEM                                         Default: OFF
38
 *   Enables this code, wolfSSL implementation, to be built.
39
 *
40
 * WOLFSSL_WC_ML_KEM_512                                      Default: OFF
41
 *   Enables the ML-KEM 512 parameter implementations.
42
 * WOLFSSL_WC_ML_KEM_768                                      Default: OFF
43
 *   Enables the ML-KEM 768 parameter implementations.
44
 * WOLFSSL_WC_ML_KEM_1024                                     Default: OFF
45
 *   Enables the ML-KEM 1024 parameter implementations.
46
 * WOLFSSL_KYBER512                                           Default: OFF
47
 *   Enables the KYBER512 parameter implementations.
48
 * WOLFSSL_KYBER768                                           Default: OFF
49
 *   Enables the KYBER768 parameter implementations.
50
 * WOLFSSL_KYBER1024                                          Default: OFF
51
 *   Enables the KYBER1024 parameter implementations.
52
 *
53
 * USE_INTEL_SPEEDUP                                          Default: OFF
54
 *   Compiles in Intel x64 specific implementations that are faster.
55
 * WOLFSSL_MLKEM_NO_LARGE_CODE                                Default: OFF
56
 *   Compiles smaller, fast code size with a speed trade-off.
57
 * WOLFSSL_MLKEM_SMALL                                        Default: OFF
58
 *   Compiles to small code size with a speed trade-off.
59
 * WOLFSSL_SMALL_STACK                                        Default: OFF
60
 *   Use less stack by dynamically allocating local variables.
61
 *
62
 * WOLFSSL_MLKEM_NTT_UNROLL                                   Default: OFF
63
 *   Enable an alternative NTT implementation that may be faster on some
64
 *   platforms and is smaller in code size.
65
 * WOLFSSL_MLKEM_INVNTT_UNROLL                                Default: OFF
66
 *   Enables an alternative inverse NTT implementation that may be faster on
67
 *   some platforms and is smaller in code size.
68
 */
69
70
#define _WC_BUILDING_WC_MLKEM_POLY_C
71
72
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
73
74
#ifdef WC_MLKEM_NO_ASM
75
    #undef USE_INTEL_SPEEDUP
76
    #undef WOLFSSL_ARMASM
77
    #undef WOLFSSL_RISCV_ASM
78
#endif
79
#ifdef WOLFSSL_X86_BUILD
80
    #undef USE_INTEL_SPEEDUP
81
#endif
82
83
#include <wolfssl/wolfcrypt/wc_mlkem.h>
84
#include <wolfssl/wolfcrypt/sha3.h>
85
#include <wolfssl/wolfcrypt/cpuid.h>
86
87
#ifdef WOLFSSL_HAVE_MLKEM
88
89
#ifdef NO_INLINE
90
    #include <wolfssl/wolfcrypt/misc.h>
91
#else
92
    #define WOLFSSL_MISC_INCLUDED
93
    #include <wolfcrypt/src/misc.c>
94
#endif
95
96
#if defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) || \
97
    defined(WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM)
98
static int mlkem_gen_matrix_i(MLKEM_PRF_T* prf, sword16* a, int k, byte* seed,
99
    int i, int transposed);
100
static int mlkem_get_noise_i(MLKEM_PRF_T* prf, int k, sword16* vec2,
101
    byte* seed, int i, int make);
102
static int mlkem_get_noise_eta2_c(MLKEM_PRF_T* prf, sword16* p,
103
    const byte* seed);
104
#endif
105
106
/* Declared in wc_mlkem.c to stop compiler optimizer from simplifying. */
107
extern sword16 wc_mlkem_opt_blocker(void);
108
109
#if defined(USE_INTEL_SPEEDUP) || (defined(__aarch64__) && \
110
    defined(WOLFSSL_ARMASM))
111
static cpuid_flags_t cpuid_flags = WC_CPUID_INITIALIZER;
112
#endif
113
114
/* Half of Q plus one. Converted message bit value of 1. */
115
0
#define MLKEM_Q_1_HALF      ((MLKEM_Q + 1) / 2)
116
/* Half of Q */
117
0
#define MLKEM_Q_HALF        (MLKEM_Q / 2)
118
119
120
/* q^-1 mod 2^16 (inverse of 3329 mod 65536) */
121
0
#define MLKEM_QINV       62209
122
123
/* Used in Barrett Reduction:
124
 *    r = a mod q
125
 * => r = a - ((V * a) >> 26) * q), as V based on 2^26
126
 * V is the multiplier that gets the quotient after shifting.
127
 */
128
0
#define MLKEM_V          (((1U << 26) + (MLKEM_Q / 2)) / MLKEM_Q)
129
130
/* Used in converting to Montgomery form.
131
 * f is the normalizer = 2^k % m.
132
 * 16-bit value cast to sword32 in use.
133
 */
134
0
#define MLKEM_F          (((word64)1 << 32) % MLKEM_Q)
135
136
/* Number of bytes in an output block of SHA-3-128 */
137
#define SHA3_128_BYTES   (WC_SHA3_128_COUNT * 8)
138
/* Number of bytes in an output block of SHA-3-256 */
139
#define SHA3_256_BYTES   (WC_SHA3_256_COUNT * 8)
140
141
/* Number of blocks to generate for matrix. */
142
#define GEN_MATRIX_NBLOCKS \
143
0
    ((12 * MLKEM_N / 8 * (1 << 12) / MLKEM_Q + XOF_BLOCK_SIZE) / XOF_BLOCK_SIZE)
144
/* Number of bytes to generate for matrix. */
145
0
#define GEN_MATRIX_SIZE     GEN_MATRIX_NBLOCKS * XOF_BLOCK_SIZE
146
147
148
/* Number of random bytes to generate for ETA3. */
149
#define ETA3_RAND_SIZE     ((3 * MLKEM_N) / 4)
150
/* Number of random bytes to generate for ETA2. */
151
#define ETA2_RAND_SIZE     ((2 * MLKEM_N) / 4)
152
153
154
/* Montgomery reduce a.
155
 *
156
 * @param  [in]  a  32-bit value to be reduced.
157
 * @return  Montgomery reduction result.
158
 */
159
#define MLKEM_MONT_RED(a) \
160
0
    (sword16)(((a) - (sword32)(((sword16)((sword16)(a) * \
161
0
                                (sword16)MLKEM_QINV)) * \
162
0
                               (sword32)MLKEM_Q)) >> 16)
163
164
/* Barrett reduce a. r = a mod q.
165
 *
166
 * Converted division to multiplication.
167
 *
168
 * @param  [in]  a  16-bit value to be reduced to range of q.
169
 * @return  Modulo result.
170
 */
171
#define MLKEM_BARRETT_RED(a) \
172
0
    (sword16)((sword16)(a) - (sword16)((sword16)( \
173
0
        ((sword32)((sword32)MLKEM_V * (sword16)(a))) >> 26) * (word16)MLKEM_Q))
174
175
176
/* Zetas for NTT. */
177
const sword16 zetas[MLKEM_N / 2] = {
178
    2285, 2571, 2970, 1812, 1493, 1422,  287,  202,
179
    3158,  622, 1577,  182,  962, 2127, 1855, 1468,
180
     573, 2004,  264,  383, 2500, 1458, 1727, 3199,
181
    2648, 1017,  732,  608, 1787,  411, 3124, 1758,
182
    1223,  652, 2777, 1015, 2036, 1491, 3047, 1785,
183
     516, 3321, 3009, 2663, 1711, 2167,  126, 1469,
184
    2476, 3239, 3058,  830,  107, 1908, 3082, 2378,
185
    2931,  961, 1821, 2604,  448, 2264,  677, 2054,
186
    2226,  430,  555,  843, 2078,  871, 1550,  105,
187
     422,  587,  177, 3094, 3038, 2869, 1574, 1653,
188
    3083,  778, 1159, 3182, 2552, 1483, 2727, 1119,
189
    1739,  644, 2457,  349,  418,  329, 3173, 3254,
190
     817, 1097,  603,  610, 1322, 2044, 1864,  384,
191
    2114, 3193, 1218, 1994, 2455,  220, 2142, 1670,
192
    2144, 1799, 2051,  794, 1819, 2475, 2459,  478,
193
    3221, 3021,  996,  991,  958, 1869, 1522, 1628
194
};
195
196
197
#if !defined(WOLFSSL_ARMASM)
198
/* Number-Theoretic Transform.
199
 *
200
 * FIPS 203, Algorithm 9: NTT(f)
201
 * Computes the NTT representation f_hat of the given polynomial f element of
202
 * R_q.
203
 *   1: f_hat <- f
204
 *   2: i <- 1
205
 *   3: for (len <- 128; len >= 2; len <- len/2)
206
 *   4:     for (start <- 0; start < 256; start <- start + 2.len)
207
 *   5:         zeta <- zetas^BitRev_7(i) mod q
208
 *   6:         i <- i + 1
209
 *   7:         for (j <- start; j < start + len; j++)
210
 *   8:             t <- zeta.f[j+len]
211
 *   9:             f_hat[j+len] <- f_hat[j] - t
212
 *  10:             f_hat[j] <- f_hat[j] + t
213
 *  11:         end for
214
 *  12:     end for
215
 *  13: end for
216
 *  14: return f_hat
217
 *
218
 * @param  [in, out]  r  Polynomial to transform.
219
 */
220
static void mlkem_ntt(sword16* r)
221
0
{
222
#ifdef WOLFSSL_MLKEM_SMALL
223
    unsigned int len;
224
    unsigned int k;
225
    unsigned int j;
226
227
    /* Step 2 */
228
    k = 1;
229
    /* Step 3 */
230
    for (len = MLKEM_N / 2; len >= 2; len >>= 1) {
231
        unsigned int start;
232
        /* Step 4 */
233
        for (start = 0; start < MLKEM_N; start = j + len) {
234
            /* Step 5, 6*/
235
            sword16 zeta = zetas[k++];
236
            /* Step 7 */
237
            for (j = start; j < start + len; ++j) {
238
                /* Step 8 */
239
                sword32 p = (sword32)zeta * r[j + len];
240
                sword16 t = MLKEM_MONT_RED(p);
241
                sword16 rj = r[j];
242
                /* Step 9 */
243
                r[j + len] = (sword16)(rj - t);
244
                /* Step 10 */
245
                r[j] = (sword16)(rj + t);
246
            }
247
        }
248
    }
249
250
    /* Reduce coefficients with quick algorithm. */
251
    for (j = 0; j < MLKEM_N; ++j) {
252
        r[j] = MLKEM_BARRETT_RED(r[j]);
253
    }
254
#elif defined(WOLFSSL_MLKEM_NO_LARGE_CODE)
255
    /* Take out the first iteration. */
256
    unsigned int len;
257
    unsigned int k = 1;
258
    unsigned int j;
259
    unsigned int start;
260
    sword16 zeta = zetas[k++];
261
262
    for (j = 0; j < MLKEM_N / 2; ++j) {
263
        sword32 p = (sword32)zeta * r[j + MLKEM_N / 2];
264
        sword16 t = MLKEM_MONT_RED(p);
265
        sword16 rj = r[j];
266
        r[j + MLKEM_N / 2] = (sword16)(rj - t);
267
        r[j] = (sword16)(rj + t);
268
    }
269
    for (len = MLKEM_N / 4; len >= 2; len >>= 1) {
270
        for (start = 0; start < MLKEM_N; start = j + len) {
271
            zeta = zetas[k++];
272
            for (j = start; j < start + len; ++j) {
273
                sword32 p = (sword32)zeta * r[j + len];
274
                sword16 t = MLKEM_MONT_RED(p);
275
                sword16 rj = r[j];
276
                r[j + len] = (sword16)(rj - t);
277
                r[j] = (sword16)(rj + t);
278
            }
279
        }
280
    }
281
282
    /* Reduce coefficients with quick algorithm. */
283
    for (j = 0; j < MLKEM_N; ++j) {
284
        r[j] = MLKEM_BARRETT_RED(r[j]);
285
    }
286
#elif defined(WOLFSSL_MLKEM_NTT_UNROLL)
287
    /* Unroll len loop (Step 3). */
288
    unsigned int k = 1;
289
    unsigned int j;
290
    unsigned int start;
291
    sword16 zeta = zetas[k++];
292
293
    /* len = 128 */
294
    for (j = 0; j < MLKEM_N / 2; ++j) {
295
        sword32 p = (sword32)zeta * r[j + MLKEM_N / 2];
296
        sword16 t = MLKEM_MONT_RED(p);
297
        sword16 rj = r[j];
298
        r[j + MLKEM_N / 2] = rj - t;
299
        r[j] = rj + t;
300
    }
301
    /* len = 64 */
302
    for (start = 0; start < MLKEM_N; start += 2 * 64) {
303
        zeta = zetas[k++];
304
        for (j = 0; j < 64; ++j) {
305
            sword32 p = (sword32)zeta * r[start + j + 64];
306
            sword16 t = MLKEM_MONT_RED(p);
307
            sword16 rj = r[start + j];
308
            r[start + j + 64] = rj - t;
309
            r[start + j] = rj + t;
310
        }
311
    }
312
    /* len = 32 */
313
    for (start = 0; start < MLKEM_N; start += 2 * 32) {
314
        zeta = zetas[k++];
315
        for (j = 0; j < 32; ++j) {
316
            sword32 p = (sword32)zeta * r[start + j + 32];
317
            sword16 t = MLKEM_MONT_RED(p);
318
            sword16 rj = r[start + j];
319
            r[start + j + 32] = rj - t;
320
            r[start + j] = rj + t;
321
        }
322
    }
323
    /* len = 16 */
324
    for (start = 0; start < MLKEM_N; start += 2 * 16) {
325
        zeta = zetas[k++];
326
        for (j = 0; j < 16; ++j) {
327
            sword32 p = (sword32)zeta * r[start + j + 16];
328
            sword16 t = MLKEM_MONT_RED(p);
329
            sword16 rj = r[start + j];
330
            r[start + j + 16] = rj - t;
331
            r[start + j] = rj + t;
332
        }
333
    }
334
    /* len = 8 */
335
    for (start = 0; start < MLKEM_N; start += 2 * 8) {
336
        zeta = zetas[k++];
337
        for (j = 0; j < 8; ++j) {
338
            sword32 p = (sword32)zeta * r[start + j + 8];
339
            sword16 t = MLKEM_MONT_RED(p);
340
            sword16 rj = r[start + j];
341
            r[start + j + 8] = rj - t;
342
            r[start + j] = rj + t;
343
        }
344
    }
345
    /* len = 4 */
346
    for (start = 0; start < MLKEM_N; start += 2 * 4) {
347
        zeta = zetas[k++];
348
        for (j = 0; j < 4; ++j) {
349
            sword32 p = (sword32)zeta * r[start + j + 4];
350
            sword16 t = MLKEM_MONT_RED(p);
351
            sword16 rj = r[start + j];
352
            r[start + j + 4] = rj - t;
353
            r[start + j] = rj + t;
354
        }
355
    }
356
    /* len = 2 */
357
    for (start = 0; start < MLKEM_N; start += 2 * 2) {
358
        zeta = zetas[k++];
359
        for (j = 0; j < 2; ++j) {
360
            sword32 p = (sword32)zeta * r[start + j + 2];
361
            sword16 t = MLKEM_MONT_RED(p);
362
            sword16 rj = r[start + j];
363
            r[start + j + 2] = rj - t;
364
            r[start + j] = rj + t;
365
        }
366
    }
367
    /* Reduce coefficients with quick algorithm. */
368
    for (j = 0; j < MLKEM_N; ++j) {
369
        r[j] = MLKEM_BARRETT_RED(r[j]);
370
    }
371
#else
372
    /* Unroll len (2, 3, 2) and start loops. */
373
0
    unsigned int j;
374
0
    sword16 t0;
375
0
    sword16 t1;
376
0
    sword16 t2;
377
0
    sword16 t3;
378
379
    /* len = 128,64 */
380
0
    sword16 zeta128 = zetas[1];
381
0
    sword16 zeta64_0 = zetas[2];
382
0
    sword16 zeta64_1 = zetas[3];
383
0
    for (j = 0; j < MLKEM_N / 8; j++) {
384
0
        sword16 r0 = r[j +   0];
385
0
        sword16 r1 = r[j +  32];
386
0
        sword16 r2 = r[j +  64];
387
0
        sword16 r3 = r[j +  96];
388
0
        sword16 r4 = r[j + 128];
389
0
        sword16 r5 = r[j + 160];
390
0
        sword16 r6 = r[j + 192];
391
0
        sword16 r7 = r[j + 224];
392
393
0
        t0 = MLKEM_MONT_RED((sword32)zeta128 * r4);
394
0
        t1 = MLKEM_MONT_RED((sword32)zeta128 * r5);
395
0
        t2 = MLKEM_MONT_RED((sword32)zeta128 * r6);
396
0
        t3 = MLKEM_MONT_RED((sword32)zeta128 * r7);
397
0
        r4 = (sword16)(r0 - t0);
398
0
        r5 = (sword16)(r1 - t1);
399
0
        r6 = (sword16)(r2 - t2);
400
0
        r7 = (sword16)(r3 - t3);
401
0
        r0 = (sword16)(r0 + t0);
402
0
        r1 = (sword16)(r1 + t1);
403
0
        r2 = (sword16)(r2 + t2);
404
0
        r3 = (sword16)(r3 + t3);
405
406
0
        t0 = MLKEM_MONT_RED((sword32)zeta64_0 * r2);
407
0
        t1 = MLKEM_MONT_RED((sword32)zeta64_0 * r3);
408
0
        t2 = MLKEM_MONT_RED((sword32)zeta64_1 * r6);
409
0
        t3 = MLKEM_MONT_RED((sword32)zeta64_1 * r7);
410
0
        r2 = (sword16)(r0 - t0);
411
0
        r3 = (sword16)(r1 - t1);
412
0
        r6 = (sword16)(r4 - t2);
413
0
        r7 = (sword16)(r5 - t3);
414
0
        r0 = (sword16)(r0 + t0);
415
0
        r1 = (sword16)(r1 + t1);
416
0
        r4 = (sword16)(r4 + t2);
417
0
        r5 = (sword16)(r5 + t3);
418
419
0
        r[j +   0] = r0;
420
0
        r[j +  32] = r1;
421
0
        r[j +  64] = r2;
422
0
        r[j +  96] = r3;
423
0
        r[j + 128] = r4;
424
0
        r[j + 160] = r5;
425
0
        r[j + 192] = r6;
426
0
        r[j + 224] = r7;
427
0
    }
428
429
    /* len = 32,16,8 */
430
0
    for (j = 0; j < MLKEM_N; j += 64) {
431
0
        unsigned int i;
432
0
        sword16 zeta32   = zetas[ 4 + j / 64 + 0];
433
0
        sword16 zeta16_0 = zetas[ 8 + j / 32 + 0];
434
0
        sword16 zeta16_1 = zetas[ 8 + j / 32 + 1];
435
0
        sword16 zeta8_0  = zetas[16 + j / 16 + 0];
436
0
        sword16 zeta8_1  = zetas[16 + j / 16 + 1];
437
0
        sword16 zeta8_2  = zetas[16 + j / 16 + 2];
438
0
        sword16 zeta8_3  = zetas[16 + j / 16 + 3];
439
0
        for (i = 0; i < 8; i++) {
440
0
            sword16 r0 = r[j + i +  0];
441
0
            sword16 r1 = r[j + i +  8];
442
0
            sword16 r2 = r[j + i + 16];
443
0
            sword16 r3 = r[j + i + 24];
444
0
            sword16 r4 = r[j + i + 32];
445
0
            sword16 r5 = r[j + i + 40];
446
0
            sword16 r6 = r[j + i + 48];
447
0
            sword16 r7 = r[j + i + 56];
448
449
0
            t0 = MLKEM_MONT_RED((sword32)zeta32 * r4);
450
0
            t1 = MLKEM_MONT_RED((sword32)zeta32 * r5);
451
0
            t2 = MLKEM_MONT_RED((sword32)zeta32 * r6);
452
0
            t3 = MLKEM_MONT_RED((sword32)zeta32 * r7);
453
0
            r4 = (sword16)(r0 - t0);
454
0
            r5 = (sword16)(r1 - t1);
455
0
            r6 = (sword16)(r2 - t2);
456
0
            r7 = (sword16)(r3 - t3);
457
0
            r0 = (sword16)(r0 + t0);
458
0
            r1 = (sword16)(r1 + t1);
459
0
            r2 = (sword16)(r2 + t2);
460
0
            r3 = (sword16)(r3 + t3);
461
462
0
            t0 = MLKEM_MONT_RED((sword32)zeta16_0 * r2);
463
0
            t1 = MLKEM_MONT_RED((sword32)zeta16_0 * r3);
464
0
            t2 = MLKEM_MONT_RED((sword32)zeta16_1 * r6);
465
0
            t3 = MLKEM_MONT_RED((sword32)zeta16_1 * r7);
466
0
            r2 = (sword16)(r0 - t0);
467
0
            r3 = (sword16)(r1 - t1);
468
0
            r6 = (sword16)(r4 - t2);
469
0
            r7 = (sword16)(r5 - t3);
470
0
            r0 = (sword16)(r0 + t0);
471
0
            r1 = (sword16)(r1 + t1);
472
0
            r4 = (sword16)(r4 + t2);
473
0
            r5 = (sword16)(r5 + t3);
474
475
0
            t0 = MLKEM_MONT_RED((sword32)zeta8_0 * r1);
476
0
            t1 = MLKEM_MONT_RED((sword32)zeta8_1 * r3);
477
0
            t2 = MLKEM_MONT_RED((sword32)zeta8_2 * r5);
478
0
            t3 = MLKEM_MONT_RED((sword32)zeta8_3 * r7);
479
0
            r1 = (sword16)(r0 - t0);
480
0
            r3 = (sword16)(r2 - t1);
481
0
            r5 = (sword16)(r4 - t2);
482
0
            r7 = (sword16)(r6 - t3);
483
0
            r0 = (sword16)(r0 + t0);
484
0
            r2 = (sword16)(r2 + t1);
485
0
            r4 = (sword16)(r4 + t2);
486
0
            r6 = (sword16)(r6 + t3);
487
488
0
            r[j + i +  0] = r0;
489
0
            r[j + i +  8] = r1;
490
0
            r[j + i + 16] = r2;
491
0
            r[j + i + 24] = r3;
492
0
            r[j + i + 32] = r4;
493
0
            r[j + i + 40] = r5;
494
0
            r[j + i + 48] = r6;
495
0
            r[j + i + 56] = r7;
496
0
        }
497
0
    }
498
499
    /* len = 4,2 and Final reduction */
500
0
    for (j = 0; j < MLKEM_N; j += 8) {
501
0
        sword16 zeta4  = zetas[32 + j / 8 + 0];
502
0
        sword16 zeta2_0 = zetas[64 + j / 4 + 0];
503
0
        sword16 zeta2_1 = zetas[64 + j / 4 + 1];
504
0
        sword16 r0 = r[j + 0];
505
0
        sword16 r1 = r[j + 1];
506
0
        sword16 r2 = r[j + 2];
507
0
        sword16 r3 = r[j + 3];
508
0
        sword16 r4 = r[j + 4];
509
0
        sword16 r5 = r[j + 5];
510
0
        sword16 r6 = r[j + 6];
511
0
        sword16 r7 = r[j + 7];
512
513
0
        t0 = MLKEM_MONT_RED((sword32)zeta4 * r4);
514
0
        t1 = MLKEM_MONT_RED((sword32)zeta4 * r5);
515
0
        t2 = MLKEM_MONT_RED((sword32)zeta4 * r6);
516
0
        t3 = MLKEM_MONT_RED((sword32)zeta4 * r7);
517
0
        r4 = (sword16)(r0 - t0);
518
0
        r5 = (sword16)(r1 - t1);
519
0
        r6 = (sword16)(r2 - t2);
520
0
        r7 = (sword16)(r3 - t3);
521
0
        r0 = (sword16)(r0 + t0);
522
0
        r1 = (sword16)(r1 + t1);
523
0
        r2 = (sword16)(r2 + t2);
524
0
        r3 = (sword16)(r3 + t3);
525
526
0
        t0 = MLKEM_MONT_RED((sword32)zeta2_0 * r2);
527
0
        t1 = MLKEM_MONT_RED((sword32)zeta2_0 * r3);
528
0
        t2 = MLKEM_MONT_RED((sword32)zeta2_1 * r6);
529
0
        t3 = MLKEM_MONT_RED((sword32)zeta2_1 * r7);
530
0
        r2 = (sword16)(r0 - t0);
531
0
        r3 = (sword16)(r1 - t1);
532
0
        r6 = (sword16)(r4 - t2);
533
0
        r7 = (sword16)(r5 - t3);
534
0
        r0 = (sword16)(r0 + t0);
535
0
        r1 = (sword16)(r1 + t1);
536
0
        r4 = (sword16)(r4 + t2);
537
0
        r5 = (sword16)(r5 + t3);
538
539
0
        r[j + 0] = MLKEM_BARRETT_RED(r0);
540
0
        r[j + 1] = MLKEM_BARRETT_RED(r1);
541
0
        r[j + 2] = MLKEM_BARRETT_RED(r2);
542
0
        r[j + 3] = MLKEM_BARRETT_RED(r3);
543
0
        r[j + 4] = MLKEM_BARRETT_RED(r4);
544
0
        r[j + 5] = MLKEM_BARRETT_RED(r5);
545
0
        r[j + 6] = MLKEM_BARRETT_RED(r6);
546
0
        r[j + 7] = MLKEM_BARRETT_RED(r7);
547
0
    }
548
0
#endif
549
0
}
550
551
#if !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \
552
    !defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
553
/* Zetas for inverse NTT. */
554
const sword16 zetas_inv[MLKEM_N / 2] = {
555
    1701, 1807, 1460, 2371, 2338, 2333,  308,  108,
556
    2851,  870,  854, 1510, 2535, 1278, 1530, 1185,
557
    1659, 1187, 3109,  874, 1335, 2111,  136, 1215,
558
    2945, 1465, 1285, 2007, 2719, 2726, 2232, 2512,
559
      75,  156, 3000, 2911, 2980,  872, 2685, 1590,
560
    2210,  602, 1846,  777,  147, 2170, 2551,  246,
561
    1676, 1755,  460,  291,  235, 3152, 2742, 2907,
562
    3224, 1779, 2458, 1251, 2486, 2774, 2899, 1103,
563
    1275, 2652, 1065, 2881,  725, 1508, 2368,  398,
564
     951,  247, 1421, 3222, 2499,  271,   90,  853,
565
    1860, 3203, 1162, 1618,  666,  320,    8, 2813,
566
    1544,  282, 1838, 1293, 2314,  552, 2677, 2106,
567
    1571,  205, 2918, 1542, 2721, 2597, 2312,  681,
568
     130, 1602, 1871,  829, 2946, 3065, 1325, 2756,
569
    1861, 1474, 1202, 2367, 3147, 1752, 2707,  171,
570
    3127, 3042, 1907, 1836, 1517,  359,  758, 1441
571
};
572
573
/* Inverse Number-Theoretic Transform.
574
 *
575
 * FIPS 203, Algorithm 10: NTT^-1(f_hat)
576
 * Computes the polynomial f element of R_q that corresponds to the given NTT
577
 * representation f element of T_q.
578
 *   1: f <- f_hat
579
 *   2: i <- 127
580
 *   3: for (len <- 2; len <= 128 ; len <- 2.len)
581
 *   4:     for (start <- 0; start < 256; start <- start + 2.len)
582
 *   5:         zeta <- zetas^BitRev_7(i) mod q
583
 *   6:         i <- i - 1
584
 *   7:         for (j <- start; j < start + len; j++)
585
 *   8:             t <- f[j]
586
 *   9:             f[j] <- t + f[j + len]
587
 *  10:             f[j + len] <- zeta.(f[j+len] - t)
588
 *  11:         end for
589
 *  12:     end for
590
 *  13: end for
591
 *  14: f <- f.3303 mod q
592
 *  15: return f
593
 *
594
 * @param  [in, out]  r  Polynomial to transform.
595
 */
596
static void mlkem_invntt(sword16* r)
597
0
{
598
#ifdef WOLFSSL_MLKEM_SMALL
599
    unsigned int len;
600
    unsigned int k;
601
    unsigned int j;
602
    sword16 zeta;
603
604
    /* Step 2 - table reversed */
605
    k = 0;
606
    /* Step 3 */
607
    for (len = 2; len <= MLKEM_N / 2; len <<= 1) {
608
        unsigned int start;
609
        /* Step 4 */
610
        for (start = 0; start < MLKEM_N; start = j + len) {
611
            /* Step 5, 6 */
612
            zeta = zetas_inv[k++];
613
            /* Step 7 */
614
            for (j = start; j < start + len; ++j) {
615
                sword32 p;
616
                /* Step 8 */
617
                sword16 rj = r[j];
618
                sword16 rjl = r[j + len];
619
                /* Step 9 */
620
                sword16 t = (sword16)(rj + rjl);
621
                r[j] = MLKEM_BARRETT_RED(t);
622
                /* Step 10 */
623
                rjl = (sword16)(rj - rjl);
624
                p = (sword32)zeta * rjl;
625
                r[j + len] = MLKEM_MONT_RED(p);
626
            }
627
        }
628
    }
629
630
    /* Step 14 */
631
    zeta = zetas_inv[127];
632
    for (j = 0; j < MLKEM_N; ++j) {
633
        sword32 p = (sword32)zeta * r[j];
634
        r[j] = MLKEM_MONT_RED(p);
635
    }
636
#elif defined(WOLFSSL_MLKEM_NO_LARGE_CODE)
637
    /* Take out last iteration. */
638
    unsigned int len;
639
    unsigned int k;
640
    unsigned int j;
641
    sword16 zeta;
642
    sword16 zeta2;
643
644
    k = 0;
645
    for (len = 2; len <= MLKEM_N / 4; len <<= 1) {
646
        unsigned int start;
647
        for (start = 0; start < MLKEM_N; start = j + len) {
648
            zeta = zetas_inv[k++];
649
            for (j = start; j < start + len; ++j) {
650
                sword32 p;
651
                sword16 rj = r[j];
652
                sword16 rjl = r[j + len];
653
                sword16 t = (sword16)(rj + rjl);
654
                r[j] = MLKEM_BARRETT_RED(t);
655
                rjl = (sword16)(rj - rjl);
656
                p = (sword32)zeta * rjl;
657
                r[j + len] = MLKEM_MONT_RED(p);
658
            }
659
        }
660
    }
661
662
    zeta = zetas_inv[126];
663
    zeta2 = zetas_inv[127];
664
    for (j = 0; j < MLKEM_N / 2; ++j) {
665
        sword32 p;
666
        sword16 rj = r[j];
667
        sword16 rjl = r[j + MLKEM_N / 2];
668
        sword16 t = (sword16)(rj + rjl);
669
        rjl = (sword16)(rj - rjl);
670
        p = (sword32)zeta * rjl;
671
        r[j] = (sword16)t;
672
        r[j + MLKEM_N / 2] = MLKEM_MONT_RED(p);
673
674
        p = (sword32)zeta2 * r[j];
675
        r[j] = MLKEM_MONT_RED(p);
676
        p = (sword32)zeta2 * r[j + MLKEM_N / 2];
677
        r[j + MLKEM_N / 2] = MLKEM_MONT_RED(p);
678
    }
679
#elif defined(WOLFSSL_MLKEM_INVNTT_UNROLL)
680
    /* Unroll len loop (Step 3). */
681
    unsigned int k;
682
    unsigned int j;
683
    unsigned int start;
684
    sword16 zeta;
685
    sword16 zeta2;
686
687
    k = 0;
688
    /* len = 2 */
689
    for (start = 0; start < MLKEM_N; start += 2 * 2) {
690
        zeta = zetas_inv[k++];
691
        for (j = 0; j < 2; ++j) {
692
            sword32 p;
693
            sword16 rj = r[start + j];
694
            sword16 rjl = r[start + j + 2];
695
            sword16 t = rj + rjl;
696
            r[start + j] = t;
697
            rjl = rj - rjl;
698
            p = (sword32)zeta * rjl;
699
            r[start + j + 2] = MLKEM_MONT_RED(p);
700
        }
701
    }
702
    /* len = 4 */
703
    for (start = 0; start < MLKEM_N; start += 2 * 4) {
704
        zeta = zetas_inv[k++];
705
        for (j = 0; j < 4; ++j) {
706
            sword32 p;
707
            sword16 rj = r[start + j];
708
            sword16 rjl = r[start + j + 4];
709
            sword16 t = rj + rjl;
710
            r[start + j] = t;
711
            rjl = rj - rjl;
712
            p = (sword32)zeta * rjl;
713
            r[start + j + 4] = MLKEM_MONT_RED(p);
714
        }
715
    }
716
    /* len = 8 */
717
    for (start = 0; start < MLKEM_N; start += 2 * 8) {
718
        zeta = zetas_inv[k++];
719
        for (j = 0; j < 8; ++j) {
720
            sword32 p;
721
            sword16 rj = r[start + j];
722
            sword16 rjl = r[start + j + 8];
723
            sword16 t = rj + rjl;
724
            /* Reduce. */
725
            r[start + j] = MLKEM_BARRETT_RED(t);
726
            rjl = rj - rjl;
727
            p = (sword32)zeta * rjl;
728
            r[start + j + 8] = MLKEM_MONT_RED(p);
729
        }
730
    }
731
    /* len = 16 */
732
    for (start = 0; start < MLKEM_N; start += 2 * 16) {
733
        zeta = zetas_inv[k++];
734
        for (j = 0; j < 16; ++j) {
735
            sword32 p;
736
            sword16 rj = r[start + j];
737
            sword16 rjl = r[start + j + 16];
738
            sword16 t = rj + rjl;
739
            r[start + j] = t;
740
            rjl = rj - rjl;
741
            p = (sword32)zeta * rjl;
742
            r[start + j + 16] = MLKEM_MONT_RED(p);
743
        }
744
    }
745
    /* len = 32 */
746
    for (start = 0; start < MLKEM_N; start += 2 * 32) {
747
        zeta = zetas_inv[k++];
748
        for (j = 0; j < 32; ++j) {
749
            sword32 p;
750
            sword16 rj = r[start + j];
751
            sword16 rjl = r[start + j + 32];
752
            sword16 t = rj + rjl;
753
            r[start + j] = t;
754
            rjl = rj - rjl;
755
            p = (sword32)zeta * rjl;
756
            r[start + j + 32] = MLKEM_MONT_RED(p);
757
        }
758
    }
759
    /* len = 64 */
760
    for (start = 0; start < MLKEM_N; start += 2 * 64) {
761
        zeta = zetas_inv[k++];
762
        for (j = 0; j < 64; ++j) {
763
            sword32 p;
764
            sword16 rj = r[start + j];
765
            sword16 rjl = r[start + j + 64];
766
            sword16 t = rj + rjl;
767
            /* Reduce. */
768
            r[start + j] = MLKEM_BARRETT_RED(t);
769
            rjl = rj - rjl;
770
            p = (sword32)zeta * rjl;
771
            r[start + j + 64] = MLKEM_MONT_RED(p);
772
        }
773
    }
774
    /* len = 128, 256 */
775
    zeta = zetas_inv[126];
776
    zeta2 = zetas_inv[127];
777
    for (j = 0; j < MLKEM_N / 2; ++j) {
778
        sword32 p;
779
        sword16 rj = r[j];
780
        sword16 rjl = r[j + MLKEM_N / 2];
781
        sword16 t = rj + rjl;
782
        rjl = rj - rjl;
783
        p = (sword32)zeta * rjl;
784
        r[j] = t;
785
        r[j + MLKEM_N / 2] = MLKEM_MONT_RED(p);
786
787
        p = (sword32)zeta2 * r[j];
788
        r[j] = MLKEM_MONT_RED(p);
789
        p = (sword32)zeta2 * r[j + MLKEM_N / 2];
790
        r[j + MLKEM_N / 2] = MLKEM_MONT_RED(p);
791
    }
792
#else
793
    /* Unroll len (2, 3, 3) and start loops. */
794
0
    unsigned int j;
795
0
    sword16 t0;
796
0
    sword16 t1;
797
0
    sword16 t2;
798
0
    sword16 t3;
799
0
    sword16 zeta64_0;
800
0
    sword16 zeta64_1;
801
0
    sword16 zeta128;
802
0
    sword16 zeta256;
803
0
    sword32 p;
804
805
0
    for (j = 0; j < MLKEM_N; j += 8) {
806
0
        sword16 zeta2_0 = zetas_inv[ 0 + j / 4 + 0];
807
0
        sword16 zeta2_1 = zetas_inv[ 0 + j / 4 + 1];
808
0
        sword16 zeta4   = zetas_inv[64 + j / 8 + 0];
809
0
        sword16 r0 = r[j + 0];
810
0
        sword16 r1 = r[j + 1];
811
0
        sword16 r2 = r[j + 2];
812
0
        sword16 r3 = r[j + 3];
813
0
        sword16 r4 = r[j + 4];
814
0
        sword16 r5 = r[j + 5];
815
0
        sword16 r6 = r[j + 6];
816
0
        sword16 r7 = r[j + 7];
817
818
0
        p = (sword32)zeta2_0 * (sword16)(r0 - r2);
819
0
        t0 = MLKEM_MONT_RED(p);
820
0
        p = (sword32)zeta2_0 * (sword16)(r1 - r3);
821
0
        t1 = MLKEM_MONT_RED(p);
822
0
        p = (sword32)zeta2_1 * (sword16)(r4 - r6);
823
0
        t2 = MLKEM_MONT_RED(p);
824
0
        p = (sword32)zeta2_1 * (sword16)(r5 - r7);
825
0
        t3 = MLKEM_MONT_RED(p);
826
0
        r0 = (sword16)(r0 + r2);
827
0
        r1 = (sword16)(r1 + r3);
828
0
        r4 = (sword16)(r4 + r6);
829
0
        r5 = (sword16)(r5 + r7);
830
0
        r2 = t0;
831
0
        r3 = t1;
832
0
        r6 = t2;
833
0
        r7 = t3;
834
835
0
        p = (sword32)zeta4 * (sword16)(r0 - r4);
836
0
        t0 = MLKEM_MONT_RED(p);
837
0
        p = (sword32)zeta4 * (sword16)(r1 - r5);
838
0
        t1 = MLKEM_MONT_RED(p);
839
0
        p = (sword32)zeta4 * (sword16)(r2 - r6);
840
0
        t2 = MLKEM_MONT_RED(p);
841
0
        p = (sword32)zeta4 * (sword16)(r3 - r7);
842
0
        t3 = MLKEM_MONT_RED(p);
843
0
        r0 = (sword16)(r0 + r4);
844
0
        r1 = (sword16)(r1 + r5);
845
0
        r2 = (sword16)(r2 + r6);
846
0
        r3 = (sword16)(r3 + r7);
847
0
        r4 = t0;
848
0
        r5 = t1;
849
0
        r6 = t2;
850
0
        r7 = t3;
851
852
0
        r[j + 0] = r0;
853
0
        r[j + 1] = r1;
854
0
        r[j + 2] = r2;
855
0
        r[j + 3] = r3;
856
0
        r[j + 4] = r4;
857
0
        r[j + 5] = r5;
858
0
        r[j + 6] = r6;
859
0
        r[j + 7] = r7;
860
0
    }
861
862
0
    for (j = 0; j < MLKEM_N; j += 64) {
863
0
        unsigned int i;
864
0
        sword16 zeta8_0  = zetas_inv[ 96 + j / 16 + 0];
865
0
        sword16 zeta8_1  = zetas_inv[ 96 + j / 16 + 1];
866
0
        sword16 zeta8_2  = zetas_inv[ 96 + j / 16 + 2];
867
0
        sword16 zeta8_3  = zetas_inv[ 96 + j / 16 + 3];
868
0
        sword16 zeta16_0 = zetas_inv[112 + j / 32 + 0];
869
0
        sword16 zeta16_1 = zetas_inv[112 + j / 32 + 1];
870
0
        sword16 zeta32   = zetas_inv[120 + j / 64 + 0];
871
0
        for (i = 0; i < 8; i++) {
872
0
            sword16 r0 = r[j + i +  0];
873
0
            sword16 r1 = r[j + i +  8];
874
0
            sword16 r2 = r[j + i + 16];
875
0
            sword16 r3 = r[j + i + 24];
876
0
            sword16 r4 = r[j + i + 32];
877
0
            sword16 r5 = r[j + i + 40];
878
0
            sword16 r6 = r[j + i + 48];
879
0
            sword16 r7 = r[j + i + 56];
880
881
0
            p = (sword32)zeta8_0 * (sword16)(r0 - r1);
882
0
            t0 = MLKEM_MONT_RED(p);
883
0
            p = (sword32)zeta8_1 * (sword16)(r2 - r3);
884
0
            t1 = MLKEM_MONT_RED(p);
885
0
            p = (sword32)zeta8_2 * (sword16)(r4 - r5);
886
0
            t2 = MLKEM_MONT_RED(p);
887
0
            p = (sword32)zeta8_3 * (sword16)(r6 - r7);
888
0
            t3 = MLKEM_MONT_RED(p);
889
0
            r0 = MLKEM_BARRETT_RED(r0 + r1);
890
0
            r2 = MLKEM_BARRETT_RED(r2 + r3);
891
0
            r4 = MLKEM_BARRETT_RED(r4 + r5);
892
0
            r6 = MLKEM_BARRETT_RED(r6 + r7);
893
0
            r1 = t0;
894
0
            r3 = t1;
895
0
            r5 = t2;
896
0
            r7 = t3;
897
898
0
            p = (sword32)zeta16_0 * (sword16)(r0 - r2);
899
0
            t0 = MLKEM_MONT_RED(p);
900
0
            p = (sword32)zeta16_0 * (sword16)(r1 - r3);
901
0
            t1 = MLKEM_MONT_RED(p);
902
0
            p = (sword32)zeta16_1 * (sword16)(r4 - r6);
903
0
            t2 = MLKEM_MONT_RED(p);
904
0
            p = (sword32)zeta16_1 * (sword16)(r5 - r7);
905
0
            t3 = MLKEM_MONT_RED(p);
906
0
            r0 = (sword16)(r0 + r2);
907
0
            r1 = (sword16)(r1 + r3);
908
0
            r4 = (sword16)(r4 + r6);
909
0
            r5 = (sword16)(r5 + r7);
910
0
            r2 = t0;
911
0
            r3 = t1;
912
0
            r6 = t2;
913
0
            r7 = t3;
914
915
0
            p = (sword32)zeta32 * (sword16)(r0 - r4);
916
0
            t0 = MLKEM_MONT_RED(p);
917
0
            p = (sword32)zeta32 * (sword16)(r1 - r5);
918
0
            t1 = MLKEM_MONT_RED(p);
919
0
            p = (sword32)zeta32 * (sword16)(r2 - r6);
920
0
            t2 = MLKEM_MONT_RED(p);
921
0
            p = (sword32)zeta32 * (sword16)(r3 - r7);
922
0
            t3 = MLKEM_MONT_RED(p);
923
0
            r0 = (sword16)(r0 + r4);
924
0
            r1 = (sword16)(r1 + r5);
925
0
            r2 = (sword16)(r2 + r6);
926
0
            r3 = (sword16)(r3 + r7);
927
0
            r4 = t0;
928
0
            r5 = t1;
929
0
            r6 = t2;
930
0
            r7 = t3;
931
932
0
            r[j + i +  0] = r0;
933
0
            r[j + i +  8] = r1;
934
0
            r[j + i + 16] = r2;
935
0
            r[j + i + 24] = r3;
936
0
            r[j + i + 32] = r4;
937
0
            r[j + i + 40] = r5;
938
0
            r[j + i + 48] = r6;
939
0
            r[j + i + 56] = r7;
940
0
        }
941
0
    }
942
943
0
    zeta64_0 = zetas_inv[124];
944
0
    zeta64_1 = zetas_inv[125];
945
0
    zeta128  = zetas_inv[126];
946
0
    zeta256  = zetas_inv[127];
947
0
    for (j = 0; j < MLKEM_N / 8; j++) {
948
0
        sword16 r0 = r[j +   0];
949
0
        sword16 r1 = r[j +  32];
950
0
        sword16 r2 = r[j +  64];
951
0
        sword16 r3 = r[j +  96];
952
0
        sword16 r4 = r[j + 128];
953
0
        sword16 r5 = r[j + 160];
954
0
        sword16 r6 = r[j + 192];
955
0
        sword16 r7 = r[j + 224];
956
957
0
        p = (sword32)zeta64_0 * (sword16)(r0 - r2);
958
0
        t0 = MLKEM_MONT_RED(p);
959
0
        p = (sword32)zeta64_0 * (sword16)(r1 - r3);
960
0
        t1 = MLKEM_MONT_RED(p);
961
0
        p = (sword32)zeta64_1 * (sword16)(r4 - r6);
962
0
        t2 = MLKEM_MONT_RED(p);
963
0
        p = (sword32)zeta64_1 * (sword16)(r5 - r7);
964
0
        t3 = MLKEM_MONT_RED(p);
965
0
        r0 = MLKEM_BARRETT_RED(r0 + r2);
966
0
        r1 = MLKEM_BARRETT_RED(r1 + r3);
967
0
        r4 = MLKEM_BARRETT_RED(r4 + r6);
968
0
        r5 = MLKEM_BARRETT_RED(r5 + r7);
969
0
        r2 = t0;
970
0
        r3 = t1;
971
0
        r6 = t2;
972
0
        r7 = t3;
973
974
0
        p = (sword32)zeta128 * (sword16)(r0 - r4);
975
0
        t0 = MLKEM_MONT_RED(p);
976
0
        p = (sword32)zeta128 * (sword16)(r1 - r5);
977
0
        t1 = MLKEM_MONT_RED(p);
978
0
        p = (sword32)zeta128 * (sword16)(r2 - r6);
979
0
        t2 = MLKEM_MONT_RED(p);
980
0
        p = (sword32)zeta128 * (sword16)(r3 - r7);
981
0
        t3 = MLKEM_MONT_RED(p);
982
0
        r0 = (sword16)(r0 + r4);
983
0
        r1 = (sword16)(r1 + r5);
984
0
        r2 = (sword16)(r2 + r6);
985
0
        r3 = (sword16)(r3 + r7);
986
0
        r4 = t0;
987
0
        r5 = t1;
988
0
        r6 = t2;
989
0
        r7 = t3;
990
991
0
        p = (sword32)zeta256 * r0;
992
0
        r0 = MLKEM_MONT_RED(p);
993
0
        p = (sword32)zeta256 * r1;
994
0
        r1 = MLKEM_MONT_RED(p);
995
0
        p = (sword32)zeta256 * r2;
996
0
        r2 = MLKEM_MONT_RED(p);
997
0
        p = (sword32)zeta256 * r3;
998
0
        r3 = MLKEM_MONT_RED(p);
999
0
        p = (sword32)zeta256 * r4;
1000
0
        r4 = MLKEM_MONT_RED(p);
1001
0
        p = (sword32)zeta256 * r5;
1002
0
        r5 = MLKEM_MONT_RED(p);
1003
0
        p = (sword32)zeta256 * r6;
1004
0
        r6 = MLKEM_MONT_RED(p);
1005
0
        p = (sword32)zeta256 * r7;
1006
0
        r7 = MLKEM_MONT_RED(p);
1007
1008
0
        r[j +   0] = r0;
1009
0
        r[j +  32] = r1;
1010
0
        r[j +  64] = r2;
1011
0
        r[j +  96] = r3;
1012
0
        r[j + 128] = r4;
1013
0
        r[j + 160] = r5;
1014
0
        r[j + 192] = r6;
1015
0
        r[j + 224] = r7;
1016
0
    }
1017
0
#endif
1018
0
}
1019
#endif
1020
1021
/* Multiplication of polynomials in Zq[X]/(X^2-zeta).
1022
 *
1023
 * Used for multiplication of elements in Rq in NTT domain.
1024
 *
1025
 * FIPS 203, Algorithm 12: BaseCaseMultiply(a0, a1, b0, b1, zeta)
1026
 * Computes the product of two degree-one polynomials with respect to a
1027
 * quadratic modulus.
1028
 *   1: c0 <- a0.b0 + a1.b1.zeta
1029
 *   2: c1 <- a0.b1 + a1.b0
1030
 *   3: return (c0, c1)
1031
 *
1032
 * @param  [out]  r     Result polynomial.
1033
 * @param  [in]   a     First factor.
1034
 * @param  [in]   b     Second factor.
1035
 * @param  [in]   zeta  Integer defining the reduction polynomial.
1036
 */
1037
static void mlkem_basemul(sword16* r, const sword16* a, const sword16* b,
1038
    sword16 zeta)
1039
0
{
1040
0
    sword16 r0;
1041
0
    sword16 a0 = a[0];
1042
0
    sword16 a1 = a[1];
1043
0
    sword16 b0 = b[0];
1044
0
    sword16 b1 = b[1];
1045
0
    sword32 p1;
1046
0
    sword32 p2;
1047
1048
    /* Step 1 */
1049
0
    p1   = (sword32)a0 * b0;
1050
0
    p2   = (sword32)a1 * b1;
1051
0
    r0   = MLKEM_MONT_RED(p2);
1052
0
    p2   = (sword32)zeta * r0;
1053
0
    p2  += p1;
1054
0
    r[0] = MLKEM_MONT_RED(p2);
1055
1056
    /* Step 2 */
1057
0
    p1   = (sword32)a0 * b1;
1058
0
    p2   = (sword32)a1 * b0;
1059
0
    p1  += p2;
1060
0
    r[1] = MLKEM_MONT_RED(p1);
1061
0
}
1062
1063
/* Multiply two polynomials in NTT domain. r = a * b.
1064
 *
1065
 * FIPS 203, Algorithm 11: MultiplyNTTs(f_hat, g_hat)
1066
 * Computes the product (in the ring T_q) of two NTT representations.
1067
 *   1: for (i <- 0; i < 128; i++)
1068
 *   2:     (h_hat[2i],h_hat[2i+1]) <-
1069
 *              BaseCaseMultiply(f_hat[2i],f_hat[2i+1],g_hat[2i],g_hat[2i+1],
1070
 *                               zetas^(BitRev_7(i)+1))
1071
 *   3: end for
1072
 *   4: return h_hat
1073
 *
1074
 * @param  [out]  r  Result polynomial.
1075
 * @param  [in]   a  First polynomial multiplier.
1076
 * @param  [in]   b  Second polynomial multiplier.
1077
 */
1078
static void mlkem_basemul_mont(sword16* r, const sword16* a, const sword16* b)
1079
0
{
1080
0
    const sword16* zeta = zetas + 64;
1081
1082
#if defined(WOLFSSL_MLKEM_SMALL)
1083
    /* Two multiplications per loop. */
1084
    unsigned int i;
1085
    /* Step 1 */
1086
    for (i = 0; i < MLKEM_N; i += 4, zeta++) {
1087
        /* Step 2 */
1088
        mlkem_basemul(r + i + 0, a + i + 0, b + i + 0, zeta[0]);
1089
        mlkem_basemul(r + i + 2, a + i + 2, b + i + 2, (sword16)(-zeta[0]));
1090
    }
1091
#elif defined(WOLFSSL_MLKEM_NO_LARGE_CODE)
1092
    /* Four multiplications per loop. */
1093
    unsigned int i;
1094
    for (i = 0; i < MLKEM_N; i += 8, zeta += 2) {
1095
        mlkem_basemul(r + i + 0, a + i + 0, b + i + 0, zeta[0]);
1096
        mlkem_basemul(r + i + 2, a + i + 2, b + i + 2, (sword16)(-zeta[0]));
1097
        mlkem_basemul(r + i + 4, a + i + 4, b + i + 4, zeta[1]);
1098
        mlkem_basemul(r + i + 6, a + i + 6, b + i + 6, (sword16)(-zeta[1]));
1099
    }
1100
#else
1101
    /* Eight multiplications per loop. */
1102
0
    unsigned int i;
1103
0
    for (i = 0; i < MLKEM_N; i += 16, zeta += 4) {
1104
0
        mlkem_basemul(r + i +  0, a + i +  0, b + i +  0, zeta[0]);
1105
0
        mlkem_basemul(r + i +  2, a + i +  2, b + i +  2, (sword16)(-zeta[0]));
1106
0
        mlkem_basemul(r + i +  4, a + i +  4, b + i +  4, zeta[1]);
1107
0
        mlkem_basemul(r + i +  6, a + i +  6, b + i +  6, (sword16)(-zeta[1]));
1108
0
        mlkem_basemul(r + i +  8, a + i +  8, b + i +  8, zeta[2]);
1109
0
        mlkem_basemul(r + i + 10, a + i + 10, b + i + 10, (sword16)(-zeta[2]));
1110
0
        mlkem_basemul(r + i + 12, a + i + 12, b + i + 12, zeta[3]);
1111
0
        mlkem_basemul(r + i + 14, a + i + 14, b + i + 14, (sword16)(-zeta[3]));
1112
0
    }
1113
0
#endif
1114
0
}
1115
1116
/* Multiply two polynomials in NTT domain and add to result. r += a * b.
1117
 *
1118
 * FIPS 203, Algorithm 11: MultiplyNTTs(f_hat, g_hat)
1119
 * Computes the product (in the ring T_q) of two NTT representations.
1120
 *   1: for (i <- 0; i < 128; i++)
1121
 *   2:     (h_hat[2i],h_hat[2i+1]) <-
1122
 *              BaseCaseMultiply(f_hat[2i],f_hat[2i+1],g_hat[2i],g_hat[2i+1],
1123
 *                               zetas^(BitRev_7(i)+1))
1124
 *   3: end for
1125
 *   4: return h_hat
1126
 * Add h_hat to r.
1127
 *
1128
 * @param  [in, out]  r  Result polynomial.
1129
 * @param  [in]       a  First polynomial multiplier.
1130
 * @param  [in]       b  Second polynomial multiplier.
1131
 */
1132
static void mlkem_basemul_mont_add(sword16* r, const sword16* a,
1133
    const sword16* b)
1134
0
{
1135
0
    const sword16* zeta = zetas + 64;
1136
1137
#if defined(WOLFSSL_MLKEM_SMALL)
1138
    /* Two multiplications per loop. */
1139
    unsigned int i;
1140
    for (i = 0; i < MLKEM_N; i += 4, zeta++) {
1141
        sword16 t0[2];
1142
        sword16 t2[2];
1143
1144
        mlkem_basemul(t0, a + i + 0, b + i + 0, zeta[0]);
1145
        mlkem_basemul(t2, a + i + 2, b + i + 2, (sword16)(-zeta[0]));
1146
1147
        r[i + 0] = (sword16)(r[i + 0] + t0[0]);
1148
        r[i + 1] = (sword16)(r[i + 1] + t0[1]);
1149
        r[i + 2] = (sword16)(r[i + 2] + t2[0]);
1150
        r[i + 3] = (sword16)(r[i + 3] + t2[1]);
1151
    }
1152
#elif defined(WOLFSSL_MLKEM_NO_LARGE_CODE)
1153
    /* Four multiplications per loop. */
1154
    unsigned int i;
1155
    for (i = 0; i < MLKEM_N; i += 8, zeta += 2) {
1156
        sword16 t0[2];
1157
        sword16 t2[2];
1158
        sword16 t4[2];
1159
        sword16 t6[2];
1160
1161
        mlkem_basemul(t0, a + i + 0, b + i + 0, zeta[0]);
1162
        mlkem_basemul(t2, a + i + 2, b + i + 2, (sword16)(-zeta[0]));
1163
        mlkem_basemul(t4, a + i + 4, b + i + 4, zeta[1]);
1164
        mlkem_basemul(t6, a + i + 6, b + i + 6, (sword16)(-zeta[1]));
1165
1166
        r[i + 0] = (sword16)(r[i + 0] + t0[0]);
1167
        r[i + 1] = (sword16)(r[i + 1] + t0[1]);
1168
        r[i + 2] = (sword16)(r[i + 2] + t2[0]);
1169
        r[i + 3] = (sword16)(r[i + 3] + t2[1]);
1170
        r[i + 4] = (sword16)(r[i + 4] + t4[0]);
1171
        r[i + 5] = (sword16)(r[i + 5] + t4[1]);
1172
        r[i + 6] = (sword16)(r[i + 6] + t6[0]);
1173
        r[i + 7] = (sword16)(r[i + 7] + t6[1]);
1174
    }
1175
#else
1176
    /* Eight multiplications per loop. */
1177
0
    unsigned int i;
1178
0
    for (i = 0; i < MLKEM_N; i += 16, zeta += 4) {
1179
0
        sword16 t0[2];
1180
0
        sword16 t2[2];
1181
0
        sword16 t4[2];
1182
0
        sword16 t6[2];
1183
0
        sword16 t8[2];
1184
0
        sword16 t10[2];
1185
0
        sword16 t12[2];
1186
0
        sword16 t14[2];
1187
1188
0
        mlkem_basemul(t0, a + i + 0, b + i + 0, zeta[0]);
1189
0
        mlkem_basemul(t2, a + i + 2, b + i + 2, (sword16)(-zeta[0]));
1190
0
        mlkem_basemul(t4, a + i + 4, b + i + 4, zeta[1]);
1191
0
        mlkem_basemul(t6, a + i + 6, b + i + 6, (sword16)(-zeta[1]));
1192
0
        mlkem_basemul(t8, a + i + 8, b + i + 8, zeta[2]);
1193
0
        mlkem_basemul(t10, a + i + 10, b + i + 10, (sword16)(-zeta[2]));
1194
0
        mlkem_basemul(t12, a + i + 12, b + i + 12, zeta[3]);
1195
0
        mlkem_basemul(t14, a + i + 14, b + i + 14, (sword16)(-zeta[3]));
1196
1197
0
        r[i + 0] = (sword16)(r[i + 0] + t0[0]);
1198
0
        r[i + 1] = (sword16)(r[i + 1] + t0[1]);
1199
0
        r[i + 2] = (sword16)(r[i + 2] + t2[0]);
1200
0
        r[i + 3] = (sword16)(r[i + 3] + t2[1]);
1201
0
        r[i + 4] = (sword16)(r[i + 4] + t4[0]);
1202
0
        r[i + 5] = (sword16)(r[i + 5] + t4[1]);
1203
0
        r[i + 6] = (sword16)(r[i + 6] + t6[0]);
1204
0
        r[i + 7] = (sword16)(r[i + 7] + t6[1]);
1205
0
        r[i + 8] = (sword16)(r[i + 8] + t8[0]);
1206
0
        r[i + 9] = (sword16)(r[i + 9] + t8[1]);
1207
0
        r[i + 10] = (sword16)(r[i + 10] + t10[0]);
1208
0
        r[i + 11] = (sword16)(r[i + 11] + t10[1]);
1209
0
        r[i + 12] = (sword16)(r[i + 12] + t12[0]);
1210
0
        r[i + 13] = (sword16)(r[i + 13] + t12[1]);
1211
0
        r[i + 14] = (sword16)(r[i + 14] + t14[0]);
1212
0
        r[i + 15] = (sword16)(r[i + 15] + t14[1]);
1213
0
    }
1214
0
#endif
1215
0
}
1216
#endif
1217
1218
/* Pointwise multiply elements of a and b, into r, and multiply by 2^-16.
1219
 *
1220
 * @param  [out]  r  Result polynomial.
1221
 * @param  [in]   a  First vector polynomial to multiply with.
1222
 * @param  [in]   b  Second vector polynomial to multiply with.
1223
 * @param  [in]   k  Number of polynomials in vector.
1224
 */
1225
static void mlkem_pointwise_acc_mont(sword16* r, const sword16* a,
1226
    const sword16* b, unsigned int k)
1227
0
{
1228
0
    unsigned int i;
1229
1230
0
    mlkem_basemul_mont(r, a, b);
1231
#ifdef WOLFSSL_MLKEM_SMALL
1232
    for (i = 1; i < k; ++i) {
1233
        mlkem_basemul_mont_add(r, a + i * MLKEM_N, b + i * MLKEM_N);
1234
    }
1235
#else
1236
0
    for (i = 1; i < k - 1; ++i) {
1237
0
        mlkem_basemul_mont_add(r, a + i * MLKEM_N, b + i * MLKEM_N);
1238
0
    }
1239
0
    mlkem_basemul_mont_add(r, a + (k - 1) * MLKEM_N, b + (k - 1) * MLKEM_N);
1240
0
#endif
1241
0
}
1242
1243
/******************************************************************************/
1244
1245
/* Initialize ML-KEM implementation.
1246
 */
1247
void mlkem_init(void)
1248
0
{
1249
#if defined(USE_INTEL_SPEEDUP) || (defined(__aarch64__) && \
1250
    defined(WOLFSSL_ARMASM))
1251
    cpuid_get_flags_ex(&cpuid_flags);
1252
#endif
1253
0
}
1254
1255
/******************************************************************************/
1256
1257
#if defined(__aarch64__) && defined(WOLFSSL_ARMASM)
1258
1259
#ifndef WOLFSSL_MLKEM_NO_MAKE_KEY
1260
/* Generate a public-private key pair from randomly generated data.
1261
 *
1262
 * FIPS 203, Algorithm 13: K-PKE.KeyGen(d)
1263
 *   ...
1264
 *   16: s_hat <- NTT(s)
1265
 *   17: e_hat <- NTT(e)
1266
 *   18: t_hat <- A_hat o s_hat + e_hat
1267
 *   ...
1268
 *
1269
 * @param  [in, out]  s  Private key vector of polynomials.
1270
 * @param  [out]      t  Public key vector of polynomials.
1271
 * @param  [in, out]  e  Error values as a vector of polynomials. Modified.
1272
 * @param  [in]       a  Random values in an array of vectors of polynomials.
1273
 * @param  [in]       k  Number of polynomials in vector.
1274
 */
1275
void mlkem_keygen(sword16* s, sword16* t, sword16* e, const sword16* a, int k)
1276
{
1277
    int i;
1278
1279
#ifndef WOLFSSL_AARCH64_NO_SQRDMLSH
1280
    if (IS_AARCH64_RDM(cpuid_flags)) {
1281
        /* Transform private key. All of result used in public key calculation.
1282
         * Step 16: s_hat = NTT(s) */
1283
        for (i = 0; i < k; ++i) {
1284
            mlkem_ntt_sqrdmlsh(s + i * MLKEM_N);
1285
        }
1286
1287
        /* For each polynomial in the vectors.
1288
         * Step 17, Step 18: Calculate public from A_hat, s_hat and e_hat. */
1289
        for (i = 0; i < k; ++i) {
1290
            /* Multiply a by private into public polynomial.
1291
             * Step 18: ... A_hat o s_hat ... */
1292
            mlkem_pointwise_acc_mont(t + i * MLKEM_N, a + i * k * MLKEM_N, s,
1293
                (unsigned int)k);
1294
            /* Convert public polynomial to Montgomery form.
1295
             * Step 18: ... MontRed(A_hat o s_hat) ... */
1296
            mlkem_to_mont_sqrdmlsh(t + i * MLKEM_N);
1297
            /* Transform error values polynomial.
1298
             * Step 17: e_hat = NTT(e) */
1299
            mlkem_ntt_sqrdmlsh(e + i * MLKEM_N);
1300
            /* Add errors to public key and reduce.
1301
             * Step 18: t_hat = BarrettRed(MontRed(A_hat o s_hat) + e_hat) */
1302
            mlkem_add_reduce(t + i * MLKEM_N, e + i * MLKEM_N);
1303
        }
1304
    }
1305
    else
1306
#endif
1307
    {
1308
        /* Transform private key. All of result used in public key calculation.
1309
         * Step 16: s_hat = NTT(s) */
1310
        for (i = 0; i < k; ++i) {
1311
            mlkem_ntt(s + i * MLKEM_N);
1312
        }
1313
1314
        /* For each polynomial in the vectors.
1315
         * Step 17, Step 18: Calculate public from A_hat, s_hat and e_hat. */
1316
        for (i = 0; i < k; ++i) {
1317
            /* Multiply a by private into public polynomial.
1318
             * Step 18: ... A_hat o s_hat ... */
1319
            mlkem_pointwise_acc_mont(t + i * MLKEM_N, a + i * k * MLKEM_N, s,
1320
                (unsigned int)k);
1321
            /* Convert public polynomial to Montgomery form.
1322
             * Step 18: ... MontRed(A_hat o s_hat) ... */
1323
            mlkem_to_mont(t + i * MLKEM_N);
1324
            /* Transform error values polynomial.
1325
             * Step 17: e_hat = NTT(e) */
1326
            mlkem_ntt(e + i * MLKEM_N);
1327
            /* Add errors to public key and reduce.
1328
             * Step 18: t_hat = BarrettRed(MontRed(A_hat o s_hat) + e_hat) */
1329
            mlkem_add_reduce(t + i * MLKEM_N, e + i * MLKEM_N);
1330
        }
1331
    }
1332
}
1333
#endif /* WOLFSSL_MLKEM_NO_MAKE_KEY */
1334
1335
#if !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \
1336
    !defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
1337
/* Encapsulate message.
1338
 *
1339
 * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE, m, r)
1340
 *   ...
1341
 *   Step 18: y_hat <- NTT(y)
1342
 *   Step 19: u <- InvNTT(A_hat_trans o y_hat) + e_1
1343
 *   ...
1344
 *   Step 21: v <- InvNTT(t_hat_trans o y_hat) + e_2 + mu
1345
 *   ...
1346
 *
1347
 * @param  [in]       t   Public key vector of polynomials.
1348
 * @param  [out]      u   Vector of polynomials.
1349
 * @param  [out]      v   Polynomial.
1350
 * @param  [in]       a   Array of vector of polynomials.
1351
 * @param  [in, out]  y   Vector of polynomials.
1352
 * @param  [in]       e1  Error Vector of polynomials.
1353
 * @param  [in]       e2  Error polynomial.
1354
 * @param  [in]       m   Message polynomial.
1355
 * @param  [in]       k   Number of polynomials in vector.
1356
 */
1357
void mlkem_encapsulate(const sword16* t, sword16* u, sword16* v,
1358
    const sword16* a, sword16* y, const sword16* e1, const sword16* e2,
1359
    const sword16* m, int k)
1360
{
1361
    int i;
1362
1363
#ifndef WOLFSSL_AARCH64_NO_SQRDMLSH
1364
    if (IS_AARCH64_RDM(cpuid_flags)) {
1365
        /* Transform y. All of result used in calculation of u and v.
1366
         * Step 18: y_hat <- NTT(y) */
1367
        for (i = 0; i < k; ++i) {
1368
            mlkem_ntt_sqrdmlsh(y + i * MLKEM_N);
1369
        }
1370
1371
        /* For each polynomial in the vectors.
1372
         * Step 19: u <- InvNTT(A_hat_trans o y_hat) + e_1 */
1373
        for (i = 0; i < k; ++i) {
1374
            /* Multiply at by y into u polynomial.
1375
             * Step 19: ... A_hat_trans o y_hat ... */
1376
            mlkem_pointwise_acc_mont(u + i * MLKEM_N, a + i * k * MLKEM_N, y,
1377
                (unsigned int)k);
1378
            /* Inverse transform u polynomial.
1379
             * Step 19: ... InvNTT(A_hat_trans o y_hat) ... */
1380
            mlkem_invntt_sqrdmlsh(u + i * MLKEM_N);
1381
            /* Add errors to u and reduce.
1382
             * Step 19: u <- InvNTT(A_hat_trans o y_hat) + e_1 */
1383
            mlkem_add_reduce(u + i * MLKEM_N, e1 + i * MLKEM_N);
1384
        }
1385
1386
        /* Multiply public key by y into v polynomial.
1387
         * Step 21: ... t_hat_trans o y_hat ... */
1388
        mlkem_pointwise_acc_mont(v, t, y, (unsigned int)k);
1389
        /* Inverse transform v.
1390
         * Step 21: ... InvNTT(t_hat_trans o y_hat) ... */
1391
        mlkem_invntt_sqrdmlsh(v);
1392
    }
1393
    else
1394
#endif
1395
    {
1396
        /* Transform y. All of result used in calculation of u and v.
1397
         * Step 18: y_hat <- NTT(y) */
1398
        for (i = 0; i < k; ++i) {
1399
            mlkem_ntt(y + i * MLKEM_N);
1400
        }
1401
1402
        /* For each polynomial in the vectors.
1403
         * Step 19: u <- InvNTT(A_hat_trans o y_hat) + e_1 */
1404
        for (i = 0; i < k; ++i) {
1405
            /* Multiply at by y into u polynomial.
1406
             * Step 19: ... A_hat_trans o y_hat ... */
1407
            mlkem_pointwise_acc_mont(u + i * MLKEM_N, a + i * k * MLKEM_N, y,
1408
                (unsigned int)k);
1409
            /* Inverse transform u polynomial.
1410
             * Step 19: ... InvNTT(A_hat_trans o y_hat) ... */
1411
            mlkem_invntt(u + i * MLKEM_N);
1412
            /* Add errors to u and reduce.
1413
             * Step 19: u <- InvNTT(A_hat_trans o y_hat) + e_1 */
1414
            mlkem_add_reduce(u + i * MLKEM_N, e1 + i * MLKEM_N);
1415
        }
1416
1417
        /* Multiply public key by y into v polynomial.
1418
         * Step 21: ... t_hat_trans o y_hat ... */
1419
        mlkem_pointwise_acc_mont(v, t, y, (unsigned int)k);
1420
        /* Inverse transform v.
1421
         * Step 21: ... InvNTT(t_hat_trans o y_hat) ... */
1422
        mlkem_invntt(v);
1423
    }
1424
    /* Add errors and message to v and reduce.
1425
     * Step 21: v <- InvNTT(t_hat_trans o y_hat) + e_2 + mu */
1426
    mlkem_add3_reduce(v, e2, m);
1427
}
1428
#endif /* !WOLFSSL_MLKEM_NO_ENCAPSULATE || !WOLFSSL_MLKEM_NO_DECAPSULATE */
1429
1430
#ifndef WOLFSSL_MLKEM_NO_DECAPSULATE
1431
/* Decapsulate message.
1432
 *
1433
 * FIPS 203, Algorithm 15: K-PKE.Decrypt(dk_PKE,c)
1434
 * Uses the decryption key to decrypt a ciphertext.
1435
 *   ...
1436
 *   6: w <- v' - InvNTT(s_hat_trans o NTT(u'))
1437
 *   ...
1438
 *
1439
 * @param  [in]       s  Decryption key as vector of polynomials.
1440
 * @param  [out]      w  Message polynomial.
1441
 * @param  [in, out]  u  Vector of polynomials containing error.
1442
 * @param  [in]       v  Encapsulated message polynomial.
1443
 * @param  [in]       k  Number of polynomials in vector.
1444
 */
1445
void mlkem_decapsulate(const sword16* s, sword16* w, sword16* u,
1446
    const sword16* v, int k)
1447
{
1448
    int i;
1449
1450
#ifndef WOLFSSL_AARCH64_NO_SQRDMLSH
1451
    if (IS_AARCH64_RDM(cpuid_flags)) {
1452
        /* Transform u. All of result used in calculation of w.
1453
         * Step 6: ... NTT(u') */
1454
        for (i = 0; i < k; ++i) {
1455
            mlkem_ntt_sqrdmlsh(u + i * MLKEM_N);
1456
        }
1457
1458
        /* Multiply private key by u into w polynomial.
1459
         * Step 6: ... s_hat_trans o NTT(u') */
1460
        mlkem_pointwise_acc_mont(w, s, u, (unsigned int)k);
1461
        /* Inverse transform w.
1462
         * Step 6: ... InvNTT(s_hat_trans o NTT(u')) */
1463
        mlkem_invntt_sqrdmlsh(w);
1464
    }
1465
    else
1466
#endif
1467
    {
1468
        /* Transform u. All of result used in calculation of w.
1469
         * Step 6: ... NTT(u') */
1470
        for (i = 0; i < k; ++i) {
1471
            mlkem_ntt(u + i * MLKEM_N);
1472
        }
1473
1474
        /* Multiply private key by u into w polynomial.
1475
         * Step 6: ... s_hat_trans o NTT(u') */
1476
        mlkem_pointwise_acc_mont(w, s, u, (unsigned int)k);
1477
        /* Inverse transform w.
1478
         * Step 6: ... InvNTT(s_hat_trans o NTT(u')) */
1479
        mlkem_invntt(w);
1480
    }
1481
    /* Subtract errors (in w) out of v and reduce into w.
1482
     * Step 6: w <- v' - InvNTT(s_hat_trans o NTT(u')) */
1483
    mlkem_rsub_reduce(w, v);
1484
}
1485
#endif /* !WOLFSSL_MLKEM_NO_DECAPSULATE */
1486
1487
#else
1488
1489
#ifndef WOLFSSL_MLKEM_NO_MAKE_KEY
1490
1491
#if !defined(WOLFSSL_MLKEM_SMALL) && !defined(WOLFSSL_MLKEM_NO_LARGE_CODE)
1492
/* Number-Theoretic Transform.
1493
 *
1494
 * FIPS 203, Algorithm 9: NTT(f)
1495
 * Computes the NTT representation f_hat of the given polynomial f element of
1496
 * R_q.
1497
 *   1: f_hat <- f
1498
 *   2: i <- 1
1499
 *   3: for (len <- 128; len >= 2; len <- len/2)
1500
 *   4:     for (start <- 0; start < 256; start <- start + 2.len)
1501
 *   5:         zeta <- zetas^BitRev_7(i) mod q
1502
 *   6:         i <- i + 1
1503
 *   7:         for (j <- start; j < start + len; j++)
1504
 *   8:             t <- zeta.f[j+len]
1505
 *   9:             f_hat[j+len] <- f_hat[j] - t
1506
 *  10:             f_hat[j] <- f_hat[j] + t
1507
 *  11:         end for
1508
 *  12:     end for
1509
 *  13: end for
1510
 *  14: return f_hat
1511
 *
1512
 * @param [in, out]  r  Polynomial to transform.
1513
 * @param [in, out]  a  Polynomial to add NTT result to.
1514
 */
1515
static void mlkem_ntt_add_to(sword16* r, sword16* a)
1516
0
{
1517
#if defined(WOLFSSL_MLKEM_NTT_UNROLL)
1518
    /* Unroll len loop (Step 3). */
1519
    unsigned int k = 1;
1520
    unsigned int j;
1521
    unsigned int start;
1522
    sword16 zeta = zetas[k++];
1523
1524
    /* len = 128 */
1525
    for (j = 0; j < MLKEM_N / 2; ++j) {
1526
        sword32 p = (sword32)zeta * r[j + MLKEM_N / 2];
1527
        sword16 t = MLKEM_MONT_RED(p);
1528
        sword16 rj = r[j];
1529
        r[j + MLKEM_N / 2] = rj - t;
1530
        r[j] = rj + t;
1531
    }
1532
    /* len = 64 */
1533
    for (start = 0; start < MLKEM_N; start += 2 * 64) {
1534
        zeta = zetas[k++];
1535
        for (j = 0; j < 64; ++j) {
1536
            sword32 p = (sword32)zeta * r[start + j + 64];
1537
            sword16 t = MLKEM_MONT_RED(p);
1538
            sword16 rj = r[start + j];
1539
            r[start + j + 64] = rj - t;
1540
            r[start + j] = rj + t;
1541
        }
1542
    }
1543
    /* len = 32 */
1544
    for (start = 0; start < MLKEM_N; start += 2 * 32) {
1545
        zeta = zetas[k++];
1546
        for (j = 0; j < 32; ++j) {
1547
            sword32 p = (sword32)zeta * r[start + j + 32];
1548
            sword16 t = MLKEM_MONT_RED(p);
1549
            sword16 rj = r[start + j];
1550
            r[start + j + 32] = rj - t;
1551
            r[start + j] = rj + t;
1552
        }
1553
    }
1554
    /* len = 16 */
1555
    for (start = 0; start < MLKEM_N; start += 2 * 16) {
1556
        zeta = zetas[k++];
1557
        for (j = 0; j < 16; ++j) {
1558
            sword32 p = (sword32)zeta * r[start + j + 16];
1559
            sword16 t = MLKEM_MONT_RED(p);
1560
            sword16 rj = r[start + j];
1561
            r[start + j + 16] = rj - t;
1562
            r[start + j] = rj + t;
1563
        }
1564
    }
1565
    /* len = 8 */
1566
    for (start = 0; start < MLKEM_N; start += 2 * 8) {
1567
        zeta = zetas[k++];
1568
        for (j = 0; j < 8; ++j) {
1569
            sword32 p = (sword32)zeta * r[start + j + 8];
1570
            sword16 t = MLKEM_MONT_RED(p);
1571
            sword16 rj = r[start + j];
1572
            r[start + j + 8] = rj - t;
1573
            r[start + j] = rj + t;
1574
        }
1575
    }
1576
    /* len = 4 */
1577
    for (start = 0; start < MLKEM_N; start += 2 * 4) {
1578
        zeta = zetas[k++];
1579
        for (j = 0; j < 4; ++j) {
1580
            sword32 p = (sword32)zeta * r[start + j + 4];
1581
            sword16 t = MLKEM_MONT_RED(p);
1582
            sword16 rj = r[start + j];
1583
            r[start + j + 4] = rj - t;
1584
            r[start + j] = rj + t;
1585
        }
1586
    }
1587
    /* len = 2 */
1588
    for (start = 0; start < MLKEM_N; start += 2 * 2) {
1589
        zeta = zetas[k++];
1590
        for (j = 0; j < 2; ++j) {
1591
            sword32 p = (sword32)zeta * r[start + j + 2];
1592
            sword16 t = MLKEM_MONT_RED(p);
1593
            sword16 rj = r[start + j];
1594
            r[start + j + 2] = rj - t;
1595
            r[start + j] = rj + t;
1596
        }
1597
    }
1598
    /* Reduce coefficients with quick algorithm. */
1599
    for (j = 0; j < MLKEM_N; ++j) {
1600
        sword16 t = a[j] + r[j];
1601
        a[j] = MLKEM_BARRETT_RED(t);
1602
    }
1603
#else /* !WOLFSSL_MLKEM_NTT_UNROLL */
1604
    /* Unroll len (2, 3, 2) and start loops. */
1605
0
    unsigned int j;
1606
0
    sword16 t0;
1607
0
    sword16 t1;
1608
0
    sword16 t2;
1609
0
    sword16 t3;
1610
1611
    /* len = 128,64 */
1612
0
    sword16 zeta128 = zetas[1];
1613
0
    sword16 zeta64_0 = zetas[2];
1614
0
    sword16 zeta64_1 = zetas[3];
1615
0
    for (j = 0; j < MLKEM_N / 8; j++) {
1616
0
        sword16 r0 = r[j +   0];
1617
0
        sword16 r1 = r[j +  32];
1618
0
        sword16 r2 = r[j +  64];
1619
0
        sword16 r3 = r[j +  96];
1620
0
        sword16 r4 = r[j + 128];
1621
0
        sword16 r5 = r[j + 160];
1622
0
        sword16 r6 = r[j + 192];
1623
0
        sword16 r7 = r[j + 224];
1624
1625
0
        t0 = MLKEM_MONT_RED((sword32)zeta128 * r4);
1626
0
        t1 = MLKEM_MONT_RED((sword32)zeta128 * r5);
1627
0
        t2 = MLKEM_MONT_RED((sword32)zeta128 * r6);
1628
0
        t3 = MLKEM_MONT_RED((sword32)zeta128 * r7);
1629
0
        r4 = (sword16)(r0 - t0);
1630
0
        r5 = (sword16)(r1 - t1);
1631
0
        r6 = (sword16)(r2 - t2);
1632
0
        r7 = (sword16)(r3 - t3);
1633
0
        r0 = (sword16)(r0 + t0);
1634
0
        r1 = (sword16)(r1 + t1);
1635
0
        r2 = (sword16)(r2 + t2);
1636
0
        r3 = (sword16)(r3 + t3);
1637
1638
0
        t0 = MLKEM_MONT_RED((sword32)zeta64_0 * r2);
1639
0
        t1 = MLKEM_MONT_RED((sword32)zeta64_0 * r3);
1640
0
        t2 = MLKEM_MONT_RED((sword32)zeta64_1 * r6);
1641
0
        t3 = MLKEM_MONT_RED((sword32)zeta64_1 * r7);
1642
0
        r2 = (sword16)(r0 - t0);
1643
0
        r3 = (sword16)(r1 - t1);
1644
0
        r6 = (sword16)(r4 - t2);
1645
0
        r7 = (sword16)(r5 - t3);
1646
0
        r0 = (sword16)(r0 + t0);
1647
0
        r1 = (sword16)(r1 + t1);
1648
0
        r4 = (sword16)(r4 + t2);
1649
0
        r5 = (sword16)(r5 + t3);
1650
1651
0
        r[j +   0] = r0;
1652
0
        r[j +  32] = r1;
1653
0
        r[j +  64] = r2;
1654
0
        r[j +  96] = r3;
1655
0
        r[j + 128] = r4;
1656
0
        r[j + 160] = r5;
1657
0
        r[j + 192] = r6;
1658
0
        r[j + 224] = r7;
1659
0
    }
1660
1661
    /* len = 32,16,8 */
1662
0
    for (j = 0; j < MLKEM_N; j += 64) {
1663
0
        unsigned int i;
1664
0
        sword16 zeta32   = zetas[ 4 + j / 64 + 0];
1665
0
        sword16 zeta16_0 = zetas[ 8 + j / 32 + 0];
1666
0
        sword16 zeta16_1 = zetas[ 8 + j / 32 + 1];
1667
0
        sword16 zeta8_0  = zetas[16 + j / 16 + 0];
1668
0
        sword16 zeta8_1  = zetas[16 + j / 16 + 1];
1669
0
        sword16 zeta8_2  = zetas[16 + j / 16 + 2];
1670
0
        sword16 zeta8_3  = zetas[16 + j / 16 + 3];
1671
0
        for (i = 0; i < 8; i++) {
1672
0
            sword16 r0 = r[j + i +  0];
1673
0
            sword16 r1 = r[j + i +  8];
1674
0
            sword16 r2 = r[j + i + 16];
1675
0
            sword16 r3 = r[j + i + 24];
1676
0
            sword16 r4 = r[j + i + 32];
1677
0
            sword16 r5 = r[j + i + 40];
1678
0
            sword16 r6 = r[j + i + 48];
1679
0
            sword16 r7 = r[j + i + 56];
1680
1681
0
            t0 = MLKEM_MONT_RED((sword32)zeta32 * r4);
1682
0
            t1 = MLKEM_MONT_RED((sword32)zeta32 * r5);
1683
0
            t2 = MLKEM_MONT_RED((sword32)zeta32 * r6);
1684
0
            t3 = MLKEM_MONT_RED((sword32)zeta32 * r7);
1685
0
            r4 = (sword16)(r0 - t0);
1686
0
            r5 = (sword16)(r1 - t1);
1687
0
            r6 = (sword16)(r2 - t2);
1688
0
            r7 = (sword16)(r3 - t3);
1689
0
            r0 = (sword16)(r0 + t0);
1690
0
            r1 = (sword16)(r1 + t1);
1691
0
            r2 = (sword16)(r2 + t2);
1692
0
            r3 = (sword16)(r3 + t3);
1693
1694
0
            t0 = MLKEM_MONT_RED((sword32)zeta16_0 * r2);
1695
0
            t1 = MLKEM_MONT_RED((sword32)zeta16_0 * r3);
1696
0
            t2 = MLKEM_MONT_RED((sword32)zeta16_1 * r6);
1697
0
            t3 = MLKEM_MONT_RED((sword32)zeta16_1 * r7);
1698
0
            r2 = (sword16)(r0 - t0);
1699
0
            r3 = (sword16)(r1 - t1);
1700
0
            r6 = (sword16)(r4 - t2);
1701
0
            r7 = (sword16)(r5 - t3);
1702
0
            r0 = (sword16)(r0 + t0);
1703
0
            r1 = (sword16)(r1 + t1);
1704
0
            r4 = (sword16)(r4 + t2);
1705
0
            r5 = (sword16)(r5 + t3);
1706
1707
0
            t0 = MLKEM_MONT_RED((sword32)zeta8_0 * r1);
1708
0
            t1 = MLKEM_MONT_RED((sword32)zeta8_1 * r3);
1709
0
            t2 = MLKEM_MONT_RED((sword32)zeta8_2 * r5);
1710
0
            t3 = MLKEM_MONT_RED((sword32)zeta8_3 * r7);
1711
0
            r1 = (sword16)(r0 - t0);
1712
0
            r3 = (sword16)(r2 - t1);
1713
0
            r5 = (sword16)(r4 - t2);
1714
0
            r7 = (sword16)(r6 - t3);
1715
0
            r0 = (sword16)(r0 + t0);
1716
0
            r2 = (sword16)(r2 + t1);
1717
0
            r4 = (sword16)(r4 + t2);
1718
0
            r6 = (sword16)(r6 + t3);
1719
1720
0
            r[j + i +  0] = r0;
1721
0
            r[j + i +  8] = r1;
1722
0
            r[j + i + 16] = r2;
1723
0
            r[j + i + 24] = r3;
1724
0
            r[j + i + 32] = r4;
1725
0
            r[j + i + 40] = r5;
1726
0
            r[j + i + 48] = r6;
1727
0
            r[j + i + 56] = r7;
1728
0
        }
1729
0
    }
1730
1731
    /* len = 4,2 and Final reduction */
1732
0
    for (j = 0; j < MLKEM_N; j += 8) {
1733
0
        sword16 zeta4  = zetas[32 + j / 8 + 0];
1734
0
        sword16 zeta2_0 = zetas[64 + j / 4 + 0];
1735
0
        sword16 zeta2_1 = zetas[64 + j / 4 + 1];
1736
0
        sword16 r0 = r[j + 0];
1737
0
        sword16 r1 = r[j + 1];
1738
0
        sword16 r2 = r[j + 2];
1739
0
        sword16 r3 = r[j + 3];
1740
0
        sword16 r4 = r[j + 4];
1741
0
        sword16 r5 = r[j + 5];
1742
0
        sword16 r6 = r[j + 6];
1743
0
        sword16 r7 = r[j + 7];
1744
1745
0
        t0 = MLKEM_MONT_RED((sword32)zeta4 * r4);
1746
0
        t1 = MLKEM_MONT_RED((sword32)zeta4 * r5);
1747
0
        t2 = MLKEM_MONT_RED((sword32)zeta4 * r6);
1748
0
        t3 = MLKEM_MONT_RED((sword32)zeta4 * r7);
1749
0
        r4 = (sword16)(r0 - t0);
1750
0
        r5 = (sword16)(r1 - t1);
1751
0
        r6 = (sword16)(r2 - t2);
1752
0
        r7 = (sword16)(r3 - t3);
1753
0
        r0 = (sword16)(r0 + t0);
1754
0
        r1 = (sword16)(r1 + t1);
1755
0
        r2 = (sword16)(r2 + t2);
1756
0
        r3 = (sword16)(r3 + t3);
1757
1758
0
        t0 = MLKEM_MONT_RED((sword32)zeta2_0 * r2);
1759
0
        t1 = MLKEM_MONT_RED((sword32)zeta2_0 * r3);
1760
0
        t2 = MLKEM_MONT_RED((sword32)zeta2_1 * r6);
1761
0
        t3 = MLKEM_MONT_RED((sword32)zeta2_1 * r7);
1762
0
        r2 = (sword16)(r0 - t0);
1763
0
        r3 = (sword16)(r1 - t1);
1764
0
        r6 = (sword16)(r4 - t2);
1765
0
        r7 = (sword16)(r5 - t3);
1766
0
        r0 = (sword16)(r0 + t0);
1767
0
        r1 = (sword16)(r1 + t1);
1768
0
        r4 = (sword16)(r4 + t2);
1769
0
        r5 = (sword16)(r5 + t3);
1770
1771
0
        r0 = (sword16)(r0 + a[j + 0]);
1772
0
        r1 = (sword16)(r1 + a[j + 1]);
1773
0
        r2 = (sword16)(r2 + a[j + 2]);
1774
0
        r3 = (sword16)(r3 + a[j + 3]);
1775
0
        r4 = (sword16)(r4 + a[j + 4]);
1776
0
        r5 = (sword16)(r5 + a[j + 5]);
1777
0
        r6 = (sword16)(r6 + a[j + 6]);
1778
0
        r7 = (sword16)(r7 + a[j + 7]);
1779
1780
0
        a[j + 0] = MLKEM_BARRETT_RED(r0);
1781
0
        a[j + 1] = MLKEM_BARRETT_RED(r1);
1782
0
        a[j + 2] = MLKEM_BARRETT_RED(r2);
1783
0
        a[j + 3] = MLKEM_BARRETT_RED(r3);
1784
0
        a[j + 4] = MLKEM_BARRETT_RED(r4);
1785
0
        a[j + 5] = MLKEM_BARRETT_RED(r5);
1786
0
        a[j + 6] = MLKEM_BARRETT_RED(r6);
1787
0
        a[j + 7] = MLKEM_BARRETT_RED(r7);
1788
0
    }
1789
0
#endif /* !WOLFSSL_MLKEM_NTT_UNROLL */
1790
0
}
1791
#endif /* !WOLFSSL_MLKEM_SMALL && !WOLFSSL_MLKEM_NO_LARGE_CODE */
1792
1793
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
1794
/* Generate a public-private key pair from randomly generated data.
1795
 *
1796
 * FIPS 203, Algorithm 13: K-PKE.KeyGen(d)
1797
 *   ...
1798
 *   16: s_hat <- NTT(s)
1799
 *   17: e_hat <- NTT(e)
1800
 *   18: t_hat <- A_hat o s_hat + e_hat
1801
 *   ...
1802
 *
1803
 * @param  [in, out]  s  Private key vector of polynomials.
1804
 * @param  [out]      t  Public key vector of polynomials.
1805
 * @param  [in, out]  e  Error values as a vector of polynomials. Modified.
1806
 * @param  [in]       a  Random values in an array of vectors of polynomials.
1807
 * @param  [in]       k  Number of polynomials in vector.
1808
 */
1809
static void mlkem_keygen_c(sword16* s, sword16* t, sword16* e, const sword16* a,
1810
    int k)
1811
0
{
1812
0
    int i;
1813
1814
    /* Transform private key. All of result used in public key calculation
1815
     * Step 16: s_hat = NTT(s) */
1816
0
    for (i = 0; i < k; ++i) {
1817
0
        mlkem_ntt(s + i * MLKEM_N);
1818
0
    }
1819
1820
    /* For each polynomial in the vectors.
1821
     * Step 17, Step 18: Calculate public from A_hat, s_hat and e_hat. */
1822
0
    for (i = 0; i < k; ++i) {
1823
0
        int j;
1824
1825
        /* Multiply a by private into public polynomial.
1826
         * Step 18: ... A_hat o s_hat ... */
1827
0
        mlkem_pointwise_acc_mont(t + i * MLKEM_N, a + i * k * MLKEM_N, s,
1828
0
            (unsigned int)k);
1829
        /* Convert public polynomial to Montgomery form.
1830
         * Step 18: ... MontRed(A_hat o s_hat) ... */
1831
0
        for (j = 0; j < MLKEM_N; ++j) {
1832
0
            sword32 n = t[i * MLKEM_N + j] * (sword32)MLKEM_F;
1833
0
            t[i * MLKEM_N + j] = MLKEM_MONT_RED(n);
1834
0
        }
1835
        /* Transform error values polynomial.
1836
         * Step 17: e_hat = NTT(e) */
1837
#if defined(WOLFSSL_MLKEM_SMALL) || defined(WOLFSSL_MLKEM_NO_LARGE_CODE)
1838
        mlkem_ntt(e + i * MLKEM_N);
1839
        /* Add errors to public key and reduce.
1840
         * Step 18: t_hat = BarrettRed(MontRed(A_hat o s_hat) + e_hat) */
1841
        for (j = 0; j < MLKEM_N; ++j) {
1842
            sword16 n = (sword16)(t[i * MLKEM_N + j] + e[i * MLKEM_N + j]);
1843
            t[i * MLKEM_N + j] = MLKEM_BARRETT_RED(n);
1844
        }
1845
#else
1846
        /* Add errors to public key and reduce.
1847
         * Step 18: t_hat = BarrettRed(MontRed(A_hat o s_hat) + e_hat) */
1848
0
        mlkem_ntt_add_to(e + i * MLKEM_N, t + i * MLKEM_N);
1849
0
#endif
1850
0
    }
1851
0
}
1852
1853
/* Generate a public-private key pair from randomly generated data.
1854
 *
1855
 * FIPS 203, Algorithm 13: K-PKE.KeyGen(d)
1856
 *   ...
1857
 *   16: s_hat <- NTT(s)
1858
 *   17: e_hat <- NTT(e)
1859
 *   18: t_hat <- A_hat o s_hat + e_hat
1860
 *   ...
1861
 *
1862
 * @param  [in, out]  s  Private key vector of polynomials.
1863
 * @param  [out]      t  Public key vector of polynomials.
1864
 * @param  [in, out]  e  Error values as a vector of polynomials. Modified.
1865
 * @param  [in]       a  Random values in an array of vectors of polynomials.
1866
 * @param  [in]       k  Number of polynomials in vector.
1867
 */
1868
void mlkem_keygen(sword16* s, sword16* t, sword16* e, const sword16* a, int k)
1869
0
{
1870
#ifdef USE_INTEL_SPEEDUP
1871
    if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
1872
        /* Alg 13: Steps 16-18 */
1873
        mlkem_keygen_avx2(s, t, e, a, k);
1874
        RESTORE_VECTOR_REGISTERS();
1875
    }
1876
    else
1877
#endif
1878
0
    {
1879
        /* Alg 13: Steps 16-18 */
1880
0
        mlkem_keygen_c(s, t, e, a, k);
1881
0
    }
1882
0
}
1883
1884
#else /* WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM */
1885
1886
/* Generate a public-private key pair from randomly generated data.
1887
 *
1888
 * FIPS 203, Algorithm 13: K-PKE.KeyGen(d)
1889
 *   3: for (i <- 0; i < k; i++)                         > generate matrix A_hat
1890
 *   ... (generate A[i])
1891
 *   7: end for
1892
 *   ...
1893
 *  13:      e[i] <- SamplePolyCBD_eta_1(PRF_eta_1(sigma, N))
1894
 *   ...
1895
 *  16: s_hat <- NTT(s)
1896
 *  17: e_hat <- NTT(e)
1897
 *  18: t_hat <- A_hat o s_hat + e_hat
1898
 *   ...
1899
 *
1900
 * @param  [in, out]  s      Private key vector of polynomials.
1901
 * @param  [out]      t      Public key vector of polynomials.
1902
 * @param  [in, out]  prf    XOF object.
1903
 * @param  [in]       tv     Temporary vector of polynomials.
1904
 * @param  [in]       k      Number of polynomials in vector.
1905
 * @param  [in]       rho    Random seed to generate matrix A from.
1906
 * @param  [in, out]  sigma  Random seed to generate noise from.
1907
 * @return  0 on success.
1908
 * @return  MEMORY_E when dynamic memory allocation fails. Only possible when
1909
 *          WOLFSSL_SMALL_STACK is defined.
1910
 * @return  Other negative value when a hash error occurred.
1911
 */
1912
int mlkem_keygen_seeds(sword16* s, sword16* t, MLKEM_PRF_T* prf,
1913
    sword16* tv, int k, byte* rho, byte* sigma)
1914
{
1915
    int i;
1916
    int ret = 0;
1917
    sword16* ai = tv;
1918
    sword16* e = tv;
1919
1920
    /* Transform private key. All of result used in public key calculation
1921
     * Step 16: s_hat = NTT(s) */
1922
    for (i = 0; i < k; ++i) {
1923
        mlkem_ntt(s + i * MLKEM_N);
1924
    }
1925
1926
    /* For each polynomial in the vectors.
1927
     * Step 17, Step 18: Calculate public from A_hat, s_hat and e_hat. */
1928
    for (i = 0; i < k; ++i) {
1929
        int j;
1930
1931
        /* Generate a vector of matrix A.
1932
         * Steps 4-6: generate A[i] */
1933
        ret = mlkem_gen_matrix_i(prf, ai, k, rho, i, 0);
1934
        if (ret != 0) {
1935
           break;
1936
        }
1937
1938
        /* Multiply a by private into public polynomial.
1939
         * Step 18: ... A_hat o s_hat ... */
1940
        mlkem_pointwise_acc_mont(t + i * MLKEM_N, ai, s, (unsigned int)k);
1941
        /* Convert public polynomial to Montgomery form.
1942
         * Step 18: ... MontRed(A_hat o s_hat) ... */
1943
        for (j = 0; j < MLKEM_N; ++j) {
1944
            sword32 n = t[i * MLKEM_N + j] * (sword32)MLKEM_F;
1945
            t[i * MLKEM_N + j] = MLKEM_MONT_RED(n);
1946
        }
1947
1948
        /* Generate noise using PRF.
1949
         * Step 13: e[i] <- SamplePolyCBD_eta_1(PRF_eta_1(sigma, N)) */
1950
        ret = mlkem_get_noise_i(prf, k, e, sigma, i, 1);
1951
        if (ret != 0) {
1952
           break;
1953
        }
1954
        /* Transform error values polynomial.
1955
         * Step 17: e_hat = NTT(e) */
1956
#if defined(WOLFSSL_MLKEM_SMALL) || defined(WOLFSSL_MLKEM_NO_LARGE_CODE)
1957
        mlkem_ntt(e);
1958
        /* Add errors to public key and reduce.
1959
         * Step 18: t_hat = BarrettRed(MontRed(A_hat o s_hat) + e_hat) */
1960
        for (j = 0; j < MLKEM_N; ++j) {
1961
            sword16 n = (sword16)(t[i * MLKEM_N + j] + e[j]);
1962
            t[i * MLKEM_N + j] = MLKEM_BARRETT_RED(n);
1963
        }
1964
#else
1965
        /* Add errors to public key and reduce.
1966
         * Step 18: t_hat = BarrettRed(MontRed(A_hat o s_hat) + e_hat) */
1967
        mlkem_ntt_add_to(e, t + i * MLKEM_N);
1968
#endif
1969
    }
1970
1971
    return ret;
1972
}
1973
1974
#endif /* WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM */
1975
#endif /* !WOLFSSL_MLKEM_NO_MAKE_KEY */
1976
1977
#if !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \
1978
    !defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
1979
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
1980
/* Encapsulate message.
1981
 *
1982
 * @param  [in]       pub  Public key vector of polynomials.
1983
 * @param  [out]      u    Vector of polynomials.
1984
 * @param  [out]      v    Polynomial.
1985
 * @param  [in]       a    Array of vector of polynomials.
1986
 * @param  [in, out]  y    Vector of polynomials.
1987
 * @param  [in]       e1   Error Vector of polynomials.
1988
 * @param  [in]       e2   Error polynomial.
1989
 * @param  [in]       m    Message polynomial.
1990
 * @param  [in]       k    Number of polynomials in vector.
1991
 */
1992
static void mlkem_encapsulate_c(const sword16* pub, sword16* u, sword16* v,
1993
    const sword16* a, sword16* y, const sword16* e1, const sword16* e2,
1994
    const sword16* m, int k)
1995
0
{
1996
0
    int i;
1997
1998
    /* Transform y. All of result used in calculation of u and v. */
1999
0
    for (i = 0; i < k; ++i) {
2000
0
        mlkem_ntt(y + i * MLKEM_N);
2001
0
    }
2002
2003
    /* For each polynomial in the vectors. */
2004
0
    for (i = 0; i < k; ++i) {
2005
0
        int j;
2006
2007
        /* Multiply at by y into u polynomial. */
2008
0
        mlkem_pointwise_acc_mont(u + i * MLKEM_N, a + i * k * MLKEM_N, y,
2009
0
            (unsigned int)k);
2010
        /* Inverse transform u polynomial. */
2011
0
        mlkem_invntt(u + i * MLKEM_N);
2012
        /* Add errors to u and reduce. */
2013
#if defined(WOLFSSL_MLKEM_SMALL) || defined(WOLFSSL_MLKEM_NO_LARGE_CODE)
2014
        for (j = 0; j < MLKEM_N; ++j) {
2015
            sword16 t = (sword16)(u[i * MLKEM_N + j] + e1[i * MLKEM_N + j]);
2016
            u[i * MLKEM_N + j] = MLKEM_BARRETT_RED(t);
2017
        }
2018
#else
2019
0
        for (j = 0; j < MLKEM_N; j += 8) {
2020
0
            sword16 t0 = (sword16)(u[i * MLKEM_N + j + 0] +
2021
0
                                   e1[i * MLKEM_N + j + 0]);
2022
0
            sword16 t1 = (sword16)(u[i * MLKEM_N + j + 1] +
2023
0
                                   e1[i * MLKEM_N + j + 1]);
2024
0
            sword16 t2 = (sword16)(u[i * MLKEM_N + j + 2] +
2025
0
                                   e1[i * MLKEM_N + j + 2]);
2026
0
            sword16 t3 = (sword16)(u[i * MLKEM_N + j + 3] +
2027
0
                                   e1[i * MLKEM_N + j + 3]);
2028
0
            sword16 t4 = (sword16)(u[i * MLKEM_N + j + 4] +
2029
0
                                   e1[i * MLKEM_N + j + 4]);
2030
0
            sword16 t5 = (sword16)(u[i * MLKEM_N + j + 5] +
2031
0
                                   e1[i * MLKEM_N + j + 5]);
2032
0
            sword16 t6 = (sword16)(u[i * MLKEM_N + j + 6] +
2033
0
                                   e1[i * MLKEM_N + j + 6]);
2034
0
            sword16 t7 = (sword16)(u[i * MLKEM_N + j + 7] +
2035
0
                                   e1[i * MLKEM_N + j + 7]);
2036
0
            u[i * MLKEM_N + j + 0] = MLKEM_BARRETT_RED(t0);
2037
0
            u[i * MLKEM_N + j + 1] = MLKEM_BARRETT_RED(t1);
2038
0
            u[i * MLKEM_N + j + 2] = MLKEM_BARRETT_RED(t2);
2039
0
            u[i * MLKEM_N + j + 3] = MLKEM_BARRETT_RED(t3);
2040
0
            u[i * MLKEM_N + j + 4] = MLKEM_BARRETT_RED(t4);
2041
0
            u[i * MLKEM_N + j + 5] = MLKEM_BARRETT_RED(t5);
2042
0
            u[i * MLKEM_N + j + 6] = MLKEM_BARRETT_RED(t6);
2043
0
            u[i * MLKEM_N + j + 7] = MLKEM_BARRETT_RED(t7);
2044
0
        }
2045
0
#endif
2046
0
    }
2047
2048
    /* Multiply public key by y into v polynomial. */
2049
0
    mlkem_pointwise_acc_mont(v, pub, y, (unsigned int)k);
2050
    /* Inverse transform v. */
2051
0
    mlkem_invntt(v);
2052
    /* Add errors and message to v and reduce. */
2053
0
    for (i = 0; i < MLKEM_N; ++i) {
2054
0
        sword16 t = (sword16)(v[i] + e2[i] + m[i]);
2055
0
        v[i] = MLKEM_BARRETT_RED(t);
2056
0
    }
2057
0
}
2058
2059
/* Encapsulate message.
2060
 *
2061
 * @param  [in]       pub  Public key vector of polynomials.
2062
 * @param  [out]      u    Vector of polynomials.
2063
 * @param  [out]      v    Polynomial.
2064
 * @param  [in]       a    Array of vector of polynomials.
2065
 * @param  [in, out]  y    Vector of polynomials.
2066
 * @param  [in]       e1   Error Vector of polynomials.
2067
 * @param  [in]       e2   Error polynomial.
2068
 * @param  [in]       m    Message polynomial.
2069
 * @param  [in]       k    Number of polynomials in vector.
2070
 */
2071
void mlkem_encapsulate(const sword16* pub, sword16* u, sword16* v,
2072
    const sword16* a, sword16* y, const sword16* e1, const sword16* e2,
2073
    const sword16* m, int k)
2074
0
{
2075
#ifdef USE_INTEL_SPEEDUP
2076
    if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
2077
        mlkem_encapsulate_avx2(pub, u, v, a, y, e1, e2, m, k);
2078
        RESTORE_VECTOR_REGISTERS();
2079
    }
2080
    else
2081
#endif
2082
0
    {
2083
0
        mlkem_encapsulate_c(pub, u, v, a, y, e1, e2, m, k);
2084
0
    }
2085
0
}
2086
2087
#else
2088
2089
/* Encapsulate message.
2090
 *
2091
 * @param  [in]       pub    Public key vector of polynomials.
2092
 * @param  [in, out]  prf    XOF object.
2093
 * @param  [out]      u      Vector of polynomials.
2094
 * @param  [in, out]  tp     Polynomial.
2095
 * @param  [in, out]  y      Vector of polynomials.
2096
 * @param  [in]       k      Number of polynomials in vector.
2097
 * @param  [in]       msg    Message to encapsulate.
2098
 * @param  [in]       seed   Random seed to generate matrix A from.
2099
 * @param  [in, out]  coins  Random seed to generate noise from.
2100
 * @return  0 on success.
2101
 * @return  MEMORY_E when dynamic memory allocation fails. Only possible when
2102
 *          WOLFSSL_SMALL_STACK is defined.
2103
 * @return  Other negative value when a hash error occurred.
2104
 */
2105
int mlkem_encapsulate_seeds(const sword16* pub, MLKEM_PRF_T* prf, sword16* u,
2106
    sword16* tp, sword16* y, int k, const byte* msg, byte* seed, byte* coins)
2107
{
2108
    int ret = 0;
2109
    int i;
2110
    sword16* a = tp;
2111
    sword16* e1 = tp;
2112
    sword16* v = tp;
2113
    sword16* e2 = tp + MLKEM_N;
2114
    sword16* m = y;
2115
2116
    /* Transform y. All of result used in calculation of u and v. */
2117
    for (i = 0; i < k; ++i) {
2118
        mlkem_ntt(y + i * MLKEM_N);
2119
    }
2120
2121
    /* For each polynomial in the vectors. */
2122
    for (i = 0; i < k; ++i) {
2123
        int j;
2124
2125
        /* Generate a vector of matrix A. */
2126
        ret = mlkem_gen_matrix_i(prf, a, k, seed, i, 1);
2127
        if (ret != 0) {
2128
           break;
2129
        }
2130
2131
        /* Multiply at by y into u polynomial. */
2132
        mlkem_pointwise_acc_mont(u + i * MLKEM_N, a, y, (unsigned int)k);
2133
        /* Inverse transform u polynomial. */
2134
        mlkem_invntt(u + i * MLKEM_N);
2135
2136
        /* Generate noise using PRF. */
2137
        ret = mlkem_get_noise_i(prf, k, e1, coins, i, 0);
2138
        if (ret != 0) {
2139
           break;
2140
        }
2141
        /* Add errors to u and reduce. */
2142
#if defined(WOLFSSL_MLKEM_SMALL) || defined(WOLFSSL_MLKEM_NO_LARGE_CODE)
2143
        for (j = 0; j < MLKEM_N; ++j) {
2144
            sword16 t = (sword16)(u[i * MLKEM_N + j] + e1[j]);
2145
            u[i * MLKEM_N + j] = MLKEM_BARRETT_RED(t);
2146
        }
2147
#else
2148
        for (j = 0; j < MLKEM_N; j += 8) {
2149
            sword16 t0 = (sword16)(u[i * MLKEM_N + j + 0] + e1[j + 0]);
2150
            sword16 t1 = (sword16)(u[i * MLKEM_N + j + 1] + e1[j + 1]);
2151
            sword16 t2 = (sword16)(u[i * MLKEM_N + j + 2] + e1[j + 2]);
2152
            sword16 t3 = (sword16)(u[i * MLKEM_N + j + 3] + e1[j + 3]);
2153
            sword16 t4 = (sword16)(u[i * MLKEM_N + j + 4] + e1[j + 4]);
2154
            sword16 t5 = (sword16)(u[i * MLKEM_N + j + 5] + e1[j + 5]);
2155
            sword16 t6 = (sword16)(u[i * MLKEM_N + j + 6] + e1[j + 6]);
2156
            sword16 t7 = (sword16)(u[i * MLKEM_N + j + 7] + e1[j + 7]);
2157
            u[i * MLKEM_N + j + 0] = MLKEM_BARRETT_RED(t0);
2158
            u[i * MLKEM_N + j + 1] = MLKEM_BARRETT_RED(t1);
2159
            u[i * MLKEM_N + j + 2] = MLKEM_BARRETT_RED(t2);
2160
            u[i * MLKEM_N + j + 3] = MLKEM_BARRETT_RED(t3);
2161
            u[i * MLKEM_N + j + 4] = MLKEM_BARRETT_RED(t4);
2162
            u[i * MLKEM_N + j + 5] = MLKEM_BARRETT_RED(t5);
2163
            u[i * MLKEM_N + j + 6] = MLKEM_BARRETT_RED(t6);
2164
            u[i * MLKEM_N + j + 7] = MLKEM_BARRETT_RED(t7);
2165
        }
2166
#endif
2167
    }
2168
2169
    /* Multiply public key by y into v polynomial. */
2170
    mlkem_pointwise_acc_mont(v, pub, y, (unsigned int)k);
2171
    /* Inverse transform v. */
2172
    mlkem_invntt(v);
2173
2174
    mlkem_from_msg(m, msg);
2175
2176
    /* Generate noise using PRF. */
2177
    coins[WC_ML_KEM_SYM_SZ] = (byte)(2 * k);
2178
    ret = mlkem_get_noise_eta2_c(prf, e2, coins);
2179
    if (ret == 0) {
2180
        /* Add errors and message to v and reduce. */
2181
    #if defined(WOLFSSL_MLKEM_SMALL) || defined(WOLFSSL_MLKEM_NO_LARGE_CODE)
2182
        for (i = 0; i < MLKEM_N; ++i) {
2183
            sword16 t = (sword16)(v[i] + e2[i] + m[i]);
2184
            v[i] = MLKEM_BARRETT_RED(t);
2185
        }
2186
    #else
2187
        for (i = 0; i < MLKEM_N; i += 8) {
2188
            sword16 t0 = (sword16)(v[i + 0] + e2[i + 0] + m[i + 0]);
2189
            sword16 t1 = (sword16)(v[i + 1] + e2[i + 1] + m[i + 1]);
2190
            sword16 t2 = (sword16)(v[i + 2] + e2[i + 2] + m[i + 2]);
2191
            sword16 t3 = (sword16)(v[i + 3] + e2[i + 3] + m[i + 3]);
2192
            sword16 t4 = (sword16)(v[i + 4] + e2[i + 4] + m[i + 4]);
2193
            sword16 t5 = (sword16)(v[i + 5] + e2[i + 5] + m[i + 5]);
2194
            sword16 t6 = (sword16)(v[i + 6] + e2[i + 6] + m[i + 6]);
2195
            sword16 t7 = (sword16)(v[i + 7] + e2[i + 7] + m[i + 7]);
2196
            v[i + 0] = MLKEM_BARRETT_RED(t0);
2197
            v[i + 1] = MLKEM_BARRETT_RED(t1);
2198
            v[i + 2] = MLKEM_BARRETT_RED(t2);
2199
            v[i + 3] = MLKEM_BARRETT_RED(t3);
2200
            v[i + 4] = MLKEM_BARRETT_RED(t4);
2201
            v[i + 5] = MLKEM_BARRETT_RED(t5);
2202
            v[i + 6] = MLKEM_BARRETT_RED(t6);
2203
            v[i + 7] = MLKEM_BARRETT_RED(t7);
2204
        }
2205
    #endif
2206
    }
2207
2208
    return ret;
2209
}
2210
#endif
2211
#endif /* !WOLFSSL_MLKEM_NO_ENCAPSULATE || !WOLFSSL_MLKEM_NO_DECAPSULATE */
2212
2213
#ifndef WOLFSSL_MLKEM_NO_DECAPSULATE
2214
2215
/* Decapsulate message.
2216
 *
2217
 * FIPS 203, Algorithm 15: K-PKE.Decrypt(dk_PKE,c)
2218
 * Uses the decryption key to decrypt a ciphertext.
2219
 *   ...
2220
 *   6: w <- v' - InvNTT(s_hat_trans o NTT(u'))
2221
 *   ...
2222
 *
2223
 * @param  [in]       s  Private key vector of polynomials.
2224
 * @param  [out]      w  Message polynomial.
2225
 * @param  [in, out]  u  Vector of polynomials containing error.
2226
 * @param  [in]       v  Encapsulated message polynomial.
2227
 * @param  [in]       k  Number of polynomials in vector.
2228
 */
2229
static void mlkem_decapsulate_c(const sword16* s, sword16* w, sword16* u,
2230
    const sword16* v, int k)
2231
0
{
2232
0
    int i;
2233
2234
    /* Transform u. All of result used in calculation of w.
2235
     * Step 6: ... NTT(u') */
2236
0
    for (i = 0; i < k; ++i) {
2237
0
        mlkem_ntt(u + i * MLKEM_N);
2238
0
    }
2239
2240
    /* Multiply private key by u into w polynomial.
2241
     * Step 6: ... s_hat_trans o NTT(u') */
2242
0
    mlkem_pointwise_acc_mont(w, s, u, (unsigned int)k);
2243
    /* Inverse transform w.
2244
     * Step 6: ... InvNTT(s_hat_trans o NTT(u')) */
2245
0
    mlkem_invntt(w);
2246
    /* Subtract errors (in w) out of v and reduce into w.
2247
     * Step 6: w <- v' - InvNTT(s_hat_trans o NTT(u')) */
2248
0
    for (i = 0; i < MLKEM_N; ++i) {
2249
0
        sword16 t = (sword16)(v[i] - w[i]);
2250
0
        w[i] = MLKEM_BARRETT_RED(t);
2251
0
    }
2252
0
}
2253
2254
/* Decapsulate message.
2255
 *
2256
 * FIPS 203, Algorithm 15: K-PKE.Decrypt(dk_PKE,c)
2257
 * Uses the decryption key to decrypt a ciphertext.
2258
 *   ...
2259
 *   6: w <- v' - InvNTT(s_hat_trans o NTT(u'))
2260
 *   ...
2261
 *
2262
 * @param  [in]       s  Private key vector of polynomials.
2263
 * @param  [out]      w  Message polynomial.
2264
 * @param  [in, out]  u  Vector of polynomials containing error.
2265
 * @param  [in]       v  Encapsulated message polynomial.
2266
 * @param  [in]       k  Number of polynomials in vector.
2267
 */
2268
void mlkem_decapsulate(const sword16* s, sword16* w, sword16* u,
2269
    const sword16* v, int k)
2270
0
{
2271
#ifdef USE_INTEL_SPEEDUP
2272
    if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
2273
        mlkem_decapsulate_avx2(s, w, u, v, k);
2274
        RESTORE_VECTOR_REGISTERS();
2275
    }
2276
    else
2277
#endif
2278
0
    {
2279
0
        mlkem_decapsulate_c(s, w, u, v, k);
2280
0
    }
2281
0
}
2282
2283
#endif /* !WOLFSSL_MLKEM_NO_DECAPSULATE */
2284
#endif
2285
2286
/******************************************************************************/
2287
2288
#if defined(USE_INTEL_SPEEDUP) && !defined(WC_SHA3_NO_ASM)
2289
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
2290
/* Deterministically generate a matrix (or transpose) of uniform integers mod q.
2291
 *
2292
 * Seed used with XOF to generate random bytes.
2293
 *
2294
 * @param  [out]  a           Matrix of uniform integers.
2295
 * @param  [in]   seed        Bytes to seed XOF generation.
2296
 * @param  [in]   transposed  Whether A or A^T is generated.
2297
 * @return  0 on success.
2298
 * @return  MEMORY_E when dynamic memory allocation fails. Only possible when
2299
 *          WOLFSSL_SMALL_STACK is defined.
2300
 */
2301
static int mlkem_gen_matrix_k2_avx2(sword16* a, byte* seed, int transposed)
2302
{
2303
    int i;
2304
#ifdef WOLFSSL_SMALL_STACK
2305
    byte *rand = NULL;
2306
    word64 *state = NULL;
2307
#else
2308
    byte rand[4 * GEN_MATRIX_SIZE + 4];
2309
    word64 state[25 * 4];
2310
#endif
2311
    unsigned int ctr0;
2312
    unsigned int ctr1;
2313
    unsigned int ctr2;
2314
    unsigned int ctr3;
2315
    byte* p;
2316
2317
#ifdef WOLFSSL_SMALL_STACK
2318
    rand = (byte*)XMALLOC(4 * GEN_MATRIX_SIZE + 4, NULL,
2319
                          DYNAMIC_TYPE_TMP_BUFFER);
2320
    state = (word64*)XMALLOC(sizeof(word64) * 25 * 4, NULL,
2321
                          DYNAMIC_TYPE_TMP_BUFFER);
2322
    if ((rand == NULL) || (state == NULL)) {
2323
        XFREE(rand, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2324
        XFREE(state, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2325
        return MEMORY_E;
2326
    }
2327
#endif
2328
2329
    /* Loading 64 bits, only using 48 bits. Loading 4 bytes more than used. */
2330
    rand[4 * GEN_MATRIX_SIZE + 0] = 0xff;
2331
    rand[4 * GEN_MATRIX_SIZE + 1] = 0xff;
2332
    rand[4 * GEN_MATRIX_SIZE + 2] = 0xff;
2333
    rand[4 * GEN_MATRIX_SIZE + 3] = 0xff;
2334
2335
    if (!transposed) {
2336
        state[4*4 + 0] = 0x1f0000 + 0x000;
2337
        state[4*4 + 1] = 0x1f0000 + 0x001;
2338
        state[4*4 + 2] = 0x1f0000 + 0x100;
2339
        state[4*4 + 3] = 0x1f0000 + 0x101;
2340
    }
2341
    else {
2342
        state[4*4 + 0] = 0x1f0000 + 0x000;
2343
        state[4*4 + 1] = 0x1f0000 + 0x100;
2344
        state[4*4 + 2] = 0x1f0000 + 0x001;
2345
        state[4*4 + 3] = 0x1f0000 + 0x101;
2346
    }
2347
2348
    sha3_128_blocksx4_seed_avx2(state, seed);
2349
    mlkem_redistribute_21_rand_avx2(state, rand + 0 * GEN_MATRIX_SIZE,
2350
        rand + 1 * GEN_MATRIX_SIZE, rand + 2 * GEN_MATRIX_SIZE,
2351
        rand + 3 * GEN_MATRIX_SIZE);
2352
    for (i = SHA3_128_BYTES; i < GEN_MATRIX_SIZE; i += SHA3_128_BYTES) {
2353
        sha3_blocksx4_avx2(state);
2354
        mlkem_redistribute_21_rand_avx2(state, rand + i + 0 * GEN_MATRIX_SIZE,
2355
            rand + i + 1 * GEN_MATRIX_SIZE, rand + i + 2 * GEN_MATRIX_SIZE,
2356
            rand + i + 3 * GEN_MATRIX_SIZE);
2357
    }
2358
2359
    /* Sample random bytes to create a polynomial. */
2360
    p = rand;
2361
    ctr0 = mlkem_rej_uniform_n_avx2(a + 0 * MLKEM_N, MLKEM_N, p,
2362
        GEN_MATRIX_SIZE);
2363
    p += GEN_MATRIX_SIZE;
2364
    ctr1 = mlkem_rej_uniform_n_avx2(a + 1 * MLKEM_N, MLKEM_N, p,
2365
        GEN_MATRIX_SIZE);
2366
    p += GEN_MATRIX_SIZE;
2367
    ctr2 = mlkem_rej_uniform_n_avx2(a + 2 * MLKEM_N, MLKEM_N, p,
2368
        GEN_MATRIX_SIZE);
2369
    p += GEN_MATRIX_SIZE;
2370
    ctr3 = mlkem_rej_uniform_n_avx2(a + 3 * MLKEM_N, MLKEM_N, p,
2371
        GEN_MATRIX_SIZE);
2372
    /* Create more blocks if too many rejected. */
2373
    while ((ctr0 < MLKEM_N) || (ctr1 < MLKEM_N) || (ctr2 < MLKEM_N) ||
2374
           (ctr3 < MLKEM_N)) {
2375
        sha3_blocksx4_avx2(state);
2376
        mlkem_redistribute_21_rand_avx2(state, rand + 0 * GEN_MATRIX_SIZE,
2377
            rand + 1 * GEN_MATRIX_SIZE, rand + 2 * GEN_MATRIX_SIZE,
2378
            rand + 3 * GEN_MATRIX_SIZE);
2379
2380
        p = rand;
2381
        ctr0 += mlkem_rej_uniform_avx2(a + 0 * MLKEM_N + ctr0, MLKEM_N - ctr0,
2382
            p, XOF_BLOCK_SIZE);
2383
        p += GEN_MATRIX_SIZE;
2384
        ctr1 += mlkem_rej_uniform_avx2(a + 1 * MLKEM_N + ctr1, MLKEM_N - ctr1,
2385
            p, XOF_BLOCK_SIZE);
2386
        p += GEN_MATRIX_SIZE;
2387
        ctr2 += mlkem_rej_uniform_avx2(a + 2 * MLKEM_N + ctr2, MLKEM_N - ctr2,
2388
            p, XOF_BLOCK_SIZE);
2389
        p += GEN_MATRIX_SIZE;
2390
        ctr3 += mlkem_rej_uniform_avx2(a + 3 * MLKEM_N + ctr3, MLKEM_N - ctr3,
2391
            p, XOF_BLOCK_SIZE);
2392
    }
2393
2394
    WC_FREE_VAR_EX(rand, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2395
    WC_FREE_VAR_EX(state, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2396
2397
    return 0;
2398
}
2399
#endif
2400
2401
#if defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768)
2402
/* Deterministically generate a matrix (or transpose) of uniform integers mod q.
2403
 *
2404
 * Seed used with XOF to generate random bytes.
2405
 *
2406
 * @param  [out]  a           Matrix of uniform integers.
2407
 * @param  [in]   seed        Bytes to seed XOF generation.
2408
 * @param  [in]   transposed  Whether A or A^T is generated.
2409
 * @return  0 on success.
2410
 * @return  MEMORY_E when dynamic memory allocation fails. Only possible when
2411
 *          WOLFSSL_SMALL_STACK is defined.
2412
 */
2413
static int mlkem_gen_matrix_k3_avx2(sword16* a, byte* seed, int transposed)
2414
{
2415
    int i;
2416
    int k;
2417
#ifdef WOLFSSL_SMALL_STACK
2418
    byte *rand = NULL;
2419
    word64 *state = NULL;
2420
#else
2421
    byte rand[4 * GEN_MATRIX_SIZE + 4];
2422
    word64 state[25 * 4];
2423
#endif
2424
    unsigned int ctr0;
2425
    unsigned int ctr1;
2426
    unsigned int ctr2;
2427
    unsigned int ctr3;
2428
    byte* p;
2429
2430
#ifdef WOLFSSL_SMALL_STACK
2431
    rand = (byte*)XMALLOC(4 * GEN_MATRIX_SIZE + 4, NULL,
2432
                          DYNAMIC_TYPE_TMP_BUFFER);
2433
    state = (word64*)XMALLOC(sizeof(word64) * 25 * 4, NULL,
2434
                          DYNAMIC_TYPE_TMP_BUFFER);
2435
    if ((rand == NULL) || (state == NULL)) {
2436
        XFREE(rand, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2437
        XFREE(state, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2438
        return MEMORY_E;
2439
    }
2440
#endif
2441
2442
    /* Loading 64 bits, only using 48 bits. Loading 4 bytes more than used. */
2443
    rand[4 * GEN_MATRIX_SIZE + 0] = 0xff;
2444
    rand[4 * GEN_MATRIX_SIZE + 1] = 0xff;
2445
    rand[4 * GEN_MATRIX_SIZE + 2] = 0xff;
2446
    rand[4 * GEN_MATRIX_SIZE + 3] = 0xff;
2447
2448
    for (k = 0; k < 2; k++) {
2449
        for (i = 0; i < 4; i++) {
2450
            if (!transposed) {
2451
                state[4*4 + i] = (word32)(0x1f0000 + (((k*4+i)/3) << 8) +
2452
                                          ((k*4+i)%3));
2453
            }
2454
            else {
2455
                state[4*4 + i] = (word32)(0x1f0000 + (((k*4+i)%3) << 8) +
2456
                                          ((k*4+i)/3));
2457
2458
            }
2459
        }
2460
2461
        sha3_128_blocksx4_seed_avx2(state, seed);
2462
        mlkem_redistribute_21_rand_avx2(state,
2463
            rand + 0 * GEN_MATRIX_SIZE, rand + 1 * GEN_MATRIX_SIZE,
2464
            rand + 2 * GEN_MATRIX_SIZE, rand + 3 * GEN_MATRIX_SIZE);
2465
        for (i = SHA3_128_BYTES; i < GEN_MATRIX_SIZE; i += SHA3_128_BYTES) {
2466
            sha3_blocksx4_avx2(state);
2467
            mlkem_redistribute_21_rand_avx2(state,
2468
                rand + i + 0 * GEN_MATRIX_SIZE, rand + i + 1 * GEN_MATRIX_SIZE,
2469
                rand + i + 2 * GEN_MATRIX_SIZE, rand + i + 3 * GEN_MATRIX_SIZE);
2470
        }
2471
2472
        /* Sample random bytes to create a polynomial. */
2473
        p = rand;
2474
        ctr0 = mlkem_rej_uniform_n_avx2(a + 0 * MLKEM_N, MLKEM_N, p,
2475
            GEN_MATRIX_SIZE);
2476
        p += GEN_MATRIX_SIZE;
2477
        ctr1 = mlkem_rej_uniform_n_avx2(a + 1 * MLKEM_N, MLKEM_N, p,
2478
            GEN_MATRIX_SIZE);
2479
        p += GEN_MATRIX_SIZE;
2480
        ctr2 = mlkem_rej_uniform_n_avx2(a + 2 * MLKEM_N, MLKEM_N, p,
2481
            GEN_MATRIX_SIZE);
2482
        p += GEN_MATRIX_SIZE;
2483
        ctr3 = mlkem_rej_uniform_n_avx2(a + 3 * MLKEM_N, MLKEM_N, p,
2484
            GEN_MATRIX_SIZE);
2485
        /* Create more blocks if too many rejected. */
2486
        while ((ctr0 < MLKEM_N) || (ctr1 < MLKEM_N) || (ctr2 < MLKEM_N) ||
2487
               (ctr3 < MLKEM_N)) {
2488
            sha3_blocksx4_avx2(state);
2489
            mlkem_redistribute_21_rand_avx2(state, rand + 0 * GEN_MATRIX_SIZE,
2490
                rand + 1 * GEN_MATRIX_SIZE, rand + 2 * GEN_MATRIX_SIZE,
2491
                rand + 3 * GEN_MATRIX_SIZE);
2492
2493
            p = rand;
2494
            ctr0 += mlkem_rej_uniform_avx2(a + 0 * MLKEM_N + ctr0,
2495
                MLKEM_N - ctr0, p, XOF_BLOCK_SIZE);
2496
            p += GEN_MATRIX_SIZE;
2497
            ctr1 += mlkem_rej_uniform_avx2(a + 1 * MLKEM_N + ctr1,
2498
                MLKEM_N - ctr1, p, XOF_BLOCK_SIZE);
2499
            p += GEN_MATRIX_SIZE;
2500
            ctr2 += mlkem_rej_uniform_avx2(a + 2 * MLKEM_N + ctr2,
2501
                MLKEM_N - ctr2, p, XOF_BLOCK_SIZE);
2502
            p += GEN_MATRIX_SIZE;
2503
            ctr3 += mlkem_rej_uniform_avx2(a + 3 * MLKEM_N + ctr3,
2504
                MLKEM_N - ctr3, p, XOF_BLOCK_SIZE);
2505
        }
2506
2507
        a += 4 * MLKEM_N;
2508
    }
2509
2510
    readUnalignedWords64(state, seed, 4);
2511
    /* Transposed value same as not. */
2512
    state[4] = 0x1f0000 + (2 << 8) + 2;
2513
    XMEMSET(state + 5, 0, sizeof(*state) * (25 - 5));
2514
    state[20] = W64LIT(0x8000000000000000);
2515
    for (i = 0; i < GEN_MATRIX_SIZE; i += SHA3_128_BYTES) {
2516
#ifndef WC_SHA3_NO_ASM
2517
        if (IS_INTEL_BMI2(cpuid_flags)) {
2518
            sha3_block_bmi2(state);
2519
        }
2520
        else if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0))
2521
        {
2522
            sha3_block_avx2(state);
2523
            RESTORE_VECTOR_REGISTERS();
2524
        }
2525
        else
2526
#endif /* !WC_SHA3_NO_ASM */
2527
        {
2528
            BlockSha3(state);
2529
        }
2530
        XMEMCPY(rand + i, state, SHA3_128_BYTES);
2531
    }
2532
    ctr0 = mlkem_rej_uniform_n_avx2(a, MLKEM_N, rand, GEN_MATRIX_SIZE);
2533
    while (ctr0 < MLKEM_N) {
2534
#ifndef WC_SHA3_NO_ASM
2535
        if (IS_INTEL_BMI2(cpuid_flags)) {
2536
            sha3_block_bmi2(state);
2537
        }
2538
        else if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0))
2539
        {
2540
            sha3_block_avx2(state);
2541
            RESTORE_VECTOR_REGISTERS();
2542
        }
2543
        else
2544
#endif /* !WC_SHA3_NO_ASM */
2545
        {
2546
            BlockSha3(state);
2547
        }
2548
        XMEMCPY(rand, state, SHA3_128_BYTES);
2549
        ctr0 += mlkem_rej_uniform_avx2(a + ctr0, MLKEM_N - ctr0, rand,
2550
            XOF_BLOCK_SIZE);
2551
    }
2552
2553
    WC_FREE_VAR_EX(rand, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2554
    WC_FREE_VAR_EX(state, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2555
2556
    return 0;
2557
}
2558
#endif
2559
#if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
2560
/* Deterministically generate a matrix (or transpose) of uniform integers mod q.
2561
 *
2562
 * Seed used with XOF to generate random bytes.
2563
 *
2564
 * @param  [out]  a           Matrix of uniform integers.
2565
 * @param  [in]   seed        Bytes to seed XOF generation.
2566
 * @param  [in]   transposed  Whether A or A^T is generated.
2567
 * @return  0 on success.
2568
 * @return  MEMORY_E when dynamic memory allocation fails. Only possible when
2569
 *          WOLFSSL_SMALL_STACK is defined.
2570
 */
2571
static int mlkem_gen_matrix_k4_avx2(sword16* a, byte* seed, int transposed)
2572
{
2573
    int i;
2574
    int k;
2575
#ifdef WOLFSSL_SMALL_STACK
2576
    byte *rand = NULL;
2577
    word64 *state = NULL;
2578
#else
2579
    byte rand[4 * GEN_MATRIX_SIZE + 4];
2580
    word64 state[25 * 4];
2581
#endif
2582
    unsigned int ctr0;
2583
    unsigned int ctr1;
2584
    unsigned int ctr2;
2585
    unsigned int ctr3;
2586
    byte* p;
2587
2588
#ifdef WOLFSSL_SMALL_STACK
2589
    rand = (byte*)XMALLOC(4 * GEN_MATRIX_SIZE + 4, NULL,
2590
                          DYNAMIC_TYPE_TMP_BUFFER);
2591
    state = (word64*)XMALLOC(sizeof(word64) * 25 * 4, NULL,
2592
                          DYNAMIC_TYPE_TMP_BUFFER);
2593
    if ((rand == NULL) || (state == NULL)) {
2594
        XFREE(rand, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2595
        XFREE(state, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2596
        return MEMORY_E;
2597
    }
2598
#endif
2599
2600
    /* Loading 64 bits, only using 48 bits. Loading 4 bytes more than used. */
2601
    rand[4 * GEN_MATRIX_SIZE + 0] = 0xff;
2602
    rand[4 * GEN_MATRIX_SIZE + 1] = 0xff;
2603
    rand[4 * GEN_MATRIX_SIZE + 2] = 0xff;
2604
    rand[4 * GEN_MATRIX_SIZE + 3] = 0xff;
2605
2606
    for (k = 0; k < 4; k++) {
2607
        for (i = 0; i < 4; i++) {
2608
            if (!transposed) {
2609
                state[4*4 + i] = (word32)(0x1f0000 + (k << 8) + i);
2610
            }
2611
            else {
2612
                state[4*4 + i] = (word32)(0x1f0000 + (i << 8) + k);
2613
            }
2614
        }
2615
2616
        sha3_128_blocksx4_seed_avx2(state, seed);
2617
        mlkem_redistribute_21_rand_avx2(state,
2618
            rand + 0 * GEN_MATRIX_SIZE, rand + 1 * GEN_MATRIX_SIZE,
2619
            rand + 2 * GEN_MATRIX_SIZE, rand + 3 * GEN_MATRIX_SIZE);
2620
        for (i = SHA3_128_BYTES; i < GEN_MATRIX_SIZE; i += SHA3_128_BYTES) {
2621
            sha3_blocksx4_avx2(state);
2622
            mlkem_redistribute_21_rand_avx2(state,
2623
                rand + i + 0 * GEN_MATRIX_SIZE, rand + i + 1 * GEN_MATRIX_SIZE,
2624
                rand + i + 2 * GEN_MATRIX_SIZE, rand + i + 3 * GEN_MATRIX_SIZE);
2625
        }
2626
2627
        /* Sample random bytes to create a polynomial. */
2628
        p = rand;
2629
        ctr0 = mlkem_rej_uniform_n_avx2(a + 0 * MLKEM_N, MLKEM_N, p,
2630
            GEN_MATRIX_SIZE);
2631
        p += GEN_MATRIX_SIZE;
2632
        ctr1 = mlkem_rej_uniform_n_avx2(a + 1 * MLKEM_N, MLKEM_N, p,
2633
            GEN_MATRIX_SIZE);
2634
        p += GEN_MATRIX_SIZE;
2635
        ctr2 = mlkem_rej_uniform_n_avx2(a + 2 * MLKEM_N, MLKEM_N, p,
2636
            GEN_MATRIX_SIZE);
2637
        p += GEN_MATRIX_SIZE;
2638
        ctr3 = mlkem_rej_uniform_n_avx2(a + 3 * MLKEM_N, MLKEM_N, p,
2639
            GEN_MATRIX_SIZE);
2640
        /* Create more blocks if too many rejected. */
2641
        while ((ctr0 < MLKEM_N) || (ctr1 < MLKEM_N) || (ctr2 < MLKEM_N) ||
2642
               (ctr3 < MLKEM_N)) {
2643
            sha3_blocksx4_avx2(state);
2644
            mlkem_redistribute_21_rand_avx2(state, rand + 0 * GEN_MATRIX_SIZE,
2645
                rand + 1 * GEN_MATRIX_SIZE, rand + 2 * GEN_MATRIX_SIZE,
2646
                rand + 3 * GEN_MATRIX_SIZE);
2647
2648
            p = rand;
2649
            ctr0 += mlkem_rej_uniform_avx2(a + 0 * MLKEM_N + ctr0,
2650
                MLKEM_N - ctr0, p, XOF_BLOCK_SIZE);
2651
            p += GEN_MATRIX_SIZE;
2652
            ctr1 += mlkem_rej_uniform_avx2(a + 1 * MLKEM_N + ctr1,
2653
                MLKEM_N - ctr1, p, XOF_BLOCK_SIZE);
2654
            p += GEN_MATRIX_SIZE;
2655
            ctr2 += mlkem_rej_uniform_avx2(a + 2 * MLKEM_N + ctr2,
2656
                MLKEM_N - ctr2, p, XOF_BLOCK_SIZE);
2657
            p += GEN_MATRIX_SIZE;
2658
            ctr3 += mlkem_rej_uniform_avx2(a + 3 * MLKEM_N + ctr3,
2659
                MLKEM_N - ctr3, p, XOF_BLOCK_SIZE);
2660
        }
2661
2662
        a += 4 * MLKEM_N;
2663
    }
2664
2665
    WC_FREE_VAR_EX(rand, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2666
    WC_FREE_VAR_EX(state, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2667
2668
    return 0;
2669
}
2670
#endif /* WOLFSSL_KYBER1024 || WOLFSSL_WC_ML_KEM_1024 */
2671
#elif defined(WOLFSSL_ARMASM) && defined(__aarch64__)
2672
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
2673
/* Deterministically generate a matrix (or transpose) of uniform integers mod q.
2674
 *
2675
 * Seed used with XOF to generate random bytes.
2676
 *
2677
 * @param  [out]  a           Matrix of uniform integers.
2678
 * @param  [in]   seed        Bytes to seed XOF generation.
2679
 * @param  [in]   transposed  Whether A or A^T is generated.
2680
 * @return  0 on success.
2681
 */
2682
static int mlkem_gen_matrix_k2_aarch64(sword16* a, byte* seed, int transposed)
2683
{
2684
    word64 state[3 * 25];
2685
    word64* st = (word64*)state;
2686
    unsigned int ctr0;
2687
    unsigned int ctr1;
2688
    unsigned int ctr2;
2689
    byte* p;
2690
2691
    if (!transposed) {
2692
        state[0*25 + 4] = 0x1f0000 + (0 << 8) + 0;
2693
        state[1*25 + 4] = 0x1f0000 + (0 << 8) + 1;
2694
        state[2*25 + 4] = 0x1f0000 + (1 << 8) + 0;
2695
    }
2696
    else {
2697
        state[0*25 + 4] = 0x1f0000 + (0 << 8) + 0;
2698
        state[1*25 + 4] = 0x1f0000 + (1 << 8) + 0;
2699
        state[2*25 + 4] = 0x1f0000 + (0 << 8) + 1;
2700
    }
2701
2702
    mlkem_shake128_blocksx3_seed_neon(state, seed);
2703
    /* Sample random bytes to create a polynomial. */
2704
    p = (byte*)st;
2705
    ctr0 = mlkem_rej_uniform_neon(a + 0 * MLKEM_N, MLKEM_N, p, XOF_BLOCK_SIZE);
2706
    p += 25 * 8;
2707
    ctr1 = mlkem_rej_uniform_neon(a + 1 * MLKEM_N, MLKEM_N, p, XOF_BLOCK_SIZE);
2708
    p += 25 * 8;
2709
    ctr2 = mlkem_rej_uniform_neon(a + 2 * MLKEM_N, MLKEM_N, p, XOF_BLOCK_SIZE);
2710
    while ((ctr0 < MLKEM_N) || (ctr1 < MLKEM_N) || (ctr2 < MLKEM_N)) {
2711
        mlkem_sha3_blocksx3_neon(st);
2712
2713
        p = (byte*)st;
2714
        ctr0 += mlkem_rej_uniform_neon(a + 0 * MLKEM_N + ctr0, MLKEM_N - ctr0,
2715
            p, XOF_BLOCK_SIZE);
2716
        p += 25 * 8;
2717
        ctr1 += mlkem_rej_uniform_neon(a + 1 * MLKEM_N + ctr1, MLKEM_N - ctr1,
2718
            p, XOF_BLOCK_SIZE);
2719
        p += 25 * 8;
2720
        ctr2 += mlkem_rej_uniform_neon(a + 2 * MLKEM_N + ctr2, MLKEM_N - ctr2,
2721
            p, XOF_BLOCK_SIZE);
2722
    }
2723
2724
    a += 3 * MLKEM_N;
2725
2726
    readUnalignedWords64(state, seed, 4);
2727
    /* Transposed value same as not. */
2728
    state[4] = 0x1f0000 + (1 << 8) + 1;
2729
    XMEMSET(state + 5, 0, sizeof(*state) * (25 - 5));
2730
    state[20] = W64LIT(0x8000000000000000);
2731
    BlockSha3(state);
2732
    p = (byte*)state;
2733
    ctr0 = mlkem_rej_uniform_neon(a, MLKEM_N, p, XOF_BLOCK_SIZE);
2734
    while (ctr0 < MLKEM_N) {
2735
        BlockSha3(state);
2736
        ctr0 += mlkem_rej_uniform_neon(a + ctr0, MLKEM_N - ctr0, p,
2737
            XOF_BLOCK_SIZE);
2738
    }
2739
2740
    return 0;
2741
}
2742
#endif
2743
2744
#if defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768)
2745
/* Deterministically generate a matrix (or transpose) of uniform integers mod q.
2746
 *
2747
 * Seed used with XOF to generate random bytes.
2748
 *
2749
 * @param  [out]  a           Matrix of uniform integers.
2750
 * @param  [in]   seed        Bytes to seed XOF generation.
2751
 * @param  [in]   transposed  Whether A or A^T is generated.
2752
 * @return  0 on success.
2753
 */
2754
static int mlkem_gen_matrix_k3_aarch64(sword16* a, byte* seed, int transposed)
2755
{
2756
    int i;
2757
    int k;
2758
    word64 state[3 * 25];
2759
    word64* st = (word64*)state;
2760
    unsigned int ctr0;
2761
    unsigned int ctr1;
2762
    unsigned int ctr2;
2763
    byte* p;
2764
2765
    for (k = 0; k < 3; k++) {
2766
        for (i = 0; i < 3; i++) {
2767
            if (!transposed) {
2768
                state[i*25 + 4] = 0x1f0000 + ((k << 8) + i);
2769
            }
2770
            else {
2771
                state[i*25 + 4] = 0x1f0000 + ((i << 8) + k);
2772
            }
2773
        }
2774
2775
        mlkem_shake128_blocksx3_seed_neon(state, seed);
2776
        /* Sample random bytes to create a polynomial. */
2777
        p = (byte*)st;
2778
        ctr0 = mlkem_rej_uniform_neon(a + 0 * MLKEM_N, MLKEM_N, p,
2779
            XOF_BLOCK_SIZE);
2780
        p += 25 * 8;
2781
        ctr1 = mlkem_rej_uniform_neon(a + 1 * MLKEM_N, MLKEM_N, p,
2782
            XOF_BLOCK_SIZE);
2783
        p += 25 * 8;
2784
        ctr2 = mlkem_rej_uniform_neon(a + 2 * MLKEM_N, MLKEM_N, p,
2785
            XOF_BLOCK_SIZE);
2786
        /* Create more blocks if too many rejected. */
2787
        while ((ctr0 < MLKEM_N) || (ctr1 < MLKEM_N) || (ctr2 < MLKEM_N)) {
2788
            mlkem_sha3_blocksx3_neon(st);
2789
2790
            p = (byte*)st;
2791
            ctr0 += mlkem_rej_uniform_neon(a + 0 * MLKEM_N + ctr0,
2792
                MLKEM_N - ctr0, p, XOF_BLOCK_SIZE);
2793
            p += 25 * 8;
2794
            ctr1 += mlkem_rej_uniform_neon(a + 1 * MLKEM_N + ctr1,
2795
                MLKEM_N - ctr1, p, XOF_BLOCK_SIZE);
2796
            p += 25 * 8;
2797
            ctr2 += mlkem_rej_uniform_neon(a + 2 * MLKEM_N + ctr2,
2798
                MLKEM_N - ctr2, p, XOF_BLOCK_SIZE);
2799
        }
2800
2801
        a += 3 * MLKEM_N;
2802
    }
2803
2804
    return 0;
2805
}
2806
#endif
2807
2808
#if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
2809
/* Deterministically generate a matrix (or transpose) of uniform integers mod q.
2810
 *
2811
 * Seed used with XOF to generate random bytes.
2812
 *
2813
 * @param  [out]  a           Matrix of uniform integers.
2814
 * @param  [in]   seed        Bytes to seed XOF generation.
2815
 * @param  [in]   transposed  Whether A or A^T is generated.
2816
 * @return  0 on success.
2817
 */
2818
static int mlkem_gen_matrix_k4_aarch64(sword16* a, byte* seed, int transposed)
2819
{
2820
    int i;
2821
    int k;
2822
    word64 state[3 * 25];
2823
    word64* st = (word64*)state;
2824
    unsigned int ctr0;
2825
    unsigned int ctr1;
2826
    unsigned int ctr2;
2827
    byte* p;
2828
2829
    for (k = 0; k < 5; k++) {
2830
        for (i = 0; i < 3; i++) {
2831
            byte bi = ((k * 3) + i) / 4;
2832
            byte bj = ((k * 3) + i) % 4;
2833
            if (!transposed) {
2834
                state[i*25 + 4] = 0x1f0000 + (bi << 8) + bj;
2835
            }
2836
            else {
2837
                state[i*25 + 4] = 0x1f0000 + (bj << 8) + bi;
2838
            }
2839
        }
2840
2841
        mlkem_shake128_blocksx3_seed_neon(state, seed);
2842
        /* Sample random bytes to create a polynomial. */
2843
        p = (byte*)st;
2844
        ctr0 = mlkem_rej_uniform_neon(a + 0 * MLKEM_N, MLKEM_N, p,
2845
            XOF_BLOCK_SIZE);
2846
        p += 25 * 8;
2847
        ctr1 = mlkem_rej_uniform_neon(a + 1 * MLKEM_N, MLKEM_N, p,
2848
            XOF_BLOCK_SIZE);
2849
        p += 25 * 8;
2850
        ctr2 = mlkem_rej_uniform_neon(a + 2 * MLKEM_N, MLKEM_N, p,
2851
            XOF_BLOCK_SIZE);
2852
        /* Create more blocks if too many rejected. */
2853
        while ((ctr0 < MLKEM_N) || (ctr1 < MLKEM_N) || (ctr2 < MLKEM_N)) {
2854
            mlkem_sha3_blocksx3_neon(st);
2855
2856
            p = (byte*)st;
2857
            ctr0 += mlkem_rej_uniform_neon(a + 0 * MLKEM_N + ctr0,
2858
                MLKEM_N - ctr0, p, XOF_BLOCK_SIZE);
2859
            p += 25 * 8;
2860
            ctr1 += mlkem_rej_uniform_neon(a + 1 * MLKEM_N + ctr1,
2861
                MLKEM_N - ctr1, p, XOF_BLOCK_SIZE);
2862
            p += 25 * 8;
2863
            ctr2 += mlkem_rej_uniform_neon(a + 2 * MLKEM_N + ctr2,
2864
                MLKEM_N - ctr2, p, XOF_BLOCK_SIZE);
2865
        }
2866
2867
        a += 3 * MLKEM_N;
2868
    }
2869
2870
    readUnalignedWords64(state, seed, 4);
2871
    /* Transposed value same as not. */
2872
    state[4] = 0x1f0000 + (3 << 8) + 3;
2873
    XMEMSET(state + 5, 0, sizeof(*state) * (25 - 5));
2874
    state[20] = W64LIT(0x8000000000000000);
2875
    BlockSha3(state);
2876
    p = (byte*)state;
2877
    ctr0 = mlkem_rej_uniform_neon(a, MLKEM_N, p, XOF_BLOCK_SIZE);
2878
    while (ctr0 < MLKEM_N) {
2879
        BlockSha3(state);
2880
        ctr0 += mlkem_rej_uniform_neon(a + ctr0, MLKEM_N - ctr0, p,
2881
            XOF_BLOCK_SIZE);
2882
    }
2883
2884
    return 0;
2885
}
2886
#endif
2887
#endif /* USE_INTEL_SPEEDUP */
2888
2889
#if !(defined(WOLFSSL_ARMASM) && defined(__aarch64__))
2890
/* Absorb the seed data for squeezing out pseudo-random data.
2891
 *
2892
 * FIPS 203, Section 4.1:
2893
 * 1. XOF.init() = SHAKE128.Init().
2894
 * 2. XOF.Absorb(ctx,str) = SHAKE128.Absorb(ctx,str).
2895
 *
2896
 * @param  [in, out]  shake128  SHAKE-128 object.
2897
 * @param  [in]       seed      Data to absorb.
2898
 * @param  [in]       len       Length of data to absorb in bytes.
2899
 * @return  0 on success always.
2900
 */
2901
static int mlkem_xof_absorb(wc_Shake* shake128, const byte* seed, int len)
2902
0
{
2903
0
    int ret;
2904
2905
0
    ret = wc_InitShake128(shake128, NULL, INVALID_DEVID);
2906
0
    if (ret == 0) {
2907
0
        ret = wc_Shake128_Absorb(shake128, seed, (word32)len);
2908
0
    }
2909
2910
0
    return ret;
2911
0
}
2912
2913
/* Squeeze the state to produce pseudo-random data.
2914
 *
2915
 * FIPS 203, Section 4.1:
2916
 * 3. XOF.Squeeze(ctx,l) = SHAKE128.Squeeze(ctx,8.l).
2917
 *
2918
 * @param  [in, out]  shake128  SHAKE-128 object.
2919
 * @param  [out]      out       Buffer to write to.
2920
 * @param  [in]       blocks    Number of blocks to write.
2921
 * @return  0 on success always.
2922
 */
2923
static int mlkem_xof_squeezeblocks(wc_Shake* shake128, byte* out, int blocks)
2924
0
{
2925
0
    return wc_Shake128_SqueezeBlocks(shake128, out, (word32)blocks);
2926
0
}
2927
#endif
2928
2929
/* New/Initialize SHA-3 object.
2930
 *
2931
 * FIPS 203, Section 4.1:
2932
 * H(s) := SHA3-256(s)
2933
 *
2934
 * @param  [in, out]  hash    SHA-3 object.
2935
 * @param  [in]       heap    Dynamic memory allocator hint.
2936
 * @param  [in]       devId   Device id.
2937
 * @return  0 on success always.
2938
 */
2939
int mlkem_hash_new(wc_Sha3* hash, void* heap, int devId)
2940
0
{
2941
0
    return wc_InitSha3_256(hash, heap, devId);
2942
0
}
2943
2944
/* Free SHA-3 object.
2945
 *
2946
 * FIPS 203, Section 4.1:
2947
 * H(s) := SHA3-256(s)
2948
 *
2949
 * @param  [in, out]  hash  SHA-3 object.
2950
 */
2951
void mlkem_hash_free(wc_Sha3* hash)
2952
0
{
2953
0
    wc_Sha3_256_Free(hash);
2954
0
}
2955
2956
/* Hash data using SHA3-256 with SHA-3 object.
2957
 *
2958
 * FIPS 203, Section 4.1:
2959
 * H(s) := SHA3-256(s)
2960
 *
2961
 * @param  [in, out]  hash     SHA-3 object.
2962
 * @param  [in]       data     Data to be hashed.
2963
 * @param  [in]       dataLen  Length of data in bytes.
2964
 * @param  [out]      out      Hash of data.
2965
 * @return  0 on success.
2966
 */
2967
int mlkem_hash256(wc_Sha3* hash, const byte* data, word32 dataLen, byte* out)
2968
0
{
2969
0
    int ret;
2970
2971
    /* Process all data. */
2972
0
    ret = wc_Sha3_256_Update(hash, data, dataLen);
2973
0
    if (ret == 0) {
2974
        /* Calculate Hash of data passed in and re-initialize. */
2975
0
        ret = wc_Sha3_256_Final(hash, out);
2976
0
    }
2977
2978
0
    return ret;
2979
0
}
2980
2981
/* Hash one or two blocks of data using SHA3-512 with SHA-3 object.
2982
 *
2983
 * FIPS 203, Section 4.1:
2984
 * G(s) := SHA3-512(s)
2985
 *
2986
 * @param  [in, out]  hash      SHA-3 object.
2987
 * @param  [in]       data1     First block of data to be hashed.
2988
 * @param  [in]       data1Len  Length of first block of data in bytes.
2989
 * @param  [in]       data2     Second block of data to be hashed. May be NULL.
2990
 * @param  [in]       data2Len  Length of second block of data in bytes.
2991
 * @param  [out]      out       Hash of all data.
2992
 * @return  0 on success.
2993
 */
2994
int mlkem_hash512(wc_Sha3* hash, const byte* data1, word32 data1Len,
2995
    const byte* data2, word32 data2Len, byte* out)
2996
0
{
2997
0
    int ret;
2998
2999
    /* Process first block of data. */
3000
0
    ret = wc_Sha3_512_Update(hash, data1, data1Len);
3001
    /* Check if there is a second block of data. */
3002
0
    if ((ret == 0) && (data2 != NULL) && (data2Len > 0)) {
3003
        /* Process second block of data. */
3004
0
        ret = wc_Sha3_512_Update(hash, data2, data2Len);
3005
0
    }
3006
0
    if (ret == 0) {
3007
        /* Calculate Hash of data passed in and re-initialize. */
3008
0
        ret = wc_Sha3_512_Final(hash, out);
3009
0
    }
3010
3011
0
    return ret;
3012
0
}
3013
3014
/* Initialize SHAKE-256 object.
3015
 *
3016
 * @param  [in, out]  prf  SHAKE-256 object.
3017
 */
3018
void mlkem_prf_init(wc_Shake* prf)
3019
0
{
3020
0
    wc_InitShake256(prf, NULL, 0);
3021
0
}
3022
3023
/* New/Initialize SHAKE-256 object.
3024
 *
3025
 * FIPS 203, Section 4.1, 4.3:
3026
 * PRF_eta(s,b) := SHAKE256(s||b,8.64.eta)
3027
 *
3028
 * @param  [in, out]  prf    SHAKE-256 object.
3029
 * @param  [in]       heap   Dynamic memory allocator hint.
3030
 * @param  [in]       devId  Device id.
3031
 * @return  0 on success always.
3032
 */
3033
int mlkem_prf_new(wc_Shake* prf, void* heap, int devId)
3034
0
{
3035
0
    return wc_InitShake256(prf, heap, devId);
3036
0
}
3037
3038
/* Free SHAKE-256 object.
3039
 *
3040
 * FIPS 203, Section 4.1, 4.3:
3041
 * PRF_eta(s,b) := SHAKE256(s||b,8.64.eta)
3042
 *
3043
 * @param  [in, out]  prf  SHAKE-256 object.
3044
 */
3045
void mlkem_prf_free(wc_Shake* prf)
3046
0
{
3047
0
    wc_Shake256_Free(prf);
3048
0
}
3049
3050
#if !(defined(WOLFSSL_ARMASM) && defined(__aarch64__))
3051
/* Create pseudo-random data from the key using SHAKE-256.
3052
 *
3053
 * FIPS 203, Section 4.1, 4.3:
3054
 * PRF_eta(s,b) := SHAKE256(s||b,8.64.eta)
3055
 *
3056
 * @param  [in, out]  shake256  SHAKE-256 object.
3057
 * @param  [out]      out       Buffer to write to.
3058
 * @param  [in]       outLen    Number of bytes to write.
3059
 * @param  [in]       key       Data to derive from. Must be:
3060
 *                                WC_ML_KEM_SYM_SZ + 1 bytes in length.
3061
 * @return  0 on success always.
3062
 */
3063
static int mlkem_prf(wc_Shake* shake256, byte* out, unsigned int outLen,
3064
    const byte* key)
3065
0
{
3066
#ifdef USE_INTEL_SPEEDUP
3067
    word64 state[25];
3068
3069
    (void)shake256;
3070
3071
    /* Put first WC_ML_KEM_SYM_SZ bytes of key into blank state. */
3072
    readUnalignedWords64(state, key, WC_ML_KEM_SYM_SZ / sizeof(word64));
3073
    /* Last byte in with end of content marker. */
3074
    state[WC_ML_KEM_SYM_SZ / 8] = 0x1f00 | key[WC_ML_KEM_SYM_SZ];
3075
    /* Set rest of state to 0. */
3076
    XMEMSET(state + WC_ML_KEM_SYM_SZ / 8 + 1, 0,
3077
        (25 - WC_ML_KEM_SYM_SZ / 8 - 1) * sizeof(word64));
3078
    /* ... except for rate marker. */
3079
    state[WC_SHA3_256_COUNT - 1] = W64LIT(0x8000000000000000);
3080
3081
    /* Generate as much output as is required. */
3082
    while (outLen > 0) {
3083
        /* Get as much of an output block as is needed. */
3084
        unsigned int len = min(outLen, WC_SHA3_256_BLOCK_SIZE);
3085
3086
        /* Perform a block operation on the state for next block of output. */
3087
#ifndef WC_SHA3_NO_ASM
3088
        if (IS_INTEL_BMI2(cpuid_flags)) {
3089
            sha3_block_bmi2(state);
3090
        }
3091
        else if (IS_INTEL_AVX2(cpuid_flags) &&
3092
                 (SAVE_VECTOR_REGISTERS2() == 0)) {
3093
            sha3_block_avx2(state);
3094
            RESTORE_VECTOR_REGISTERS();
3095
        }
3096
        else
3097
#endif /* !WC_SHA3_NO_ASM */
3098
        {
3099
            BlockSha3(state);
3100
        }
3101
3102
        /* Copy the state as output. */
3103
        XMEMCPY(out, state, len);
3104
        /* Update output pointer and length. */
3105
        out += len;
3106
        outLen -= len;
3107
    }
3108
3109
    /* state holds secret PRF output. */
3110
    ForceZero(state, sizeof(state));
3111
    return 0;
3112
#else
3113
0
    int ret;
3114
3115
    /* Process all data. */
3116
0
    ret = wc_Shake256_Update(shake256, key, WC_ML_KEM_SYM_SZ + 1);
3117
0
    if (ret == 0) {
3118
        /* Calculate Hash of data passed in and re-initialize. */
3119
0
        ret = wc_Shake256_Final(shake256, out, outLen);
3120
0
    }
3121
3122
0
    return ret;
3123
0
#endif
3124
0
}
3125
#endif
3126
3127
#ifdef WOLFSSL_MLKEM_KYBER
3128
#ifdef USE_INTEL_SPEEDUP
3129
/* Create pseudo-random key from the seed using SHAKE-256.
3130
 *
3131
 * @param  [in]  seed      Data to derive from.
3132
 * @param  [in]  seedLen   Length of data to derive from in bytes.
3133
 * @param  [out] out       Buffer to write to.
3134
 * @param  [in]  outLen    Number of bytes to derive.
3135
 * @return  0 on success always.
3136
 */
3137
int mlkem_kdf(const byte* seed, int seedLen, byte* out, int outLen)
3138
{
3139
    word64 state[25];
3140
    word32 len64 = seedLen / 8;
3141
3142
    readUnalignedWords64(state, seed, len64);
3143
    state[len64] = 0x1f;
3144
    XMEMSET(state + len64 + 1, 0, (25 - len64 - 1) * sizeof(word64));
3145
    state[WC_SHA3_256_COUNT - 1] = W64LIT(0x8000000000000000);
3146
3147
#ifndef WC_SHA3_NO_ASM
3148
    if (IS_INTEL_BMI2(cpuid_flags)) {
3149
        sha3_block_bmi2(state);
3150
    }
3151
    else if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
3152
        sha3_block_avx2(state);
3153
        RESTORE_VECTOR_REGISTERS();
3154
    }
3155
    else
3156
#endif
3157
    {
3158
        BlockSha3(state);
3159
    }
3160
    XMEMCPY(out, state, outLen);
3161
3162
    /* state holds secret KDF output. */
3163
    ForceZero(state, sizeof(state));
3164
    return 0;
3165
}
3166
#endif
3167
3168
#if defined(WOLFSSL_ARMASM) && defined(__aarch64__)
3169
/* Create pseudo-random key from the seed using SHAKE-256.
3170
 *
3171
 * @param  [in]  seed      Data to derive from.
3172
 * @param  [in]  seedLen   Length of data to derive from in bytes.
3173
 * @param  [out] out       Buffer to write to.
3174
 * @param  [in]  outLen    Number of bytes to derive.
3175
 * @return  0 on success always.
3176
 */
3177
int mlkem_kdf(const byte* seed, int seedLen, byte* out, int outLen)
3178
{
3179
    word64 state[25];
3180
    word32 len64 = seedLen / 8;
3181
3182
    readUnalignedWords64(state, seed, len64);
3183
    state[len64] = 0x1f;
3184
    XMEMSET(state + len64 + 1, 0, (25 - len64 - 1) * sizeof(word64));
3185
    state[WC_SHA3_256_COUNT - 1] = W64LIT(0x8000000000000000);
3186
3187
    BlockSha3(state);
3188
    XMEMCPY(out, state, outLen);
3189
3190
    /* state holds secret KDF output. */
3191
    ForceZero(state, sizeof(state));
3192
    return 0;
3193
}
3194
#endif
3195
#endif
3196
3197
#ifndef WOLFSSL_NO_ML_KEM
3198
/* Derive the secret from z and cipher text.
3199
 *
3200
 * @param [in, out]  prf   SHAKE-256 object.
3201
 * @param [in]       z     Implicit rejection value.
3202
 * @param [in]       ct    Cipher text.
3203
 * @param [in]       ctSz  Length of cipher text in bytes.
3204
 * @param [out]      ss    Shared secret.
3205
 * @return  0 on success.
3206
 * @return  MEMORY_E when dynamic memory allocation failed.
3207
 * @return  Other negative value when a hash error occurred.
3208
 */
3209
int mlkem_derive_secret(wc_Shake* prf, const byte* z, const byte* ct,
3210
    word32 ctSz, byte* ss)
3211
0
{
3212
0
    int ret;
3213
3214
#ifdef USE_INTEL_SPEEDUP
3215
    XMEMCPY(prf->t, z, WC_ML_KEM_SYM_SZ);
3216
    XMEMCPY(prf->t + WC_ML_KEM_SYM_SZ, ct,
3217
        WC_SHA3_256_COUNT * 8 - WC_ML_KEM_SYM_SZ);
3218
    prf->i = WC_ML_KEM_SYM_SZ + WC_SHA3_256_COUNT * 8 - WC_ML_KEM_SYM_SZ;
3219
    ct += WC_SHA3_256_COUNT * 8 - WC_ML_KEM_SYM_SZ;
3220
    ctSz -= WC_SHA3_256_COUNT * 8 - WC_ML_KEM_SYM_SZ;
3221
    ret = wc_Shake256_Update(prf, ct, ctSz);
3222
    if (ret == 0) {
3223
        ret = wc_Shake256_Final(prf, ss, WC_ML_KEM_SS_SZ);
3224
    }
3225
#else
3226
0
    ret = wc_InitShake256(prf, NULL, INVALID_DEVID);
3227
0
    if (ret == 0) {
3228
0
        ret = wc_Shake256_Update(prf, z, WC_ML_KEM_SYM_SZ);
3229
0
    }
3230
0
    if (ret == 0) {
3231
0
        ret = wc_Shake256_Update(prf, ct, ctSz);
3232
0
    }
3233
0
    if (ret == 0) {
3234
0
        ret = wc_Shake256_Final(prf, ss, WC_ML_KEM_SS_SZ);
3235
0
    }
3236
0
#endif
3237
3238
0
    return ret;
3239
0
}
3240
#endif
3241
3242
#if !defined(WOLFSSL_ARMASM)
3243
/* Rejection sampling on uniform random bytes to generate uniform random
3244
 * integers mod q.
3245
 *
3246
 * FIPS 203, Algorithm 7: SampleNTT(B)
3247
 * Takes a 32-byte seed and two indices as input and outputs a pseudorandom
3248
 * element of T_q.
3249
 *   ...
3250
 *   4: while j < 256 do
3251
 *   5:     (ctx,C) <- XOF.Squeeze(ctx,3)
3252
 *   6:     d1 <- C[0] + 256.(C[1] mod 16)
3253
 *   7:     d2 <- lower(C[1] / 16) + 16.C[2]
3254
 *   8:     if d1 < q then
3255
 *   9:         a_hat[j] <- d1
3256
 *  10:         j <- j + 1
3257
 *  11:     end if
3258
 *  12:     if d2 < q and j < 256 then
3259
 *  13:         a_hat[j] <- d2
3260
 *  14:         j <- j + 1
3261
 *  15:     end if
3262
 *  16: end while
3263
 *  ...
3264
 *
3265
 * @param  [out]  p     Uniform random integers mod q.
3266
 * @param  [in]   len   Maximum number of integers.
3267
 * @param  [in]   r     Uniform random bytes buffer.
3268
 * @param  [in]   rLen  Length of random data in buffer.
3269
 * @return  Number of integers sampled.
3270
 */
3271
static unsigned int mlkem_rej_uniform_c(sword16* p, unsigned int len,
3272
    const byte* r, unsigned int rLen)
3273
0
{
3274
0
    unsigned int i;
3275
0
    unsigned int j;
3276
3277
#if defined(WOLFSSL_MLKEM_SMALL) || !defined(WC_64BIT_CPU) || \
3278
    defined(BIG_ENDIAN_ORDER)
3279
    /* Keep sampling until max number of integers reached or buffer is used up.
3280
     * Step 4. */
3281
    for (i = 0, j = 0; (i < len) && (j <= rLen - 3); j += 3) {
3282
        /* Step 5 - Now using 3 bytes of what the caller generated. */
3283
        /* Use 24 bits (3 bytes) as two 12 bits integers. */
3284
        /* Step 6. */
3285
        sword16 v0 = ((r[0] >> 0) | ((word16)r[1] << 8)) & 0xFFF;
3286
        /* Step 7. */
3287
        sword16 v1 = ((r[1] >> 4) | ((word16)r[2] << 4)) & 0xFFF;
3288
3289
        /* Reject first 12-bit integer if greater than or equal to q.
3290
         * Step 8 */
3291
        if (v0 < MLKEM_Q) {
3292
            /* Steps 9-10 */
3293
            p[i++] = v0;
3294
        }
3295
        /* Check second if we don't have enough integers yet.
3296
         * Reject second 12-bit integer if greater than or equal to q.
3297
         * Step 12 */
3298
        if ((i < len) && (v1 < MLKEM_Q)) {
3299
            /* Steps 13-14 */
3300
            p[i++] = v1;
3301
        }
3302
3303
        /* Move over used bytes. */
3304
        r += 3;
3305
    }
3306
#else
3307
    /* Unroll loops. Minimal work per loop. */
3308
0
    unsigned int minJ;
3309
3310
    /* Calculate minimum number of 6 byte data blocks to get all required
3311
     * numbers assuming no rejections. */
3312
0
    minJ = len / 4 * 6;
3313
0
    if (minJ > rLen)
3314
0
        minJ = rLen;
3315
0
    i = 0;
3316
0
    for (j = 0; j < minJ; j += 6) {
3317
        /* Use 48 bits (6 bytes) as four 12-bit integers. */
3318
0
        word64 r_word = readUnalignedWord64(r);
3319
0
        sword16 v0 =  r_word        & 0xfff;
3320
0
        sword16 v1 = (r_word >> 12) & 0xfff;
3321
0
        sword16 v2 = (r_word >> 24) & 0xfff;
3322
0
        sword16 v3 = (r_word >> 36) & 0xfff;
3323
3324
0
        p[i] = v0;
3325
0
        i += (v0 < MLKEM_Q);
3326
0
        p[i] = v1;
3327
0
        i += (v1 < MLKEM_Q);
3328
0
        p[i] = v2;
3329
0
        i += (v2 < MLKEM_Q);
3330
0
        p[i] = v3;
3331
0
        i += (v3 < MLKEM_Q);
3332
3333
        /* Move over used bytes. */
3334
0
        r += 6;
3335
0
    }
3336
    /* Check whether we have all the numbers we need. */
3337
0
    if (j < rLen) {
3338
        /* Keep trying until we have fewer than 4 numbers to find or data is
3339
         * used up. */
3340
0
        for (; (i + 4 < len) && (j < rLen); j += 6) {
3341
            /* Use 48 bits (6 bytes) as four 12-bit integers. */
3342
0
            word64 r_word = readUnalignedWord64(r);
3343
0
            sword16 v0 =  r_word        & 0xfff;
3344
0
            sword16 v1 = (r_word >> 12) & 0xfff;
3345
0
            sword16 v2 = (r_word >> 24) & 0xfff;
3346
0
            sword16 v3 = (r_word >> 36) & 0xfff;
3347
3348
0
            p[i] = v0;
3349
0
            i += (v0 < MLKEM_Q);
3350
0
            p[i] = v1;
3351
0
            i += (v1 < MLKEM_Q);
3352
0
            p[i] = v2;
3353
0
            i += (v2 < MLKEM_Q);
3354
0
            p[i] = v3;
3355
0
            i += (v3 < MLKEM_Q);
3356
3357
            /* Move over used bytes. */
3358
0
            r += 6;
3359
0
        }
3360
        /* Keep trying until we have all the numbers we need or the data is used
3361
         * up. */
3362
0
        for (; (i < len) && (j < rLen); j += 6) {
3363
            /* Use 48 bits (6 bytes) as four 12-bit integers. */
3364
0
            word64 r_word = readUnalignedWord64(r);
3365
0
            sword16 v0 =  r_word        & 0xfff;
3366
0
            sword16 v1 = (r_word >> 12) & 0xfff;
3367
0
            sword16 v2 = (r_word >> 24) & 0xfff;
3368
0
            sword16 v3 = (r_word >> 36) & 0xfff;
3369
3370
            /* Reject first 12-bit integer if greater than or equal to q. */
3371
0
            if (v0 < MLKEM_Q) {
3372
0
                p[i++] = v0;
3373
0
            }
3374
            /* Check second if we don't have enough integers yet.
3375
             * Reject second 12-bit integer if greater than or equal to q. */
3376
0
            if ((i < len) && (v1 < MLKEM_Q)) {
3377
0
                p[i++] = v1;
3378
0
            }
3379
            /* Check third if we don't have enough integers yet.
3380
             * Reject third 12-bit integer if greater than or equal to q. */
3381
0
            if ((i < len) && (v2 < MLKEM_Q)) {
3382
0
                p[i++] = v2;
3383
0
            }
3384
            /* Check fourth if we don't have enough integers yet.
3385
             * Reject fourth 12-bit integer if greater than or equal to q. */
3386
0
            if ((i < len) && (v3 < MLKEM_Q)) {
3387
0
                p[i++] = v3;
3388
0
            }
3389
3390
            /* Move over used bytes. */
3391
0
            r += 6;
3392
0
        }
3393
0
    }
3394
0
#endif
3395
3396
0
    return i;
3397
0
}
3398
#endif
3399
3400
#if !defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) || \
3401
    !defined(WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM)
3402
3403
#if !(defined(WOLFSSL_ARMASM) && defined(__aarch64__))
3404
/* Deterministically generate a matrix (or transpose) of uniform integers mod q.
3405
 *
3406
 * Seed used with XOF to generate random bytes.
3407
 *
3408
 * FIPS 203, Algorithm 13: K-PKE.KeyGen(d)
3409
 *   ...
3410
 *   3: for (i <- 0; i < k; i++)
3411
 *   4:     for (j <- 0; j < k; j++)
3412
 *   5:         A_hat[i,j] <- SampleNTT(rho||j||i)
3413
 *   6:     end for
3414
 *   7: end for
3415
 *   ...
3416
 * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE,m,r)
3417
 *   ...
3418
 *   4: for (i <- 0; i < k; i++)
3419
 *   5:     for (j <- 0; j < k; j++)
3420
 *   6:         A_hat[i,j] <- SampleNTT(rho||j||i)  (Transposed is rho||i||j)
3421
 *   7:     end for
3422
 *   8: end for
3423
 *   ...
3424
 * FIPS 203, Algorithm 7: SampleNTT(B)
3425
 * Takes a 32-byte seed and two indices as input and outputs a pseudorandom
3426
 * element of T_q.
3427
 *   1: ctx <- XOF.init()
3428
 *   2: ctx <- XOF.Absorb(ctx,B)
3429
 *   3: j <- 0
3430
 *   4: while j < 256 do
3431
 *   5:     (ctx,C) <- XOF.Squeeze(ctx,3)
3432
 *   ...
3433
 *  16: end while
3434
 *  17: return a_hat
3435
 *
3436
 * @param  [in, out]  prf         XOF object.
3437
 * @param  [out]      a           Matrix of uniform integers.
3438
 * @param  [in]       k           Number of dimensions. k x k polynomials.
3439
 * @param  [in]       seed        Bytes to seed XOF generation.
3440
 * @param  [in]       transposed  Whether A or A^T is generated.
3441
 * @return  0 on success.
3442
 * @return  MEMORY_E when dynamic memory allocation fails. Only possible when
3443
 *          WOLFSSL_SMALL_STACK is defined.
3444
 */
3445
static int mlkem_gen_matrix_c(MLKEM_PRF_T* prf, sword16* a, int k, byte* seed,
3446
    int transposed)
3447
0
{
3448
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
3449
    byte* rand;
3450
#else
3451
0
    byte rand[GEN_MATRIX_SIZE + 2];
3452
0
#endif
3453
0
    byte extSeed[WC_ML_KEM_SYM_SZ + 2];
3454
0
    int ret = 0;
3455
0
    int i;
3456
3457
    /* Copy seed into buffer that has space for i and j to be appended. */
3458
0
    XMEMCPY(extSeed, seed, WC_ML_KEM_SYM_SZ);
3459
3460
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
3461
    /* Allocate large amount of memory to hold random bytes to be sampled. */
3462
    rand = (byte*)XMALLOC(GEN_MATRIX_SIZE + 2, NULL, DYNAMIC_TYPE_TMP_BUFFER);
3463
    if (rand == NULL) {
3464
        ret = MEMORY_E;
3465
    }
3466
#endif
3467
3468
0
#if !defined(WOLFSSL_MLKEM_SMALL) && defined(WC_64BIT_CPU)
3469
    /* Loading 64 bits, only using 48 bits. Loading 2 bytes more than used. */
3470
0
    if (ret == 0) {
3471
0
        rand[GEN_MATRIX_SIZE+0] = 0xff;
3472
0
        rand[GEN_MATRIX_SIZE+1] = 0xff;
3473
0
    }
3474
0
#endif
3475
3476
    /* Generate each vector of polynomials.
3477
     * Alg 13, Step 3. Alg 14, Step 4. */
3478
0
    for (i = 0; (ret == 0) && (i < k); i++, a += k * MLKEM_N) {
3479
0
        int j;
3480
        /* Generate each polynomial in vector from seed with indices.
3481
         * Alg 13, Step 4. Alg 14, Step 5. */
3482
0
        for (j = 0; (ret == 0) && (j < k); j++) {
3483
0
            if (transposed) {
3484
                /* Alg 14, Step 6: .. rho||i||j ... */
3485
0
                extSeed[WC_ML_KEM_SYM_SZ + 0] = (byte)i;
3486
0
                extSeed[WC_ML_KEM_SYM_SZ + 1] = (byte)j;
3487
0
            }
3488
0
            else {
3489
                /* Alg 13, Step 5: .. rho||j||i ... */
3490
0
                extSeed[WC_ML_KEM_SYM_SZ + 0] = (byte)j;
3491
0
                extSeed[WC_ML_KEM_SYM_SZ + 1] = (byte)i;
3492
0
            }
3493
            /* Absorb the index specific seed.
3494
             * Alg 7, Step 1-2 */
3495
0
            ret = mlkem_xof_absorb(prf, extSeed, sizeof(extSeed));
3496
0
            if (ret == 0) {
3497
                /* Create data based on the seed.
3498
                 * Alg 7, Step 5. Generating enough to, on average, be able to
3499
                 * get enough valid values. */
3500
0
                ret = mlkem_xof_squeezeblocks(prf, rand, GEN_MATRIX_NBLOCKS);
3501
0
            }
3502
0
            if (ret == 0) {
3503
0
                unsigned int ctr;
3504
3505
                /* Sample random bytes to create a polynomial.
3506
                 * Alg 7, Step 3 - implicitly counter is 0.
3507
                 * Alg 7, Step 4-16. */
3508
0
                ctr = mlkem_rej_uniform_c(a + j * MLKEM_N, MLKEM_N, rand,
3509
0
                    GEN_MATRIX_SIZE);
3510
                /* Create more blocks if too many rejected.
3511
                 * Alg 7, Step 4. */
3512
0
                while (ctr < MLKEM_N) {
3513
                    /* Alg 7, Step 5. */
3514
0
                    mlkem_xof_squeezeblocks(prf, rand, 1);
3515
                    /* Alg 7, Step 4-16. */
3516
0
                    ctr += mlkem_rej_uniform_c(a + j * MLKEM_N + ctr,
3517
0
                        MLKEM_N - ctr, rand, XOF_BLOCK_SIZE);
3518
0
                }
3519
0
            }
3520
0
        }
3521
0
    }
3522
3523
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
3524
    /* Dispose of temporary buffer. */
3525
    XFREE(rand, NULL, DYNAMIC_TYPE_TMP_BUFFER);
3526
#endif
3527
3528
0
    return ret;
3529
0
}
3530
#endif
3531
3532
/* Deterministically generate a matrix (or transpose) of uniform integers mod q.
3533
 *
3534
 * Seed used with XOF to generate random bytes.
3535
 *
3536
 * FIPS 203, Algorithm 13: K-PKE.KeyGen(d), Steps 3-7
3537
 * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE,m,r), Steps 4-8
3538
 *
3539
 * @param  [in, out]  prf         XOF object.
3540
 * @param  [out]      a           Matrix of uniform integers.
3541
 * @param  [in]       k           Number of dimensions. k x k polynomials.
3542
 * @param  [in]       seed        Bytes to seed XOF generation.
3543
 * @param  [in]       transposed  Whether A or A^T is generated.
3544
 * @return  0 on success.
3545
 * @return  MEMORY_E when dynamic memory allocation fails. Only possible when
3546
 *          WOLFSSL_SMALL_STACK is defined.
3547
 */
3548
int mlkem_gen_matrix(MLKEM_PRF_T* prf, sword16* a, int k, byte* seed,
3549
    int transposed)
3550
0
{
3551
0
    int ret;
3552
3553
0
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
3554
0
    if (k == WC_ML_KEM_512_K) {
3555
#if defined(WOLFSSL_ARMASM) && defined(__aarch64__)
3556
        ret = mlkem_gen_matrix_k2_aarch64(a, seed, transposed);
3557
#else
3558
    #if defined(USE_INTEL_SPEEDUP) && !defined(WC_SHA3_NO_ASM)
3559
        if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
3560
            ret = mlkem_gen_matrix_k2_avx2(a, seed, transposed);
3561
            RESTORE_VECTOR_REGISTERS();
3562
        }
3563
        else
3564
    #endif
3565
0
        {
3566
0
            ret = mlkem_gen_matrix_c(prf, a, WC_ML_KEM_512_K, seed, transposed);
3567
0
        }
3568
0
#endif
3569
0
    }
3570
0
    else
3571
0
#endif
3572
0
#if defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768)
3573
0
    if (k == WC_ML_KEM_768_K) {
3574
#if defined(WOLFSSL_ARMASM) && defined(__aarch64__)
3575
        ret = mlkem_gen_matrix_k3_aarch64(a, seed, transposed);
3576
#else
3577
    #if defined(USE_INTEL_SPEEDUP) && !defined(WC_SHA3_NO_ASM)
3578
        if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
3579
            ret = mlkem_gen_matrix_k3_avx2(a, seed, transposed);
3580
            RESTORE_VECTOR_REGISTERS();
3581
        }
3582
        else
3583
    #endif
3584
0
        {
3585
0
            ret = mlkem_gen_matrix_c(prf, a, WC_ML_KEM_768_K, seed, transposed);
3586
0
        }
3587
0
#endif
3588
0
    }
3589
0
    else
3590
0
#endif
3591
0
#if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
3592
0
    if (k == WC_ML_KEM_1024_K) {
3593
#if defined(WOLFSSL_ARMASM) && defined(__aarch64__)
3594
        ret = mlkem_gen_matrix_k4_aarch64(a, seed, transposed);
3595
#else
3596
    #if defined(USE_INTEL_SPEEDUP) && !defined(WC_SHA3_NO_ASM)
3597
        if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
3598
            ret = mlkem_gen_matrix_k4_avx2(a, seed, transposed);
3599
            RESTORE_VECTOR_REGISTERS();
3600
        }
3601
        else
3602
    #endif
3603
0
        {
3604
0
            ret = mlkem_gen_matrix_c(prf, a, WC_ML_KEM_1024_K, seed,
3605
0
                transposed);
3606
0
        }
3607
0
#endif
3608
0
    }
3609
0
    else
3610
0
#endif
3611
0
    {
3612
0
        ret = BAD_STATE_E;
3613
0
    }
3614
3615
0
    (void)prf;
3616
3617
0
    return ret;
3618
0
}
3619
3620
#endif
3621
3622
#if defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) || \
3623
    defined(WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM)
3624
3625
/* Deterministically generate a matrix (or transpose) of uniform integers mod q.
3626
 *
3627
 * Seed used with XOF to generate random bytes.
3628
 *
3629
 * FIPS 203, Algorithm 13: K-PKE.KeyGen(d)
3630
 * ...
3631
 * 4:     for (j <- 0; j < k; j++)
3632
 * 5:         A_hat[i,j] <- SampleNTT(rho||j||i)
3633
 * 6:     end for
3634
 * ...
3635
 * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE,m,r)
3636
 * ...
3637
 * 5:     for (j <- 0; j < k; j++)
3638
 * 6:         A_hat[i,j] <- SampleNTT(rho||j||i)  (Transposed is rho||i||j)
3639
 * 7:     end for
3640
 * ...
3641
 *
3642
 * @param  [in, out]  prf         XOF object.
3643
 * @param  [out]      a           Matrix of uniform integers.
3644
 * @param  [in]       k           Number of dimensions. k x k polynomials.
3645
 * @param  [in]       seed        Bytes to seed XOF generation.
3646
 * @param  [in]       i           Index of vector to generate.
3647
 * @param  [in]       transposed  Whether A or A^T is generated.
3648
 * @return  0 on success.
3649
 * @return  MEMORY_E when dynamic memory allocation fails. Only possible when
3650
 *          WOLFSSL_SMALL_STACK is defined.
3651
 */
3652
static int mlkem_gen_matrix_i(MLKEM_PRF_T* prf, sword16* a, int k, byte* seed,
3653
    int i, int transposed)
3654
{
3655
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
3656
    byte* rand;
3657
#else
3658
    byte rand[GEN_MATRIX_SIZE + 2];
3659
#endif
3660
    byte extSeed[WC_ML_KEM_SYM_SZ + 2];
3661
    int ret = 0;
3662
    int j;
3663
3664
    XMEMCPY(extSeed, seed, WC_ML_KEM_SYM_SZ);
3665
3666
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
3667
    /* Allocate large amount of memory to hold random bytes to be sampled. */
3668
    rand = (byte*)XMALLOC(GEN_MATRIX_SIZE + 2, NULL, DYNAMIC_TYPE_TMP_BUFFER);
3669
    if (rand == NULL) {
3670
        ret = MEMORY_E;
3671
    }
3672
#endif
3673
3674
#if !defined(WOLFSSL_MLKEM_SMALL) && defined(WC_64BIT_CPU)
3675
    /* Loading 64 bits, only using 48 bits. Loading 2 bytes more than used. */
3676
    if (ret == 0) {
3677
        rand[GEN_MATRIX_SIZE+0] = 0xff;
3678
        rand[GEN_MATRIX_SIZE+1] = 0xff;
3679
    }
3680
#endif
3681
3682
    /* Generate each polynomial in vector from seed with indices.
3683
     * Alg 13, Step 4. Alg 14, Step 5. */
3684
    for (j = 0; (ret == 0) && (j < k); j++) {
3685
        if (transposed) {
3686
            /* Alg 14, Step 6: .. rho||i||j ... */
3687
            extSeed[WC_ML_KEM_SYM_SZ + 0] = (byte)i;
3688
            extSeed[WC_ML_KEM_SYM_SZ + 1] = (byte)j;
3689
        }
3690
        else {
3691
            /* Alg 13, Step 5: .. rho||j||i ... */
3692
            extSeed[WC_ML_KEM_SYM_SZ + 0] = (byte)j;
3693
            extSeed[WC_ML_KEM_SYM_SZ + 1] = (byte)i;
3694
        }
3695
        /* Absorb the index specific seed.
3696
         * Alg 7, Step 1-2 */
3697
        ret = mlkem_xof_absorb(prf, extSeed, sizeof(extSeed));
3698
        if (ret == 0) {
3699
            /* Create data based on the seed.
3700
             * Alg 7, Step 5. Generating enough to, on average, be able to get
3701
             * enough valid values. */
3702
            ret = mlkem_xof_squeezeblocks(prf, rand, GEN_MATRIX_NBLOCKS);
3703
        }
3704
        if (ret == 0) {
3705
            unsigned int ctr;
3706
3707
            /* Sample random bytes to create a polynomial.
3708
             * Alg 7, Step 3 - implicitly counter is 0.
3709
             * Alg 7, Step 4-16. */
3710
            ctr = mlkem_rej_uniform_c(a + j * MLKEM_N, MLKEM_N, rand,
3711
                GEN_MATRIX_SIZE);
3712
            /* Create more blocks if too many rejected.
3713
             * Alg 7, Step 4. */
3714
            while (ctr < MLKEM_N) {
3715
                /* Alg 7, Step 5. */
3716
                mlkem_xof_squeezeblocks(prf, rand, 1);
3717
                /* Alg 7, Step 4-16. */
3718
                ctr += mlkem_rej_uniform_c(a + j * MLKEM_N + ctr,
3719
                    MLKEM_N - ctr, rand, XOF_BLOCK_SIZE);
3720
            }
3721
        }
3722
    }
3723
3724
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
3725
    /* Dispose of temporary buffer. */
3726
    XFREE(rand, NULL, DYNAMIC_TYPE_TMP_BUFFER);
3727
#endif
3728
3729
    return ret;
3730
}
3731
3732
#endif
3733
3734
3735
/******************************************************************************/
3736
3737
/* Subtract one 2 bit value from another out of a larger number.
3738
 *
3739
 * FIPS 203, Algorithm 8: SamplePolyCBD_eta(B)
3740
 * Takes a seed as input and outputs a pseudorandom sample from the distribution
3741
 * D_eta(R_q).
3742
 *
3743
 * @param  [in]  d  Value containing sequential 2 bit values.
3744
 * @param  [in]  i  Start index of the two values in 2 bits each.
3745
 * @return  Difference of the two values with range -2..2.
3746
 */
3747
#define ETA2_SUB(d, i) \
3748
0
    (sword16)(((sword16)(((d) >> ((i) * 4 + 0)) & 0x3)) - \
3749
0
              ((sword16)(((d) >> ((i) * 4 + 2)) & 0x3)))
3750
3751
/* Compute polynomial with coefficients distributed according to a centered
3752
 * binomial distribution with parameter eta2 from uniform random bytes.
3753
 *
3754
 * FIPS 203, Algorithm 8: SamplePolyCBD_eta(B)
3755
 * Takes a seed as input and outputs a pseudorandom sample from the distribution
3756
 * D_eta(R_q).
3757
 *
3758
 * @param [out]  p  Polynomial computed.
3759
 * @param [in]   r  Random bytes.
3760
 */
3761
static void mlkem_cbd_eta2(sword16* p, const byte* r)
3762
0
{
3763
0
    unsigned int i;
3764
3765
#ifndef WORD64_AVAILABLE
3766
    /* Calculate eight integer coefficients at a time. */
3767
    for (i = 0; i < MLKEM_N; i += 8) {
3768
    #ifdef WOLFSSL_MLKEM_SMALL
3769
        unsigned int j;
3770
    #endif
3771
        /* Take the next 4 bytes, little endian, as a 32 bit value. */
3772
    #ifdef BIG_ENDIAN_ORDER
3773
        word32 t = ByteReverseWord32(readUnalignedWord32(r));
3774
    #else
3775
        word32 t = readUnalignedWord32(r);
3776
    #endif
3777
        word32 d;
3778
        /* Add second bits to first. */
3779
        d  = (t >> 0) & 0x55555555;
3780
        d += (t >> 1) & 0x55555555;
3781
        /* Values 0, 1 or 2 in consecutive 2 bits.
3782
         * 0 - 1/4, 1 - 2/4, 2 - 1/4. */
3783
3784
    #ifdef WOLFSSL_MLKEM_SMALL
3785
        for (j = 0; j < 8; j++) {
3786
            p[i + j] = ETA2_SUB(d, j);
3787
        }
3788
    #else
3789
        p[i + 0] = ETA2_SUB(d, 0);
3790
        p[i + 1] = ETA2_SUB(d, 1);
3791
        p[i + 2] = ETA2_SUB(d, 2);
3792
        p[i + 3] = ETA2_SUB(d, 3);
3793
        p[i + 4] = ETA2_SUB(d, 4);
3794
        p[i + 5] = ETA2_SUB(d, 5);
3795
        p[i + 6] = ETA2_SUB(d, 6);
3796
        p[i + 7] = ETA2_SUB(d, 7);
3797
    #endif
3798
        /* -2 - 1/16, -1 - 4/16, 0 - 6/16, 1 - 4/16, 2 - 1/16  */
3799
3800
        /* Move over used bytes. */
3801
        r += 4;
3802
    }
3803
#else
3804
    /* Calculate sixteen integer coefficients at a time. */
3805
0
    for (i = 0; i < MLKEM_N; i += 16) {
3806
    #ifdef WOLFSSL_MLKEM_SMALL
3807
        unsigned int j;
3808
    #endif
3809
        /* Take the next 8 bytes, little endian, as a 64 bit value. */
3810
    #ifdef BIG_ENDIAN_ORDER
3811
        word64 t = ByteReverseWord64(readUnalignedWord64(r));
3812
    #else
3813
0
        word64 t = readUnalignedWord64(r);
3814
0
    #endif
3815
0
        word64 d;
3816
        /* Add second bits to first. */
3817
0
        d  = (t >> 0) & 0x5555555555555555L;
3818
0
        d += (t >> 1) & 0x5555555555555555L;
3819
        /* Values 0, 1 or 2 in consecutive 2 bits.
3820
         * 0 - 1/4, 1 - 2/4, 2 - 1/4. */
3821
3822
    #ifdef WOLFSSL_MLKEM_SMALL
3823
        for (j = 0; j < 16; j++) {
3824
            p[i + j] = ETA2_SUB(d, j);
3825
        }
3826
    #else
3827
0
        p[i +  0] = ETA2_SUB(d,  0);
3828
0
        p[i +  1] = ETA2_SUB(d,  1);
3829
0
        p[i +  2] = ETA2_SUB(d,  2);
3830
0
        p[i +  3] = ETA2_SUB(d,  3);
3831
0
        p[i +  4] = ETA2_SUB(d,  4);
3832
0
        p[i +  5] = ETA2_SUB(d,  5);
3833
0
        p[i +  6] = ETA2_SUB(d,  6);
3834
0
        p[i +  7] = ETA2_SUB(d,  7);
3835
0
        p[i +  8] = ETA2_SUB(d,  8);
3836
0
        p[i +  9] = ETA2_SUB(d,  9);
3837
0
        p[i + 10] = ETA2_SUB(d, 10);
3838
0
        p[i + 11] = ETA2_SUB(d, 11);
3839
0
        p[i + 12] = ETA2_SUB(d, 12);
3840
0
        p[i + 13] = ETA2_SUB(d, 13);
3841
0
        p[i + 14] = ETA2_SUB(d, 14);
3842
0
        p[i + 15] = ETA2_SUB(d, 15);
3843
0
    #endif
3844
        /* -2 - 1/16, -1 - 4/16, 0 - 6/16, 1 - 4/16, 2 - 1/16  */
3845
3846
        /* Move over used bytes. */
3847
0
        r += 8;
3848
0
    }
3849
0
#endif
3850
0
}
3851
3852
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
3853
/* Subtract one 3 bit value from another out of a larger number.
3854
 *
3855
 * FIPS 203, Algorithm 8: SamplePolyCBD_eta(B)
3856
 * Takes a seed as input and outputs a pseudorandom sample from the distribution
3857
 * D_eta(R_q).
3858
 *
3859
 * @param  [in]  d  Value containing sequential 3 bit values.
3860
 * @param  [in]  i  Start index of the two values in 3 bits each.
3861
 * @return  Difference of the two values with range -3..3.
3862
 */
3863
#define ETA3_SUB(d, i) \
3864
0
    (sword16)(((sword16)(((d) >> ((i) * 6 + 0)) & 0x7)) - \
3865
0
              ((sword16)(((d) >> ((i) * 6 + 3)) & 0x7)))
3866
3867
/* Compute polynomial with coefficients distributed according to a centered
3868
 * binomial distribution with parameter eta3 from uniform random bytes.
3869
 *
3870
 * FIPS 203, Algorithm 8: SamplePolyCBD_eta(B)
3871
 * Takes a seed as input and outputs a pseudorandom sample from the distribution
3872
 * D_eta(R_q).
3873
 *
3874
 * @param [out]  p  Polynomial computed.
3875
 * @param [in]   r  Random bytes.
3876
 */
3877
static void mlkem_cbd_eta3(sword16* p, const byte* r)
3878
0
{
3879
0
    unsigned int i;
3880
3881
#if defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_MLKEM_NO_LARGE_CODE) || \
3882
    defined(BIG_ENDIAN_ORDER)
3883
#ifndef WORD64_AVAILABLE
3884
    /* Calculate four integer coefficients at a time. */
3885
    for (i = 0; i < MLKEM_N; i += 4) {
3886
    #ifdef WOLFSSL_MLKEM_SMALL
3887
        unsigned int j;
3888
    #endif
3889
        /* Take the next 3 bytes, little endian, as a 24 bit value. */
3890
        word32 t = (((word32)(r[0])) <<  0) |
3891
                   (((word32)(r[1])) <<  8) |
3892
                   (((word32)(r[2])) << 16);
3893
        word32 d;
3894
        /* Add second and third bits to first. */
3895
        d  = (t >> 0) & 0x00249249;
3896
        d += (t >> 1) & 0x00249249;
3897
        d += (t >> 2) & 0x00249249;
3898
        /* Values 0, 1, 2 or 3 in consecutive 3 bits.
3899
         * 0 - 1/8, 1 - 3/8, 2 - 3/8, 3 - 1/8. */
3900
3901
    #ifdef WOLFSSL_MLKEM_SMALL
3902
        for (j = 0; j < 4; j++) {
3903
            p[i + j] = ETA3_SUB(d, j);
3904
        }
3905
    #else
3906
        p[i + 0] = ETA3_SUB(d, 0);
3907
        p[i + 1] = ETA3_SUB(d, 1);
3908
        p[i + 2] = ETA3_SUB(d, 2);
3909
        p[i + 3] = ETA3_SUB(d, 3);
3910
    #endif
3911
        /* -3-1/64, -2-6/64, -1-15/64, 0-20/64, 1-15/64, 2-6/64, 3-1/64 */
3912
3913
        /* Move over used bytes. */
3914
        r += 3;
3915
    }
3916
#else
3917
    /* Calculate eight integer coefficients at a time. */
3918
    for (i = 0; i < MLKEM_N; i += 8) {
3919
    #ifdef WOLFSSL_MLKEM_SMALL
3920
        unsigned int j;
3921
    #endif
3922
        /* Take the next 6 bytes, little endian, as a 48 bit value. */
3923
        word64 t = (((word64)(r[0])) <<  0) |
3924
                   (((word64)(r[1])) <<  8) |
3925
                   (((word64)(r[2])) << 16) |
3926
                   (((word64)(r[3])) << 24) |
3927
                   (((word64)(r[4])) << 32) |
3928
                   (((word64)(r[5])) << 40);
3929
        word64 d;
3930
        /* Add second and third bits to first. */
3931
        d  = (t >> 0) & 0x0000249249249249L;
3932
        d += (t >> 1) & 0x0000249249249249L;
3933
        d += (t >> 2) & 0x0000249249249249L;
3934
        /* Values 0, 1, 2 or 3 in consecutive 3 bits.
3935
         * 0 - 1/8, 1 - 3/8, 2 - 3/8, 3 - 1/8. */
3936
3937
    #ifdef WOLFSSL_MLKEM_SMALL
3938
        for (j = 0; j < 8; j++) {
3939
            p[i + j] = ETA3_SUB(d, j);
3940
        }
3941
    #else
3942
        p[i + 0] = ETA3_SUB(d, 0);
3943
        p[i + 1] = ETA3_SUB(d, 1);
3944
        p[i + 2] = ETA3_SUB(d, 2);
3945
        p[i + 3] = ETA3_SUB(d, 3);
3946
        p[i + 4] = ETA3_SUB(d, 4);
3947
        p[i + 5] = ETA3_SUB(d, 5);
3948
        p[i + 6] = ETA3_SUB(d, 6);
3949
        p[i + 7] = ETA3_SUB(d, 7);
3950
    #endif
3951
        /* -3-1/64, -2-6/64, -1-15/64, 0-20/64, 1-15/64, 2-6/64, 3-1/64 */
3952
3953
        /* Move over used bytes. */
3954
        r += 6;
3955
    }
3956
#endif /* WORD64_AVAILABLE */
3957
#else
3958
    /* Calculate eight integer coefficients at a time. */
3959
0
    for (i = 0; i < MLKEM_N; i += 16) {
3960
0
        const word32* r32 = (const word32*)r;
3961
        /* Take the next 12 bytes, little endian, as 24 bit values. */
3962
0
        word32 t0 =   r32[0]                          & 0xffffff;
3963
0
        word32 t1 = ((r32[0] >> 24) | (r32[1] <<  8)) & 0xffffff;
3964
0
        word32 t2 = ((r32[1] >> 16) | (r32[2] << 16)) & 0xffffff;
3965
0
        word32 t3 =   r32[2] >>  8                              ;
3966
0
        word32 d0;
3967
0
        word32 d1;
3968
0
        word32 d2;
3969
0
        word32 d3;
3970
3971
        /* Add second and third bits to first. */
3972
0
        d0  = (t0 >> 0) & 0x00249249;
3973
0
        d0 += (t0 >> 1) & 0x00249249;
3974
0
        d0 += (t0 >> 2) & 0x00249249;
3975
0
        d1  = (t1 >> 0) & 0x00249249;
3976
0
        d1 += (t1 >> 1) & 0x00249249;
3977
0
        d1 += (t1 >> 2) & 0x00249249;
3978
0
        d2  = (t2 >> 0) & 0x00249249;
3979
0
        d2 += (t2 >> 1) & 0x00249249;
3980
0
        d2 += (t2 >> 2) & 0x00249249;
3981
0
        d3  = (t3 >> 0) & 0x00249249;
3982
0
        d3 += (t3 >> 1) & 0x00249249;
3983
0
        d3 += (t3 >> 2) & 0x00249249;
3984
        /* Values 0, 1, 2 or 3 in consecutive 3 bits.
3985
         * 0 - 1/8, 1 - 3/8, 2 - 3/8, 3 - 1/8. */
3986
3987
0
        p[i +  0] = ETA3_SUB(d0, 0);
3988
0
        p[i +  1] = ETA3_SUB(d0, 1);
3989
0
        p[i +  2] = ETA3_SUB(d0, 2);
3990
0
        p[i +  3] = ETA3_SUB(d0, 3);
3991
0
        p[i +  4] = ETA3_SUB(d1, 0);
3992
0
        p[i +  5] = ETA3_SUB(d1, 1);
3993
0
        p[i +  6] = ETA3_SUB(d1, 2);
3994
0
        p[i +  7] = ETA3_SUB(d1, 3);
3995
0
        p[i +  8] = ETA3_SUB(d2, 0);
3996
0
        p[i +  9] = ETA3_SUB(d2, 1);
3997
0
        p[i + 10] = ETA3_SUB(d2, 2);
3998
0
        p[i + 11] = ETA3_SUB(d2, 3);
3999
0
        p[i + 12] = ETA3_SUB(d3, 0);
4000
0
        p[i + 13] = ETA3_SUB(d3, 1);
4001
0
        p[i + 14] = ETA3_SUB(d3, 2);
4002
0
        p[i + 15] = ETA3_SUB(d3, 3);
4003
        /* -3-1/64, -2-6/64, -1-15/64, 0-20/64, 1-15/64, 2-6/64, 3-1/64 */
4004
4005
        /* Move over used bytes. */
4006
0
        r += 12;
4007
0
    }
4008
0
#endif /* WOLFSSL_SMALL_STACK || WOLFSSL_MLKEM_NO_LARGE_CODE ||
4009
        * BIG_ENDIAN_ORDER */
4010
0
}
4011
#endif
4012
4013
#if !(defined(__aarch64__) && defined(WOLFSSL_ARMASM))
4014
4015
/* Get noise/error by calculating random bytes and sampling to a binomial
4016
 * distribution.
4017
 *
4018
 * FIPS 203, Algorithm 13: K-PKE.KeyGen(d)
4019
 *   ...
4020
 *   9:     s[i] <- SamplePolyCBD_eta_1(PRF_eta_1(sigma, N))
4021
 *   ...
4022
 *  13:     e[i] <- SamplePolyCBD_eta_1(PRF_eta_1(sigma, N))
4023
 *   ...
4024
 * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE,m,r)
4025
 *   ...
4026
 *  10:     y[i] <- SamplePolyCBD_eta_1(PRF_eta_1(r, N))
4027
 *   ...
4028
 *
4029
 * @param  [in, out]  prf   Pseudo-random function object.
4030
 * @param  [out]      p     Polynomial.
4031
 * @param  [in]       seed  Seed to use when calculating random.
4032
 * @param  [in]       eta1  Size of noise/error integers.
4033
 * @return  0 on success.
4034
 */
4035
static int mlkem_get_noise_eta1_c(MLKEM_PRF_T* prf, sword16* p,
4036
    const byte* seed, byte eta1)
4037
0
{
4038
0
    int ret;
4039
4040
0
    (void)eta1;
4041
4042
0
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
4043
0
    if (eta1 == MLKEM_CBD_ETA3) {
4044
0
        byte rand[ETA3_RAND_SIZE];
4045
4046
        /* Calculate random bytes from seed with PRF. */
4047
0
        ret = mlkem_prf(prf, rand, sizeof(rand), seed);
4048
0
        if (ret == 0) {
4049
            /* Sample for values in range -3..3 from 3 bits of random. */
4050
0
            mlkem_cbd_eta3(p, rand);
4051
0
         }
4052
        /* rand holds secret noise. */
4053
0
        ForceZero(rand, sizeof(rand));
4054
0
    }
4055
0
    else
4056
0
#endif
4057
0
    {
4058
0
        byte rand[ETA2_RAND_SIZE];
4059
4060
        /* Calculate random bytes from seed with PRF. */
4061
0
        ret = mlkem_prf(prf, rand, sizeof(rand), seed);
4062
0
        if (ret == 0) {
4063
            /* Sample for values in range -2..2 from 2 bits of random. */
4064
0
            mlkem_cbd_eta2(p, rand);
4065
0
        }
4066
        /* rand holds secret noise. */
4067
0
        ForceZero(rand, sizeof(rand));
4068
0
    }
4069
4070
0
    return ret;
4071
0
}
4072
4073
/* Get noise/error by calculating random bytes and sampling to a binomial
4074
 * distribution. Values -2..2
4075
 *
4076
 * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE,m,r)
4077
 *   ...
4078
 *  14:     e1[i] <- SamplePolyCBD_eta_2(PRF_eta_2(r, N))
4079
 *   ...
4080
 *  17:     e2 <- SamplePolyCBD_eta_2(PRF_eta_2(r, N))
4081
 *   ...
4082
 *
4083
 * @param  [in, out]  prf   Pseudo-random function object.
4084
 * @param  [out]      p     Polynomial.
4085
 * @param  [in]       seed  Seed to use when calculating random.
4086
 * @return  0 on success.
4087
 */
4088
static int mlkem_get_noise_eta2_c(MLKEM_PRF_T* prf, sword16* p,
4089
    const byte* seed)
4090
0
{
4091
0
    int ret;
4092
0
    byte rand[ETA2_RAND_SIZE];
4093
4094
    /* Calculate random bytes from seed with PRF. */
4095
0
    ret = mlkem_prf(prf, rand, sizeof(rand), seed);
4096
0
    if (ret == 0) {
4097
0
        mlkem_cbd_eta2(p, rand);
4098
0
    }
4099
4100
    /* rand holds secret noise. */
4101
0
    ForceZero(rand, sizeof(rand));
4102
0
    return ret;
4103
0
}
4104
4105
#endif
4106
4107
#if defined(USE_INTEL_SPEEDUP) && !defined(WC_SHA3_NO_ASM)
4108
#define PRF_RAND_SZ   (2 * SHA3_256_BYTES)
4109
4110
#if defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768) || \
4111
    defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
4112
/* Get the noise/error by calculating random bytes.
4113
 *
4114
 * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE,m,r)
4115
 *   ...
4116
 *  14:     e1[i] <- SamplePolyCBD_eta_2(PRF_eta_2(r, N))
4117
 *   ...
4118
 *  17:     e2 <- SamplePolyCBD_eta_2(PRF_eta_2(r, N))
4119
 *   ...
4120
 *
4121
 * @param  [out]  rand  Random number byte array.
4122
 * @param  [in]   seed  Seed to generate random from.
4123
 * @param  [in]   o     Offset of seed count.
4124
 */
4125
static void mlkem_get_noise_x4_eta2_avx2(byte* rand, byte* seed, byte o)
4126
{
4127
    int i;
4128
    word64 state[25 * 4];
4129
4130
    for (i = 0; i < 4; i++) {
4131
        state[4*4 + i] = (word32)(0x1f00 + i + o);
4132
    }
4133
4134
    sha3_256_blocksx4_seed_avx2(state, seed);
4135
    mlkem_redistribute_16_rand_avx2(state, rand + 0 * ETA2_RAND_SIZE,
4136
        rand + 1 * ETA2_RAND_SIZE, rand + 2 * ETA2_RAND_SIZE,
4137
        rand + 3 * ETA2_RAND_SIZE);
4138
4139
    /* state is secret-seeded; caller zeroizes rand. */
4140
    ForceZero(state, sizeof(state));
4141
}
4142
#endif
4143
4144
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512) || \
4145
    defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
4146
/* Get noise/error by calculating random bytes and sampling to a binomial
4147
 * distribution. Values -2..2
4148
 *
4149
 * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE,m,r)
4150
 *   ...
4151
 *  14:     e1[i] <- SamplePolyCBD_eta_2(PRF_eta_2(r, N))
4152
 *   ...
4153
 *  17:     e2 <- SamplePolyCBD_eta_2(PRF_eta_2(r, N))
4154
 *   ...
4155
 *
4156
 * @param  [in, out]  prf   Pseudo-random function object.
4157
 * @param  [out]      p     Polynomial.
4158
 * @param  [in]       seed  Seed to use when calculating random.
4159
 * @return  0 on success.
4160
 */
4161
static int mlkem_get_noise_eta2_avx2(MLKEM_PRF_T* prf, sword16* p,
4162
    const byte* seed)
4163
{
4164
    word64 state[25];
4165
4166
    (void)prf;
4167
4168
    /* Put first WC_ML_KEM_SYM_SZ bytes of key into blank state. */
4169
    readUnalignedWords64(state, seed, WC_ML_KEM_SYM_SZ / sizeof(word64));
4170
    /* Last byte in with end of content marker. */
4171
    state[WC_ML_KEM_SYM_SZ / 8] = 0x1f00 | seed[WC_ML_KEM_SYM_SZ];
4172
    /* Set rest of state to 0. */
4173
    XMEMSET(state + WC_ML_KEM_SYM_SZ / 8 + 1, 0,
4174
        (25 - WC_ML_KEM_SYM_SZ / 8 - 1) * sizeof(word64));
4175
    /* ... except for rate marker. */
4176
    state[WC_SHA3_256_COUNT - 1] = W64LIT(0x8000000000000000);
4177
4178
    /* Perform a block operation on the state for next block of output. */
4179
#ifndef WC_SHA3_NO_ASM
4180
    if (IS_INTEL_BMI2(cpuid_flags)) {
4181
        sha3_block_bmi2(state);
4182
    }
4183
    else if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
4184
        sha3_block_avx2(state);
4185
        RESTORE_VECTOR_REGISTERS();
4186
    }
4187
    else
4188
#endif /* !WC_SHA3_NO_ASM */
4189
    {
4190
        BlockSha3(state);
4191
    }
4192
    mlkem_cbd_eta2_avx2(p, (byte*)state);
4193
4194
    /* state holds secret noise. */
4195
    ForceZero(state, sizeof(state));
4196
    return 0;
4197
}
4198
#endif
4199
4200
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
4201
/* Get the noise/error by calculating random bytes.
4202
 *
4203
 * FIPS 203, Algorithm 13: K-PKE.KeyGen(d)
4204
 *   ...
4205
 *   9:     s[i] <- SamplePolyCBD_eta_1(PRF_eta_1(sigma, N))
4206
 *   ...
4207
 *  13:     e[i] <- SamplePolyCBD_eta_1(PRF_eta_1(sigma, N))
4208
 *   ...
4209
 * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE,m,r)
4210
 *   ...
4211
 *  10:     y[i] <- SamplePolyCBD_eta_1(PRF_eta_1(r, N))
4212
 *   ...
4213
 *
4214
 * @param  [out]  rand  Random number byte array.
4215
 * @param  [in]   seed  Seed to generate random from.
4216
 */
4217
static void mlkem_get_noise_x4_eta3_avx2(byte* rand, byte* seed)
4218
{
4219
    word64 state[25 * 4];
4220
    int i;
4221
4222
    state[4*4 + 0] = 0x1f00 + 0;
4223
    state[4*4 + 1] = 0x1f00 + 1;
4224
    state[4*4 + 2] = 0x1f00 + 2;
4225
    state[4*4 + 3] = 0x1f00 + 3;
4226
4227
    sha3_256_blocksx4_seed_avx2(state, seed);
4228
    mlkem_redistribute_17_rand_avx2(state, rand + 0 * PRF_RAND_SZ,
4229
        rand + 1 * PRF_RAND_SZ, rand + 2 * PRF_RAND_SZ,
4230
        rand + 3 * PRF_RAND_SZ);
4231
    i = SHA3_256_BYTES;
4232
    sha3_blocksx4_avx2(state);
4233
    mlkem_redistribute_8_rand_avx2(state, rand + i + 0 * PRF_RAND_SZ,
4234
        rand + i + 1 * PRF_RAND_SZ, rand + i + 2 * PRF_RAND_SZ,
4235
        rand + i + 3 * PRF_RAND_SZ);
4236
4237
    /* state is secret-seeded; caller zeroizes rand. */
4238
    ForceZero(state, sizeof(state));
4239
}
4240
4241
/* Get the noise/error by calculating random bytes and sampling to a binomial
4242
 * distribution.
4243
 *
4244
 * @param  [in, out]  prf   Pseudo-random function object.
4245
 * @param  [out]      vec1  First Vector of polynomials.
4246
 * @param  [out]      vec2  Second Vector of polynomials.
4247
 * @param  [out]      poly  Polynomial.
4248
 * @param  [in, out]  seed  Seed to use when calculating random.
4249
 * @return  0 on success.
4250
 * @return  MEMORY_E when dynamic memory allocation fails. Only possible when
4251
 *          WOLFSSL_SMALL_STACK is defined.
4252
 */
4253
static int mlkem_get_noise_k2_avx2(MLKEM_PRF_T* prf, sword16* vec1,
4254
    sword16* vec2, sword16* poly, byte* seed)
4255
{
4256
    int ret = 0;
4257
    WC_DECLARE_VAR(rand, byte, 4 * PRF_RAND_SZ, 0);
4258
4259
    WC_ALLOC_VAR_EX(rand, byte, 4 * PRF_RAND_SZ, NULL, DYNAMIC_TYPE_TMP_BUFFER,
4260
        return MEMORY_E);
4261
4262
    mlkem_get_noise_x4_eta3_avx2(rand, seed);
4263
    mlkem_cbd_eta3_avx2(vec1          , rand + 0 * PRF_RAND_SZ);
4264
    mlkem_cbd_eta3_avx2(vec1 + MLKEM_N, rand + 1 * PRF_RAND_SZ);
4265
    if (poly == NULL) {
4266
        mlkem_cbd_eta3_avx2(vec2          , rand + 2 * PRF_RAND_SZ);
4267
        mlkem_cbd_eta3_avx2(vec2 + MLKEM_N, rand + 3 * PRF_RAND_SZ);
4268
    }
4269
    else {
4270
        mlkem_cbd_eta2_avx2(vec2          , rand + 2 * PRF_RAND_SZ);
4271
        mlkem_cbd_eta2_avx2(vec2 + MLKEM_N, rand + 3 * PRF_RAND_SZ);
4272
4273
        seed[WC_ML_KEM_SYM_SZ] = 4;
4274
        ret = mlkem_get_noise_eta2_avx2(prf, poly, seed);
4275
    }
4276
4277
    /* rand holds secret noise. */
4278
    ForceZero(rand, 4 * PRF_RAND_SZ);
4279
    WC_FREE_VAR_EX(rand, NULL, DYNAMIC_TYPE_TMP_BUFFER);
4280
4281
    return ret;
4282
}
4283
#endif
4284
4285
#if defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768)
4286
/* Get the noise/error by calculating random bytes and sampling to a binomial
4287
 * distribution.
4288
 *
4289
 * @param  [out]      vec1  First Vector of polynomials.
4290
 * @param  [out]      vec2  Second Vector of polynomials.
4291
 * @param  [out]      poly  Polynomial.
4292
 * @param  [in]       seed  Seed to use when calculating random.
4293
 * @return  0 on success.
4294
 */
4295
static int mlkem_get_noise_k3_avx2(sword16* vec1, sword16* vec2, sword16* poly,
4296
    byte* seed)
4297
{
4298
    byte rand[4 * ETA2_RAND_SIZE];
4299
4300
    mlkem_get_noise_x4_eta2_avx2(rand, seed, 0);
4301
    mlkem_cbd_eta2_avx2(vec1              , rand + 0 * ETA2_RAND_SIZE);
4302
    mlkem_cbd_eta2_avx2(vec1 + 1 * MLKEM_N, rand + 1 * ETA2_RAND_SIZE);
4303
    mlkem_cbd_eta2_avx2(vec1 + 2 * MLKEM_N, rand + 2 * ETA2_RAND_SIZE);
4304
    mlkem_cbd_eta2_avx2(vec2              , rand + 3 * ETA2_RAND_SIZE);
4305
    mlkem_get_noise_x4_eta2_avx2(rand, seed, 4);
4306
    mlkem_cbd_eta2_avx2(vec2 + 1 * MLKEM_N, rand + 0 * ETA2_RAND_SIZE);
4307
    mlkem_cbd_eta2_avx2(vec2 + 2 * MLKEM_N, rand + 1 * ETA2_RAND_SIZE);
4308
    if (poly != NULL) {
4309
        mlkem_cbd_eta2_avx2(poly, rand + 2 * ETA2_RAND_SIZE);
4310
    }
4311
4312
    /* rand holds secret noise. */
4313
    ForceZero(rand, sizeof(rand));
4314
    return 0;
4315
}
4316
#endif
4317
4318
#if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
4319
/* Get the noise/error by calculating random bytes and sampling to a binomial
4320
 * distribution.
4321
 *
4322
 * @param  [in, out]  prf   Pseudo-random function object.
4323
 * @param  [out]      vec1  First Vector of polynomials.
4324
 * @param  [out]      vec2  Second Vector of polynomials.
4325
 * @param  [out]      poly  Polynomial.
4326
 * @param  [in, out]  seed  Seed to use when calculating random.
4327
 * @return  0 on success.
4328
 */
4329
static int mlkem_get_noise_k4_avx2(MLKEM_PRF_T* prf, sword16* vec1,
4330
    sword16* vec2, sword16* poly, byte* seed)
4331
{
4332
    int ret = 0;
4333
    byte rand[4 * ETA2_RAND_SIZE];
4334
4335
    (void)prf;
4336
4337
    mlkem_get_noise_x4_eta2_avx2(rand, seed, 0);
4338
    mlkem_cbd_eta2_avx2(vec1              , rand + 0 * ETA2_RAND_SIZE);
4339
    mlkem_cbd_eta2_avx2(vec1 + 1 * MLKEM_N, rand + 1 * ETA2_RAND_SIZE);
4340
    mlkem_cbd_eta2_avx2(vec1 + 2 * MLKEM_N, rand + 2 * ETA2_RAND_SIZE);
4341
    mlkem_cbd_eta2_avx2(vec1 + 3 * MLKEM_N, rand + 3 * ETA2_RAND_SIZE);
4342
    mlkem_get_noise_x4_eta2_avx2(rand, seed, 4);
4343
    mlkem_cbd_eta2_avx2(vec2              , rand + 0 * ETA2_RAND_SIZE);
4344
    mlkem_cbd_eta2_avx2(vec2 + 1 * MLKEM_N, rand + 1 * ETA2_RAND_SIZE);
4345
    mlkem_cbd_eta2_avx2(vec2 + 2 * MLKEM_N, rand + 2 * ETA2_RAND_SIZE);
4346
    mlkem_cbd_eta2_avx2(vec2 + 3 * MLKEM_N, rand + 3 * ETA2_RAND_SIZE);
4347
    if (poly != NULL) {
4348
        seed[WC_ML_KEM_SYM_SZ] = 8;
4349
        ret = mlkem_get_noise_eta2_avx2(prf, poly, seed);
4350
    }
4351
4352
    /* rand holds secret noise. */
4353
    ForceZero(rand, sizeof(rand));
4354
    return ret;
4355
}
4356
#endif
4357
#endif /* USE_INTEL_SPEEDUP */
4358
4359
#if defined(__aarch64__) && defined(WOLFSSL_ARMASM)
4360
4361
#define PRF_RAND_SZ   (2 * SHA3_256_BYTES)
4362
4363
/* Get the noise/error by calculating random bytes.
4364
 *
4365
 * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE,m,r)
4366
 *   ...
4367
 *  14:     e1[i] <- SamplePolyCBD_eta_2(PRF_eta_2(r, N))
4368
 *   ...
4369
 *  17:     e2 <- SamplePolyCBD_eta_2(PRF_eta_2(r, N))
4370
 *   ...
4371
 *
4372
 * @param  [out]  rand  Random number byte array.
4373
 * @param  [in]   seed  Seed to generate random from.
4374
 * @param  [in]   o     Offset of seed count.
4375
 */
4376
static void mlkem_get_noise_x3_eta2_aarch64(byte* rand, byte* seed, byte o)
4377
{
4378
    word64* state = (word64*)rand;
4379
4380
    state[0*25 + 4] = 0x1f00 + 0 + o;
4381
    state[1*25 + 4] = 0x1f00 + 1 + o;
4382
    state[2*25 + 4] = 0x1f00 + 2 + o;
4383
4384
    mlkem_shake256_blocksx3_seed_neon(state, seed);
4385
}
4386
4387
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
4388
/* Get the noise/error by calculating random bytes.
4389
 *
4390
 * FIPS 203, Algorithm 13: K-PKE.KeyGen(d)
4391
 *   ...
4392
 *   9:     s[i] <- SamplePolyCBD_eta_1(PRF_eta_1(sigma, N))
4393
 *   ...
4394
 *  13:     e[i] <- SamplePolyCBD_eta_1(PRF_eta_1(sigma, N))
4395
 *   ...
4396
 * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE,m,r)
4397
 *   ...
4398
 *  10:     y[i] <- SamplePolyCBD_eta_1(PRF_eta_1(r, N))
4399
 *   ...
4400
 *
4401
 * @param  [out]  rand  Random number byte array.
4402
 * @param  [in]   seed  Seed to generate random from.
4403
 * @param  [in]   o     Offset of seed count.
4404
 */
4405
static void mlkem_get_noise_x3_eta3_aarch64(byte* rand, byte* seed, byte o)
4406
{
4407
    word64 state[3 * 25];
4408
4409
    state[0*25 + 4] = 0x1f00 + 0 + o;
4410
    state[1*25 + 4] = 0x1f00 + 1 + o;
4411
    state[2*25 + 4] = 0x1f00 + 2 + o;
4412
4413
    mlkem_shake256_blocksx3_seed_neon(state, seed);
4414
    XMEMCPY(rand + 0 * ETA3_RAND_SIZE, state + 0*25, SHA3_256_BYTES);
4415
    XMEMCPY(rand + 1 * ETA3_RAND_SIZE, state + 1*25, SHA3_256_BYTES);
4416
    XMEMCPY(rand + 2 * ETA3_RAND_SIZE, state + 2*25, SHA3_256_BYTES);
4417
    mlkem_sha3_blocksx3_neon(state);
4418
    rand += SHA3_256_BYTES;
4419
    XMEMCPY(rand + 0 * ETA3_RAND_SIZE, state + 0*25,
4420
        ETA3_RAND_SIZE - SHA3_256_BYTES);
4421
    XMEMCPY(rand + 1 * ETA3_RAND_SIZE, state + 1*25,
4422
        ETA3_RAND_SIZE - SHA3_256_BYTES);
4423
    XMEMCPY(rand + 2 * ETA3_RAND_SIZE, state + 2*25,
4424
        ETA3_RAND_SIZE - SHA3_256_BYTES);
4425
4426
    /* state is secret-seeded; caller zeroizes rand. */
4427
    ForceZero(state, sizeof(state));
4428
}
4429
4430
/* Get the noise/error by calculating random bytes.
4431
 *
4432
 * FIPS 203, Algorithm 13: K-PKE.KeyGen(d)
4433
 *   ...
4434
 *  13:     e[i] <- SamplePolyCBD_eta_1(PRF_eta_1(sigma, N))
4435
 *   ...
4436
 *
4437
 * @param  [out]  rand  Random number byte array.
4438
 * @param  [in]   seed  Seed to generate random from.
4439
 * @param  [in]   o     Offset of seed count.
4440
 */
4441
static void mlkem_get_noise_eta3_aarch64(byte* rand, byte* seed, byte o)
4442
{
4443
    word64 state[25];
4444
4445
    state[0] = ((word64*)seed)[0];
4446
    state[1] = ((word64*)seed)[1];
4447
    state[2] = ((word64*)seed)[2];
4448
    state[3] = ((word64*)seed)[3];
4449
    state[4] = 0x1f00 + o;
4450
    XMEMSET(state + 5, 0, sizeof(*state) * (25 - 5));
4451
    state[16] = W64LIT(0x8000000000000000);
4452
    BlockSha3(state);
4453
    XMEMCPY(rand                 , state, SHA3_256_BYTES);
4454
    BlockSha3(state);
4455
    XMEMCPY(rand + SHA3_256_BYTES, state, ETA3_RAND_SIZE - SHA3_256_BYTES);
4456
4457
    /* state is secret-seeded; caller zeroizes rand. */
4458
    ForceZero(state, sizeof(state));
4459
}
4460
4461
/* Get the noise/error by calculating random bytes and sampling to a binomial
4462
 * distribution.
4463
 *
4464
 * @param  [out]      vec1  First Vector of polynomials.
4465
 * @param  [out]      vec2  Second Vector of polynomials.
4466
 * @param  [out]      poly  Polynomial.
4467
 * @param  [in]       seed  Seed to use when calculating random.
4468
 * @return  0 on success.
4469
 */
4470
static int mlkem_get_noise_k2_aarch64(sword16* vec1, sword16* vec2,
4471
    sword16* poly, byte* seed)
4472
{
4473
    int ret = 0;
4474
    byte rand[3 * 25 * 8];
4475
4476
    mlkem_get_noise_x3_eta3_aarch64(rand, seed, 0);
4477
    mlkem_cbd_eta3(vec1          , rand + 0 * ETA3_RAND_SIZE);
4478
    mlkem_cbd_eta3(vec1 + MLKEM_N, rand + 1 * ETA3_RAND_SIZE);
4479
    if (poly == NULL) {
4480
        mlkem_cbd_eta3(vec2          , rand + 2 * ETA3_RAND_SIZE);
4481
        mlkem_get_noise_eta3_aarch64(rand, seed, 3);
4482
        mlkem_cbd_eta3(vec2 + MLKEM_N, rand                     );
4483
    }
4484
    else {
4485
        mlkem_get_noise_x3_eta2_aarch64(rand, seed, 2);
4486
        mlkem_cbd_eta2(vec2          , rand + 0 * 25 * 8);
4487
        mlkem_cbd_eta2(vec2 + MLKEM_N, rand + 1 * 25 * 8);
4488
        mlkem_cbd_eta2(poly          , rand + 2 * 25 * 8);
4489
    }
4490
4491
    /* rand holds secret noise. */
4492
    ForceZero(rand, sizeof(rand));
4493
    return ret;
4494
}
4495
#endif
4496
4497
#if defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768)
4498
/* Get the noise/error by calculating random bytes.
4499
 *
4500
 * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE,m,r)
4501
 *   ...
4502
 *  14:     e1[i] <- SamplePolyCBD_eta_2(PRF_eta_2(r, N))
4503
 *   ...
4504
 *  17:     e2 <- SamplePolyCBD_eta_2(PRF_eta_2(r, N))
4505
 *   ...
4506
 *
4507
 * @param  [out]  rand  Random number byte array.
4508
 * @param  [in]   seed  Seed to generate random from.
4509
 * @param  [in]   o     Offset of seed count.
4510
 */
4511
static void mlkem_get_noise_eta2_aarch64(byte* rand, byte* seed, byte o)
4512
{
4513
    word64* state = (word64*)rand;
4514
4515
    state[0] = ((word64*)seed)[0];
4516
    state[1] = ((word64*)seed)[1];
4517
    state[2] = ((word64*)seed)[2];
4518
    state[3] = ((word64*)seed)[3];
4519
    /* Transposed value same as not. */
4520
    state[4] = 0x1f00 + o;
4521
    XMEMSET(state + 5, 0, sizeof(*state) * (25 - 5));
4522
    state[16] = W64LIT(0x8000000000000000);
4523
    BlockSha3(state);
4524
}
4525
4526
/* Get the noise/error by calculating random bytes and sampling to a binomial
4527
 * distribution.
4528
 *
4529
 * @param  [out]      vec1  First Vector of polynomials.
4530
 * @param  [out]      vec2  Second Vector of polynomials.
4531
 * @param  [out]      poly  Polynomial.
4532
 * @param  [in]       seed  Seed to use when calculating random.
4533
 * @return  0 on success.
4534
 */
4535
static int mlkem_get_noise_k3_aarch64(sword16* vec1, sword16* vec2,
4536
     sword16* poly, byte* seed)
4537
{
4538
    byte rand[3 * 25 * 8];
4539
4540
    mlkem_get_noise_x3_eta2_aarch64(rand, seed, 0);
4541
    mlkem_cbd_eta2(vec1              , rand + 0 * 25 * 8);
4542
    mlkem_cbd_eta2(vec1 + 1 * MLKEM_N, rand + 1 * 25 * 8);
4543
    mlkem_cbd_eta2(vec1 + 2 * MLKEM_N, rand + 2 * 25 * 8);
4544
    mlkem_get_noise_x3_eta2_aarch64(rand, seed, 3);
4545
    mlkem_cbd_eta2(vec2              , rand + 0 * 25 * 8);
4546
    mlkem_cbd_eta2(vec2 + 1 * MLKEM_N, rand + 1 * 25 * 8);
4547
    mlkem_cbd_eta2(vec2 + 2 * MLKEM_N, rand + 2 * 25 * 8);
4548
    if (poly != NULL) {
4549
        mlkem_get_noise_eta2_aarch64(rand, seed, 6);
4550
        mlkem_cbd_eta2(poly              , rand + 0 * 25 * 8);
4551
    }
4552
4553
    /* rand holds secret noise. */
4554
    ForceZero(rand, sizeof(rand));
4555
    return 0;
4556
}
4557
#endif
4558
4559
#if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
4560
/* Get the noise/error by calculating random bytes and sampling to a binomial
4561
 * distribution.
4562
 *
4563
 * @param  [out]      vec1  First Vector of polynomials.
4564
 * @param  [out]      vec2  Second Vector of polynomials.
4565
 * @param  [out]      poly  Polynomial.
4566
 * @param  [in]       seed  Seed to use when calculating random.
4567
 * @return  0 on success.
4568
 */
4569
static int mlkem_get_noise_k4_aarch64(sword16* vec1, sword16* vec2,
4570
    sword16* poly, byte* seed)
4571
{
4572
    int ret = 0;
4573
    byte rand[3 * 25 * 8];
4574
4575
    mlkem_get_noise_x3_eta2_aarch64(rand, seed, 0);
4576
    mlkem_cbd_eta2(vec1              , rand + 0 * 25 * 8);
4577
    mlkem_cbd_eta2(vec1 + 1 * MLKEM_N, rand + 1 * 25 * 8);
4578
    mlkem_cbd_eta2(vec1 + 2 * MLKEM_N, rand + 2 * 25 * 8);
4579
    mlkem_get_noise_x3_eta2_aarch64(rand, seed, 3);
4580
    mlkem_cbd_eta2(vec1 + 3 * MLKEM_N, rand + 0 * 25 * 8);
4581
    mlkem_cbd_eta2(vec2              , rand + 1 * 25 * 8);
4582
    mlkem_cbd_eta2(vec2 + 1 * MLKEM_N, rand + 2 * 25 * 8);
4583
    mlkem_get_noise_x3_eta2_aarch64(rand, seed, 6);
4584
    mlkem_cbd_eta2(vec2 + 2 * MLKEM_N, rand + 0 * 25 * 8);
4585
    mlkem_cbd_eta2(vec2 + 3 * MLKEM_N, rand + 1 * 25 * 8);
4586
    if (poly != NULL) {
4587
        mlkem_cbd_eta2(poly,               rand + 2 * 25 * 8);
4588
    }
4589
4590
    /* rand holds secret noise. */
4591
    ForceZero(rand, sizeof(rand));
4592
    return ret;
4593
}
4594
#endif
4595
#endif /* __aarch64__ && WOLFSSL_ARMASM */
4596
4597
#if !(defined(__aarch64__) && defined(WOLFSSL_ARMASM))
4598
4599
/* Get the noise/error by calculating random bytes and sampling to a binomial
4600
 * distribution.
4601
 *
4602
 * @param  [in, out]  prf   Pseudo-random function object.
4603
 * @param  [in]       k     Number of polynomials in vector.
4604
 * @param  [out]      vec1  First Vector of polynomials.
4605
 * @param  [in]       eta1  Size of noise/error integers with first vector.
4606
 * @param  [out]      vec2  Second Vector of polynomials.
4607
 * @param  [in]       eta2  Size of noise/error integers with second vector.
4608
 * @param  [out]      poly  Polynomial.
4609
 * @param  [in, out]  seed  Seed to use when calculating random.
4610
 * @return  0 on success.
4611
 */
4612
static int mlkem_get_noise_c(MLKEM_PRF_T* prf, int k, sword16* vec1, int eta1,
4613
    sword16* vec2, int eta2, sword16* poly, byte* seed)
4614
0
{
4615
0
    int ret = 0;
4616
0
    int i;
4617
4618
    /* First noise generation has a seed with 0x00 appended. */
4619
0
    seed[WC_ML_KEM_SYM_SZ] = 0;
4620
    /* Generate noise as private key. */
4621
0
    for (i = 0; (ret == 0) && (i < k); i++) {
4622
        /* Generate noise for each dimension of vector. */
4623
0
        ret = mlkem_get_noise_eta1_c(prf, vec1 + i * MLKEM_N, seed, (byte)eta1);
4624
        /* Increment value of appended byte. */
4625
0
        seed[WC_ML_KEM_SYM_SZ]++;
4626
0
    }
4627
0
    if ((ret == 0) && (vec2 != NULL)) {
4628
        /* Generate noise for error. */
4629
0
        for (i = 0; (ret == 0) && (i < k); i++) {
4630
            /* Generate noise for each dimension of vector. */
4631
0
            ret = mlkem_get_noise_eta1_c(prf, vec2 + i * MLKEM_N, seed,
4632
0
                (byte)eta2);
4633
            /* Increment value of appended byte. */
4634
0
            seed[WC_ML_KEM_SYM_SZ]++;
4635
0
        }
4636
0
    }
4637
0
    else {
4638
0
        seed[WC_ML_KEM_SYM_SZ] = (byte)(2 * k);
4639
0
    }
4640
0
    if ((ret == 0) && (poly != NULL)) {
4641
        /* Generating random error polynomial. */
4642
0
        ret = mlkem_get_noise_eta2_c(prf, poly, seed);
4643
0
    }
4644
4645
0
    return ret;
4646
0
}
4647
4648
#endif /* !(__aarch64__ && WOLFSSL_ARMASM) */
4649
4650
/* Get the noise/error by calculating random bytes and sampling to a binomial
4651
 * distribution.
4652
 *
4653
 * @param  [in, out]  prf   Pseudo-random function object.
4654
 * @param  [in]       k     Number of polynomials in vector.
4655
 * @param  [out]      vec1  First Vector of polynomials.
4656
 * @param  [out]      vec2  Second Vector of polynomials.
4657
 * @param  [out]      poly  Polynomial.
4658
 * @param  [in, out]  seed  Seed to use when calculating random.
4659
 * @return  0 on success.
4660
 */
4661
int mlkem_get_noise(MLKEM_PRF_T* prf, int k, sword16* vec1, sword16* vec2,
4662
    sword16* poly, byte* seed)
4663
0
{
4664
0
    int ret;
4665
4666
0
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
4667
0
    if (k == WC_ML_KEM_512_K) {
4668
#if defined(WOLFSSL_ARMASM) && defined(__aarch64__)
4669
        ret = mlkem_get_noise_k2_aarch64(vec1, vec2, poly, seed);
4670
#else
4671
    #if defined(USE_INTEL_SPEEDUP) && !defined(WC_SHA3_NO_ASM)
4672
        if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
4673
            ret = mlkem_get_noise_k2_avx2(prf, vec1, vec2, poly, seed);
4674
            RESTORE_VECTOR_REGISTERS();
4675
        }
4676
        else
4677
    #endif
4678
0
        if (poly == NULL) {
4679
0
            ret = mlkem_get_noise_c(prf, k, vec1, MLKEM_CBD_ETA3, vec2,
4680
0
                MLKEM_CBD_ETA3, NULL, seed);
4681
0
        }
4682
0
        else {
4683
0
            ret = mlkem_get_noise_c(prf, k, vec1, MLKEM_CBD_ETA3, vec2,
4684
0
                MLKEM_CBD_ETA2, poly, seed);
4685
0
        }
4686
0
#endif
4687
0
    }
4688
0
    else
4689
0
#endif
4690
0
#if defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768)
4691
0
    if (k == WC_ML_KEM_768_K) {
4692
#if defined(WOLFSSL_ARMASM) && defined(__aarch64__)
4693
        ret = mlkem_get_noise_k3_aarch64(vec1, vec2, poly, seed);
4694
#else
4695
    #if defined(USE_INTEL_SPEEDUP) && !defined(WC_SHA3_NO_ASM)
4696
        if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
4697
            ret = mlkem_get_noise_k3_avx2(vec1, vec2, poly, seed);
4698
            RESTORE_VECTOR_REGISTERS();
4699
        }
4700
        else
4701
    #endif
4702
0
        {
4703
0
            ret = mlkem_get_noise_c(prf, k, vec1, MLKEM_CBD_ETA2, vec2,
4704
0
                MLKEM_CBD_ETA2, poly, seed);
4705
0
        }
4706
0
#endif
4707
0
    }
4708
0
    else
4709
0
#endif
4710
0
#if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
4711
0
    if (k == WC_ML_KEM_1024_K) {
4712
#if defined(WOLFSSL_ARMASM) && defined(__aarch64__)
4713
        ret = mlkem_get_noise_k4_aarch64(vec1, vec2, poly, seed);
4714
#else
4715
    #if defined(USE_INTEL_SPEEDUP) && !defined(WC_SHA3_NO_ASM)
4716
        if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
4717
            ret = mlkem_get_noise_k4_avx2(prf, vec1, vec2, poly, seed);
4718
            RESTORE_VECTOR_REGISTERS();
4719
        }
4720
        else
4721
    #endif
4722
0
        {
4723
0
            ret = mlkem_get_noise_c(prf, k, vec1, MLKEM_CBD_ETA2, vec2,
4724
0
                MLKEM_CBD_ETA2, poly, seed);
4725
0
        }
4726
0
#endif
4727
0
    }
4728
0
    else
4729
0
#endif
4730
0
    {
4731
0
        ret = BAD_STATE_E;
4732
0
    }
4733
4734
0
    (void)prf;
4735
4736
0
    return ret;
4737
0
}
4738
4739
#if defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) || \
4740
    defined(WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM)
4741
/* Get the noise/error by calculating random bytes and sampling to a binomial
4742
 * distribution.
4743
 *
4744
 * @param  [in, out]  prf   Pseudo-random function object.
4745
 * @param  [in]       k     Number of polynomials in vector.
4746
 * @param  [out]      vec2  Second Vector of polynomials.
4747
 * @param  [in, out]  seed  Seed to use when calculating random.
4748
 * @param  [in]       i     Index of vector to generate.
4749
 * @param  [in]       make  Indicates generation is for making a key.
4750
 * @return  0 on success.
4751
 */
4752
static int mlkem_get_noise_i(MLKEM_PRF_T* prf, int k, sword16* vec2,
4753
    byte* seed, int i, int make)
4754
{
4755
    int ret;
4756
4757
    /* Initialize the PRF (generating matrix A leaves it in uninitialized
4758
     * state). */
4759
    mlkem_prf_init(prf);
4760
4761
    /* Set index of polynomial of second vector into seed. */
4762
    seed[WC_ML_KEM_SYM_SZ] = (byte)(k + i);
4763
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
4764
    if ((k == WC_ML_KEM_512_K) && make) {
4765
        ret = mlkem_get_noise_eta1_c(prf, vec2, seed, MLKEM_CBD_ETA3);
4766
    }
4767
    else
4768
#endif
4769
    {
4770
        ret = mlkem_get_noise_eta1_c(prf, vec2, seed, MLKEM_CBD_ETA2);
4771
    }
4772
4773
    (void)make;
4774
    return ret;
4775
}
4776
#endif
4777
4778
/******************************************************************************/
4779
4780
#if !(defined(__aarch64__) && defined(WOLFSSL_ARMASM))
4781
/* Compare two byte arrays of equal size.
4782
 *
4783
 * @param [in]  a   First array to compare.
4784
 * @param [in]  b   Second array to compare.
4785
 * @param [in]  sz  Size of arrays in bytes.
4786
 * @return  0 on success.
4787
 * @return  -1 on failure.
4788
 */
4789
static int mlkem_cmp_c(const byte* a, const byte* b, int sz)
4790
0
{
4791
0
    int i;
4792
0
    byte r = 0;
4793
4794
    /* Constant time comparison of the encapsulated message and cipher text. */
4795
0
    for (i = 0; i < sz; i++) {
4796
0
        r |= a[i] ^ b[i];
4797
0
    }
4798
0
    return (int)(0 - ((-(word32)r) >> 31));
4799
0
}
4800
#endif
4801
4802
/* Compare two byte arrays of equal size.
4803
 *
4804
 * @param [in]  a   First array to compare.
4805
 * @param [in]  b   Second array to compare.
4806
 * @param [in]  sz  Size of arrays in bytes.
4807
 * @return  0 on success.
4808
 * @return  -1 on failure.
4809
 */
4810
int mlkem_cmp(const byte* a, const byte* b, int sz)
4811
0
{
4812
#if defined(__aarch64__) && defined(WOLFSSL_ARMASM)
4813
    return mlkem_cmp_neon(a, b, sz);
4814
#else
4815
0
    int fail;
4816
4817
#ifdef USE_INTEL_SPEEDUP
4818
    if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
4819
        fail = mlkem_cmp_avx2(a, b, sz);
4820
        RESTORE_VECTOR_REGISTERS();
4821
    }
4822
    else
4823
#endif
4824
0
    {
4825
0
        fail = mlkem_cmp_c(a, b, sz);
4826
0
    }
4827
4828
0
    return fail;
4829
0
#endif
4830
0
}
4831
4832
/******************************************************************************/
4833
4834
#if !defined(WOLFSSL_ARMASM)
4835
4836
/* Conditional subtraction of q to each coefficient of a polynomial.
4837
 *
4838
 * FIPS 203, Section 4.2.1, Compression and decompression
4839
 *
4840
 * @param  [in, out]  p  Polynomial.
4841
 */
4842
static MLKEM_NOINLINE void mlkem_csubq_c(sword16* p)
4843
0
{
4844
0
    unsigned int i;
4845
4846
0
    for (i = 0; i < MLKEM_N; ++i) {
4847
0
        sword16 t = (sword16)(p[i] - MLKEM_Q);
4848
        /* When top bit set, -ve number - need to add q back. */
4849
0
        p[i] = (sword16)(((word16)(-((word16)t >> 15)) & MLKEM_Q) +
4850
0
            (word16)t);
4851
0
    }
4852
0
}
4853
4854
#elif defined(__aarch64__)
4855
4856
/* Conditional subtraction of q to each coefficient of a polynomial.
4857
 *
4858
 * FIPS 203, Section 4.2.1, Compression and decompression
4859
 *
4860
 * @param  [in, out]  p  Polynomial.
4861
 */
4862
#define mlkem_csubq_c   mlkem_csubq_neon
4863
4864
#elif defined(WOLFSSL_ARMASM_THUMB2)
4865
4866
/* Conditional subtraction of q to each coefficient of a polynomial.
4867
 *
4868
 * FIPS 203, Section 4.2.1, Compression and decompression
4869
 *
4870
 * @param  [in, out]  p  Polynomial.
4871
 */
4872
#define mlkem_csubq_c   mlkem_thumb2_csubq
4873
4874
#else
4875
4876
/* Conditional subtraction of q to each coefficient of a polynomial.
4877
 *
4878
 * FIPS 203, Section 4.2.1, Compression and decompression
4879
 *
4880
 * @param  [in, out]  p  Polynomial.
4881
 */
4882
#define mlkem_csubq_c   mlkem_arm32_csubq
4883
4884
#endif
4885
4886
/******************************************************************************/
4887
4888
#if defined(CONV_WITH_DIV) || !defined(WORD64_AVAILABLE)
4889
4890
/* Compress value.
4891
 *
4892
 * Uses div operator that may be slow and not constant-time.
4893
 *
4894
 * FIPS 203, Section 4.2.1, Compression and decompression
4895
 *
4896
 * @param  [in]  v  Vector of polynomials.
4897
 * @param  [in]  i  Index of polynomial in vector.
4898
 * @param  [in]  j  Index into polynomial.
4899
 * @param  [in]  k  Offset from indices.
4900
 * @param  [in]  s  Shift amount to apply to value being compressed.
4901
 * @param  [in]  m  Mask to apply get the required number of bits.
4902
 * @return  Compressed value.
4903
 */
4904
#define TO_COMP_WORD_VEC(v, i, j, k, s, m) \
4905
    ((((word32)v[i * MLKEM_N + j + k] << s) + MLKEM_Q_HALF) / MLKEM_Q) & m
4906
4907
/* Compress value to 10 bits.
4908
 *
4909
 * Uses div operator that may be slow and not constant-time.
4910
 *
4911
 * FIPS 203, Section 4.2.1, Compression and decompression
4912
 *
4913
 * @param  [in]  v  Vector of polynomials.
4914
 * @param  [in]  i  Index of polynomial in vector.
4915
 * @param  [in]  j  Index into polynomial.
4916
 * @param  [in]  k  Offset from indices.
4917
 * @return  Compressed value.
4918
 */
4919
#define TO_COMP_WORD_10(v, i, j, k) \
4920
    TO_COMP_WORD_VEC(v, i, j, k, 10, 0x3ff)
4921
4922
/* Compress value to 11 bits.
4923
 *
4924
 * Uses div operator that may be slow and not constant-time.
4925
 *
4926
 * FIPS 203, Section 4.2.1, Compression and decompression
4927
 *
4928
 * @param  [in]  v  Vector of polynomials.
4929
 * @param  [in]  i  Index of polynomial in vector.
4930
 * @param  [in]  j  Index into polynomial.
4931
 * @param  [in]  k  Offset from indices.
4932
 * @return  Compressed value.
4933
 */
4934
#define TO_COMP_WORD_11(v, i, j, k) \
4935
    TO_COMP_WORD_VEC(v, i, j, k, 11, 0x7ff)
4936
4937
#else
4938
4939
/* Multiplier that does div q.
4940
 * ((1 << 53) + MLKEM_Q_HALF) / MLKEM_Q
4941
 */
4942
0
#define MLKEM_V53         0x275f6ed0176UL
4943
/* Multiplier times half of q.
4944
 * MLKEM_V53 * (MLKEM_Q_HALF + 1)
4945
 */
4946
0
#define MLKEM_V53_HALF    0x10013afb768076UL
4947
4948
/* Multiplier that does div q.
4949
 * ((1 << 54) + MLKEM_Q_HALF) / MLKEM_Q
4950
 */
4951
0
#define MLKEM_V54         0x4ebedda02ecUL
4952
/* Multiplier times half of q.
4953
 * MLKEM_V54 * (MLKEM_Q_HALF + 1)
4954
 */
4955
0
#define MLKEM_V54_HALF    0x200275f6ed00ecUL
4956
4957
/* Compress value to 10 bits.
4958
 *
4959
 * Uses mul instead of div.
4960
 *
4961
 * FIPS 203, Section 4.2.1, Compression and decompression
4962
 *
4963
 * @param  [in]  v  Vector of polynomials.
4964
 * @param  [in]  i  Index of polynomial in vector.
4965
 * @param  [in]  j  Index into polynomial.
4966
 * @param  [in]  k  Offset from indices.
4967
 * @return  Compressed value.
4968
 */
4969
#define TO_COMP_WORD_10(v, i, j, k) \
4970
0
    (sword16)((((MLKEM_V54 << 10) * (word64)(v)[(i) * MLKEM_N + (j) + (k)]) + \
4971
0
               MLKEM_V54_HALF) >> 54)
4972
4973
/* Compress value to 11 bits.
4974
 *
4975
 * Uses mul instead of div.
4976
 * Only works for values in range: 0..3228
4977
 *
4978
 * FIPS 203, Section 4.2.1, Compression and decompression
4979
 *
4980
 * @param  [in]  v  Vector of polynomials.
4981
 * @param  [in]  i  Index of polynomial in vector.
4982
 * @param  [in]  j  Index into polynomial.
4983
 * @param  [in]  k  Offset from indices.
4984
 * @return  Compressed value.
4985
 */
4986
#define TO_COMP_WORD_11(v, i, j, k) \
4987
0
    (sword16)((((MLKEM_V53 << 11) * (word64)(v)[(i) * MLKEM_N + (j) + (k)]) + \
4988
0
               MLKEM_V53_HALF) >> 53)
4989
4990
#endif /* CONV_WITH_DIV */
4991
4992
#if !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \
4993
    !defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
4994
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512) || \
4995
    defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768)
4996
/* Compress the vector of polynomials into a byte array with 10 bits each.
4997
 *
4998
 * FIPS 203, Section 4.2.1, Compression and decompression
4999
 *
5000
 * @param  [out]      r  Array of bytes.
5001
 * @param  [in, out]  v  Vector of polynomials.
5002
 * @param  [in]       k  Number of polynomials in vector.
5003
 */
5004
static void mlkem_vec_compress_10_c(byte* r, sword16* v, unsigned int k)
5005
0
{
5006
0
    unsigned int i;
5007
0
    unsigned int j;
5008
5009
0
    for (i = 0; i < k; i++) {
5010
        /* Reduce each coefficient to mod q. */
5011
0
        mlkem_csubq_c(v + i * MLKEM_N);
5012
        /* All values are now positive. */
5013
0
    }
5014
5015
    /* Each polynomial. */
5016
0
    for (i = 0; i < k; i++) {
5017
#if defined(WOLFSSL_SMALL_STACK) || defined(WOLFSSL_MLKEM_NO_LARGE_CODE) || \
5018
    defined(BIG_ENDIAN_ORDER)
5019
        /* Each 4 polynomial coefficients. */
5020
        for (j = 0; j < MLKEM_N; j += 4) {
5021
        #ifdef WOLFSSL_MLKEM_SMALL
5022
            unsigned int l;
5023
            sword16 t[4];
5024
            /* Compress four polynomial values to 10 bits each. */
5025
            for (l = 0; l < 4; l++) {
5026
                t[l] = TO_COMP_WORD_10(v, i, j, l);
5027
            }
5028
5029
            /* Pack four 10-bit values into byte array. */
5030
            r[ 0] = (t[0] >> 0);
5031
            r[ 1] = (t[0] >> 8) | (t[1] << 2);
5032
            r[ 2] = (t[1] >> 6) | (t[2] << 4);
5033
            r[ 3] = (t[2] >> 4) | (t[3] << 6);
5034
            r[ 4] = (t[3] >> 2);
5035
        #else
5036
            /* Compress four polynomial values to 10 bits each. */
5037
            sword16 t0 = TO_COMP_WORD_10(v, i, j, 0);
5038
            sword16 t1 = TO_COMP_WORD_10(v, i, j, 1);
5039
            sword16 t2 = TO_COMP_WORD_10(v, i, j, 2);
5040
            sword16 t3 = TO_COMP_WORD_10(v, i, j, 3);
5041
5042
            /* Pack four 10-bit values into byte array. */
5043
            r[ 0] = (byte)( t0 >> 0);
5044
            r[ 1] = (byte)((t0 >> 8) | (t1 << 2));
5045
            r[ 2] = (byte)((t1 >> 6) | (t2 << 4));
5046
            r[ 3] = (byte)((t2 >> 4) | (t3 << 6));
5047
            r[ 4] = (byte)( t3 >> 2);
5048
        #endif
5049
5050
            /* Move over set bytes. */
5051
            r += 5;
5052
        }
5053
#else
5054
        /* Each 16 polynomial coefficients. */
5055
0
        for (j = 0; j < MLKEM_N; j += 16) {
5056
            /* Compress four polynomial values to 10 bits each. */
5057
0
            sword16 t0  = TO_COMP_WORD_10(v, i, j, 0);
5058
0
            sword16 t1  = TO_COMP_WORD_10(v, i, j, 1);
5059
0
            sword16 t2  = TO_COMP_WORD_10(v, i, j, 2);
5060
0
            sword16 t3  = TO_COMP_WORD_10(v, i, j, 3);
5061
0
            sword16 t4  = TO_COMP_WORD_10(v, i, j, 4);
5062
0
            sword16 t5  = TO_COMP_WORD_10(v, i, j, 5);
5063
0
            sword16 t6  = TO_COMP_WORD_10(v, i, j, 6);
5064
0
            sword16 t7  = TO_COMP_WORD_10(v, i, j, 7);
5065
0
            sword16 t8  = TO_COMP_WORD_10(v, i, j, 8);
5066
0
            sword16 t9  = TO_COMP_WORD_10(v, i, j, 9);
5067
0
            sword16 t10 = TO_COMP_WORD_10(v, i, j, 10);
5068
0
            sword16 t11 = TO_COMP_WORD_10(v, i, j, 11);
5069
0
            sword16 t12 = TO_COMP_WORD_10(v, i, j, 12);
5070
0
            sword16 t13 = TO_COMP_WORD_10(v, i, j, 13);
5071
0
            sword16 t14 = TO_COMP_WORD_10(v, i, j, 14);
5072
0
            sword16 t15 = TO_COMP_WORD_10(v, i, j, 15);
5073
5074
0
            word32* r32 = (word32*)r;
5075
            /* Pack sixteen 10-bit values into byte array. */
5076
0
            r32[0] =  (word32)t0         | ((word32)t1  << 10) |
5077
0
                     ((word32)t2  << 20) | ((word32)t3  << 30);
5078
0
            r32[1] = ((word32)t3  >>  2) | ((word32)t4  <<  8) |
5079
0
                     ((word32)t5  << 18) | ((word32)t6  << 28);
5080
0
            r32[2] = ((word32)t6  >>  4) | ((word32)t7  <<  6) |
5081
0
                     ((word32)t8  << 16) | ((word32)t9  << 26);
5082
0
            r32[3] = ((word32)t9  >>  6) | ((word32)t10 <<  4) |
5083
0
                     ((word32)t11 << 14) | ((word32)t12 << 24);
5084
0
            r32[4] = ((word32)t12 >>  8) | ((word32)t13 <<  2) |
5085
0
                     ((word32)t14 << 12) | ((word32)t15 << 22);
5086
5087
            /* Move over set bytes. */
5088
0
            r += 20;
5089
0
        }
5090
0
#endif
5091
0
    }
5092
0
}
5093
5094
/* Compress the vector of polynomials into a byte array with 10 bits each.
5095
 *
5096
 * FIPS 203, Section 4.2.1, Compression and decompression
5097
 *
5098
 * @param  [out]      r  Array of bytes.
5099
 * @param  [in, out]  v  Vector of polynomials.
5100
 * @param  [in]       k  Number of polynomials in vector.
5101
 */
5102
void mlkem_vec_compress_10(byte* r, sword16* v, unsigned int k)
5103
0
{
5104
#ifdef USE_INTEL_SPEEDUP
5105
    if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
5106
        mlkem_compress_10_avx2(r, v, (int)k);
5107
        RESTORE_VECTOR_REGISTERS();
5108
    }
5109
    else
5110
#endif
5111
0
    {
5112
0
        mlkem_vec_compress_10_c(r, v, k);
5113
0
    }
5114
0
}
5115
#endif
5116
5117
#if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
5118
/* Compress the vector of polynomials into a byte array with 11 bits each.
5119
 *
5120
 * FIPS 203, Section 4.2.1, Compression and decompression
5121
 *
5122
 * @param  [out]      r  Array of bytes.
5123
 * @param  [in, out]  v  Vector of polynomials.
5124
 */
5125
static void mlkem_vec_compress_11_c(byte* r, sword16* v)
5126
0
{
5127
0
    unsigned int i;
5128
0
    unsigned int j;
5129
#ifdef WOLFSSL_MLKEM_SMALL
5130
    unsigned int k;
5131
#endif
5132
5133
0
    for (i = 0; i < 4; i++) {
5134
        /* Reduce each coefficient to mod q. */
5135
0
        mlkem_csubq_c(v + i * MLKEM_N);
5136
        /* All values are now positive. */
5137
0
    }
5138
5139
    /* Each polynomial. */
5140
0
    for (i = 0; i < 4; i++) {
5141
        /* Each 8 polynomial coefficients. */
5142
0
        for (j = 0; j < MLKEM_N; j += 8) {
5143
        #ifdef WOLFSSL_MLKEM_SMALL
5144
            sword16 t[8];
5145
            /* Compress eight polynomial values to 11 bits each. */
5146
            for (k = 0; k < 8; k++) {
5147
                t[k] = TO_COMP_WORD_11(v, i, j, k);
5148
            }
5149
5150
            /* Pack eight 11-bit values into byte array. */
5151
            r[ 0] = (byte)( t[0] >>  0);
5152
            r[ 1] = (byte)((t[0] >>  8) | (t[1] << 3));
5153
            r[ 2] = (byte)((t[1] >>  5) | (t[2] << 6));
5154
            r[ 3] = (byte)( t[2] >>  2);
5155
            r[ 4] = (byte)((t[2] >> 10) | (t[3] << 1));
5156
            r[ 5] = (byte)((t[3] >>  7) | (t[4] << 4));
5157
            r[ 6] = (byte)((t[4] >>  4) | (t[5] << 7));
5158
            r[ 7] = (byte)( t[5] >>  1);
5159
            r[ 8] = (byte)((t[5] >>  9) | (t[6] << 2));
5160
            r[ 9] = (byte)((t[6] >>  6) | (t[7] << 5));
5161
            r[10] = (byte)( t[7] >>  3);
5162
        #else
5163
            /* Compress eight polynomial values to 11 bits each. */
5164
0
            sword16 t0 = TO_COMP_WORD_11(v, i, j, 0);
5165
0
            sword16 t1 = TO_COMP_WORD_11(v, i, j, 1);
5166
0
            sword16 t2 = TO_COMP_WORD_11(v, i, j, 2);
5167
0
            sword16 t3 = TO_COMP_WORD_11(v, i, j, 3);
5168
0
            sword16 t4 = TO_COMP_WORD_11(v, i, j, 4);
5169
0
            sword16 t5 = TO_COMP_WORD_11(v, i, j, 5);
5170
0
            sword16 t6 = TO_COMP_WORD_11(v, i, j, 6);
5171
0
            sword16 t7 = TO_COMP_WORD_11(v, i, j, 7);
5172
5173
            /* Pack eight 11-bit values into byte array. */
5174
0
            r[ 0] = (byte)( t0 >>  0);
5175
0
            r[ 1] = (byte)((t0 >>  8) | (t1 << 3));
5176
0
            r[ 2] = (byte)((t1 >>  5) | (t2 << 6));
5177
0
            r[ 3] = (byte)( t2 >>  2);
5178
0
            r[ 4] = (byte)((t2 >> 10) | (t3 << 1));
5179
0
            r[ 5] = (byte)((t3 >>  7) | (t4 << 4));
5180
0
            r[ 6] = (byte)((t4 >>  4) | (t5 << 7));
5181
0
            r[ 7] = (byte)( t5 >>  1);
5182
0
            r[ 8] = (byte)((t5 >>  9) | (t6 << 2));
5183
0
            r[ 9] = (byte)((t6 >>  6) | (t7 << 5));
5184
0
            r[10] = (byte)( t7 >>  3);
5185
0
        #endif
5186
5187
            /* Move over set bytes. */
5188
0
            r += 11;
5189
0
        }
5190
0
    }
5191
0
}
5192
5193
/* Compress the vector of polynomials into a byte array with 11 bits each.
5194
 *
5195
 * FIPS 203, Section 4.2.1, Compression and decompression
5196
 *
5197
 * @param  [out]      r  Array of bytes.
5198
 * @param  [in, out]  v  Vector of polynomials.
5199
 */
5200
void mlkem_vec_compress_11(byte* r, sword16* v)
5201
0
{
5202
#ifdef USE_INTEL_SPEEDUP
5203
    if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
5204
        mlkem_compress_11_avx2(r, v, 4);
5205
        RESTORE_VECTOR_REGISTERS();
5206
    }
5207
    else
5208
#endif
5209
0
    {
5210
0
        mlkem_vec_compress_11_c(r, v);
5211
0
    }
5212
0
}
5213
#endif
5214
#endif /* !WOLFSSL_MLKEM_NO_ENCAPSULATE || !WOLFSSL_MLKEM_NO_DECAPSULATE */
5215
5216
#ifndef WOLFSSL_MLKEM_NO_DECAPSULATE
5217
/* Decompress a 10 bit value.
5218
 *
5219
 * FIPS 203, Section 4.2.1, Compression and decompression
5220
 *
5221
 * @param  [out]  v  Vector of polynomials.
5222
 * @param  [in]   i  Index of polynomial in vector.
5223
 * @param  [in]   j  Index into polynomial.
5224
 * @param  [in]   k  Offset from indices.
5225
 * @param  [in]   t  Value to decompress.
5226
 */
5227
#define DECOMP_10(v, i, j, k, t) \
5228
0
    v[(i) * MLKEM_N + 4 * (j) + (k)] = \
5229
0
        (sword16)((((word32)((t) & 0x3ff) * MLKEM_Q) + 512) >> 10)
5230
5231
/* Decompress an 11 bit value.
5232
 *
5233
 * FIPS 203, Section 4.2.1, Compression and decompression
5234
 *
5235
 * @param  [out]  v  Vector of polynomials.
5236
 * @param  [in]   i  Index of polynomial in vector.
5237
 * @param  [in]   j  Index into polynomial.
5238
 * @param  [in]   k  Offset from indices.
5239
 * @param  [in]   t  Value to decompress.
5240
 */
5241
#define DECOMP_11(v, i, j, k, t) \
5242
0
    v[(i) * MLKEM_N + 8 * (j) + (k)] = \
5243
0
        (sword16)((((word32)((t) & 0x7ff) * MLKEM_Q) + 1024) >> 11)
5244
5245
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512) || \
5246
    defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768)
5247
/* Decompress the byte array of packed 10 bits into vector of polynomials.
5248
 *
5249
 * FIPS 203, Section 4.2.1, Compression and decompression
5250
 *
5251
 * @param  [out]  v  Vector of polynomials.
5252
 * @param  [in]   b  Array of bytes.
5253
 * @param  [in]   k  Number of polynomials in vector.
5254
 */
5255
static void mlkem_vec_decompress_10_c(sword16* v, const byte* b, unsigned int k)
5256
0
{
5257
0
    unsigned int i;
5258
0
    unsigned int j;
5259
#ifdef WOLFSSL_MLKEM_SMALL
5260
    unsigned int l;
5261
#endif
5262
5263
    /* Each polynomial. */
5264
0
    for (i = 0; i < k; i++) {
5265
        /* Each 4 polynomial coefficients. */
5266
0
        for (j = 0; j < MLKEM_N / 4; j++) {
5267
        #ifdef WOLFSSL_MLKEM_SMALL
5268
            word16 t[4];
5269
            /* Extract out 4 values of 10 bits each. */
5270
            t[0] = (word16)((b[0] >> 0) | ((word16)b[ 1] << 8));
5271
            t[1] = (word16)((b[1] >> 2) | ((word16)b[ 2] << 6));
5272
            t[2] = (word16)((b[2] >> 4) | ((word16)b[ 3] << 4));
5273
            t[3] = (word16)((b[3] >> 6) | ((word16)b[ 4] << 2));
5274
            b += 5;
5275
5276
            /* Decompress 4 values. */
5277
            for (l = 0; l < 4; l++) {
5278
                DECOMP_10(v, i, j, l, t[l]);
5279
            }
5280
        #else
5281
            /* Extract out 4 values of 10 bits each. */
5282
0
            word16 t0 = (word16)((b[0] >> 0) | ((word16)b[ 1] << 8));
5283
0
            word16 t1 = (word16)((b[1] >> 2) | ((word16)b[ 2] << 6));
5284
0
            word16 t2 = (word16)((b[2] >> 4) | ((word16)b[ 3] << 4));
5285
0
            word16 t3 = (word16)((b[3] >> 6) | ((word16)b[ 4] << 2));
5286
0
            b += 5;
5287
5288
            /* Decompress 4 values. */
5289
0
            DECOMP_10(v, i, j, 0, t0);
5290
0
            DECOMP_10(v, i, j, 1, t1);
5291
0
            DECOMP_10(v, i, j, 2, t2);
5292
0
            DECOMP_10(v, i, j, 3, t3);
5293
0
        #endif
5294
0
        }
5295
0
    }
5296
0
}
5297
5298
/* Decompress the byte array of packed 10 bits into vector of polynomials.
5299
 *
5300
 * FIPS 203, Section 4.2.1, Compression and decompression
5301
 *
5302
 * @param  [out]  v  Vector of polynomials.
5303
 * @param  [in]   b  Array of bytes.
5304
 * @param  [in]   k  Number of polynomials in vector.
5305
 */
5306
void mlkem_vec_decompress_10(sword16* v, const byte* b, unsigned int k)
5307
0
{
5308
#ifdef USE_INTEL_SPEEDUP
5309
    if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
5310
        mlkem_decompress_10_avx2(v, b, (int)k);
5311
        RESTORE_VECTOR_REGISTERS();
5312
    }
5313
    else
5314
#endif
5315
0
    {
5316
0
        mlkem_vec_decompress_10_c(v, b, k);
5317
0
    }
5318
0
}
5319
#endif
5320
#if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
5321
/* Decompress the byte array of packed 11 bits into vector of polynomials.
5322
 *
5323
 * FIPS 203, Section 4.2.1, Compression and decompression
5324
 *
5325
 * @param  [out]  v       Vector of polynomials.
5326
 * @param  [in]   b       Array of bytes.
5327
 */
5328
static void mlkem_vec_decompress_11_c(sword16* v, const byte* b)
5329
0
{
5330
0
    unsigned int i;
5331
0
    unsigned int j;
5332
#ifdef WOLFSSL_MLKEM_SMALL
5333
    unsigned int l;
5334
#endif
5335
5336
    /* Each polynomial. */
5337
0
    for (i = 0; i < 4; i++) {
5338
        /* Each 8 polynomial coefficients. */
5339
0
        for (j = 0; j < MLKEM_N / 8; j++) {
5340
        #ifdef WOLFSSL_MLKEM_SMALL
5341
            word16 t[8];
5342
            /* Extract out 8 values of 11 bits each. */
5343
            t[0] = (word16)((b[0] >> 0) | ((word16)b[ 1] << 8));
5344
            t[1] = (word16)((b[1] >> 3) | ((word16)b[ 2] << 5));
5345
            t[2] = (word16)((b[2] >> 6) | ((word16)b[ 3] << 2) |
5346
                   ((word16)b[4] << 10));
5347
            t[3] = (word16)((b[4] >> 1) | ((word16)b[ 5] << 7));
5348
            t[4] = (word16)((b[5] >> 4) | ((word16)b[ 6] << 4));
5349
            t[5] = (word16)((b[6] >> 7) | ((word16)b[ 7] << 1) |
5350
                   ((word16)b[8] <<  9));
5351
            t[6] = (word16)((b[8] >> 2) | ((word16)b[ 9] << 6));
5352
            t[7] = (word16)((b[9] >> 5) | ((word16)b[10] << 3));
5353
            b += 11;
5354
5355
            /* Decompress 8 values. */
5356
            for (l = 0; l < 8; l++) {
5357
                DECOMP_11(v, i, j, l, t[l]);
5358
            }
5359
        #else
5360
            /* Extract out 8 values of 11 bits each. */
5361
0
            word16 t0 = (word16)((b[0] >> 0) | ((word16)b[ 1] << 8));
5362
0
            word16 t1 = (word16)((b[1] >> 3) | ((word16)b[ 2] << 5));
5363
0
            word16 t2 = (word16)((b[2] >> 6) | ((word16)b[ 3] << 2) |
5364
0
                   ((word16)b[4] << 10));
5365
0
            word16 t3 = (word16)((b[4] >> 1) | ((word16)b[ 5] << 7));
5366
0
            word16 t4 = (word16)((b[5] >> 4) | ((word16)b[ 6] << 4));
5367
0
            word16 t5 = (word16)((b[6] >> 7) | ((word16)b[ 7] << 1) |
5368
0
                   ((word16)b[8] <<  9));
5369
0
            word16 t6 = (word16)((b[8] >> 2) | ((word16)b[ 9] << 6));
5370
0
            word16 t7 = (word16)((b[9] >> 5) | ((word16)b[10] << 3));
5371
0
            b += 11;
5372
5373
            /* Decompress 8 values. */
5374
0
            DECOMP_11(v, i, j, 0, t0);
5375
0
            DECOMP_11(v, i, j, 1, t1);
5376
0
            DECOMP_11(v, i, j, 2, t2);
5377
0
            DECOMP_11(v, i, j, 3, t3);
5378
0
            DECOMP_11(v, i, j, 4, t4);
5379
0
            DECOMP_11(v, i, j, 5, t5);
5380
0
            DECOMP_11(v, i, j, 6, t6);
5381
0
            DECOMP_11(v, i, j, 7, t7);
5382
0
        #endif
5383
0
        }
5384
0
    }
5385
0
}
5386
5387
/* Decompress the byte array of packed 11 bits into vector of polynomials.
5388
 *
5389
 * FIPS 203, Section 4.2.1, Compression and decompression
5390
 *
5391
 * @param  [out]  v       Vector of polynomials.
5392
 * @param  [in]   b       Array of bytes.
5393
 */
5394
void mlkem_vec_decompress_11(sword16* v, const byte* b)
5395
0
{
5396
#ifdef USE_INTEL_SPEEDUP
5397
    if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
5398
        mlkem_decompress_11_avx2(v, b, 4);
5399
        RESTORE_VECTOR_REGISTERS();
5400
    }
5401
    else
5402
#endif
5403
0
    {
5404
0
        mlkem_vec_decompress_11_c(v, b);
5405
0
    }
5406
0
}
5407
#endif
5408
#endif /* !WOLFSSL_MLKEM_NO_DECAPSULATE */
5409
5410
#ifdef CONV_WITH_DIV
5411
5412
/* Compress value.
5413
 *
5414
 * Uses div operator that may be slow and not constant-time.
5415
 *
5416
 * FIPS 203, Section 4.2.1, Compression and decompression
5417
 *
5418
 * @param  [in]  v  Vector of polynomials.
5419
 * @param  [in]  i  Index into polynomial.
5420
 * @param  [in]  j  Offset from indices.
5421
 * @param  [in]  s  Shift amount to apply to value being compressed.
5422
 * @param  [in]  m  Mask to apply to get the required number of bits.
5423
 * @return  Compressed value.
5424
 */
5425
#define TO_COMP_WORD(v, i, j, s, m) \
5426
    ((((word32)v[i + j] << s) + MLKEM_Q_HALF) / MLKEM_Q) & m
5427
5428
/* Compress value to 4 bits.
5429
 *
5430
 * Uses div operator that may be slow and not constant-time.
5431
 *
5432
 * FIPS 203, Section 4.2.1, Compression and decompression
5433
 *
5434
 * @param  [in]  p  Polynomial.
5435
 * @param  [in]  i  Index into polynomial.
5436
 * @param  [in]  j  Offset from indices.
5437
 * @return  Compressed value.
5438
 */
5439
#define TO_COMP_WORD_4(p, i, j) \
5440
    TO_COMP_WORD(p, i, j, 4, 0xf)
5441
5442
/* Compress value to 5 bits.
5443
 *
5444
 * Uses div operator that may be slow and not constant-time.
5445
 *
5446
 * FIPS 203, Section 4.2.1, Compression and decompression
5447
 *
5448
 * @param  [in]  p  Polynomial.
5449
 * @param  [in]  i  Index into polynomial.
5450
 * @param  [in]  j  Offset from indices.
5451
 * @return  Compressed value.
5452
 */
5453
#define TO_COMP_WORD_5(p, i, j) \
5454
    TO_COMP_WORD(p, i, j, 5, 0x1f)
5455
5456
#else
5457
5458
/* Multiplier that does div q. */
5459
0
#define MLKEM_V28         ((word32)(((1U << 28) + MLKEM_Q_HALF)) / MLKEM_Q)
5460
/* Multiplier times half of q plus one. */
5461
0
#define MLKEM_V28_HALF    ((word32)(MLKEM_V28 * (MLKEM_Q_HALF + 1)))
5462
5463
/* Multiplier that does div q. */
5464
0
#define MLKEM_V27         ((word32)(((1U << 27) + MLKEM_Q_HALF)) / MLKEM_Q)
5465
/* Multiplier times half of q. */
5466
0
#define MLKEM_V27_HALF    ((word32)(MLKEM_V27 * MLKEM_Q_HALF))
5467
5468
/* Compress value to 4 bits.
5469
 *
5470
 * Uses mul instead of div.
5471
 *
5472
 * FIPS 203, Section 4.2.1, Compression and decompression
5473
 *
5474
 * @param  [in]  p  Polynomial.
5475
 * @param  [in]  i  Index into polynomial.
5476
 * @param  [in]  j  Offset from indices.
5477
 * @return  Compressed value.
5478
 */
5479
#define TO_COMP_WORD_4(p, i, j) \
5480
0
    (byte)((((MLKEM_V28 << 4) * (word32)(p)[(i) + (j)]) + MLKEM_V28_HALF) >> 28)
5481
5482
/* Compress value to 5 bits.
5483
 *
5484
 * Uses mul instead of div.
5485
 *
5486
 * FIPS 203, Section 4.2.1, Compression and decompression
5487
 *
5488
 * @param  [in]  p  Polynomial.
5489
 * @param  [in]  i  Index into polynomial.
5490
 * @param  [in]  j  Offset from indices.
5491
 * @return  Compressed value.
5492
 */
5493
#define TO_COMP_WORD_5(p, i, j) \
5494
0
    (byte)((((MLKEM_V27 << 5) * (word32)(p)[(i) + (j)]) + MLKEM_V27_HALF) >> 27)
5495
5496
#endif /* CONV_WITH_DIV */
5497
5498
#if !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \
5499
    !defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
5500
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512) || \
5501
    defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768)
5502
/* Compress a polynomial into byte array with coefficients of 4 bits.
5503
 *
5504
 * FIPS 203, Section 4.2.1, Compression and decompression
5505
 *
5506
 * @param  [out]      b  Array of bytes.
5507
 * @param  [in, out]  p  Polynomial.
5508
 */
5509
static void mlkem_compress_4_c(byte* b, sword16* p)
5510
0
{
5511
0
    unsigned int i;
5512
#ifdef WOLFSSL_MLKEM_SMALL
5513
    unsigned int j;
5514
    byte t[8];
5515
#endif
5516
5517
    /* Reduce each coefficient to mod q. */
5518
0
    mlkem_csubq_c(p);
5519
    /* All values are now positive. */
5520
5521
    /* Each 8 polynomial coefficients. */
5522
0
    for (i = 0; i < MLKEM_N; i += 8) {
5523
    #ifdef WOLFSSL_MLKEM_SMALL
5524
        /* Compress eight polynomial values to 4 bits each. */
5525
        for (j = 0; j < 8; j++) {
5526
            t[j] = TO_COMP_WORD_4(p, i, j);
5527
        }
5528
5529
        b[0] = (byte)(t[0] | (t[1] << 4));
5530
        b[1] = (byte)(t[2] | (t[3] << 4));
5531
        b[2] = (byte)(t[4] | (t[5] << 4));
5532
        b[3] = (byte)(t[6] | (t[7] << 4));
5533
    #else
5534
        /* Compress eight polynomial values to 4 bits each. */
5535
0
        byte t0 = TO_COMP_WORD_4(p, i, 0);
5536
0
        byte t1 = TO_COMP_WORD_4(p, i, 1);
5537
0
        byte t2 = TO_COMP_WORD_4(p, i, 2);
5538
0
        byte t3 = TO_COMP_WORD_4(p, i, 3);
5539
0
        byte t4 = TO_COMP_WORD_4(p, i, 4);
5540
0
        byte t5 = TO_COMP_WORD_4(p, i, 5);
5541
0
        byte t6 = TO_COMP_WORD_4(p, i, 6);
5542
0
        byte t7 = TO_COMP_WORD_4(p, i, 7);
5543
5544
        /* Pack eight 4-bit values into byte array. */
5545
0
        b[0] = (byte)(t0 | (t1 << 4));
5546
0
        b[1] = (byte)(t2 | (t3 << 4));
5547
0
        b[2] = (byte)(t4 | (t5 << 4));
5548
0
        b[3] = (byte)(t6 | (t7 << 4));
5549
0
    #endif
5550
5551
        /* Move over set bytes. */
5552
0
        b += 4;
5553
0
    }
5554
0
}
5555
5556
/* Compress a polynomial into byte array with coefficients of 4 bits.
5557
 *
5558
 * FIPS 203, Section 4.2.1, Compression and decompression
5559
 *
5560
 * @param  [out]      b  Array of bytes.
5561
 * @param  [in, out]  p  Polynomial.
5562
 */
5563
void mlkem_compress_4(byte* b, sword16* p)
5564
0
{
5565
#ifdef USE_INTEL_SPEEDUP
5566
    if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
5567
        mlkem_compress_4_avx2(b, p);
5568
        RESTORE_VECTOR_REGISTERS();
5569
    }
5570
    else
5571
#endif
5572
0
    {
5573
0
        mlkem_compress_4_c(b, p);
5574
0
    }
5575
0
}
5576
#endif
5577
#if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
5578
/* Compress a polynomial into byte array with coefficients of 5 bits.
5579
 *
5580
 * FIPS 203, Section 4.2.1, Compression and decompression
5581
 *
5582
 * @param  [out]      b  Array of bytes.
5583
 * @param  [in, out]  p  Polynomial.
5584
 */
5585
static void mlkem_compress_5_c(byte* b, sword16* p)
5586
0
{
5587
0
    unsigned int i;
5588
#ifdef WOLFSSL_MLKEM_SMALL
5589
    unsigned int j;
5590
    byte t[8];
5591
#endif
5592
5593
    /* Reduce each coefficient to mod q. */
5594
0
    mlkem_csubq_c(p);
5595
    /* All values are now positive. */
5596
5597
0
    for (i = 0; i < MLKEM_N; i += 8) {
5598
    #ifdef WOLFSSL_MLKEM_SMALL
5599
        /* Compress eight polynomial values to 5 bits each. */
5600
        for (j = 0; j < 8; j++) {
5601
            t[j] = TO_COMP_WORD_5(p, i, j);
5602
        }
5603
5604
        /* Pack 5 bits into byte array. */
5605
        b[0] = (byte)((t[0] >> 0) | (t[1] << 5));
5606
        b[1] = (byte)((t[1] >> 3) | (t[2] << 2) | (t[3] << 7));
5607
        b[2] = (byte)((t[3] >> 1) | (t[4] << 4));
5608
        b[3] = (byte)((t[4] >> 4) | (t[5] << 1) | (t[6] << 6));
5609
        b[4] = (byte)((t[6] >> 2) | (t[7] << 3));
5610
    #else
5611
        /* Compress eight polynomial values to 5 bits each. */
5612
0
        byte t0 = TO_COMP_WORD_5(p, i, 0);
5613
0
        byte t1 = TO_COMP_WORD_5(p, i, 1);
5614
0
        byte t2 = TO_COMP_WORD_5(p, i, 2);
5615
0
        byte t3 = TO_COMP_WORD_5(p, i, 3);
5616
0
        byte t4 = TO_COMP_WORD_5(p, i, 4);
5617
0
        byte t5 = TO_COMP_WORD_5(p, i, 5);
5618
0
        byte t6 = TO_COMP_WORD_5(p, i, 6);
5619
0
        byte t7 = TO_COMP_WORD_5(p, i, 7);
5620
5621
        /* Pack eight 5-bit values into byte array. */
5622
0
        b[0] = (byte)((t0 >> 0) | (t1 << 5));
5623
0
        b[1] = (byte)((t1 >> 3) | (t2 << 2) | (t3 << 7));
5624
0
        b[2] = (byte)((t3 >> 1) | (t4 << 4));
5625
0
        b[3] = (byte)((t4 >> 4) | (t5 << 1) | (t6 << 6));
5626
0
        b[4] = (byte)((t6 >> 2) | (t7 << 3));
5627
0
    #endif
5628
5629
        /* Move over set bytes. */
5630
0
        b += 5;
5631
0
    }
5632
0
}
5633
5634
/* Compress a polynomial into byte array with coefficients of 5 bits.
5635
 *
5636
 * FIPS 203, Section 4.2.1, Compression and decompression
5637
 *
5638
 * @param  [out]      b  Array of bytes.
5639
 * @param  [in, out]  p  Polynomial.
5640
 */
5641
void mlkem_compress_5(byte* b, sword16* p)
5642
0
{
5643
#ifdef USE_INTEL_SPEEDUP
5644
    if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
5645
        mlkem_compress_5_avx2(b, p);
5646
        RESTORE_VECTOR_REGISTERS();
5647
    }
5648
    else
5649
#endif
5650
0
    {
5651
0
        mlkem_compress_5_c(b, p);
5652
0
    }
5653
0
}
5654
#endif
5655
#endif /* !WOLFSSL_MLKEM_NO_ENCAPSULATE || !WOLFSSL_MLKEM_NO_DECAPSULATE */
5656
5657
#ifndef WOLFSSL_MLKEM_NO_DECAPSULATE
5658
/* Decompress a 4 bit value.
5659
 *
5660
 * FIPS 203, Section 4.2.1, Compression and decompression
5661
 *
5662
 * @param  [out]  p  Polynomial.
5663
 * @param  [in]   i  Index into polynomial.
5664
 * @param  [in]   j  Offset from indices.
5665
 * @param  [in]   t  Value to decompress.
5666
 */
5667
#define DECOMP_4(p, i, j, t) \
5668
0
    p[(i) + (j)] = (sword16)(((word16)((t) * MLKEM_Q) + 8) >> 4)
5669
5670
/* Decompress a 5 bit value.
5671
 *
5672
 * FIPS 203, Section 4.2.1, Compression and decompression
5673
 *
5674
 * @param  [out]  p  Polynomial.
5675
 * @param  [in]   i  Index into polynomial.
5676
 * @param  [in]   j  Offset from indices.
5677
 * @param  [in]   t  Value to decompress.
5678
 */
5679
#define DECOMP_5(p, i, j, t) \
5680
0
    p[(i) + (j)] = (sword16)((((word32)((t) & 0x1f) * MLKEM_Q) + 16) >> 5)
5681
5682
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512) || \
5683
    defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768)
5684
/* Decompress the byte array of packed 4 bits into polynomial.
5685
 *
5686
 * FIPS 203, Section 4.2.1, Compression and decompression
5687
 *
5688
 * @param  [out]  p       Polynomial.
5689
 * @param  [in]   b       Array of bytes.
5690
 */
5691
static void mlkem_decompress_4_c(sword16* p, const byte* b)
5692
0
{
5693
0
    unsigned int i;
5694
5695
    /* 2 coefficients at a time. */
5696
0
    for (i = 0; i < MLKEM_N; i += 2) {
5697
        /* 2 coefficients decompressed from one byte. */
5698
0
        DECOMP_4(p, i, 0, b[0] & 0xf);
5699
0
        DECOMP_4(p, i, 1, b[0] >>  4);
5700
0
        b += 1;
5701
0
    }
5702
0
}
5703
5704
/* Decompress the byte array of packed 4 bits into polynomial.
5705
 *
5706
 * FIPS 203, Section 4.2.1, Compression and decompression
5707
 *
5708
 * @param  [out]  p       Polynomial.
5709
 * @param  [in]   b       Array of bytes.
5710
 */
5711
void mlkem_decompress_4(sword16* p, const byte* b)
5712
0
{
5713
#ifdef USE_INTEL_SPEEDUP
5714
    if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
5715
        mlkem_decompress_4_avx2(p, b);
5716
        RESTORE_VECTOR_REGISTERS();
5717
    }
5718
    else
5719
#endif
5720
0
    {
5721
0
        mlkem_decompress_4_c(p, b);
5722
0
    }
5723
0
}
5724
#endif
5725
#if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
5726
/* Decompress the byte array of packed 5 bits into polynomial.
5727
 *
5728
 * FIPS 203, Section 4.2.1, Compression and decompression
5729
 *
5730
 * @param  [out]  p       Polynomial.
5731
 * @param  [in]   b       Array of bytes.
5732
 */
5733
static void mlkem_decompress_5_c(sword16* p, const byte* b)
5734
0
{
5735
0
    unsigned int i;
5736
5737
    /* Each 8 polynomial coefficients. */
5738
0
    for (i = 0; i < MLKEM_N; i += 8) {
5739
    #ifdef WOLFSSL_MLKEM_SMALL
5740
        unsigned int j;
5741
        byte t[8];
5742
5743
        /* Extract out 8 values of 5 bits each. */
5744
        t[0] = (b[0] >> 0);
5745
        t[1] = (byte)((b[0] >> 5) | (b[1] << 3));
5746
        t[2] = (b[1] >> 2);
5747
        t[3] = (byte)((b[1] >> 7) | (b[2] << 1));
5748
        t[4] = (byte)((b[2] >> 4) | (b[3] << 4));
5749
        t[5] = (b[3] >> 1);
5750
        t[6] = (byte)((b[3] >> 6) | (b[4] << 2));
5751
        t[7] = (b[4] >> 3);
5752
        b += 5;
5753
5754
        /* Decompress 8 values. */
5755
        for (j = 0; j < 8; j++) {
5756
            DECOMP_5(p, i, j, t[j]);
5757
        }
5758
    #else
5759
        /* Extract out 8 values of 5 bits each. */
5760
0
        byte t0 = (b[0] >> 0);
5761
0
        byte t1 = (byte)((b[0] >> 5) | (b[1] << 3));
5762
0
        byte t2 = (b[1] >> 2);
5763
0
        byte t3 = (byte)((b[1] >> 7) | (b[2] << 1));
5764
0
        byte t4 = (byte)((b[2] >> 4) | (b[3] << 4));
5765
0
        byte t5 = (b[3] >> 1);
5766
0
        byte t6 = (byte)((b[3] >> 6) | (b[4] << 2));
5767
0
        byte t7 = (b[4] >> 3);
5768
0
        b += 5;
5769
5770
        /* Decompress 8 values. */
5771
0
        DECOMP_5(p, i, 0, t0);
5772
0
        DECOMP_5(p, i, 1, t1);
5773
0
        DECOMP_5(p, i, 2, t2);
5774
0
        DECOMP_5(p, i, 3, t3);
5775
0
        DECOMP_5(p, i, 4, t4);
5776
0
        DECOMP_5(p, i, 5, t5);
5777
0
        DECOMP_5(p, i, 6, t6);
5778
0
        DECOMP_5(p, i, 7, t7);
5779
0
    #endif
5780
0
    }
5781
0
}
5782
5783
/* Decompress the byte array of packed 5 bits into polynomial.
5784
 *
5785
 * FIPS 203, Section 4.2.1, Compression and decompression
5786
 *
5787
 * @param  [out]  p       Polynomial.
5788
 * @param  [in]   b       Array of bytes.
5789
 */
5790
void mlkem_decompress_5(sword16* p, const byte* b)
5791
0
{
5792
#ifdef USE_INTEL_SPEEDUP
5793
    if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
5794
        mlkem_decompress_5_avx2(p, b);
5795
        RESTORE_VECTOR_REGISTERS();
5796
    }
5797
    else
5798
#endif
5799
0
    {
5800
0
        mlkem_decompress_5_c(p, b);
5801
0
    }
5802
0
}
5803
#endif
5804
#endif /* !WOLFSSL_MLKEM_NO_DECAPSULATE */
5805
5806
/******************************************************************************/
5807
5808
#if !(defined(__aarch64__) && defined(WOLFSSL_ARMASM))
5809
#if !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \
5810
    !defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
5811
/* Convert bit from byte to 0 or (MLKEM_Q + 1) / 2.
5812
 *
5813
 * Constant time implementation.
5814
 * XOR in wc_mlkem_opt_blocker() to ensure optimizer doesn't know what will be
5815
 * ANDed with MLKEM_Q_1_HALF and can't optimize to non-constant time code.
5816
 *
5817
 * FIPS 203, Algorithm 6: ByteDecode_d(B)
5818
 *
5819
 * @param  [out]  p    Polynomial to hold converted value.
5820
 * @param  [in]   msg  Message to get bit from byte.
5821
 * @param  [in]   i    Index of byte from message.
5822
 * @param  [in]   j    Index of bit in byte.
5823
 */
5824
#define FROM_MSG_BIT(p, msg, i, j) \
5825
0
    ((p)[8 * (i) + (j)] = (((sword16)0 - (sword16)(((msg)[i] >> (j)) & 1)) ^ \
5826
0
                          wc_mlkem_opt_blocker()) & MLKEM_Q_1_HALF)
5827
5828
/* Convert message to polynomial.
5829
 *
5830
 * FIPS 203, Algorithm 6: ByteDecode_d(B)
5831
 *
5832
 * @param  [out]  p    Polynomial.
5833
 * @param  [in]   msg  Message as a byte array.
5834
 */
5835
static void mlkem_from_msg_c(sword16* p, const byte* msg)
5836
0
{
5837
0
    unsigned int i;
5838
5839
    /* For each byte of the message. */
5840
0
    for (i = 0; i < MLKEM_N / 8; i++) {
5841
    #ifdef WOLFSSL_MLKEM_SMALL
5842
        unsigned int j;
5843
        /* For each bit of the message. */
5844
        for (j = 0; j < 8; j++) {
5845
            FROM_MSG_BIT(p, msg, i, j);
5846
        }
5847
    #else
5848
0
        FROM_MSG_BIT(p, msg, i, 0);
5849
0
        FROM_MSG_BIT(p, msg, i, 1);
5850
0
        FROM_MSG_BIT(p, msg, i, 2);
5851
0
        FROM_MSG_BIT(p, msg, i, 3);
5852
0
        FROM_MSG_BIT(p, msg, i, 4);
5853
0
        FROM_MSG_BIT(p, msg, i, 5);
5854
0
        FROM_MSG_BIT(p, msg, i, 6);
5855
0
        FROM_MSG_BIT(p, msg, i, 7);
5856
0
    #endif
5857
0
    }
5858
0
}
5859
5860
/* Convert message to polynomial.
5861
 *
5862
 * FIPS 203, Algorithm 6: ByteDecode_d(B)
5863
 *
5864
 * @param  [out]  p    Polynomial.
5865
 * @param  [in]   msg  Message as a byte array.
5866
 */
5867
void mlkem_from_msg(sword16* p, const byte* msg)
5868
0
{
5869
#ifdef USE_INTEL_SPEEDUP
5870
    if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
5871
        mlkem_from_msg_avx2(p, msg);
5872
        RESTORE_VECTOR_REGISTERS();
5873
    }
5874
    else
5875
#endif
5876
0
    {
5877
0
        mlkem_from_msg_c(p, msg);
5878
0
    }
5879
0
}
5880
#endif
5881
5882
#ifndef WOLFSSL_MLKEM_NO_DECAPSULATE
5883
#ifdef CONV_WITH_DIV
5884
5885
/* Convert value to bit.
5886
 *
5887
 * Uses div operator that may be slow.
5888
 *
5889
 * FIPS 203, Algorithm 5: ByteEncode_d(F)
5890
 *
5891
 * @param  [in, out]  m   Message.
5892
 * @param  [in]       p   Polynomial.
5893
 * @param  [in]       i   Index of byte in message.
5894
 * @param  [in]       j   Index of bit in byte.
5895
 */
5896
#define TO_MSG_BIT(m, p, i, j) \
5897
    m[i] |= (((((sword16)p[8 * i + j] << 1) + MLKEM_Q_HALF) / MLKEM_Q) & 1) << j
5898
5899
#else
5900
5901
/* Multiplier that does div q. */
5902
0
#define MLKEM_V31       (((1U << 31) + (MLKEM_Q / 2)) / MLKEM_Q)
5903
/* 2 * multiplier that does div q. Only need bit 32 of result. */
5904
0
#define MLKEM_V31_2     ((word32)(MLKEM_V31 * 2))
5905
/* Multiplier times half of q. */
5906
0
#define MLKEM_V31_HALF    ((word32)(MLKEM_V31 * MLKEM_Q_HALF))
5907
5908
/* Convert value to bit.
5909
 *
5910
 * Uses mul instead of div.
5911
 *
5912
 * FIPS 203, Algorithm 5: ByteEncode_d(F)
5913
 *
5914
 * @param  [in, out]  m   Message.
5915
 * @param  [in]       p   Polynomial.
5916
 * @param  [in]       i   Index of byte in message.
5917
 * @param  [in]       j   Index of bit in byte.
5918
 */
5919
#define TO_MSG_BIT(m, p, i, j) \
5920
0
    (m)[i] |= (byte)((((MLKEM_V31_2 * (word16)(p)[8 * (i) + (j)]) + \
5921
0
                       MLKEM_V31_HALF) >> 31) << (j))
5922
5923
#endif /* CONV_WITH_DIV */
5924
5925
/* Convert polynomial to message.
5926
 *
5927
 * FIPS 203, Algorithm 5: ByteEncode_d(F)
5928
 *
5929
 * @param  [out]      msg  Message as a byte array.
5930
 * @param  [in, out]  p    Polynomial.
5931
 */
5932
static void mlkem_to_msg_c(byte* msg, sword16* p)
5933
0
{
5934
0
    unsigned int i;
5935
5936
    /* Reduce each coefficient to mod q. */
5937
0
    mlkem_csubq_c(p);
5938
    /* All values are now in range. */
5939
5940
0
    for (i = 0; i < MLKEM_N / 8; i++) {
5941
    #ifdef WOLFSSL_MLKEM_SMALL
5942
        unsigned int j;
5943
        msg[i] = 0;
5944
        for (j = 0; j < 8; j++) {
5945
            TO_MSG_BIT(msg, p, i, j);
5946
        }
5947
    #else
5948
0
        msg[i] = 0;
5949
0
        TO_MSG_BIT(msg, p, i, 0);
5950
0
        TO_MSG_BIT(msg, p, i, 1);
5951
0
        TO_MSG_BIT(msg, p, i, 2);
5952
0
        TO_MSG_BIT(msg, p, i, 3);
5953
0
        TO_MSG_BIT(msg, p, i, 4);
5954
0
        TO_MSG_BIT(msg, p, i, 5);
5955
0
        TO_MSG_BIT(msg, p, i, 6);
5956
0
        TO_MSG_BIT(msg, p, i, 7);
5957
0
    #endif
5958
0
    }
5959
0
}
5960
5961
/* Convert polynomial to message.
5962
 *
5963
 * FIPS 203, Algorithm 5: ByteEncode_d(F)
5964
 *
5965
 * @param  [out]      msg  Message as a byte array.
5966
 * @param  [in, out]  p    Polynomial.
5967
 */
5968
void mlkem_to_msg(byte* msg, sword16* p)
5969
0
{
5970
#ifdef USE_INTEL_SPEEDUP
5971
     if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
5972
        /* Convert the polynomial into an array of bytes (message). */
5973
        mlkem_to_msg_avx2(msg, p);
5974
        RESTORE_VECTOR_REGISTERS();
5975
    }
5976
    else
5977
#endif
5978
0
    {
5979
0
        mlkem_to_msg_c(msg, p);
5980
0
    }
5981
0
}
5982
#endif /* !WOLFSSL_MLKEM_NO_DECAPSULATE */
5983
#else
5984
#if !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \
5985
    !defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
5986
/* Convert message to polynomial.
5987
 *
5988
 * FIPS 203, Algorithm 6: ByteDecode_d(B)
5989
 *
5990
 * @param  [out]  p    Polynomial.
5991
 * @param  [in]   msg  Message as a byte array.
5992
 */
5993
void mlkem_from_msg(sword16* p, const byte* msg)
5994
{
5995
    mlkem_from_msg_neon(p, msg);
5996
}
5997
#endif /* !WOLFSSL_MLKEM_NO_ENCAPSULATE || !WOLFSSL_MLKEM_NO_DECAPSULATE */
5998
5999
#ifndef WOLFSSL_MLKEM_NO_DECAPSULATE
6000
/* Convert polynomial to message.
6001
 *
6002
 * FIPS 203, Algorithm 5: ByteEncode_d(F)
6003
 *
6004
 * @param  [out]      msg  Message as a byte array.
6005
 * @param  [in, out]  p    Polynomial.
6006
 */
6007
void mlkem_to_msg(byte* msg, sword16* p)
6008
{
6009
    mlkem_to_msg_neon(msg, p);
6010
}
6011
#endif /* WOLFSSL_MLKEM_NO_DECAPSULATE */
6012
#endif /* !(__aarch64__ && WOLFSSL_ARMASM) */
6013
6014
/******************************************************************************/
6015
6016
/* Convert bytes to polynomial.
6017
 *
6018
 * Consecutive 12 bits hold each coefficient of polynomial.
6019
 * Used in decoding private and public keys.
6020
 *
6021
 * FIPS 203, Algorithm 6: ByteDecode_d(B)
6022
 *
6023
 * @param  [out]  p  Vector of polynomials.
6024
 * @param  [in]   b  Array of bytes.
6025
 * @param  [in]   k  Number of polynomials in vector.
6026
 */
6027
static void mlkem_from_bytes_c(sword16* p, const byte* b, int k)
6028
0
{
6029
0
    int i;
6030
0
    int j;
6031
6032
0
    for (j = 0; j < k; j++) {
6033
0
        for (i = 0; i < MLKEM_N / 2; i++) {
6034
0
            p[2 * i + 0] = ((b[3 * i + 0] >> 0) |
6035
0
                            ((word16)b[3 * i + 1] << 8)) & 0xfff;
6036
0
            p[2 * i + 1] = ((b[3 * i + 1] >> 4) |
6037
0
                            ((word16)b[3 * i + 2] << 4)) & 0xfff;
6038
0
        }
6039
0
        p += MLKEM_N;
6040
0
        b += WC_ML_KEM_POLY_SIZE;
6041
0
    }
6042
0
}
6043
6044
/* Convert bytes to polynomial.
6045
 *
6046
 * Consecutive 12 bits hold each coefficient of polynomial.
6047
 * Used in decoding private and public keys.
6048
 *
6049
 * FIPS 203, Algorithm 6: ByteDecode_d(B)
6050
 *
6051
 * @param  [out]  p  Vector of polynomials.
6052
 * @param  [in]   b  Array of bytes.
6053
 * @param  [in]   k  Number of polynomials in vector.
6054
 */
6055
void mlkem_from_bytes(sword16* p, const byte* b, int k)
6056
0
{
6057
#ifdef USE_INTEL_SPEEDUP
6058
     if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
6059
        int i;
6060
6061
        for (i = 0; i < k; i++) {
6062
            mlkem_from_bytes_avx2(p, b);
6063
            p += MLKEM_N;
6064
            b += WC_ML_KEM_POLY_SIZE;
6065
        }
6066
6067
        RESTORE_VECTOR_REGISTERS();
6068
    }
6069
    else
6070
#endif
6071
0
    {
6072
0
        mlkem_from_bytes_c(p, b, k);
6073
0
    }
6074
0
}
6075
6076
/* Convert polynomial to bytes.
6077
 *
6078
 * Consecutive 12 bits hold each coefficient of polynomial.
6079
 * Used in encoding private and public keys.
6080
 *
6081
 * FIPS 203, Algorithm 5: ByteEncode_d(F)
6082
 *
6083
 * @param  [out]      b  Array of bytes.
6084
 * @param  [in, out]  p  Polynomial.
6085
 * @param  [in]       k  Number of polynomials in vector.
6086
 */
6087
static void mlkem_to_bytes_c(byte* b, sword16* p, int k)
6088
0
{
6089
0
    int i;
6090
0
    int j;
6091
6092
0
    for (j = 0; j < k; j++) {
6093
        /* Reduce each coefficient to mod q. */
6094
0
        mlkem_csubq_c(p);
6095
        /* All values are now positive. */
6096
6097
0
        for (i = 0; i < MLKEM_N / 2; i++) {
6098
0
            word16 t0 = (word16)p[2 * i];
6099
0
            word16 t1 = (word16)p[2 * i + 1];
6100
0
            b[3 * i + 0] = (byte)(t0 >> 0);
6101
0
            b[3 * i + 1] = (byte)((t0 >> 8) | (t1 << 4));
6102
0
            b[3 * i + 2] = (byte)(t1 >> 4);
6103
0
        }
6104
0
        p += MLKEM_N;
6105
0
        b += WC_ML_KEM_POLY_SIZE;
6106
0
    }
6107
0
}
6108
6109
/* Convert polynomial to bytes.
6110
 *
6111
 * Consecutive 12 bits hold each coefficient of polynomial.
6112
 * Used in encoding private and public keys.
6113
 *
6114
 * FIPS 203, Algorithm 5: ByteEncode_d(F)
6115
 *
6116
 * @param  [out]      b  Array of bytes.
6117
 * @param  [in, out]  p  Polynomial.
6118
 * @param  [in]       k  Number of polynomials in vector.
6119
 */
6120
void mlkem_to_bytes(byte* b, sword16* p, int k)
6121
0
{
6122
#ifdef USE_INTEL_SPEEDUP
6123
     if (IS_INTEL_AVX2(cpuid_flags) && (SAVE_VECTOR_REGISTERS2() == 0)) {
6124
        int i;
6125
6126
        for (i = 0; i < k; i++) {
6127
            mlkem_to_bytes_avx2(b, p);
6128
            p += MLKEM_N;
6129
            b += WC_ML_KEM_POLY_SIZE;
6130
        }
6131
6132
        RESTORE_VECTOR_REGISTERS();
6133
    }
6134
    else
6135
#endif
6136
0
    {
6137
0
        mlkem_to_bytes_c(b, p, k);
6138
0
    }
6139
0
}
6140
6141
/**
6142
 * Check the vector coefficients are reduced modulo q.
6143
 *
6144
 * FIPS 203, Sections 7.2 and 7.3: encapsulation and decapsulation keys must
6145
 * decode to coefficients in Z_q; reject any that are not reduced.
6146
 *
6147
 * @param [in] p  Key - vector of polynomials.
6148
 * @param [in] k  Number of polynomials in vector.
6149
 * @return  0 when all values are in range.
6150
 * @return  PUBLIC_KEY_E when at least one value is out of range.
6151
 */
6152
int mlkem_check_reduced(const sword16* p, int k)
6153
0
{
6154
0
    int ret = 0;
6155
0
    int i;
6156
6157
0
    for (i = 0; i < k * MLKEM_N; i++) {
6158
0
        if (p[i] >= MLKEM_Q) {
6159
0
            ret = PUBLIC_KEY_E;
6160
0
            break;
6161
0
        }
6162
0
    }
6163
6164
0
    return ret;
6165
0
}
6166
6167
#endif /* WOLFSSL_HAVE_MLKEM */