Coverage Report

Created: 2026-04-01 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wolfssl-normal-math/wolfcrypt/src/wc_mlkem.c
Line
Count
Source
1
/* wc_mlkem.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
/* Possible Kyber options:
32
 *
33
 * WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM                                  Default: OFF
34
 *   Uses less dynamic memory to perform key generation.
35
 *   Has a small performance trade-off.
36
 *   Only usable with C implementation.
37
 *
38
 * WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM                              Default: OFF
39
 *   Uses less dynamic memory to perform encapsulation.
40
 *   Affects decapsulation too as encapsulation called.
41
 *   Has a small performance trade-off.
42
 *   Only usable with C implementation.
43
 *
44
 * WOLFSSL_MLKEM_NO_MAKE_KEY                                        Default: OFF
45
 *   Disable the make key or key generation API.
46
 *   Reduces the code size.
47
 *   Turn on when only doing encapsulation.
48
 *
49
 * WOLFSSL_MLKEM_NO_ENCAPSULATE                                     Default: OFF
50
 *   Disable the encapsulation API.
51
 *   Reduces the code size.
52
 *   Turn on when doing make key/decapsulation.
53
 *
54
 * WOLFSSL_MLKEM_NO_DECAPSULATE                                     Default: OFF
55
 *   Disable the decapsulation API.
56
 *   Reduces the code size.
57
 *   Turn on when only doing encapsulation.
58
 *
59
 * WOLFSSL_MLKEM_CACHE_A                                           Default: OFF
60
 *   Stores the matrix A during key generation for use in encapsulation when
61
 *   performing decapsulation.
62
 *   KyberKey is 8KB larger but decapsulation is significantly faster.
63
 *   Turn on when performing make key and decapsulation with same object.
64
 */
65
66
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
67
68
#ifdef WC_MLKEM_NO_ASM
69
    #undef USE_INTEL_SPEEDUP
70
    #undef WOLFSSL_ARMASM
71
    #undef WOLFSSL_RISCV_ASM
72
#endif
73
74
#include <wolfssl/wolfcrypt/mlkem.h>
75
#include <wolfssl/wolfcrypt/wc_mlkem.h>
76
#include <wolfssl/wolfcrypt/hash.h>
77
#include <wolfssl/wolfcrypt/memory.h>
78
79
#ifdef NO_INLINE
80
    #include <wolfssl/wolfcrypt/misc.h>
81
#else
82
    #define WOLFSSL_MISC_INCLUDED
83
    #include <wolfcrypt/src/misc.c>
84
#endif
85
86
#if defined(USE_INTEL_SPEEDUP) || \
87
    (defined(__aarch64__) && defined(WOLFSSL_ARMASM))
88
    #if defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) || \
89
        defined(WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM)
90
        #error "Can't use small memory with assembly optimized code"
91
    #endif
92
#endif
93
#if defined(WOLFSSL_MLKEM_CACHE_A)
94
    #if defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) || \
95
        defined(WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM)
96
        #error "Can't cache A with small memory code"
97
    #endif
98
#endif
99
100
#if defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
101
    defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
102
    defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
103
    #error "No ML-KEM operations to be built."
104
#endif
105
106
#ifdef WOLFSSL_WC_MLKEM
107
108
#ifdef DEBUG_MLKEM
109
void print_polys(const char* name, const sword16* a, int d1, int d2);
110
void print_polys(const char* name, const sword16* a, int d1, int d2)
111
{
112
    int i;
113
    int j;
114
    int k;
115
116
    fprintf(stderr, "%s: %d %d\n", name, d1, d2);
117
    for (i = 0; i < d1; i++) {
118
        for (j = 0; j < d2; j++) {
119
            for (k = 0; k < 256; k++) {
120
                fprintf(stderr, "%9d,", a[(i*d2*256) + (j*256) + k]);
121
                if ((k % 8) == 7) fprintf(stderr, "\n");
122
            }
123
            fprintf(stderr, "\n");
124
        }
125
    }
126
}
127
#endif
128
129
#ifdef DEBUG_MLKEM
130
void print_data(const char* name, const byte* d, int len);
131
void print_data(const char* name, const byte* d, int len)
132
{
133
    int i;
134
135
    fprintf(stderr, "%s\n", name);
136
    for (i = 0; i < len; i++) {
137
        fprintf(stderr, "0x%02x,", d[i]);
138
        if ((i % 16) == 15) fprintf(stderr, "\n");
139
    }
140
    fprintf(stderr, "\n");
141
}
142
#endif
143
144
/******************************************************************************/
145
146
/* Use SHA3-256 to generate 32-bytes of hash. */
147
3.25k
#define MLKEM_HASH_H            mlkem_hash256
148
/* Use SHA3-512 to generate 64-bytes of hash. */
149
3.25k
#define MLKEM_HASH_G            mlkem_hash512
150
/* Use SHAKE-256 as a key derivation function (KDF). */
151
#if defined(USE_INTEL_SPEEDUP) || \
152
        (defined(WOLFSSL_ARMASM) && defined(__aarch64__))
153
    #define MLKEM_KDF               mlkem_kdf
154
#else
155
    #define MLKEM_KDF               wc_Shake256Hash
156
#endif
157
158
/******************************************************************************/
159
160
/* Helper function with volatile variable, to force compiler not to optimize
161
 * code in mlkem_from_msg().
162
 */
163
sword16 wc_mlkem_opt_blocker(void);
164
0
sword16 wc_mlkem_opt_blocker(void) {
165
0
    static volatile sword16 static_mlkem_opt_blocker = 0;
166
0
    return static_mlkem_opt_blocker;
167
0
}
168
169
/******************************************************************************/
170
171
#ifndef WC_NO_CONSTRUCTORS
172
/**
173
 * Create a new ML-KEM key object.
174
 *
175
 * Allocates and initializes a ML-KEM key object.
176
 *
177
 * @param  [in]   type         Type of key:
178
 *                               WC_ML_KEM_512, WC_ML_KEM_768, WC_ML_KEM_1024,
179
 *                               KYBER512, KYBER768, KYBER1024.
180
 * @param  [in]   heap         Dynamic memory hint.
181
 * @param  [in]   devId        Device Id.
182
 * @return Pointer to new MlKemKey object, or NULL on failure.
183
 */
184
185
MlKemKey* wc_MlKemKey_New(int type, void* heap, int devId)
186
0
{
187
0
    int ret;
188
0
    MlKemKey* key = (MlKemKey*)XMALLOC(sizeof(MlKemKey), heap,
189
0
        DYNAMIC_TYPE_TMP_BUFFER);
190
0
    if (key != NULL) {
191
0
        ret = wc_MlKemKey_Init(key, type, heap, devId);
192
0
        if (ret != 0) {
193
0
            XFREE(key, heap, DYNAMIC_TYPE_TMP_BUFFER);
194
0
            key = NULL;
195
0
        }
196
0
    }
197
198
0
    return key;
199
0
}
200
201
/**
202
 * Delete and free a ML-KEM key object.
203
 *
204
 * Frees resources associated with a ML-KEM key object and sets pointer to NULL.
205
 *
206
 * @param  [in]      key    ML-KEM key object to delete.
207
 * @param  [in, out] key_p  Pointer to key pointer to set to NULL.
208
 * @return  0 on success.
209
 * @return  BAD_FUNC_ARG when key is NULL.
210
 */
211
212
int wc_MlKemKey_Delete(MlKemKey* key, MlKemKey** key_p)
213
0
{
214
0
    if (key == NULL)
215
0
        return BAD_FUNC_ARG;
216
0
    wc_MlKemKey_Free(key);
217
0
    XFREE(key, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
218
0
    if (key_p != NULL)
219
0
        *key_p = NULL;
220
221
0
    return 0;
222
0
}
223
#endif /* !WC_NO_CONSTRUCTORS */
224
225
/**
226
 * Initialize the Kyber key.
227
 *
228
 * @param  [out]  key    Kyber key object to initialize.
229
 * @param  [in]   type   Type of key:
230
 *                         WC_ML_KEM_512, WC_ML_KEM_768, WC_ML_KEM_1024,
231
 *                         KYBER512, KYBER768, KYBER1024.
232
 * @param  [in]   heap   Dynamic memory hint.
233
 * @param  [in]   devId  Device Id.
234
 * @return  0 on success.
235
 * @return  BAD_FUNC_ARG when key is NULL or type is unrecognized.
236
 * @return  NOT_COMPILED_IN when key type is not supported.
237
 */
238
int wc_MlKemKey_Init(MlKemKey* key, int type, void* heap, int devId)
239
3.26k
{
240
3.26k
    int ret = 0;
241
242
    /* Validate key. */
243
3.26k
    if (key == NULL) {
244
0
        ret = BAD_FUNC_ARG;
245
0
    }
246
3.26k
    if (ret == 0) {
247
        /* Validate type. */
248
3.26k
        switch (type) {
249
0
    #ifndef WOLFSSL_NO_ML_KEM
250
0
        case WC_ML_KEM_512:
251
        #ifndef WOLFSSL_WC_ML_KEM_512
252
            /* Code not compiled in for Kyber-512. */
253
            ret = NOT_COMPILED_IN;
254
        #endif
255
0
            break;
256
3.22k
        case WC_ML_KEM_768:
257
        #ifndef WOLFSSL_WC_ML_KEM_768
258
            /* Code not compiled in for Kyber-768. */
259
            ret = NOT_COMPILED_IN;
260
        #endif
261
3.22k
            break;
262
34
        case WC_ML_KEM_1024:
263
        #ifndef WOLFSSL_WC_ML_KEM_1024
264
            /* Code not compiled in for Kyber-1024. */
265
            ret = NOT_COMPILED_IN;
266
        #endif
267
34
            break;
268
0
    #endif
269
    #ifdef WOLFSSL_MLKEM_KYBER
270
        case KYBER512:
271
        #ifndef WOLFSSL_KYBER512
272
            /* Code not compiled in for Kyber-512. */
273
            ret = NOT_COMPILED_IN;
274
        #endif
275
            break;
276
        case KYBER768:
277
        #ifndef WOLFSSL_KYBER768
278
            /* Code not compiled in for Kyber-768. */
279
            ret = NOT_COMPILED_IN;
280
        #endif
281
            break;
282
        case KYBER1024:
283
        #ifndef WOLFSSL_KYBER1024
284
            /* Code not compiled in for Kyber-1024. */
285
            ret = NOT_COMPILED_IN;
286
        #endif
287
            break;
288
    #endif
289
0
        default:
290
            /* No other values supported. */
291
0
            ret = BAD_FUNC_ARG;
292
0
            break;
293
3.26k
        }
294
3.26k
    }
295
3.26k
    if (ret == 0) {
296
        /* Keep type for parameters. */
297
3.26k
        key->type = type;
298
        /* Cache heap pointer. */
299
3.26k
        key->heap = heap;
300
3.26k
    #ifdef WOLF_CRYPTO_CB
301
        /* Cache device id - not used in this algorithm yet. */
302
3.26k
        key->devId = devId;
303
3.26k
    #endif
304
3.26k
        key->flags = 0;
305
306
        /* Zero out all data. */
307
3.26k
        XMEMSET(&key->prf, 0, sizeof(key->prf));
308
309
        /* Initialize the hash algorithm object. */
310
3.26k
        ret = mlkem_hash_new(&key->hash, heap, devId);
311
3.26k
    }
312
3.26k
    if (ret == 0) {
313
        /* Initialize the PRF algorithm object. */
314
3.26k
        ret = mlkem_prf_new(&key->prf, heap, devId);
315
3.26k
    }
316
3.26k
    if (ret == 0) {
317
3.26k
        mlkem_init();
318
3.26k
    }
319
320
3.26k
    (void)devId;
321
322
3.26k
    return ret;
323
3.26k
}
324
325
/**
326
 * Free the Kyber key object.
327
 *
328
 * @param  [in, out]  key   Kyber key object to dispose of.
329
 * @return  0 on success.
330
 */
331
int wc_MlKemKey_Free(MlKemKey* key)
332
6.49k
{
333
6.49k
    if (key != NULL) {
334
        /* Dispose of PRF object. */
335
3.26k
        mlkem_prf_free(&key->prf);
336
        /* Dispose of hash object. */
337
3.26k
        mlkem_hash_free(&key->hash);
338
        /* Ensure all private data is zeroed. */
339
3.26k
        ForceZero(&key->hash, sizeof(key->hash));
340
3.26k
        ForceZero(&key->prf, sizeof(key->prf));
341
3.26k
        ForceZero(key->priv, sizeof(key->priv));
342
3.26k
        ForceZero(key->z, sizeof(key->z));
343
3.26k
    }
344
345
6.49k
    return 0;
346
6.49k
}
347
348
/******************************************************************************/
349
350
#ifndef WOLFSSL_MLKEM_NO_MAKE_KEY
351
/**
352
 * Make a Kyber key object using a random number generator.
353
 *
354
 * FIPS 203 - Algorithm 19: ML-KEM.KeyGen()
355
 * Generates an encapsulation key and a corresponding decapsulation key.
356
 *   1: d <- B_32                                        >  d is 32 random bytes
357
 *   2: z <- B_32                                        >  z is 32 random bytes
358
 *   3: if d == NULL or z == NULL then
359
 *   4:   return falsum
360
 *                  > return an error indication if random bit generation failed
361
 *   5: end if
362
 *   6: (ek,dk) <- ML-KEM.KeyGen_Internal(d, z)
363
 *                                       > run internal key generation algorithm
364
 *   7: return (ek,dk)
365
 *
366
 * @param  [in, out]  key   Kyber key object.
367
 * @param  [in]       rng   Random number generator.
368
 * @return  0 on success.
369
 * @return  BAD_FUNC_ARG when key or rng is NULL.
370
 * @return  MEMORY_E when dynamic memory allocation failed.
371
 * @return  RNG_FAILURE_E when generating random numbers failed.
372
 * @return  DRBG_CONT_FAILURE when random number generator health check fails.
373
 */
374
int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng)
375
3.25k
{
376
3.25k
#ifndef WC_NO_RNG
377
3.25k
    int ret = 0;
378
3.25k
    unsigned char rand[WC_ML_KEM_MAKEKEY_RAND_SZ];
379
380
    /* Validate parameters. */
381
3.25k
    if ((key == NULL) || (rng == NULL)) {
382
0
        ret = BAD_FUNC_ARG;
383
0
    }
384
385
3.25k
    if (ret == 0) {
386
        /* Generate random to use with PRFs.
387
         * Step 1: d is 32 random bytes
388
         * Step 2: z is 32 random bytes
389
         */
390
3.25k
        ret = wc_RNG_GenerateBlock(rng, rand, WC_ML_KEM_SYM_SZ * 2);
391
        /* Step 3: ret is not zero when d == NULL or z == NULL. */
392
3.25k
    }
393
3.25k
    if (ret == 0) {
394
        /* Make a key pair from the random.
395
         * Step 6. run internal key generation algorithm
396
         * Step 7. public and private key are stored in key
397
         */
398
3.25k
        ret = wc_KyberKey_MakeKeyWithRandom(key, rand, sizeof(rand));
399
3.25k
    }
400
401
    /* Ensure seeds are zeroized. */
402
3.25k
    ForceZero((void*)rand, (word32)sizeof(rand));
403
404
    /* Step 4: return ret != 0 on falsum or internal key generation failure. */
405
3.25k
    return ret;
406
#else
407
    (void)key;
408
    (void)rng;
409
    return NOT_COMPILED_IN;
410
#endif /* WC_NO_RNG */
411
3.25k
}
412
413
/**
414
 * Make a Kyber key object using random data.
415
 *
416
 * FIPS 203 - Algorithm 16: ML-KEM.KeyGen_internal(d,z)
417
 * Uses randomness to generate an encapsulation key and a corresponding
418
 * decapsulation key.
419
 *   1: (ek_PKE,dk_PKE) <- K-PKE.KeyGen(d)        > run key generation for K-PKE
420
 *   ...
421
 *
422
 * FIPS 203 - Algorithm 13: K-PKE.KeyGen(d)
423
 * Uses randomness to generate an encryption key and a corresponding decryption
424
 * key.
425
 *   1: (rho,sigma) <- G(d||k)
426
 *                         > expand 32+1 bytes to two pseudorandom 32-byte seeds
427
 *   2: N <- 0
428
 *   3-7: generate matrix A_hat
429
 *   8-11: generate s
430
 *   12-15: generate e
431
 *   16-18: calculate t_hat from A_hat, s and e
432
 *   ...
433
 *
434
 * @param  [in, out]  key   Kyber key object.
435
 * @param  [in]       rand  Random data.
436
 * @param  [in]       len   Length of random data in bytes.
437
 * @return  0 on success.
438
 * @return  BAD_FUNC_ARG when key or rand is NULL.
439
 * @return  BUFFER_E when length is not WC_ML_KEM_MAKEKEY_RAND_SZ.
440
 * @return  NOT_COMPILED_IN when key type is not supported.
441
 * @return  MEMORY_E when dynamic memory allocation failed.
442
 */
443
int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand,
444
    int len)
445
3.25k
{
446
3.25k
    byte buf[2 * WC_ML_KEM_SYM_SZ + 1];
447
3.25k
    byte* rho = buf;
448
3.25k
#ifndef WC_MLKEM_FAULT_HARDEN
449
3.25k
    byte* sigma = buf + WC_ML_KEM_SYM_SZ;
450
#else
451
    byte sigma[WC_ML_KEM_SYM_SZ + 1];
452
#endif
453
3.25k
#ifndef WOLFSSL_NO_MALLOC
454
3.25k
    sword16* e = NULL;
455
#else
456
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
457
#ifndef WOLFSSL_MLKEM_CACHE_A
458
    sword16 e[(WC_ML_KEM_MAX_K + 1) * WC_ML_KEM_MAX_K * MLKEM_N];
459
#else
460
    sword16 e[WC_ML_KEM_MAX_K * MLKEM_N];
461
#endif
462
#else
463
    sword16 e[WC_ML_KEM_MAX_K * MLKEM_N];
464
#endif
465
#endif
466
3.25k
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
467
3.25k
    sword16* a = NULL;
468
3.25k
#endif
469
3.25k
    sword16* s = NULL;
470
3.25k
    sword16* t = NULL;
471
3.25k
    int ret = 0;
472
3.25k
    int k = 0;
473
474
    /* Validate parameters. */
475
3.25k
    if ((key == NULL) || (rand == NULL)) {
476
0
        ret = BAD_FUNC_ARG;
477
0
    }
478
3.25k
    if ((ret == 0) && (len != WC_ML_KEM_MAKEKEY_RAND_SZ)) {
479
0
        ret = BUFFER_E;
480
0
    }
481
482
3.25k
    if (ret == 0) {
483
3.25k
        key->flags = 0;
484
485
        /* Establish parameters based on key type. */
486
3.25k
        switch (key->type) {
487
0
#ifndef WOLFSSL_NO_ML_KEM
488
0
    #ifdef WOLFSSL_WC_ML_KEM_512
489
0
        case WC_ML_KEM_512:
490
0
            k = WC_ML_KEM_512_K;
491
0
            break;
492
0
    #endif
493
0
    #ifdef WOLFSSL_WC_ML_KEM_768
494
3.22k
        case WC_ML_KEM_768:
495
3.22k
            k = WC_ML_KEM_768_K;
496
3.22k
            break;
497
0
    #endif
498
0
    #ifdef WOLFSSL_WC_ML_KEM_1024
499
34
        case WC_ML_KEM_1024:
500
34
            k = WC_ML_KEM_1024_K;
501
34
            break;
502
0
    #endif
503
0
#endif
504
#ifdef WOLFSSL_MLKEM_KYBER
505
    #ifdef WOLFSSL_KYBER512
506
        case KYBER512:
507
            k = KYBER512_K;
508
            break;
509
    #endif
510
    #ifdef WOLFSSL_KYBER768
511
        case KYBER768:
512
            k = KYBER768_K;
513
            break;
514
    #endif
515
    #ifdef WOLFSSL_KYBER1024
516
        case KYBER1024:
517
            k = KYBER1024_K;
518
            break;
519
    #endif
520
#endif
521
0
        default:
522
            /* No other values supported. */
523
0
            ret = NOT_COMPILED_IN;
524
0
            break;
525
3.25k
        }
526
3.25k
    }
527
528
3.25k
#ifndef WOLFSSL_NO_MALLOC
529
3.25k
    if (ret == 0) {
530
        /* Allocate dynamic memory for matrix and error vector. */
531
3.25k
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
532
3.25k
#ifndef WOLFSSL_MLKEM_CACHE_A
533
        /* e (v) | a (m) */
534
3.25k
        e = (sword16*)XMALLOC((size_t)((k + 1) * k * MLKEM_N) * sizeof(sword16),
535
3.25k
            key->heap, DYNAMIC_TYPE_TMP_BUFFER);
536
#else
537
        /* e (v) */
538
        e = (sword16*)XMALLOC((size_t)(k * MLKEM_N) * sizeof(sword16),
539
            key->heap, DYNAMIC_TYPE_TMP_BUFFER);
540
#endif
541
#else
542
        /* e (v) */
543
        e = (sword16*)XMALLOC((size_t)(k * MLKEM_N) * sizeof(sword16),
544
            key->heap, DYNAMIC_TYPE_TMP_BUFFER);
545
#endif
546
3.25k
        if (e == NULL) {
547
4
            ret = MEMORY_E;
548
4
        }
549
3.25k
    }
550
3.25k
#endif
551
3.25k
    if (ret == 0) {
552
3.25k
        const byte* d = rand;
553
554
#ifdef WOLFSSL_MLKEM_CACHE_A
555
        a = key->a;
556
#elif !defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM)
557
        /* Matrix A allocated at end of error vector. */
558
3.25k
        a = e + (k * MLKEM_N);
559
3.25k
#endif
560
561
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
562
        if (key->type & MLKEM_KYBER)
563
#endif
564
#ifdef WOLFSSL_MLKEM_KYBER
565
        {
566
            /* Expand 32 bytes of random to 64. */
567
            ret = MLKEM_HASH_G(&key->hash, d, WC_ML_KEM_SYM_SZ, NULL, 0, buf);
568
        }
569
#endif
570
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
571
        else
572
#endif
573
3.25k
#ifndef WOLFSSL_NO_ML_KEM
574
3.25k
        {
575
3.25k
            buf[0] = (byte)k;
576
            /* Expand 33 bytes of random to 64.
577
             * Alg 13: Step 1: (rho,sigma) <- G(d||k)
578
             */
579
3.25k
            ret = MLKEM_HASH_G(&key->hash, d, WC_ML_KEM_SYM_SZ, buf, 1, buf);
580
3.25k
        }
581
3.25k
#endif
582
3.25k
    }
583
#ifdef WC_MLKEM_FAULT_HARDEN
584
    if (ret == 0) {
585
        XMEMCPY(sigma, buf + WC_ML_KEM_SYM_SZ, WC_ML_KEM_SYM_SZ);
586
        /* Check that correct data was copied and pointer not changed. */
587
        if (XMEMCMP(sigma, rho, WC_ML_KEM_SYM_SZ) == 0) {
588
            ret = BAD_COND_E;
589
        }
590
        /* Check that rho is sigma - rho may have been modified. */
591
        if (XMEMCMP(sigma, rho + WC_ML_KEM_SYM_SZ, WC_ML_KEM_SYM_SZ) != 0) {
592
            ret = BAD_COND_E;
593
        }
594
    }
595
#endif
596
3.25k
    if (ret == 0) {
597
3.25k
        const byte* z = rand + WC_ML_KEM_SYM_SZ;
598
3.25k
        s = key->priv;
599
3.25k
        t = key->pub;
600
601
        /* Cache the public seed for use in encapsulation and encoding public
602
         * key. */
603
3.25k
        XMEMCPY(key->pubSeed, rho, WC_ML_KEM_SYM_SZ);
604
        /* Cache the z value for decapsulation and encoding private key. */
605
3.25k
        XMEMCPY(key->z, z, sizeof(key->z));
606
607
        /* Initialize PRF for use in noise generation. */
608
3.25k
        mlkem_prf_init(&key->prf);
609
3.25k
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
610
        /* Generate noise using PRF.
611
         * Alg 13: Steps 8-15: generate s and e
612
         */
613
3.25k
        ret = mlkem_get_noise(&key->prf, k, s, e, NULL, sigma);
614
3.25k
    }
615
3.25k
    if (ret == 0) {
616
        /* Generate the matrix A.
617
         * Alg 13: Steps 3-7
618
         */
619
3.25k
        ret = mlkem_gen_matrix(&key->prf, a, k, rho, 0);
620
3.25k
    }
621
3.25k
    if (ret == 0) {
622
        /* Generate key pair from random data.
623
         * Alg 13: Steps 16-18.
624
         */
625
3.25k
        mlkem_keygen(s, t, e, a, k);
626
#else
627
        /* Generate noise using PRF.
628
         * Alg 13: Steps 8-11: generate s
629
         */
630
        ret = mlkem_get_noise(&key->prf, k, s, NULL, NULL, sigma);
631
    }
632
    if (ret == 0) {
633
        /* Generate key pair from private vector and seeds.
634
         * Alg 13: Steps 3-7: generate matrix A_hat
635
         * Alg 13: Steps 12-15: generate e
636
         * Alg 13: Steps 16-18: calculate t_hat from A_hat, s and e
637
         */
638
        ret = mlkem_keygen_seeds(s, t, &key->prf, e, k, rho, sigma);
639
    }
640
    if (ret == 0) {
641
#endif
642
        /* Private and public key are set/available. */
643
3.25k
        key->flags |= MLKEM_FLAG_PRIV_SET | MLKEM_FLAG_PUB_SET;
644
#ifdef WOLFSSL_MLKEM_CACHE_A
645
        key->flags |= MLKEM_FLAG_A_SET;
646
#endif
647
3.25k
    }
648
649
3.25k
#ifndef WOLFSSL_NO_MALLOC
650
    /* Free dynamic memory allocated in function. */
651
3.25k
    if (key != NULL) {
652
3.25k
        XFREE(e, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
653
3.25k
    }
654
3.25k
#endif
655
656
3.25k
    return ret;
657
3.25k
}
658
#endif /* !WOLFSSL_MLKEM_NO_MAKE_KEY */
659
660
/******************************************************************************/
661
662
/**
663
 * Get the size in bytes of cipher text for key.
664
 *
665
 * @param  [in]   key  Kyber key object.
666
 * @param  [out]  len  Length of cipher text in bytes.
667
 * @return  0 on success.
668
 * @return  BAD_FUNC_ARG when key or len is NULL.
669
 * @return  NOT_COMPILED_IN when key type is not supported.
670
 */
671
int wc_MlKemKey_CipherTextSize(MlKemKey* key, word32* len)
672
0
{
673
0
    int ret = 0;
674
675
    /* Validate parameters. */
676
0
    if ((key == NULL) || (len == NULL)) {
677
0
        ret = BAD_FUNC_ARG;
678
0
    }
679
680
0
    if (ret == 0) {
681
        /* Return in 'len' size of the cipher text for the type of this key. */
682
0
        switch (key->type) {
683
0
#ifndef WOLFSSL_NO_ML_KEM
684
0
    #ifdef WOLFSSL_WC_ML_KEM_512
685
0
        case WC_ML_KEM_512:
686
0
            *len = WC_ML_KEM_512_CIPHER_TEXT_SIZE;
687
0
            break;
688
0
    #endif
689
0
    #ifdef WOLFSSL_WC_ML_KEM_768
690
0
        case WC_ML_KEM_768:
691
0
            *len = WC_ML_KEM_768_CIPHER_TEXT_SIZE;
692
0
            break;
693
0
    #endif
694
0
    #ifdef WOLFSSL_WC_ML_KEM_1024
695
0
        case WC_ML_KEM_1024:
696
0
            *len = WC_ML_KEM_1024_CIPHER_TEXT_SIZE;
697
0
            break;
698
0
    #endif
699
0
#endif
700
#ifdef WOLFSSL_MLKEM_KYBER
701
    #ifdef WOLFSSL_KYBER512
702
        case KYBER512:
703
            *len = KYBER512_CIPHER_TEXT_SIZE;
704
            break;
705
    #endif
706
    #ifdef WOLFSSL_KYBER768
707
        case KYBER768:
708
            *len = KYBER768_CIPHER_TEXT_SIZE;
709
            break;
710
    #endif
711
    #ifdef WOLFSSL_KYBER1024
712
        case KYBER1024:
713
            *len = KYBER1024_CIPHER_TEXT_SIZE;
714
            break;
715
    #endif
716
#endif
717
0
        default:
718
            /* No other values supported. */
719
0
            ret = NOT_COMPILED_IN;
720
0
            break;
721
0
        }
722
0
    }
723
724
0
    return ret;
725
0
}
726
727
/**
728
 * Size of a shared secret in bytes. Always KYBER_SS_SZ.
729
 *
730
 * @param  [in]   key  Kyber key object. Not used.
731
 * @param  [out]  len  Size of the shared secret created with a Kyber key.
732
 * @return  0 on success.
733
 * @return  BAD_FUNC_ARG when len is NULL.
734
 */
735
int wc_MlKemKey_SharedSecretSize(MlKemKey* key, word32* len)
736
0
{
737
0
    int ret = 0;
738
739
0
    if (len == NULL) {
740
0
        ret = BAD_FUNC_ARG;
741
0
    }
742
0
    else {
743
0
        *len = WC_ML_KEM_SS_SZ;
744
0
    }
745
746
0
    (void)key;
747
0
    return ret;
748
0
}
749
750
#if !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \
751
    !defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
752
/* Encapsulate data and derive secret.
753
 *
754
 * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE, m, r)
755
 * Uses the encryption key to encrypt a plaintext message using the randomness
756
 * r.
757
 *   1: N <- 0
758
 *   2: t_hat <- ByteDecode_12(ek_PKE[0:384k])
759
 *                                   > run ByteDecode_12 k times to decode t_hat
760
 *   3: rho <- ek_PKE[384k : 384k + 32]
761
 *                                            > extract 32-byte seed from ek_PKE
762
 *   4-8: generate matrix A_hat
763
 *   9-12: generate y
764
 *   13-16: generate e_1
765
 *   17: generate e_2
766
 *   18-19: calculate u
767
 *   20: mu <- Decompress_1(ByteDecode_1(m))
768
 *   21: calculate v
769
 *   22: c_1 <- ByteEncode_d_u(Compress_d_u(u))
770
 *                                 > run ByteEncode_d_u and Compress_d_u k times
771
 *   23: c_2 <- ByteEncode_d_v(Compress_d_v(v))
772
 *   24: return c <- (c_1||c_2)
773
 *
774
 * @param  [in]  key  Kyber key object.
775
 * @param  [in]  m    Random bytes.
776
 * @param  [in]  r    Seed to feed to PRF when generating y, e1 and e2.
777
 * @param  [out] c    Calculated cipher text.
778
 * @return  0 on success.
779
 * @return  NOT_COMPILED_IN when key type is not supported.
780
 */
781
static int mlkemkey_encapsulate(MlKemKey* key, const byte* m, byte* r, byte* c)
782
0
{
783
0
    int ret = 0;
784
0
    sword16* a = NULL;
785
0
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
786
0
    sword16* mu = NULL;
787
0
    sword16* e1 = NULL;
788
0
    sword16* e2 = NULL;
789
0
#endif
790
0
    unsigned int k = 0;
791
0
    unsigned int compVecSz = 0;
792
0
#ifndef WOLFSSL_NO_MALLOC
793
0
    sword16* y = NULL;
794
#else
795
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
796
    sword16 y[((WC_ML_KEM_MAX_K + 3) * WC_ML_KEM_MAX_K + 3) * MLKEM_N];
797
#else
798
    sword16 y[3 * WC_ML_KEM_MAX_K * MLKEM_N];
799
#endif
800
#endif
801
0
    sword16* u = 0;
802
0
    sword16* v = 0;
803
804
    /* Establish parameters based on key type. */
805
0
    switch (key->type) {
806
0
#ifndef WOLFSSL_NO_ML_KEM
807
0
#ifdef WOLFSSL_WC_ML_KEM_512
808
0
    case WC_ML_KEM_512:
809
0
        k = WC_ML_KEM_512_K;
810
0
        compVecSz = WC_ML_KEM_512_POLY_VEC_COMPRESSED_SZ;
811
0
        break;
812
0
#endif
813
0
#ifdef WOLFSSL_WC_ML_KEM_768
814
0
    case WC_ML_KEM_768:
815
0
        k = WC_ML_KEM_768_K;
816
0
        compVecSz = WC_ML_KEM_768_POLY_VEC_COMPRESSED_SZ;
817
0
        break;
818
0
#endif
819
0
#ifdef WOLFSSL_WC_ML_KEM_1024
820
0
    case WC_ML_KEM_1024:
821
0
        k = WC_ML_KEM_1024_K;
822
0
        compVecSz = WC_ML_KEM_1024_POLY_VEC_COMPRESSED_SZ;
823
0
        break;
824
0
#endif
825
0
#endif
826
#ifdef WOLFSSL_MLKEM_KYBER
827
#ifdef WOLFSSL_KYBER512
828
    case KYBER512:
829
        k = KYBER512_K;
830
        compVecSz = KYBER512_POLY_VEC_COMPRESSED_SZ;
831
        break;
832
#endif
833
#ifdef WOLFSSL_KYBER768
834
    case KYBER768:
835
        k = KYBER768_K;
836
        compVecSz = KYBER768_POLY_VEC_COMPRESSED_SZ;
837
        break;
838
#endif
839
#ifdef WOLFSSL_KYBER1024
840
    case KYBER1024:
841
        k = KYBER1024_K;
842
        compVecSz = KYBER1024_POLY_VEC_COMPRESSED_SZ;
843
        break;
844
#endif
845
#endif
846
0
    default:
847
        /* No other values supported. */
848
0
        ret = NOT_COMPILED_IN;
849
0
        break;
850
0
    }
851
852
0
#ifndef WOLFSSL_NO_MALLOC
853
0
    if (ret == 0) {
854
        /* Allocate dynamic memory for all matrices, vectors and polynomials. */
855
0
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
856
0
        y = (sword16*)XMALLOC(((k + 3) * k + 3) * MLKEM_N * sizeof(sword16),
857
0
            key->heap, DYNAMIC_TYPE_TMP_BUFFER);
858
#else
859
        y = (sword16*)XMALLOC(3 * k * MLKEM_N * sizeof(sword16), key->heap,
860
            DYNAMIC_TYPE_TMP_BUFFER);
861
#endif
862
0
        if (y == NULL) {
863
0
            ret = MEMORY_E;
864
0
        }
865
0
    }
866
0
#endif
867
868
0
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
869
0
    if (ret == 0) {
870
        /* Assign allocated dynamic memory to pointers.
871
         * y (b) | a (m) | mu (p) | e1 (p) | e2 (v) | u (v) | v (p) */
872
0
        a  = y  + MLKEM_N * k;
873
0
        mu = a  + MLKEM_N * k * k;
874
0
        e1 = mu + MLKEM_N;
875
0
        e2 = e1 + MLKEM_N * k;
876
877
        /* Convert msg to a polynomial.
878
         * Step 20: mu <- Decompress_1(ByteDecode_1(m)) */
879
0
        mlkem_from_msg(mu, m);
880
881
        /* Initialize the PRF for use in the noise generation. */
882
0
        mlkem_prf_init(&key->prf);
883
        /* Generate noise using PRF.
884
         * Steps 9-17: generate y, e_1, e_2
885
         */
886
0
        ret = mlkem_get_noise(&key->prf, (int)k, y, e1, e2, r);
887
0
    }
888
    #ifdef WOLFSSL_MLKEM_CACHE_A
889
    if ((ret == 0) && ((key->flags & MLKEM_FLAG_A_SET) != 0)) {
890
        unsigned int i;
891
        /* Transpose matrix.
892
         *   Steps 4-8: generate matrix A_hat (from original) */
893
        for (i = 0; i < k; i++) {
894
            unsigned int j;
895
            for (j = 0; j < k; j++) {
896
                XMEMCPY(&a[(i * k + j) * MLKEM_N],
897
                        &key->a[(j * k + i) * MLKEM_N],
898
                        MLKEM_N * 2);
899
            }
900
        }
901
    }
902
    else
903
    #endif /* WOLFSSL_MLKEM_CACHE_A */
904
0
    if (ret == 0) {
905
        /* Generate the transposed matrix.
906
         *   Step 4-8: generate matrix A_hat */
907
0
        ret = mlkem_gen_matrix(&key->prf, a, (int)k, key->pubSeed, 1);
908
0
    }
909
0
    if (ret == 0) {
910
        /* Assign remaining allocated dynamic memory to pointers.
911
         * y (b) | a (m) | mu (p) | e1 (p) | e2 (v) | u (v) | v (p) */
912
0
        u  = e2 + MLKEM_N;
913
0
        v  = u  + MLKEM_N * k;
914
915
        /* Perform encapsulation maths.
916
         *   Steps 18-19, 21: calculate u and v */
917
0
        mlkem_encapsulate(key->pub, u, v, a, y, e1, e2, mu, (int)k);
918
0
    }
919
#else /* WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM */
920
    if (ret == 0) {
921
        /* Assign allocated dynamic memory to pointers.
922
         * y (v) | a (v) | u (v) */
923
        a = y + MLKEM_N * k;
924
925
        /* Initialize the PRF for use in the noise generation. */
926
        mlkem_prf_init(&key->prf);
927
        /* Generate noise using PRF.
928
         * Steps 9-12: generate y */
929
        ret = mlkem_get_noise(&key->prf, (int)k, y, NULL, NULL, r);
930
    }
931
    if (ret == 0) {
932
        /* Assign remaining allocated dynamic memory to pointers.
933
         * y (v) | at (v) | u (v) */
934
        u  = a + MLKEM_N * k;
935
        v  = a;
936
937
        /* Perform encapsulation maths.
938
         *   Steps 13-17: generate e_1 and e_2
939
         *   Steps 18-19, 21: calculate u and v */
940
        ret = mlkem_encapsulate_seeds(key->pub, &key->prf, u, a, y, (int)k, m,
941
            key->pubSeed, r);
942
    }
943
#endif /* WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM */
944
945
0
    if (ret == 0) {
946
0
        byte* c1 = c;
947
0
        byte* c2 = c + compVecSz;
948
949
0
    #if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
950
0
        if (k == WC_ML_KEM_512_K) {
951
            /* Step 22: c_1 <- ByteEncode_d_u(Compress_d_u(u)) */
952
0
            mlkem_vec_compress_10(c1, u, k);
953
            /* Step 23: c_2 <- ByteEncode_d_v(Compress_d_v(v)) */
954
0
            mlkem_compress_4(c2, v);
955
            /* Step 24: return c <- (c_1||c_2) */
956
0
        }
957
0
    #endif
958
0
    #if defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768)
959
0
        if (k == WC_ML_KEM_768_K) {
960
            /* Step 22: c_1 <- ByteEncode_d_u(Compress_d_u(u)) */
961
0
            mlkem_vec_compress_10(c1, u, k);
962
            /* Step 23: c_2 <- ByteEncode_d_v(Compress_d_v(v)) */
963
0
            mlkem_compress_4(c2, v);
964
            /* Step 24: return c <- (c_1||c_2) */
965
0
        }
966
0
    #endif
967
0
    #if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
968
0
        if (k == WC_ML_KEM_1024_K) {
969
            /* Step 22: c_1 <- ByteEncode_d_u(Compress_d_u(u)) */
970
0
            mlkem_vec_compress_11(c1, u);
971
            /* Step 23: c_2 <- ByteEncode_d_v(Compress_d_v(v)) */
972
0
            mlkem_compress_5(c2, v);
973
            /* Step 24: return c <- (c_1||c_2) */
974
0
        }
975
0
    #endif
976
0
    }
977
978
0
#ifndef WOLFSSL_NO_MALLOC
979
    /* Dispose of dynamic memory allocated in function. */
980
0
    XFREE(y, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
981
0
#endif
982
983
0
    return ret;
984
0
}
985
#endif
986
987
#if !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \
988
    !defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
989
static int wc_mlkemkey_check_h(MlKemKey* key)
990
0
{
991
0
    int ret = 0;
992
993
    /* If public hash (h) is not stored against key, calculate it
994
     * (fields set explicitly instead of using decode).
995
     * Step 1: ... H(ek)...
996
     */
997
0
    if ((key->flags & MLKEM_FLAG_H_SET) == 0) {
998
0
    #ifndef WOLFSSL_NO_MALLOC
999
0
        byte* pubKey = NULL;
1000
0
        word32 pubKeyLen;
1001
    #else
1002
        byte pubKey[WC_ML_KEM_MAX_PUBLIC_KEY_SIZE];
1003
        word32 pubKeyLen;
1004
    #endif
1005
1006
        /* Determine how big an encoded public key will be. */
1007
0
        ret = wc_KyberKey_PublicKeySize(key, &pubKeyLen);
1008
0
        if (ret == 0) {
1009
0
    #ifndef WOLFSSL_NO_MALLOC
1010
            /* Allocate dynamic memory for encoded public key. */
1011
0
            pubKey = (byte*)XMALLOC(pubKeyLen, key->heap,
1012
0
                DYNAMIC_TYPE_TMP_BUFFER);
1013
0
            if (pubKey == NULL) {
1014
0
                ret = MEMORY_E;
1015
0
            }
1016
0
        }
1017
0
        if (ret == 0) {
1018
0
    #endif
1019
            /* Encode public key - h is hash of encoded public key. */
1020
0
            ret = wc_KyberKey_EncodePublicKey(key, pubKey, pubKeyLen);
1021
0
        }
1022
0
    #ifndef WOLFSSL_NO_MALLOC
1023
        /* Dispose of encoded public key. */
1024
0
        XFREE(pubKey, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
1025
0
     #endif
1026
0
    }
1027
0
    if ((ret == 0) && ((key->flags & MLKEM_FLAG_H_SET) == 0)) {
1028
        /* Implementation issue if h not cached and flag set. */
1029
0
        ret = BAD_STATE_E;
1030
0
    }
1031
1032
0
    return ret;
1033
0
}
1034
#endif
1035
1036
#ifndef WOLFSSL_MLKEM_NO_ENCAPSULATE
1037
/**
1038
 * Encapsulate with random number generator and derive secret.
1039
 *
1040
 * FIPS 203, Algorithm 20: ML-KEM.Encaps(ek)
1041
 * Uses the encapsulation key to generate a shared secret key and an associated
1042
 * ciphertext.
1043
 *   1: m <- B_32                                         > m is 32 random bytes
1044
 *   2: if m == NULL then
1045
 *   3:     return falsum
1046
 *   4: end if
1047
 *   5: (K,c) <- ML-KEM.Encaps_internal(ek,m)
1048
 *                                        > run internal encapsulation algorithm
1049
 *   6: return (K,c)
1050
 *
1051
 * @param  [in]   key  Kyber key object.
1052
 * @param  [out]  c    Cipher text.
1053
 * @param  [out]  k    Shared secret generated.
1054
 * @param  [in]   rng  Random number generator.
1055
 * @return  0 on success.
1056
 * @return  BAD_FUNC_ARG when key, c, k or rng is NULL.
1057
 * @return  NOT_COMPILED_IN when key type is not supported.
1058
 * @return  MEMORY_E when dynamic memory allocation failed.
1059
 */
1060
int wc_MlKemKey_Encapsulate(MlKemKey* key, unsigned char* c, unsigned char* k,
1061
    WC_RNG* rng)
1062
0
{
1063
0
#ifndef WC_NO_RNG
1064
0
    int ret = 0;
1065
0
    unsigned char m[WC_ML_KEM_ENC_RAND_SZ];
1066
1067
    /* Validate parameters. */
1068
0
    if ((key == NULL) || (c == NULL) || (k == NULL) || (rng == NULL)) {
1069
0
        ret = BAD_FUNC_ARG;
1070
0
    }
1071
1072
0
    if (ret == 0) {
1073
        /* Generate seed for use with PRFs.
1074
         * Step 1: m is 32 random bytes
1075
         */
1076
0
        ret = wc_RNG_GenerateBlock(rng, m, sizeof(m));
1077
        /* Step 2: ret is not zero when m == NULL. */
1078
0
    }
1079
0
    if (ret == 0) {
1080
        /* Encapsulate with the random.
1081
         * Step 5: run internal encapsulation algorithm
1082
         */
1083
0
        ret = wc_KyberKey_EncapsulateWithRandom(key, c, k, m, sizeof(m));
1084
0
    }
1085
1086
    /* Step 3: return ret != 0 on falsum or internal key generation failure. */
1087
0
    return ret;
1088
#else
1089
    (void)key;
1090
    (void)c;
1091
    (void)k;
1092
    (void)rng;
1093
    return NOT_COMPILED_IN;
1094
#endif /* WC_NO_RNG */
1095
0
}
1096
1097
/**
1098
 * Encapsulate with random data and derive secret.
1099
 *
1100
 * FIPS 203, Algorithm 17: ML-KEM.Encaps_internal(ek, m)
1101
 * Uses the encapsulation key and randomness to generate a key and an associated
1102
 * ciphertext.
1103
 *   Step 1: (K,r) <- G(m||H(ek))
1104
 *                                 > derive shared secret key K and randomness r
1105
 *   Step 2: c <- K-PKE.Encrypt(ek, m, r)
1106
 *                                     > encrypt m using K-PKE with randomness r
1107
 *   Step 3: return (K,c)
1108
 *
1109
 * @param  [out]  c    Cipher text.
1110
 * @param  [out]  k    Shared secret generated.
1111
 * @param  [in]   m    Random bytes.
1112
 * @param  [in]   len  Length of random bytes.
1113
 * @return  0 on success.
1114
 * @return  BAD_FUNC_ARG when key, c, k or m is NULL.
1115
 * @return  BUFFER_E when len is not WC_ML_KEM_ENC_RAND_SZ.
1116
 * @return  NOT_COMPILED_IN when key type is not supported.
1117
 * @return  MEMORY_E when dynamic memory allocation failed.
1118
 */
1119
int wc_MlKemKey_EncapsulateWithRandom(MlKemKey* key, unsigned char* c,
1120
    unsigned char* k, const unsigned char* m, int len)
1121
0
{
1122
#ifdef WOLFSSL_MLKEM_KYBER
1123
    byte msg[KYBER_SYM_SZ];
1124
#endif
1125
0
    byte kr[2 * KYBER_SYM_SZ + 1];
1126
0
    int ret = 0;
1127
#ifdef WOLFSSL_MLKEM_KYBER
1128
    unsigned int cSz = 0;
1129
#endif
1130
1131
    /* Validate parameters. */
1132
0
    if ((key == NULL) || (c == NULL) || (k == NULL) || (m == NULL)) {
1133
0
        ret = BAD_FUNC_ARG;
1134
0
    }
1135
0
    if ((ret == 0) && (len != WC_ML_KEM_ENC_RAND_SZ)) {
1136
0
        ret = BUFFER_E;
1137
0
    }
1138
1139
#ifdef WOLFSSL_MLKEM_KYBER
1140
    if (ret == 0) {
1141
        /* Establish parameters based on key type. */
1142
        switch (key->type) {
1143
#ifndef WOLFSSL_NO_ML_KEM
1144
    #ifdef WOLFSSL_WC_ML_KEM_512
1145
        case WC_ML_KEM_512:
1146
    #endif
1147
    #ifdef WOLFSSL_WC_ML_KEM_768
1148
        case WC_ML_KEM_768:
1149
    #endif
1150
    #ifdef WOLFSSL_WC_ML_KEM_1024
1151
        case WC_ML_KEM_1024:
1152
    #endif
1153
            break;
1154
#endif
1155
    #ifdef WOLFSSL_KYBER512
1156
        case KYBER512:
1157
            cSz = KYBER512_CIPHER_TEXT_SIZE;
1158
            break;
1159
    #endif
1160
    #ifdef WOLFSSL_KYBER768
1161
        case KYBER768:
1162
            cSz = KYBER768_CIPHER_TEXT_SIZE;
1163
            break;
1164
    #endif
1165
    #ifdef WOLFSSL_KYBER1024
1166
        case KYBER1024:
1167
            cSz = KYBER1024_CIPHER_TEXT_SIZE;
1168
            break;
1169
    #endif
1170
        default:
1171
            /* No other values supported. */
1172
            ret = NOT_COMPILED_IN;
1173
            break;
1174
        }
1175
    }
1176
#endif
1177
1178
0
    if (ret == 0) {
1179
0
        ret = wc_mlkemkey_check_h(key);
1180
0
    }
1181
1182
#ifdef WOLFSSL_MLKEM_KYBER
1183
    if (ret == 0) {
1184
#ifndef WOLFSSL_NO_ML_KEM
1185
        if (key->type & MLKEM_KYBER)
1186
#endif
1187
        {
1188
            /* Hash random to anonymize as seed data. */
1189
            ret = MLKEM_HASH_H(&key->hash, m, WC_ML_KEM_SYM_SZ, msg);
1190
        }
1191
    }
1192
#endif
1193
0
    if (ret == 0) {
1194
        /* Hash message into seed buffer. */
1195
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
1196
        if (key->type & MLKEM_KYBER)
1197
#endif
1198
#ifdef WOLFSSL_MLKEM_KYBER
1199
        {
1200
            ret = MLKEM_HASH_G(&key->hash, msg, WC_ML_KEM_SYM_SZ, key->h,
1201
                WC_ML_KEM_SYM_SZ, kr);
1202
        }
1203
#endif
1204
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
1205
        else
1206
#endif
1207
0
#ifndef WOLFSSL_NO_ML_KEM
1208
0
        {
1209
            /* Step 1: (K,r) <- G(m||H(ek)) */
1210
0
            ret = MLKEM_HASH_G(&key->hash, m, WC_ML_KEM_SYM_SZ, key->h,
1211
0
                WC_ML_KEM_SYM_SZ, kr);
1212
0
        }
1213
0
#endif
1214
0
    }
1215
1216
0
    if (ret == 0) {
1217
        /* Encapsulate the message using the key and the seed. */
1218
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
1219
        if (key->type & MLKEM_KYBER)
1220
#endif
1221
#ifdef WOLFSSL_MLKEM_KYBER
1222
        {
1223
            ret = mlkemkey_encapsulate(key, msg, kr + WC_ML_KEM_SYM_SZ, c);
1224
        }
1225
#endif
1226
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
1227
        else
1228
#endif
1229
0
#ifndef WOLFSSL_NO_ML_KEM
1230
0
        {
1231
            /* Step 2: c <- K-PKE.Encrypt(ek,m,r) */
1232
0
            ret = mlkemkey_encapsulate(key, m, kr + WC_ML_KEM_SYM_SZ, c);
1233
0
        }
1234
0
#endif
1235
0
    }
1236
1237
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
1238
    if (key->type & MLKEM_KYBER)
1239
#endif
1240
#ifdef WOLFSSL_MLKEM_KYBER
1241
    {
1242
        if (ret == 0) {
1243
            /* Hash the cipher text after the seed. */
1244
            ret = MLKEM_HASH_H(&key->hash, c, cSz, kr + WC_ML_KEM_SYM_SZ);
1245
        }
1246
        if (ret == 0) {
1247
            /* Derive the secret from the seed and hash of cipher text. */
1248
            ret = MLKEM_KDF(kr, 2 * WC_ML_KEM_SYM_SZ, k, WC_ML_KEM_SS_SZ);
1249
        }
1250
    }
1251
#endif
1252
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
1253
    else
1254
#endif
1255
0
#ifndef WOLFSSL_NO_ML_KEM
1256
0
    {
1257
0
        if (ret == 0) {
1258
            /* return (K,c) */
1259
0
            XMEMCPY(k, kr, WC_ML_KEM_SS_SZ);
1260
0
        }
1261
0
    }
1262
0
#endif
1263
1264
0
    ForceZero(kr, sizeof(kr));
1265
1266
0
    return ret;
1267
0
}
1268
#endif /* !WOLFSSL_MLKEM_NO_ENCAPSULATE */
1269
1270
/******************************************************************************/
1271
1272
#ifndef WOLFSSL_MLKEM_NO_DECAPSULATE
1273
/* Decapsulate cipher text to the message using key.
1274
 *
1275
 * FIPS 203, Algorithm 15: K-PKE.Decrypt(dk_PKE,c)
1276
 * Uses the decryption key to decrypt a ciphertext.
1277
 *   1: c1 <- c[0 : 32.d_u.k]
1278
 *   2: c2 <- c[32.d_u.k : 32(d_u.k + d_v)]
1279
 *   3: u' <- Decompress_d_u(ByteDecode_d_u(c1))
1280
 *   4: v' <- Decompress_d_v(ByteDecode_d_v(c2))
1281
 *   ...
1282
 *   6: w <- v' - InvNTT(s_hat_trans o NTT(u'))
1283
 *   7: m <- ByteEncode_1(Compress_1(w))
1284
 *   8: return m
1285
 *
1286
 * @param  [in]   key  Kyber key object.
1287
 * @param  [out]  m    Message that was encapsulated.
1288
 * @param  [in]   c    Cipher text.
1289
 * @return  0 on success.
1290
 * @return  NOT_COMPILED_IN when key type is not supported.
1291
 * @return  MEMORY_E when dynamic memory allocation failed.
1292
 */
1293
static MLKEM_NOINLINE int mlkemkey_decapsulate(MlKemKey* key, byte* m,
1294
    const byte* c)
1295
0
{
1296
0
    int ret = 0;
1297
0
    sword16* v;
1298
0
    sword16* w;
1299
0
    unsigned int k = 0;
1300
0
    unsigned int compVecSz;
1301
0
#if defined(WOLFSSL_SMALL_STACK) || \
1302
0
    (!defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC))
1303
0
    sword16* u = NULL;
1304
#else
1305
    sword16 u[(WC_ML_KEM_MAX_K + 1) * MLKEM_N];
1306
#endif
1307
1308
    /* Establish parameters based on key type. */
1309
0
    switch (key->type) {
1310
0
#ifndef WOLFSSL_NO_ML_KEM
1311
0
#ifdef WOLFSSL_WC_ML_KEM_512
1312
0
    case WC_ML_KEM_512:
1313
0
        k = WC_ML_KEM_512_K;
1314
0
        compVecSz = WC_ML_KEM_512_POLY_VEC_COMPRESSED_SZ;
1315
0
        break;
1316
0
#endif
1317
0
#ifdef WOLFSSL_WC_ML_KEM_768
1318
0
    case WC_ML_KEM_768:
1319
0
        k = WC_ML_KEM_768_K;
1320
0
        compVecSz = WC_ML_KEM_768_POLY_VEC_COMPRESSED_SZ;
1321
0
        break;
1322
0
#endif
1323
0
#ifdef WOLFSSL_WC_ML_KEM_1024
1324
0
    case WC_ML_KEM_1024:
1325
0
        k = WC_ML_KEM_1024_K;
1326
0
        compVecSz = WC_ML_KEM_1024_POLY_VEC_COMPRESSED_SZ;
1327
0
        break;
1328
0
#endif
1329
0
#endif
1330
#ifdef WOLFSSL_MLKEM_KYBER
1331
#ifdef WOLFSSL_KYBER512
1332
    case KYBER512:
1333
        k = KYBER512_K;
1334
        compVecSz = KYBER512_POLY_VEC_COMPRESSED_SZ;
1335
        break;
1336
#endif
1337
#ifdef WOLFSSL_KYBER768
1338
    case KYBER768:
1339
        k = KYBER768_K;
1340
        compVecSz = KYBER768_POLY_VEC_COMPRESSED_SZ;
1341
        break;
1342
#endif
1343
#ifdef WOLFSSL_KYBER1024
1344
    case KYBER1024:
1345
        k = KYBER1024_K;
1346
        compVecSz = KYBER1024_POLY_VEC_COMPRESSED_SZ;
1347
        break;
1348
#endif
1349
#endif
1350
0
    default:
1351
        /* No other values supported. */
1352
0
        ret = NOT_COMPILED_IN;
1353
0
        break;
1354
0
    }
1355
1356
0
#if defined(WOLFSSL_SMALL_STACK) || \
1357
0
    (!defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC))
1358
0
    if (ret == 0) {
1359
        /* Allocate dynamic memory for a vector and a polynomial. */
1360
0
        u = (sword16*)XMALLOC((k + 1) * MLKEM_N * sizeof(sword16), key->heap,
1361
0
            DYNAMIC_TYPE_TMP_BUFFER);
1362
0
        if (u == NULL) {
1363
0
            ret = MEMORY_E;
1364
0
        }
1365
0
    }
1366
0
#endif
1367
0
    if (ret == 0) {
1368
        /* Step 1: c1 <- c[0 : 32.d_u.k] */
1369
0
        const byte* c1 = c;
1370
        /* Step 2: c2 <- c[32.d_u.k : 32(d_u.k + d_v)] */
1371
0
        const byte* c2 = c + compVecSz;
1372
1373
        /* Assign allocated dynamic memory to pointers.
1374
         * u (v) | v (p) */
1375
0
        v = u + k * MLKEM_N;
1376
0
        w = u;
1377
1378
0
    #if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
1379
0
        if (k == WC_ML_KEM_512_K) {
1380
            /* Step 3: u' <- Decompress_d_u(ByteDecode_d_u(c1)) */
1381
0
            mlkem_vec_decompress_10(u, c1, k);
1382
            /* Step 4: v' <- Decompress_d_v(ByteDecode_d_v(c2)) */
1383
0
            mlkem_decompress_4(v, c2);
1384
0
        }
1385
0
    #endif
1386
0
    #if defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768)
1387
0
        if (k == WC_ML_KEM_768_K) {
1388
            /* Step 3: u' <- Decompress_d_u(ByteDecode_d_u(c1)) */
1389
0
            mlkem_vec_decompress_10(u, c1, k);
1390
            /* Step 4: v' <- Decompress_d_v(ByteDecode_d_v(c2)) */
1391
0
            mlkem_decompress_4(v, c2);
1392
0
        }
1393
0
    #endif
1394
0
    #if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
1395
0
        if (k == WC_ML_KEM_1024_K) {
1396
            /* Step 3: u' <- Decompress_d_u(ByteDecode_d_u(c1)) */
1397
0
            mlkem_vec_decompress_11(u, c1);
1398
            /* Step 4: v' <- Decompress_d_v(ByteDecode_d_v(c2)) */
1399
0
            mlkem_decompress_5(v, c2);
1400
0
        }
1401
0
    #endif
1402
1403
        /* Decapsulate the cipher text into polynomial.
1404
         * Step 6: w <- v' - InvNTT(s_hat_trans o NTT(u')) */
1405
0
        mlkem_decapsulate(key->priv, w, u, v, (int)k);
1406
1407
        /* Convert the polynomial into a array of bytes (message).
1408
         * Step 7: m <- ByteEncode_1(Compress_1(w)) */
1409
0
        mlkem_to_msg(m, w);
1410
        /* Step 8: return m */
1411
0
    }
1412
1413
0
#if defined(WOLFSSL_SMALL_STACK) || \
1414
0
    (!defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC))
1415
    /* Dispose of dynamically memory allocated in function. */
1416
0
    XFREE(u, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
1417
0
#endif
1418
1419
0
    return ret;
1420
0
}
1421
1422
/**
1423
 * Decapsulate the cipher text to calculate the shared secret.
1424
 *
1425
 * Validates the cipher text by encapsulating and comparing with data passed in.
1426
 *
1427
 * FIPS 203, Algorithm 21: ML-KEM.Decaps(dk, c)
1428
 * Uses the decapsulation key to produce a shared secret key from a ciphertext.
1429
 *   1: K' <- ML-KEM.Decaps_internal(dk,c)
1430
 *                                        > run internal decapsulation algorithm
1431
 *   2: return K'
1432
 *
1433
 * FIPS 203, Algorithm 18: ML-KEM.Decaps_internal(dk, c)
1434
 * Uses the decapsulation key to produce a shared secret key from a ciphertext.
1435
 *   ...
1436
 *   1: dk_PKE <- dk[0 : 384k]
1437
 *                        > extract (from KEM decaps key) the PKE decryption key
1438
 *   2: ek_PKE <- dk[384k : 768k + 32]
1439
 *                                                  > extract PKE encryption key
1440
 *   3: h <- dk[768k + 32 : 768k + 64]
1441
 *                                          > extract hash of PKE encryption key
1442
 *   4: z <- dk[768k + 64 : 768k + 96]
1443
 *                                            > extract implicit rejection value
1444
 *   5: m' <- K-PKE.Decrypt(dk_PKE, c)                      > decrypt ciphertext
1445
 *   6: (K', r') <- G(m'||h)
1446
 *   7: K_bar <- J(z||c)
1447
 *   8: c' <- K-PKE.Encrypt(ek_PKE, m', r')
1448
 *                                  > re-encrypt using the derived randomness r'
1449
 *   9: if c != c' then
1450
 *  10:      K' <- K_bar
1451
 *                            > if ciphertexts do not match, "implicitly reject"
1452
 *  11: end if
1453
 *  12: return K'
1454
 *
1455
 * @param  [in]   key  Kyber key object.
1456
 * @param  [out]  ss   Shared secret.
1457
 * @param  [in]   ct   Cipher text.
1458
 * @param  [in]   len  Length of cipher text.
1459
 * @return  0 on success.
1460
 * @return  BAD_FUNC_ARG when key, ss or ct are NULL.
1461
 * @return  NOT_COMPILED_IN when key type is not supported.
1462
 * @return  BUFFER_E when len is not the length of cipher text for the key type.
1463
 * @return  MEMORY_E when dynamic memory allocation failed.
1464
 */
1465
int wc_MlKemKey_Decapsulate(MlKemKey* key, unsigned char* ss,
1466
    const unsigned char* ct, word32 len)
1467
0
{
1468
0
    byte msg[WC_ML_KEM_SYM_SZ];
1469
0
    byte kr[2 * WC_ML_KEM_SYM_SZ + 1];
1470
0
    int ret = 0;
1471
0
    unsigned int ctSz = 0;
1472
0
    unsigned int i = 0;
1473
0
    int fail = 0;
1474
0
#if !defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC)
1475
0
    byte* cmp = NULL;
1476
#else
1477
    byte cmp[WC_ML_KEM_MAX_CIPHER_TEXT_SIZE];
1478
#endif
1479
1480
    /* Validate parameters. */
1481
0
    if ((key == NULL) || (ss == NULL) || (ct == NULL)) {
1482
0
        ret = BAD_FUNC_ARG;
1483
0
    }
1484
1485
0
    if (ret == 0) {
1486
        /* Establish cipher text size based on key type. */
1487
0
        switch (key->type) {
1488
0
#ifndef WOLFSSL_NO_ML_KEM
1489
0
    #ifdef WOLFSSL_WC_ML_KEM_512
1490
0
        case WC_ML_KEM_512:
1491
0
            ctSz = WC_ML_KEM_512_CIPHER_TEXT_SIZE;
1492
0
            break;
1493
0
    #endif
1494
0
    #ifdef WOLFSSL_WC_ML_KEM_768
1495
0
        case WC_ML_KEM_768:
1496
0
            ctSz = WC_ML_KEM_768_CIPHER_TEXT_SIZE;
1497
0
            break;
1498
0
    #endif
1499
0
    #ifdef WOLFSSL_WC_ML_KEM_1024
1500
0
        case WC_ML_KEM_1024:
1501
0
            ctSz = WC_ML_KEM_1024_CIPHER_TEXT_SIZE;
1502
0
            break;
1503
0
    #endif
1504
0
#endif
1505
#ifdef WOLFSSL_MLKEM_KYBER
1506
    #ifdef WOLFSSL_KYBER512
1507
        case KYBER512:
1508
            ctSz = KYBER512_CIPHER_TEXT_SIZE;
1509
            break;
1510
    #endif
1511
    #ifdef WOLFSSL_KYBER768
1512
        case KYBER768:
1513
            ctSz = KYBER768_CIPHER_TEXT_SIZE;
1514
            break;
1515
    #endif
1516
    #ifdef WOLFSSL_KYBER1024
1517
        case KYBER1024:
1518
            ctSz = KYBER1024_CIPHER_TEXT_SIZE;
1519
            break;
1520
    #endif
1521
#endif
1522
0
        default:
1523
            /* No other values supported. */
1524
0
            ret = NOT_COMPILED_IN;
1525
0
            break;
1526
0
        }
1527
0
    }
1528
1529
    /* Ensure the cipher text passed in is the correct size. */
1530
0
    if ((ret == 0) && (len != ctSz)) {
1531
0
        ret = BUFFER_E;
1532
0
    }
1533
1534
0
#if !defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC)
1535
0
    if (ret == 0) {
1536
        /* Allocate memory for cipher text that is generated. */
1537
0
        cmp = (byte*)XMALLOC(ctSz, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
1538
0
        if (cmp == NULL) {
1539
0
            ret = MEMORY_E;
1540
0
        }
1541
0
    }
1542
0
#endif
1543
1544
0
    if (ret == 0) {
1545
        /* Decapsulate the cipher text. */
1546
0
        ret = mlkemkey_decapsulate(key, msg, ct);
1547
0
    }
1548
0
    if (ret == 0) {
1549
        /* Check we have H, hash of public, set. */
1550
0
        ret = wc_mlkemkey_check_h(key);
1551
0
    }
1552
0
    if (ret == 0) {
1553
        /* Hash message into seed buffer. */
1554
0
        ret = MLKEM_HASH_G(&key->hash, msg, WC_ML_KEM_SYM_SZ, key->h,
1555
0
            WC_ML_KEM_SYM_SZ, kr);
1556
0
    }
1557
0
    if (ret == 0) {
1558
        /* Encapsulate the message. */
1559
0
        ret = mlkemkey_encapsulate(key, msg, kr + WC_ML_KEM_SYM_SZ, cmp);
1560
0
    }
1561
0
    if (ret == 0) {
1562
        /* Compare generated cipher text with that passed in. */
1563
0
        fail = mlkem_cmp(ct, cmp, (int)ctSz);
1564
1565
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
1566
        if (key->type & MLKEM_KYBER)
1567
#endif
1568
#ifdef WOLFSSL_MLKEM_KYBER
1569
        {
1570
            /* Hash the cipher text after the seed. */
1571
            ret = MLKEM_HASH_H(&key->hash, ct, ctSz, kr + WC_ML_KEM_SYM_SZ);
1572
            if (ret == 0) {
1573
                /* Change seed to z on comparison failure. */
1574
                for (i = 0; i < WC_ML_KEM_SYM_SZ; i++) {
1575
                    kr[i] ^= (kr[i] ^ key->z[i]) & fail;
1576
                }
1577
1578
                /* Derive the secret from the seed and hash of cipher text. */
1579
                ret = MLKEM_KDF(kr, 2 * WC_ML_KEM_SYM_SZ, ss, WC_ML_KEM_SS_SZ);
1580
            }
1581
        }
1582
#endif
1583
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
1584
        else
1585
#endif
1586
0
#ifndef WOLFSSL_NO_ML_KEM
1587
0
        {
1588
0
            ret = mlkem_derive_secret(&key->prf, key->z, ct, ctSz, msg);
1589
0
            if (ret == 0) {
1590
               /* Set secret to kr or fake secret on comparison failure. */
1591
0
               for (i = 0; i < WC_ML_KEM_SYM_SZ; i++) {
1592
0
                   ss[i] = (byte)(kr[i] ^ ((kr[i] ^ msg[i]) & fail));
1593
0
               }
1594
0
            }
1595
0
        }
1596
0
#endif
1597
0
    }
1598
1599
0
#if !defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC)
1600
    /* Dispose of dynamic memory allocated in function. */
1601
0
    if (key != NULL) {
1602
0
        XFREE(cmp, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
1603
0
    }
1604
0
#endif
1605
1606
0
    ForceZero(msg, sizeof(msg));
1607
0
    ForceZero(kr, sizeof(kr));
1608
1609
0
    return ret;
1610
0
}
1611
#endif /* WOLFSSL_MLKEM_NO_DECAPSULATE */
1612
1613
/******************************************************************************/
1614
1615
/**
1616
 * Get the public key and public seed from bytes.
1617
 *
1618
 * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE, m, r)
1619
 *   ...
1620
 *   2: t <- ByteDecode_12(ek_PKE[0 : 384k])
1621
 *   3: rho <- ek_PKE[384k :  384k + 32]
1622
 *   ...
1623
 *
1624
 * @param [out] pub      Public key - vector.
1625
 * @param [out] pubSeed  Public seed.
1626
 * @param [in]  p        Public key data.
1627
 * @param [in]  k        Number of polynomials in vector.
1628
 */
1629
static void mlkemkey_decode_public(sword16* pub, byte* pubSeed, const byte* p,
1630
    unsigned int k)
1631
0
{
1632
0
    unsigned int i;
1633
1634
    /* Decode public key that is vector of polynomials.
1635
     * Step 2: t <- ByteDecode_12(ek_PKE[0 : 384k]) */
1636
0
    mlkem_from_bytes(pub, p, (int)k);
1637
0
    p += k * WC_ML_KEM_POLY_SIZE;
1638
1639
    /* Read public key seed.
1640
     * Step 3: rho <- ek_PKE[384k :  384k + 32] */
1641
0
    for (i = 0; i < WC_ML_KEM_SYM_SZ; i++) {
1642
0
        pubSeed[i] = p[i];
1643
0
    }
1644
0
}
1645
1646
/**
1647
 * Decode the private key.
1648
 *
1649
 * Private Vector | Public Key | Public Hash | Randomizer
1650
 *
1651
 * FIPS 203, Algorithm 18: ML-KEM.Decaps_internal(dk, c)
1652
 *   1: dk_PKE <- dk[0 : 384k]
1653
 *                        > extract (from KEM decaps key) the PKE decryption key
1654
 *   2: ek_PKE <- dk[384k : 768k + 32]
1655
 *                                                  > extract PKE encryption key
1656
 *   3: h <- dk[768k + 32 : 768k + 64]
1657
 *                                          > extract hash of PKE encryption key
1658
 *   4: z <- dk[768k + 64 : 768k + 96]
1659
 *                                            > extract implicit rejection value
1660
 *
1661
 * FIPS 203, Algorithm 15: K-PKE.Decrypt(dk_PKE, c)
1662
 *   ...
1663
 *   5: s_hat <- ByteDecode_12(dk_PKE)
1664
 *   ...
1665
 *
1666
 * @param  [in, out]  key  Kyber key object.
1667
 * @param  [in]       in   Buffer holding encoded key.
1668
 * @param  [in]       len  Length of data in buffer.
1669
 * @return  0 on success.
1670
 * @return  BAD_FUNC_ARG when key or in is NULL.
1671
 * @return  NOT_COMPILED_IN when key type is not supported.
1672
 * @return  BUFFER_E when len is not the correct size.
1673
 */
1674
int wc_MlKemKey_DecodePrivateKey(MlKemKey* key, const unsigned char* in,
1675
    word32 len)
1676
0
{
1677
0
    int ret = 0;
1678
0
    word32 privLen = 0;
1679
0
    word32 pubLen = 0;
1680
0
    unsigned int k = 0;
1681
0
    const unsigned char* p = in;
1682
1683
    /* Validate parameters. */
1684
0
    if ((key == NULL) || (in == NULL)) {
1685
0
        ret = BAD_FUNC_ARG;
1686
0
    }
1687
1688
0
    if (ret == 0) {
1689
        /* Establish parameters based on key type. */
1690
0
        switch (key->type) {
1691
0
#ifndef WOLFSSL_NO_ML_KEM
1692
0
    #ifdef WOLFSSL_WC_ML_KEM_512
1693
0
        case WC_ML_KEM_512:
1694
0
            k = WC_ML_KEM_512_K;
1695
0
            privLen = WC_ML_KEM_512_PRIVATE_KEY_SIZE;
1696
0
            pubLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE;
1697
0
            break;
1698
0
    #endif
1699
0
    #ifdef WOLFSSL_WC_ML_KEM_768
1700
0
        case WC_ML_KEM_768:
1701
0
            k = WC_ML_KEM_768_K;
1702
0
            privLen = WC_ML_KEM_768_PRIVATE_KEY_SIZE;
1703
0
            pubLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE;
1704
0
            break;
1705
0
    #endif
1706
0
    #ifdef WOLFSSL_WC_ML_KEM_1024
1707
0
        case WC_ML_KEM_1024:
1708
0
            k = WC_ML_KEM_1024_K;
1709
0
            privLen = WC_ML_KEM_1024_PRIVATE_KEY_SIZE;
1710
0
            pubLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE;
1711
0
            break;
1712
0
    #endif
1713
0
#endif
1714
#ifdef WOLFSSL_MLKEM_KYBER
1715
    #ifdef WOLFSSL_KYBER512
1716
        case KYBER512:
1717
            k = KYBER512_K;
1718
            privLen = KYBER512_PRIVATE_KEY_SIZE;
1719
            pubLen = KYBER512_PUBLIC_KEY_SIZE;
1720
            break;
1721
    #endif
1722
    #ifdef WOLFSSL_KYBER768
1723
        case KYBER768:
1724
            k = KYBER768_K;
1725
            privLen = KYBER768_PRIVATE_KEY_SIZE;
1726
            pubLen = KYBER768_PUBLIC_KEY_SIZE;
1727
            break;
1728
    #endif
1729
    #ifdef WOLFSSL_KYBER1024
1730
        case KYBER1024:
1731
            k = KYBER1024_K;
1732
            privLen = KYBER1024_PRIVATE_KEY_SIZE;
1733
            pubLen = KYBER1024_PUBLIC_KEY_SIZE;
1734
            break;
1735
    #endif
1736
#endif
1737
0
        default:
1738
            /* No other values supported. */
1739
0
            ret = NOT_COMPILED_IN;
1740
0
            break;
1741
0
        }
1742
0
    }
1743
    /* Ensure the data is the correct length for the key type. */
1744
0
    if ((ret == 0) && (len != privLen)) {
1745
0
        ret = BUFFER_E;
1746
0
    }
1747
1748
0
    if (ret == 0) {
1749
        /* Decode private key that is vector of polynomials.
1750
         * Alg 18 Step 1: dk_PKE <- dk[0 : 384k]
1751
         * Alg 15 Step 5: s_hat <- ByteDecode_12(dk_PKE) */
1752
0
        mlkem_from_bytes(key->priv, p, (int)k);
1753
0
        p += k * WC_ML_KEM_POLY_SIZE;
1754
1755
        /* Decode the public key that is after the private key. */
1756
0
        mlkemkey_decode_public(key->pub, key->pubSeed, p, k);
1757
        /* Compute the hash of the public key. */
1758
0
        ret = MLKEM_HASH_H(&key->hash, p, pubLen, key->h);
1759
0
        if (ret != 0) {
1760
0
            ForceZero(key->priv, k * MLKEM_N);
1761
0
        }
1762
0
    }
1763
1764
0
    if (ret == 0) {
1765
0
        p += pubLen;
1766
        /* Compare computed public key hash with stored hash */
1767
0
        if (XMEMCMP(key->h, p, WC_ML_KEM_SYM_SZ) != 0) {
1768
0
            ForceZero(key->priv, k * MLKEM_N);
1769
0
            ret = MLKEM_PUB_HASH_E;
1770
0
        }
1771
0
    }
1772
1773
0
    if (ret == 0) {
1774
        /* Copy the hash of the encoded public key that is after public key. */
1775
0
        XMEMCPY(key->h, p, sizeof(key->h));
1776
0
        p += WC_ML_KEM_SYM_SZ;
1777
        /* Copy the z (randomizer) that is after hash. */
1778
0
        XMEMCPY(key->z, p, sizeof(key->z));
1779
1780
        /* Set flags */
1781
0
        key->flags |= MLKEM_FLAG_H_SET | MLKEM_FLAG_BOTH_SET;
1782
0
    }
1783
1784
0
    return ret;
1785
0
}
1786
1787
/**
1788
 * Decode public key.
1789
 *
1790
 * Public vector | Public Seed
1791
 *
1792
 * @param  [in, out]  key  Kyber key object.
1793
 * @param  [in]       in   Buffer holding encoded key.
1794
 * @param  [in]       len  Length of data in buffer.
1795
 * @return  0 on success.
1796
 * @return  BAD_FUNC_ARG when key or in is NULL.
1797
 * @return  NOT_COMPILED_IN when key type is not supported.
1798
 * @return  BUFFER_E when len is not the correct size.
1799
 */
1800
int wc_MlKemKey_DecodePublicKey(MlKemKey* key, const unsigned char* in,
1801
    word32 len)
1802
0
{
1803
0
    int ret = 0;
1804
0
    word32 pubLen = 0;
1805
0
    unsigned int k = 0;
1806
0
    const unsigned char* p = in;
1807
1808
0
    if ((key == NULL) || (in == NULL)) {
1809
0
        ret = BAD_FUNC_ARG;
1810
0
    }
1811
1812
0
    if (ret == 0) {
1813
        /* Establish parameters based on key type. */
1814
0
        switch (key->type) {
1815
0
#ifndef WOLFSSL_NO_ML_KEM
1816
0
    #ifdef WOLFSSL_WC_ML_KEM_512
1817
0
        case WC_ML_KEM_512:
1818
0
            k = WC_ML_KEM_512_K;
1819
0
            pubLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE;
1820
0
            break;
1821
0
    #endif
1822
0
    #ifdef WOLFSSL_WC_ML_KEM_768
1823
0
        case WC_ML_KEM_768:
1824
0
            k = WC_ML_KEM_768_K;
1825
0
            pubLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE;
1826
0
            break;
1827
0
    #endif
1828
0
    #ifdef WOLFSSL_WC_ML_KEM_1024
1829
0
        case WC_ML_KEM_1024:
1830
0
            k = WC_ML_KEM_1024_K;
1831
0
            pubLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE;
1832
0
            break;
1833
0
    #endif
1834
0
#endif
1835
#ifdef WOLFSSL_MLKEM_KYBER
1836
    #ifdef WOLFSSL_KYBER512
1837
        case KYBER512:
1838
            k = KYBER512_K;
1839
            pubLen = KYBER512_PUBLIC_KEY_SIZE;
1840
            break;
1841
    #endif
1842
    #ifdef WOLFSSL_KYBER768
1843
        case KYBER768:
1844
            k = KYBER768_K;
1845
            pubLen = KYBER768_PUBLIC_KEY_SIZE;
1846
            break;
1847
    #endif
1848
    #ifdef WOLFSSL_KYBER1024
1849
        case KYBER1024:
1850
            k = KYBER1024_K;
1851
            pubLen = KYBER1024_PUBLIC_KEY_SIZE;
1852
            break;
1853
    #endif
1854
#endif
1855
0
        default:
1856
            /* No other values supported. */
1857
0
            ret = NOT_COMPILED_IN;
1858
0
            break;
1859
0
        }
1860
0
    }
1861
    /* Ensure the data is the correct length for the key type. */
1862
0
    if ((ret == 0) && (len != pubLen)) {
1863
0
        ret = BUFFER_E;
1864
0
    }
1865
1866
0
    if (ret == 0) {
1867
0
        mlkemkey_decode_public(key->pub, key->pubSeed, p, k);
1868
0
        ret = mlkem_check_public(key->pub, (int)k);
1869
0
    }
1870
0
    if (ret == 0) {
1871
        /* Calculate public hash. */
1872
0
        ret = MLKEM_HASH_H(&key->hash, in, len, key->h);
1873
0
    }
1874
0
    if (ret == 0) {
1875
        /* Record public key and public hash set. */
1876
0
        key->flags |= MLKEM_FLAG_PUB_SET | MLKEM_FLAG_H_SET;
1877
0
    }
1878
1879
0
    return ret;
1880
0
}
1881
1882
/**
1883
 * Get the size in bytes of encoded private key for the key.
1884
 *
1885
 * @param  [in]   key  Kyber key object.
1886
 * @param  [out]  len  Length of encoded private key in bytes.
1887
 * @return  0 on success.
1888
 * @return  BAD_FUNC_ARG when key or len is NULL.
1889
 * @return  NOT_COMPILED_IN when key type is not supported.
1890
 */
1891
int wc_MlKemKey_PrivateKeySize(MlKemKey* key, word32* len)
1892
3.26k
{
1893
3.26k
    int ret = 0;
1894
1895
    /* Validate parameters. */
1896
3.26k
    if ((key == NULL) || (len == NULL)) {
1897
0
        ret = BAD_FUNC_ARG;
1898
0
    }
1899
1900
3.26k
    if (ret == 0) {
1901
        /* Return in 'len' size of the encoded private key for the type of this
1902
         * key. */
1903
3.26k
        switch (key->type) {
1904
0
#ifndef WOLFSSL_NO_ML_KEM
1905
0
    #ifdef WOLFSSL_WC_ML_KEM_512
1906
0
        case WC_ML_KEM_512:
1907
0
            *len = WC_ML_KEM_512_PRIVATE_KEY_SIZE;
1908
0
            break;
1909
0
    #endif
1910
0
    #ifdef WOLFSSL_WC_ML_KEM_768
1911
3.22k
        case WC_ML_KEM_768:
1912
3.22k
            *len = WC_ML_KEM_768_PRIVATE_KEY_SIZE;
1913
3.22k
            break;
1914
0
    #endif
1915
0
    #ifdef WOLFSSL_WC_ML_KEM_1024
1916
33
        case WC_ML_KEM_1024:
1917
33
            *len = WC_ML_KEM_1024_PRIVATE_KEY_SIZE;
1918
33
            break;
1919
0
    #endif
1920
0
#endif
1921
#ifdef WOLFSSL_MLKEM_KYBER
1922
    #ifdef WOLFSSL_KYBER512
1923
        case KYBER512:
1924
            *len = KYBER512_PRIVATE_KEY_SIZE;
1925
            break;
1926
    #endif
1927
    #ifdef WOLFSSL_KYBER768
1928
        case KYBER768:
1929
            *len = KYBER768_PRIVATE_KEY_SIZE;
1930
            break;
1931
    #endif
1932
    #ifdef WOLFSSL_KYBER1024
1933
        case KYBER1024:
1934
            *len = KYBER1024_PRIVATE_KEY_SIZE;
1935
            break;
1936
    #endif
1937
#endif
1938
0
        default:
1939
            /* No other values supported. */
1940
0
            ret = NOT_COMPILED_IN;
1941
0
            break;
1942
3.26k
        }
1943
3.26k
    }
1944
1945
3.26k
    return ret;
1946
3.26k
}
1947
1948
/**
1949
 * Get the size in bytes of encoded public key for the key.
1950
 *
1951
 * @param  [in]   key  Kyber key object.
1952
 * @param  [out]  len  Length of encoded public key in bytes.
1953
 * @return  0 on success.
1954
 * @return  BAD_FUNC_ARG when key or len is NULL.
1955
 * @return  NOT_COMPILED_IN when key type is not supported.
1956
 */
1957
int wc_MlKemKey_PublicKeySize(MlKemKey* key, word32* len)
1958
3.26k
{
1959
3.26k
    int ret = 0;
1960
1961
    /* Validate parameters. */
1962
3.26k
    if ((key == NULL) || (len == NULL)) {
1963
0
        ret = BAD_FUNC_ARG;
1964
0
    }
1965
1966
3.26k
    if (ret == 0) {
1967
        /* Return in 'len' size of the encoded public key for the type of this
1968
         * key. */
1969
3.26k
        switch (key->type) {
1970
0
#ifndef WOLFSSL_NO_ML_KEM
1971
0
    #ifdef WOLFSSL_WC_ML_KEM_512
1972
0
        case WC_ML_KEM_512:
1973
0
            *len = WC_ML_KEM_512_PUBLIC_KEY_SIZE;
1974
0
            break;
1975
0
    #endif
1976
0
    #ifdef WOLFSSL_WC_ML_KEM_768
1977
3.22k
        case WC_ML_KEM_768:
1978
3.22k
            *len = WC_ML_KEM_768_PUBLIC_KEY_SIZE;
1979
3.22k
            break;
1980
0
    #endif
1981
0
    #ifdef WOLFSSL_WC_ML_KEM_1024
1982
33
        case WC_ML_KEM_1024:
1983
33
            *len = WC_ML_KEM_1024_PUBLIC_KEY_SIZE;
1984
33
            break;
1985
0
    #endif
1986
0
#endif
1987
#ifdef WOLFSSL_MLKEM_KYBER
1988
    #ifdef WOLFSSL_KYBER512
1989
        case KYBER512:
1990
            *len = KYBER512_PUBLIC_KEY_SIZE;
1991
            break;
1992
    #endif
1993
    #ifdef WOLFSSL_KYBER768
1994
        case KYBER768:
1995
            *len = KYBER768_PUBLIC_KEY_SIZE;
1996
            break;
1997
    #endif
1998
    #ifdef WOLFSSL_KYBER1024
1999
        case KYBER1024:
2000
            *len = KYBER1024_PUBLIC_KEY_SIZE;
2001
            break;
2002
    #endif
2003
#endif
2004
0
        default:
2005
            /* No other values supported. */
2006
0
            ret = NOT_COMPILED_IN;
2007
0
            break;
2008
3.26k
        }
2009
3.26k
    }
2010
2011
3.26k
    return ret;
2012
3.26k
}
2013
2014
/**
2015
 * Encode the private key.
2016
 *
2017
 * Private Vector | Public Key | Public Hash | Randomizer
2018
 *
2019
 * FIPS 203, Algorithm 16: ML-KEM.KeyGen_internal(d,z)
2020
 *   ...
2021
 *   3: dk <- (dk_PKE||ek||H(ek)||z)
2022
 *   ...
2023
 * FIPS 203, Algorithm 13: K-PKE.KeyGen(d)
2024
 *   ...
2025
 *   20: dk_PKE  <- ByteEncode_12(s_hat)
2026
 *   ...
2027
 *
2028
 * @param  [in]   key  Kyber key object.
2029
 * @param  [out]  out  Buffer to hold data.
2030
 * @param  [in]   len  Size of buffer in bytes.
2031
 * @return  0 on success.
2032
 * @return  BAD_FUNC_ARG when key or out is NULL or private/public key not
2033
 * available.
2034
 * @return  NOT_COMPILED_IN when key type is not supported.
2035
 */
2036
int wc_MlKemKey_EncodePrivateKey(MlKemKey* key, unsigned char* out, word32 len)
2037
3.25k
{
2038
3.25k
    int ret = 0;
2039
3.25k
    unsigned int k = 0;
2040
3.25k
    unsigned int pubLen = 0;
2041
3.25k
    unsigned int privLen = 0;
2042
3.25k
    unsigned char* p = out;
2043
2044
3.25k
    if ((key == NULL) || (out == NULL)) {
2045
0
        ret = BAD_FUNC_ARG;
2046
0
    }
2047
3.25k
    if ((ret == 0) &&
2048
3.25k
            ((key->flags & MLKEM_FLAG_BOTH_SET) != MLKEM_FLAG_BOTH_SET)) {
2049
0
        ret = BAD_FUNC_ARG;
2050
0
    }
2051
2052
3.25k
    if (ret == 0) {
2053
3.25k
        switch (key->type) {
2054
0
#ifndef WOLFSSL_NO_ML_KEM
2055
0
    #ifdef WOLFSSL_WC_ML_KEM_512
2056
0
        case WC_ML_KEM_512:
2057
0
            k = WC_ML_KEM_512_K;
2058
0
            pubLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE;
2059
0
            privLen = WC_ML_KEM_512_PRIVATE_KEY_SIZE;
2060
0
            break;
2061
0
    #endif
2062
0
    #ifdef WOLFSSL_WC_ML_KEM_768
2063
3.21k
        case WC_ML_KEM_768:
2064
3.21k
            k = WC_ML_KEM_768_K;
2065
3.21k
            pubLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE;
2066
3.21k
            privLen = WC_ML_KEM_768_PRIVATE_KEY_SIZE;
2067
3.21k
            break;
2068
0
    #endif
2069
0
    #ifdef WOLFSSL_WC_ML_KEM_1024
2070
33
        case WC_ML_KEM_1024:
2071
33
            k = WC_ML_KEM_1024_K;
2072
33
            pubLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE;
2073
33
            privLen = WC_ML_KEM_1024_PRIVATE_KEY_SIZE;
2074
33
            break;
2075
0
    #endif
2076
0
#endif
2077
#ifdef WOLFSSL_MLKEM_KYBER
2078
    #ifdef WOLFSSL_KYBER512
2079
        case KYBER512:
2080
            k = KYBER512_K;
2081
            pubLen = KYBER512_PUBLIC_KEY_SIZE;
2082
            privLen = KYBER512_PRIVATE_KEY_SIZE;
2083
            break;
2084
    #endif
2085
    #ifdef WOLFSSL_KYBER768
2086
        case KYBER768:
2087
            k = KYBER768_K;
2088
            pubLen = KYBER768_PUBLIC_KEY_SIZE;
2089
            privLen = KYBER768_PRIVATE_KEY_SIZE;
2090
            break;
2091
    #endif
2092
    #ifdef WOLFSSL_KYBER1024
2093
        case KYBER1024:
2094
            k = KYBER1024_K;
2095
            pubLen = KYBER1024_PUBLIC_KEY_SIZE;
2096
            privLen = KYBER1024_PRIVATE_KEY_SIZE;
2097
            break;
2098
    #endif
2099
#endif
2100
0
        default:
2101
            /* No other values supported. */
2102
0
            ret = NOT_COMPILED_IN;
2103
0
            break;
2104
3.25k
        }
2105
3.25k
    }
2106
    /* Check buffer is big enough for encoding. */
2107
3.25k
    if ((ret == 0) && (len != privLen)) {
2108
0
        ret = BUFFER_E;
2109
0
    }
2110
2111
3.25k
    if (ret == 0) {
2112
        /* Encode private key that is vector of polynomials. */
2113
3.25k
        mlkem_to_bytes(p, key->priv, (int)k);
2114
3.25k
        p += WC_ML_KEM_POLY_SIZE * k;
2115
2116
        /* Encode public key. */
2117
3.25k
        ret = wc_KyberKey_EncodePublicKey(key, p, pubLen);
2118
3.25k
        p += pubLen;
2119
3.25k
    }
2120
    /* Ensure hash of public key is available. */
2121
3.25k
    if ((ret == 0) && ((key->flags & MLKEM_FLAG_H_SET) == 0)) {
2122
0
        ret = MLKEM_HASH_H(&key->hash, p - pubLen, pubLen, key->h);
2123
0
    }
2124
3.25k
    if (ret == 0) {
2125
        /* Public hash is available. */
2126
3.25k
        key->flags |= MLKEM_FLAG_H_SET;
2127
        /* Append public hash. */
2128
3.25k
        XMEMCPY(p, key->h, sizeof(key->h));
2129
3.25k
        p += WC_ML_KEM_SYM_SZ;
2130
        /* Append z (randomizer). */
2131
3.25k
        XMEMCPY(p, key->z, sizeof(key->z));
2132
3.25k
    }
2133
2134
3.25k
    return ret;
2135
3.25k
}
2136
2137
/**
2138
 * Encode the public key.
2139
 *
2140
 * Public vector | Public Seed
2141
 *
2142
 * FIPS 203, Algorithm 16: ML-KEM.KeyGen_internal(d,z)
2143
 *   ...
2144
 *   2: ek <- ek_PKE
2145
 *   ...
2146
 * FIPS 203, Algorithm 13: K-PKE.KeyGen(d)
2147
 *   ...
2148
 *   19: ek_PKE  <- ByteEncode_12(t_hat)||rho
2149
 *   ...
2150
 *
2151
 * @param  [in]   key  Kyber key object.
2152
 * @param  [out]  out  Buffer to hold data.
2153
 * @param  [in]   len  Size of buffer in bytes.
2154
 * @return  0 on success.
2155
 * @return  BAD_FUNC_ARG when key or out is NULL or public key not available.
2156
 * @return  NOT_COMPILED_IN when key type is not supported.
2157
 */
2158
int wc_MlKemKey_EncodePublicKey(MlKemKey* key, unsigned char* out, word32 len)
2159
6.50k
{
2160
6.50k
    int ret = 0;
2161
6.50k
    unsigned int k = 0;
2162
6.50k
    unsigned int pubLen = 0;
2163
6.50k
    unsigned char* p = out;
2164
2165
6.50k
    if ((key == NULL) || (out == NULL)) {
2166
0
        ret = BAD_FUNC_ARG;
2167
0
    }
2168
6.50k
    if ((ret == 0) &&
2169
6.50k
            ((key->flags & MLKEM_FLAG_PUB_SET) != MLKEM_FLAG_PUB_SET)) {
2170
0
        ret = BAD_FUNC_ARG;
2171
0
    }
2172
2173
6.50k
    if (ret == 0) {
2174
6.50k
        switch (key->type) {
2175
0
#ifndef WOLFSSL_NO_ML_KEM
2176
0
    #ifdef WOLFSSL_WC_ML_KEM_512
2177
0
        case WC_ML_KEM_512:
2178
0
            k = WC_ML_KEM_512_K;
2179
0
            pubLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE;
2180
0
            break;
2181
0
    #endif
2182
0
    #ifdef WOLFSSL_WC_ML_KEM_768
2183
6.43k
        case WC_ML_KEM_768:
2184
6.43k
            k = WC_ML_KEM_768_K;
2185
6.43k
            pubLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE;
2186
6.43k
            break;
2187
0
    #endif
2188
0
    #ifdef WOLFSSL_WC_ML_KEM_1024
2189
66
        case WC_ML_KEM_1024:
2190
66
            k = WC_ML_KEM_1024_K;
2191
66
            pubLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE;
2192
66
            break;
2193
0
    #endif
2194
0
#endif
2195
#ifdef WOLFSSL_MLKEM_KYBER
2196
    #ifdef WOLFSSL_KYBER512
2197
        case KYBER512:
2198
            k = KYBER512_K;
2199
            pubLen = KYBER512_PUBLIC_KEY_SIZE;
2200
            break;
2201
    #endif
2202
    #ifdef WOLFSSL_KYBER768
2203
        case KYBER768:
2204
            k = KYBER768_K;
2205
            pubLen = KYBER768_PUBLIC_KEY_SIZE;
2206
            break;
2207
    #endif
2208
    #ifdef WOLFSSL_KYBER1024
2209
        case KYBER1024:
2210
            k = KYBER1024_K;
2211
            pubLen = KYBER1024_PUBLIC_KEY_SIZE;
2212
            break;
2213
    #endif
2214
#endif
2215
0
        default:
2216
            /* No other values supported. */
2217
0
            ret = NOT_COMPILED_IN;
2218
0
            break;
2219
6.50k
        }
2220
6.50k
    }
2221
    /* Check buffer is big enough for encoding. */
2222
6.50k
    if ((ret == 0) && (len != pubLen)) {
2223
0
        ret = BUFFER_E;
2224
0
    }
2225
2226
6.50k
    if (ret == 0) {
2227
6.50k
        int i;
2228
2229
        /* Encode public key polynomial by polynomial. */
2230
6.50k
        mlkem_to_bytes(p, key->pub, (int)k);
2231
6.50k
        p += k * WC_ML_KEM_POLY_SIZE;
2232
2233
        /* Append public seed. */
2234
214k
        for (i = 0; i < WC_ML_KEM_SYM_SZ; i++) {
2235
208k
            p[i] = key->pubSeed[i];
2236
208k
        }
2237
2238
        /* Make sure public hash is set. */
2239
6.50k
        if ((key->flags & MLKEM_FLAG_H_SET) == 0) {
2240
3.25k
            ret = MLKEM_HASH_H(&key->hash, out, len, key->h);
2241
3.25k
        }
2242
6.50k
    }
2243
6.50k
    if (ret == 0) {
2244
        /* Public hash is set. */
2245
6.50k
        key->flags |= MLKEM_FLAG_H_SET;
2246
6.50k
    }
2247
2248
6.50k
    return ret;
2249
6.50k
}
2250
2251
#endif /* WOLFSSL_WC_MLKEM */