#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#ifdef WC_MLKEM_NO_ASM
#undef USE_INTEL_SPEEDUP
#undef WOLFSSL_ARMASM
#undef WOLFSSL_RISCV_ASM
#endif
#include <wolfssl/wolfcrypt/mlkem.h>
#include <wolfssl/wolfcrypt/wc_mlkem.h>
#include <wolfssl/wolfcrypt/hash.h>
#include <wolfssl/wolfcrypt/memory.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#if defined(USE_INTEL_SPEEDUP) || \
(defined(__aarch64__) && defined(WOLFSSL_ARMASM))
#if defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) || \
defined(WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM)
#error "Can't use small memory with assembly optimized code"
#endif
#endif
#if defined(WOLFSSL_MLKEM_CACHE_A)
#if defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) || \
defined(WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM)
#error "Can't cache A with small memory code"
#endif
#endif
#if defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
#error "No ML-KEM operations to be built."
#endif
#ifdef WOLFSSL_WC_MLKEM
#ifdef DEBUG_MLKEM
void print_polys(const char* name, const sword16* a, int d1, int d2);
void print_polys(const char* name, const sword16* a, int d1, int d2)
{
int i;
int j;
int k;
fprintf(stderr, "%s: %d %d\n", name, d1, d2);
for (i = 0; i < d1; i++) {
for (j = 0; j < d2; j++) {
for (k = 0; k < 256; k++) {
fprintf(stderr, "%9d,", a[(i*d2*256) + (j*256) + k]);
if ((k % 8) == 7) fprintf(stderr, "\n");
}
fprintf(stderr, "\n");
}
}
}
#endif
#ifdef DEBUG_MLKEM
void print_data(const char* name, const byte* d, int len);
void print_data(const char* name, const byte* d, int len)
{
int i;
fprintf(stderr, "%s\n", name);
for (i = 0; i < len; i++) {
fprintf(stderr, "0x%02x,", d[i]);
if ((i % 16) == 15) fprintf(stderr, "\n");
}
fprintf(stderr, "\n");
}
#endif
#define MLKEM_HASH_H mlkem_hash256
#define MLKEM_HASH_G mlkem_hash512
#if defined(USE_INTEL_SPEEDUP) || \
(defined(WOLFSSL_ARMASM) && defined(__aarch64__))
#define MLKEM_KDF mlkem_kdf
#else
#define MLKEM_KDF wc_Shake256Hash
#endif
sword16 wc_mlkem_opt_blocker(void);
sword16 wc_mlkem_opt_blocker(void) {
static volatile sword16 static_mlkem_opt_blocker = 0;
return static_mlkem_opt_blocker;
}
#ifndef WC_NO_CONSTRUCTORS
MlKemKey* wc_MlKemKey_New(int type, void* heap, int devId)
{
int ret;
MlKemKey* key = (MlKemKey*)XMALLOC(sizeof(MlKemKey), heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (key != NULL) {
ret = wc_MlKemKey_Init(key, type, heap, devId);
if (ret != 0) {
XFREE(key, heap, DYNAMIC_TYPE_TMP_BUFFER);
key = NULL;
}
}
return key;
}
int wc_MlKemKey_Delete(MlKemKey* key, MlKemKey** key_p)
{
if (key == NULL)
return BAD_FUNC_ARG;
wc_MlKemKey_Free(key);
XFREE(key, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (key_p != NULL)
*key_p = NULL;
return 0;
}
#endif
int wc_MlKemKey_Init(MlKemKey* key, int type, void* heap, int devId)
{
int ret = 0;
if (key == NULL) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
switch (type) {
#ifndef WOLFSSL_NO_ML_KEM
case WC_ML_KEM_512:
#ifndef WOLFSSL_WC_ML_KEM_512
ret = NOT_COMPILED_IN;
#endif
break;
case WC_ML_KEM_768:
#ifndef WOLFSSL_WC_ML_KEM_768
ret = NOT_COMPILED_IN;
#endif
break;
case WC_ML_KEM_1024:
#ifndef WOLFSSL_WC_ML_KEM_1024
ret = NOT_COMPILED_IN;
#endif
break;
#endif
#ifdef WOLFSSL_MLKEM_KYBER
case KYBER512:
#ifndef WOLFSSL_KYBER512
ret = NOT_COMPILED_IN;
#endif
break;
case KYBER768:
#ifndef WOLFSSL_KYBER768
ret = NOT_COMPILED_IN;
#endif
break;
case KYBER1024:
#ifndef WOLFSSL_KYBER1024
ret = NOT_COMPILED_IN;
#endif
break;
#endif
default:
ret = BAD_FUNC_ARG;
break;
}
}
if (ret == 0) {
key->type = type;
key->heap = heap;
#ifdef WOLF_CRYPTO_CB
key->devId = devId;
#endif
key->flags = 0;
XMEMSET(&key->prf, 0, sizeof(key->prf));
ret = mlkem_hash_new(&key->hash, heap, devId);
}
if (ret == 0) {
ret = mlkem_prf_new(&key->prf, heap, devId);
}
if (ret == 0) {
mlkem_init();
}
(void)devId;
return ret;
}
int wc_MlKemKey_Free(MlKemKey* key)
{
if (key != NULL) {
mlkem_prf_free(&key->prf);
mlkem_hash_free(&key->hash);
ForceZero(&key->hash, sizeof(key->hash));
ForceZero(&key->prf, sizeof(key->prf));
ForceZero(key->priv, sizeof(key->priv));
ForceZero(key->z, sizeof(key->z));
}
return 0;
}
#ifndef WOLFSSL_MLKEM_NO_MAKE_KEY
int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng)
{
#ifndef WC_NO_RNG
int ret = 0;
unsigned char rand[WC_ML_KEM_MAKEKEY_RAND_SZ];
if ((key == NULL) || (rng == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
ret = wc_RNG_GenerateBlock(rng, rand, WC_ML_KEM_SYM_SZ * 2);
}
if (ret == 0) {
ret = wc_KyberKey_MakeKeyWithRandom(key, rand, sizeof(rand));
}
ForceZero((void*)rand, (word32)sizeof(rand));
return ret;
#else
(void)key;
(void)rng;
return NOT_COMPILED_IN;
#endif
}
int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand,
int len)
{
byte buf[2 * WC_ML_KEM_SYM_SZ + 1];
byte* rho = buf;
#ifndef WC_MLKEM_FAULT_HARDEN
byte* sigma = buf + WC_ML_KEM_SYM_SZ;
#else
byte sigma[WC_ML_KEM_SYM_SZ + 1];
#endif
#ifndef WOLFSSL_NO_MALLOC
sword16* e = NULL;
#else
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
#ifndef WOLFSSL_MLKEM_CACHE_A
sword16 e[(WC_ML_KEM_MAX_K + 1) * WC_ML_KEM_MAX_K * MLKEM_N];
#else
sword16 e[WC_ML_KEM_MAX_K * MLKEM_N];
#endif
#else
sword16 e[WC_ML_KEM_MAX_K * MLKEM_N];
#endif
#endif
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
sword16* a = NULL;
#endif
sword16* s = NULL;
sword16* t = NULL;
int ret = 0;
int k = 0;
if ((key == NULL) || (rand == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (len != WC_ML_KEM_MAKEKEY_RAND_SZ)) {
ret = BUFFER_E;
}
if (ret == 0) {
key->flags = 0;
switch (key->type) {
#ifndef WOLFSSL_NO_ML_KEM
#ifdef WOLFSSL_WC_ML_KEM_512
case WC_ML_KEM_512:
k = WC_ML_KEM_512_K;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_768
case WC_ML_KEM_768:
k = WC_ML_KEM_768_K;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_1024
case WC_ML_KEM_1024:
k = WC_ML_KEM_1024_K;
break;
#endif
#endif
#ifdef WOLFSSL_MLKEM_KYBER
#ifdef WOLFSSL_KYBER512
case KYBER512:
k = KYBER512_K;
break;
#endif
#ifdef WOLFSSL_KYBER768
case KYBER768:
k = KYBER768_K;
break;
#endif
#ifdef WOLFSSL_KYBER1024
case KYBER1024:
k = KYBER1024_K;
break;
#endif
#endif
default:
ret = NOT_COMPILED_IN;
break;
}
}
#ifndef WOLFSSL_NO_MALLOC
if (ret == 0) {
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
#ifndef WOLFSSL_MLKEM_CACHE_A
e = (sword16*)XMALLOC((size_t)((k + 1) * k * MLKEM_N) * sizeof(sword16),
key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#else
e = (sword16*)XMALLOC((size_t)(k * MLKEM_N) * sizeof(sword16),
key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
#else
e = (sword16*)XMALLOC((size_t)(k * MLKEM_N) * sizeof(sword16),
key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
if (e == NULL) {
ret = MEMORY_E;
}
}
#endif
if (ret == 0) {
const byte* d = rand;
#ifdef WOLFSSL_MLKEM_CACHE_A
a = key->a;
#elif !defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM)
a = e + (k * MLKEM_N);
#endif
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
if (key->type & MLKEM_KYBER)
#endif
#ifdef WOLFSSL_MLKEM_KYBER
{
ret = MLKEM_HASH_G(&key->hash, d, WC_ML_KEM_SYM_SZ, NULL, 0, buf);
}
#endif
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
else
#endif
#ifndef WOLFSSL_NO_ML_KEM
{
buf[0] = (byte)k;
ret = MLKEM_HASH_G(&key->hash, d, WC_ML_KEM_SYM_SZ, buf, 1, buf);
}
#endif
}
#ifdef WC_MLKEM_FAULT_HARDEN
if (ret == 0) {
XMEMCPY(sigma, buf + WC_ML_KEM_SYM_SZ, WC_ML_KEM_SYM_SZ);
if (XMEMCMP(sigma, rho, WC_ML_KEM_SYM_SZ) == 0) {
ret = BAD_COND_E;
}
if (XMEMCMP(sigma, rho + WC_ML_KEM_SYM_SZ, WC_ML_KEM_SYM_SZ) != 0) {
ret = BAD_COND_E;
}
}
#endif
if (ret == 0) {
const byte* z = rand + WC_ML_KEM_SYM_SZ;
s = key->priv;
t = key->pub;
XMEMCPY(key->pubSeed, rho, WC_ML_KEM_SYM_SZ);
XMEMCPY(key->z, z, sizeof(key->z));
mlkem_prf_init(&key->prf);
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
ret = mlkem_get_noise(&key->prf, k, s, e, NULL, sigma);
}
if (ret == 0) {
ret = mlkem_gen_matrix(&key->prf, a, k, rho, 0);
}
if (ret == 0) {
mlkem_keygen(s, t, e, a, k);
#else
ret = mlkem_get_noise(&key->prf, k, s, NULL, NULL, sigma);
}
if (ret == 0) {
ret = mlkem_keygen_seeds(s, t, &key->prf, e, k, rho, sigma);
}
if (ret == 0) {
#endif
key->flags |= MLKEM_FLAG_PRIV_SET | MLKEM_FLAG_PUB_SET;
#ifdef WOLFSSL_MLKEM_CACHE_A
key->flags |= MLKEM_FLAG_A_SET;
#endif
}
#ifndef WOLFSSL_NO_MALLOC
if (key != NULL) {
XFREE(e, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
return ret;
}
#endif
int wc_MlKemKey_CipherTextSize(MlKemKey* key, word32* len)
{
int ret = 0;
if ((key == NULL) || (len == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
switch (key->type) {
#ifndef WOLFSSL_NO_ML_KEM
#ifdef WOLFSSL_WC_ML_KEM_512
case WC_ML_KEM_512:
*len = WC_ML_KEM_512_CIPHER_TEXT_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_768
case WC_ML_KEM_768:
*len = WC_ML_KEM_768_CIPHER_TEXT_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_1024
case WC_ML_KEM_1024:
*len = WC_ML_KEM_1024_CIPHER_TEXT_SIZE;
break;
#endif
#endif
#ifdef WOLFSSL_MLKEM_KYBER
#ifdef WOLFSSL_KYBER512
case KYBER512:
*len = KYBER512_CIPHER_TEXT_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER768
case KYBER768:
*len = KYBER768_CIPHER_TEXT_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER1024
case KYBER1024:
*len = KYBER1024_CIPHER_TEXT_SIZE;
break;
#endif
#endif
default:
ret = NOT_COMPILED_IN;
break;
}
}
return ret;
}
int wc_MlKemKey_SharedSecretSize(MlKemKey* key, word32* len)
{
int ret = 0;
if (len == NULL) {
ret = BAD_FUNC_ARG;
}
else {
*len = WC_ML_KEM_SS_SZ;
}
(void)key;
return ret;
}
#if !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
static int mlkemkey_encapsulate(MlKemKey* key, const byte* m, byte* r, byte* c)
{
int ret = 0;
sword16* a = NULL;
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
sword16* mu = NULL;
sword16* e1 = NULL;
sword16* e2 = NULL;
#endif
unsigned int k = 0;
unsigned int compVecSz = 0;
#ifndef WOLFSSL_NO_MALLOC
sword16* y = NULL;
#else
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
sword16 y[((WC_ML_KEM_MAX_K + 3) * WC_ML_KEM_MAX_K + 3) * MLKEM_N];
#else
sword16 y[3 * WC_ML_KEM_MAX_K * MLKEM_N];
#endif
#endif
sword16* u = 0;
sword16* v = 0;
switch (key->type) {
#ifndef WOLFSSL_NO_ML_KEM
#ifdef WOLFSSL_WC_ML_KEM_512
case WC_ML_KEM_512:
k = WC_ML_KEM_512_K;
compVecSz = WC_ML_KEM_512_POLY_VEC_COMPRESSED_SZ;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_768
case WC_ML_KEM_768:
k = WC_ML_KEM_768_K;
compVecSz = WC_ML_KEM_768_POLY_VEC_COMPRESSED_SZ;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_1024
case WC_ML_KEM_1024:
k = WC_ML_KEM_1024_K;
compVecSz = WC_ML_KEM_1024_POLY_VEC_COMPRESSED_SZ;
break;
#endif
#endif
#ifdef WOLFSSL_MLKEM_KYBER
#ifdef WOLFSSL_KYBER512
case KYBER512:
k = KYBER512_K;
compVecSz = KYBER512_POLY_VEC_COMPRESSED_SZ;
break;
#endif
#ifdef WOLFSSL_KYBER768
case KYBER768:
k = KYBER768_K;
compVecSz = KYBER768_POLY_VEC_COMPRESSED_SZ;
break;
#endif
#ifdef WOLFSSL_KYBER1024
case KYBER1024:
k = KYBER1024_K;
compVecSz = KYBER1024_POLY_VEC_COMPRESSED_SZ;
break;
#endif
#endif
default:
ret = NOT_COMPILED_IN;
break;
}
#ifndef WOLFSSL_NO_MALLOC
if (ret == 0) {
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
y = (sword16*)XMALLOC(((k + 3) * k + 3) * MLKEM_N * sizeof(sword16),
key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#else
y = (sword16*)XMALLOC(3 * k * MLKEM_N * sizeof(sword16), key->heap,
DYNAMIC_TYPE_TMP_BUFFER);
#endif
if (y == NULL) {
ret = MEMORY_E;
}
}
#endif
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
if (ret == 0) {
a = y + MLKEM_N * k;
mu = a + MLKEM_N * k * k;
e1 = mu + MLKEM_N;
e2 = e1 + MLKEM_N * k;
mlkem_from_msg(mu, m);
mlkem_prf_init(&key->prf);
ret = mlkem_get_noise(&key->prf, (int)k, y, e1, e2, r);
}
#ifdef WOLFSSL_MLKEM_CACHE_A
if ((ret == 0) && ((key->flags & MLKEM_FLAG_A_SET) != 0)) {
unsigned int i;
for (i = 0; i < k; i++) {
unsigned int j;
for (j = 0; j < k; j++) {
XMEMCPY(&a[(i * k + j) * MLKEM_N],
&key->a[(j * k + i) * MLKEM_N],
MLKEM_N * 2);
}
}
}
else
#endif
if (ret == 0) {
ret = mlkem_gen_matrix(&key->prf, a, (int)k, key->pubSeed, 1);
}
if (ret == 0) {
u = e2 + MLKEM_N;
v = u + MLKEM_N * k;
mlkem_encapsulate(key->pub, u, v, a, y, e1, e2, mu, (int)k);
}
#else
if (ret == 0) {
a = y + MLKEM_N * k;
mlkem_prf_init(&key->prf);
ret = mlkem_get_noise(&key->prf, (int)k, y, NULL, NULL, r);
}
if (ret == 0) {
u = a + MLKEM_N * k;
v = a;
ret = mlkem_encapsulate_seeds(key->pub, &key->prf, u, a, y, (int)k, m,
key->pubSeed, r);
}
#endif
if (ret == 0) {
byte* c1 = c;
byte* c2 = c + compVecSz;
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
if (k == WC_ML_KEM_512_K) {
mlkem_vec_compress_10(c1, u, k);
mlkem_compress_4(c2, v);
}
#endif
#if defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768)
if (k == WC_ML_KEM_768_K) {
mlkem_vec_compress_10(c1, u, k);
mlkem_compress_4(c2, v);
}
#endif
#if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
if (k == WC_ML_KEM_1024_K) {
mlkem_vec_compress_11(c1, u);
mlkem_compress_5(c2, v);
}
#endif
}
#ifndef WOLFSSL_NO_MALLOC
XFREE(y, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ret;
}
#endif
#if !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
static int wc_mlkemkey_check_h(MlKemKey* key)
{
int ret = 0;
if ((key->flags & MLKEM_FLAG_H_SET) == 0) {
#ifndef WOLFSSL_NO_MALLOC
byte* pubKey = NULL;
word32 pubKeyLen;
#else
byte pubKey[WC_ML_KEM_MAX_PUBLIC_KEY_SIZE];
word32 pubKeyLen;
#endif
ret = wc_KyberKey_PublicKeySize(key, &pubKeyLen);
if (ret == 0) {
#ifndef WOLFSSL_NO_MALLOC
pubKey = (byte*)XMALLOC(pubKeyLen, key->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (pubKey == NULL) {
ret = MEMORY_E;
}
}
if (ret == 0) {
#endif
ret = wc_KyberKey_EncodePublicKey(key, pubKey, pubKeyLen);
}
#ifndef WOLFSSL_NO_MALLOC
XFREE(pubKey, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
}
if ((ret == 0) && ((key->flags & MLKEM_FLAG_H_SET) == 0)) {
ret = BAD_STATE_E;
}
return ret;
}
#endif
#ifndef WOLFSSL_MLKEM_NO_ENCAPSULATE
int wc_MlKemKey_Encapsulate(MlKemKey* key, unsigned char* c, unsigned char* k,
WC_RNG* rng)
{
#ifndef WC_NO_RNG
int ret = 0;
unsigned char m[WC_ML_KEM_ENC_RAND_SZ];
if ((key == NULL) || (c == NULL) || (k == NULL) || (rng == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
ret = wc_RNG_GenerateBlock(rng, m, sizeof(m));
}
if (ret == 0) {
ret = wc_KyberKey_EncapsulateWithRandom(key, c, k, m, sizeof(m));
}
return ret;
#else
(void)key;
(void)c;
(void)k;
(void)rng;
return NOT_COMPILED_IN;
#endif
}
int wc_MlKemKey_EncapsulateWithRandom(MlKemKey* key, unsigned char* c,
unsigned char* k, const unsigned char* m, int len)
{
#ifdef WOLFSSL_MLKEM_KYBER
byte msg[KYBER_SYM_SZ];
#endif
byte kr[2 * KYBER_SYM_SZ + 1];
int ret = 0;
#ifdef WOLFSSL_MLKEM_KYBER
unsigned int cSz = 0;
#endif
if ((key == NULL) || (c == NULL) || (k == NULL) || (m == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && (len != WC_ML_KEM_ENC_RAND_SZ)) {
ret = BUFFER_E;
}
#ifdef WOLFSSL_MLKEM_KYBER
if (ret == 0) {
switch (key->type) {
#ifndef WOLFSSL_NO_ML_KEM
#ifdef WOLFSSL_WC_ML_KEM_512
case WC_ML_KEM_512:
#endif
#ifdef WOLFSSL_WC_ML_KEM_768
case WC_ML_KEM_768:
#endif
#ifdef WOLFSSL_WC_ML_KEM_1024
case WC_ML_KEM_1024:
#endif
break;
#endif
#ifdef WOLFSSL_KYBER512
case KYBER512:
cSz = KYBER512_CIPHER_TEXT_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER768
case KYBER768:
cSz = KYBER768_CIPHER_TEXT_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER1024
case KYBER1024:
cSz = KYBER1024_CIPHER_TEXT_SIZE;
break;
#endif
default:
ret = NOT_COMPILED_IN;
break;
}
}
#endif
if (ret == 0) {
ret = wc_mlkemkey_check_h(key);
}
#ifdef WOLFSSL_MLKEM_KYBER
if (ret == 0) {
#ifndef WOLFSSL_NO_ML_KEM
if (key->type & MLKEM_KYBER)
#endif
{
ret = MLKEM_HASH_H(&key->hash, m, WC_ML_KEM_SYM_SZ, msg);
}
}
#endif
if (ret == 0) {
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
if (key->type & MLKEM_KYBER)
#endif
#ifdef WOLFSSL_MLKEM_KYBER
{
ret = MLKEM_HASH_G(&key->hash, msg, WC_ML_KEM_SYM_SZ, key->h,
WC_ML_KEM_SYM_SZ, kr);
}
#endif
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
else
#endif
#ifndef WOLFSSL_NO_ML_KEM
{
ret = MLKEM_HASH_G(&key->hash, m, WC_ML_KEM_SYM_SZ, key->h,
WC_ML_KEM_SYM_SZ, kr);
}
#endif
}
if (ret == 0) {
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
if (key->type & MLKEM_KYBER)
#endif
#ifdef WOLFSSL_MLKEM_KYBER
{
ret = mlkemkey_encapsulate(key, msg, kr + WC_ML_KEM_SYM_SZ, c);
}
#endif
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
else
#endif
#ifndef WOLFSSL_NO_ML_KEM
{
ret = mlkemkey_encapsulate(key, m, kr + WC_ML_KEM_SYM_SZ, c);
}
#endif
}
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
if (key->type & MLKEM_KYBER)
#endif
#ifdef WOLFSSL_MLKEM_KYBER
{
if (ret == 0) {
ret = MLKEM_HASH_H(&key->hash, c, cSz, kr + WC_ML_KEM_SYM_SZ);
}
if (ret == 0) {
ret = MLKEM_KDF(kr, 2 * WC_ML_KEM_SYM_SZ, k, WC_ML_KEM_SS_SZ);
}
}
#endif
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
else
#endif
#ifndef WOLFSSL_NO_ML_KEM
{
if (ret == 0) {
XMEMCPY(k, kr, WC_ML_KEM_SS_SZ);
}
}
#endif
ForceZero(kr, sizeof(kr));
return ret;
}
#endif
#ifndef WOLFSSL_MLKEM_NO_DECAPSULATE
static MLKEM_NOINLINE int mlkemkey_decapsulate(MlKemKey* key, byte* m,
const byte* c)
{
int ret = 0;
sword16* v;
sword16* w;
unsigned int k = 0;
unsigned int compVecSz;
#if defined(WOLFSSL_SMALL_STACK) || \
(!defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC))
sword16* u = NULL;
#else
sword16 u[(WC_ML_KEM_MAX_K + 1) * MLKEM_N];
#endif
switch (key->type) {
#ifndef WOLFSSL_NO_ML_KEM
#ifdef WOLFSSL_WC_ML_KEM_512
case WC_ML_KEM_512:
k = WC_ML_KEM_512_K;
compVecSz = WC_ML_KEM_512_POLY_VEC_COMPRESSED_SZ;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_768
case WC_ML_KEM_768:
k = WC_ML_KEM_768_K;
compVecSz = WC_ML_KEM_768_POLY_VEC_COMPRESSED_SZ;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_1024
case WC_ML_KEM_1024:
k = WC_ML_KEM_1024_K;
compVecSz = WC_ML_KEM_1024_POLY_VEC_COMPRESSED_SZ;
break;
#endif
#endif
#ifdef WOLFSSL_MLKEM_KYBER
#ifdef WOLFSSL_KYBER512
case KYBER512:
k = KYBER512_K;
compVecSz = KYBER512_POLY_VEC_COMPRESSED_SZ;
break;
#endif
#ifdef WOLFSSL_KYBER768
case KYBER768:
k = KYBER768_K;
compVecSz = KYBER768_POLY_VEC_COMPRESSED_SZ;
break;
#endif
#ifdef WOLFSSL_KYBER1024
case KYBER1024:
k = KYBER1024_K;
compVecSz = KYBER1024_POLY_VEC_COMPRESSED_SZ;
break;
#endif
#endif
default:
ret = NOT_COMPILED_IN;
break;
}
#if defined(WOLFSSL_SMALL_STACK) || \
(!defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC))
if (ret == 0) {
u = (sword16*)XMALLOC((k + 1) * MLKEM_N * sizeof(sword16), key->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (u == NULL) {
ret = MEMORY_E;
}
}
#endif
if (ret == 0) {
const byte* c1 = c;
const byte* c2 = c + compVecSz;
v = u + k * MLKEM_N;
w = u;
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
if (k == WC_ML_KEM_512_K) {
mlkem_vec_decompress_10(u, c1, k);
mlkem_decompress_4(v, c2);
}
#endif
#if defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768)
if (k == WC_ML_KEM_768_K) {
mlkem_vec_decompress_10(u, c1, k);
mlkem_decompress_4(v, c2);
}
#endif
#if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024)
if (k == WC_ML_KEM_1024_K) {
mlkem_vec_decompress_11(u, c1);
mlkem_decompress_5(v, c2);
}
#endif
mlkem_decapsulate(key->priv, w, u, v, (int)k);
mlkem_to_msg(m, w);
}
#if defined(WOLFSSL_SMALL_STACK) || \
(!defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC))
XFREE(u, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ret;
}
int wc_MlKemKey_Decapsulate(MlKemKey* key, unsigned char* ss,
const unsigned char* ct, word32 len)
{
byte msg[WC_ML_KEM_SYM_SZ];
byte kr[2 * WC_ML_KEM_SYM_SZ + 1];
int ret = 0;
unsigned int ctSz = 0;
unsigned int i = 0;
int fail = 0;
#if !defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC)
byte* cmp = NULL;
#else
byte cmp[WC_ML_KEM_MAX_CIPHER_TEXT_SIZE];
#endif
if ((key == NULL) || (ss == NULL) || (ct == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) && ((key->flags & MLKEM_FLAG_PRIV_SET) == 0)) {
ret = BAD_STATE_E;
}
if (ret == 0) {
switch (key->type) {
#ifndef WOLFSSL_NO_ML_KEM
#ifdef WOLFSSL_WC_ML_KEM_512
case WC_ML_KEM_512:
ctSz = WC_ML_KEM_512_CIPHER_TEXT_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_768
case WC_ML_KEM_768:
ctSz = WC_ML_KEM_768_CIPHER_TEXT_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_1024
case WC_ML_KEM_1024:
ctSz = WC_ML_KEM_1024_CIPHER_TEXT_SIZE;
break;
#endif
#endif
#ifdef WOLFSSL_MLKEM_KYBER
#ifdef WOLFSSL_KYBER512
case KYBER512:
ctSz = KYBER512_CIPHER_TEXT_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER768
case KYBER768:
ctSz = KYBER768_CIPHER_TEXT_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER1024
case KYBER1024:
ctSz = KYBER1024_CIPHER_TEXT_SIZE;
break;
#endif
#endif
default:
ret = NOT_COMPILED_IN;
break;
}
}
if ((ret == 0) && (len != ctSz)) {
ret = BUFFER_E;
}
#if !defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC)
if (ret == 0) {
cmp = (byte*)XMALLOC(ctSz, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (cmp == NULL) {
ret = MEMORY_E;
}
}
#endif
if (ret == 0) {
ret = mlkemkey_decapsulate(key, msg, ct);
}
if (ret == 0) {
ret = wc_mlkemkey_check_h(key);
}
if (ret == 0) {
ret = MLKEM_HASH_G(&key->hash, msg, WC_ML_KEM_SYM_SZ, key->h,
WC_ML_KEM_SYM_SZ, kr);
}
if (ret == 0) {
ret = mlkemkey_encapsulate(key, msg, kr + WC_ML_KEM_SYM_SZ, cmp);
}
if (ret == 0) {
fail = mlkem_cmp(ct, cmp, (int)ctSz);
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
if (key->type & MLKEM_KYBER)
#endif
#ifdef WOLFSSL_MLKEM_KYBER
{
ret = MLKEM_HASH_H(&key->hash, ct, ctSz, kr + WC_ML_KEM_SYM_SZ);
if (ret == 0) {
for (i = 0; i < WC_ML_KEM_SYM_SZ; i++) {
kr[i] ^= (kr[i] ^ key->z[i]) & fail;
}
ret = MLKEM_KDF(kr, 2 * WC_ML_KEM_SYM_SZ, ss, WC_ML_KEM_SS_SZ);
}
}
#endif
#if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM)
else
#endif
#ifndef WOLFSSL_NO_ML_KEM
{
ret = mlkem_derive_secret(&key->prf, key->z, ct, ctSz, msg);
if (ret == 0) {
for (i = 0; i < WC_ML_KEM_SYM_SZ; i++) {
ss[i] = (byte)(kr[i] ^ ((kr[i] ^ msg[i]) & fail));
}
}
}
#endif
}
#if !defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC)
if (key != NULL) {
XFREE(cmp, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
ForceZero(msg, sizeof(msg));
ForceZero(kr, sizeof(kr));
return ret;
}
#endif
static void mlkemkey_decode_public(sword16* pub, byte* pubSeed, const byte* p,
unsigned int k)
{
unsigned int i;
mlkem_from_bytes(pub, p, (int)k);
p += k * WC_ML_KEM_POLY_SIZE;
for (i = 0; i < WC_ML_KEM_SYM_SZ; i++) {
pubSeed[i] = p[i];
}
}
int wc_MlKemKey_DecodePrivateKey(MlKemKey* key, const unsigned char* in,
word32 len)
{
int ret = 0;
word32 privLen = 0;
word32 pubLen = 0;
unsigned int k = 0;
const unsigned char* p = in;
if ((key == NULL) || (in == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
switch (key->type) {
#ifndef WOLFSSL_NO_ML_KEM
#ifdef WOLFSSL_WC_ML_KEM_512
case WC_ML_KEM_512:
k = WC_ML_KEM_512_K;
privLen = WC_ML_KEM_512_PRIVATE_KEY_SIZE;
pubLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_768
case WC_ML_KEM_768:
k = WC_ML_KEM_768_K;
privLen = WC_ML_KEM_768_PRIVATE_KEY_SIZE;
pubLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_1024
case WC_ML_KEM_1024:
k = WC_ML_KEM_1024_K;
privLen = WC_ML_KEM_1024_PRIVATE_KEY_SIZE;
pubLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE;
break;
#endif
#endif
#ifdef WOLFSSL_MLKEM_KYBER
#ifdef WOLFSSL_KYBER512
case KYBER512:
k = KYBER512_K;
privLen = KYBER512_PRIVATE_KEY_SIZE;
pubLen = KYBER512_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER768
case KYBER768:
k = KYBER768_K;
privLen = KYBER768_PRIVATE_KEY_SIZE;
pubLen = KYBER768_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER1024
case KYBER1024:
k = KYBER1024_K;
privLen = KYBER1024_PRIVATE_KEY_SIZE;
pubLen = KYBER1024_PUBLIC_KEY_SIZE;
break;
#endif
#endif
default:
ret = NOT_COMPILED_IN;
break;
}
}
if ((ret == 0) && (len != privLen)) {
ret = BUFFER_E;
}
if (ret == 0) {
mlkem_from_bytes(key->priv, p, (int)k);
p += k * WC_ML_KEM_POLY_SIZE;
mlkemkey_decode_public(key->pub, key->pubSeed, p, k);
ret = MLKEM_HASH_H(&key->hash, p, pubLen, key->h);
if (ret != 0) {
ForceZero(key->priv, k * MLKEM_N);
}
}
if (ret == 0) {
p += pubLen;
if (XMEMCMP(key->h, p, WC_ML_KEM_SYM_SZ) != 0) {
ForceZero(key->priv, k * MLKEM_N);
ret = MLKEM_PUB_HASH_E;
}
}
if (ret == 0) {
XMEMCPY(key->h, p, sizeof(key->h));
p += WC_ML_KEM_SYM_SZ;
XMEMCPY(key->z, p, sizeof(key->z));
key->flags |= MLKEM_FLAG_H_SET | MLKEM_FLAG_BOTH_SET;
}
return ret;
}
int wc_MlKemKey_DecodePublicKey(MlKemKey* key, const unsigned char* in,
word32 len)
{
int ret = 0;
word32 pubLen = 0;
unsigned int k = 0;
const unsigned char* p = in;
if ((key == NULL) || (in == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
switch (key->type) {
#ifndef WOLFSSL_NO_ML_KEM
#ifdef WOLFSSL_WC_ML_KEM_512
case WC_ML_KEM_512:
k = WC_ML_KEM_512_K;
pubLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_768
case WC_ML_KEM_768:
k = WC_ML_KEM_768_K;
pubLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_1024
case WC_ML_KEM_1024:
k = WC_ML_KEM_1024_K;
pubLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE;
break;
#endif
#endif
#ifdef WOLFSSL_MLKEM_KYBER
#ifdef WOLFSSL_KYBER512
case KYBER512:
k = KYBER512_K;
pubLen = KYBER512_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER768
case KYBER768:
k = KYBER768_K;
pubLen = KYBER768_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER1024
case KYBER1024:
k = KYBER1024_K;
pubLen = KYBER1024_PUBLIC_KEY_SIZE;
break;
#endif
#endif
default:
ret = NOT_COMPILED_IN;
break;
}
}
if ((ret == 0) && (len != pubLen)) {
ret = BUFFER_E;
}
if (ret == 0) {
mlkemkey_decode_public(key->pub, key->pubSeed, p, k);
ret = mlkem_check_public(key->pub, (int)k);
}
if (ret == 0) {
ret = MLKEM_HASH_H(&key->hash, in, len, key->h);
}
if (ret == 0) {
key->flags |= MLKEM_FLAG_PUB_SET | MLKEM_FLAG_H_SET;
}
return ret;
}
int wc_MlKemKey_PrivateKeySize(MlKemKey* key, word32* len)
{
int ret = 0;
if ((key == NULL) || (len == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
switch (key->type) {
#ifndef WOLFSSL_NO_ML_KEM
#ifdef WOLFSSL_WC_ML_KEM_512
case WC_ML_KEM_512:
*len = WC_ML_KEM_512_PRIVATE_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_768
case WC_ML_KEM_768:
*len = WC_ML_KEM_768_PRIVATE_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_1024
case WC_ML_KEM_1024:
*len = WC_ML_KEM_1024_PRIVATE_KEY_SIZE;
break;
#endif
#endif
#ifdef WOLFSSL_MLKEM_KYBER
#ifdef WOLFSSL_KYBER512
case KYBER512:
*len = KYBER512_PRIVATE_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER768
case KYBER768:
*len = KYBER768_PRIVATE_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER1024
case KYBER1024:
*len = KYBER1024_PRIVATE_KEY_SIZE;
break;
#endif
#endif
default:
ret = NOT_COMPILED_IN;
break;
}
}
return ret;
}
int wc_MlKemKey_PublicKeySize(MlKemKey* key, word32* len)
{
int ret = 0;
if ((key == NULL) || (len == NULL)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
switch (key->type) {
#ifndef WOLFSSL_NO_ML_KEM
#ifdef WOLFSSL_WC_ML_KEM_512
case WC_ML_KEM_512:
*len = WC_ML_KEM_512_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_768
case WC_ML_KEM_768:
*len = WC_ML_KEM_768_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_1024
case WC_ML_KEM_1024:
*len = WC_ML_KEM_1024_PUBLIC_KEY_SIZE;
break;
#endif
#endif
#ifdef WOLFSSL_MLKEM_KYBER
#ifdef WOLFSSL_KYBER512
case KYBER512:
*len = KYBER512_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER768
case KYBER768:
*len = KYBER768_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER1024
case KYBER1024:
*len = KYBER1024_PUBLIC_KEY_SIZE;
break;
#endif
#endif
default:
ret = NOT_COMPILED_IN;
break;
}
}
return ret;
}
int wc_MlKemKey_EncodePrivateKey(MlKemKey* key, unsigned char* out, word32 len)
{
int ret = 0;
unsigned int k = 0;
unsigned int pubLen = 0;
unsigned int privLen = 0;
unsigned char* p = out;
if ((key == NULL) || (out == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) &&
((key->flags & MLKEM_FLAG_BOTH_SET) != MLKEM_FLAG_BOTH_SET)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
switch (key->type) {
#ifndef WOLFSSL_NO_ML_KEM
#ifdef WOLFSSL_WC_ML_KEM_512
case WC_ML_KEM_512:
k = WC_ML_KEM_512_K;
pubLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE;
privLen = WC_ML_KEM_512_PRIVATE_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_768
case WC_ML_KEM_768:
k = WC_ML_KEM_768_K;
pubLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE;
privLen = WC_ML_KEM_768_PRIVATE_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_1024
case WC_ML_KEM_1024:
k = WC_ML_KEM_1024_K;
pubLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE;
privLen = WC_ML_KEM_1024_PRIVATE_KEY_SIZE;
break;
#endif
#endif
#ifdef WOLFSSL_MLKEM_KYBER
#ifdef WOLFSSL_KYBER512
case KYBER512:
k = KYBER512_K;
pubLen = KYBER512_PUBLIC_KEY_SIZE;
privLen = KYBER512_PRIVATE_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER768
case KYBER768:
k = KYBER768_K;
pubLen = KYBER768_PUBLIC_KEY_SIZE;
privLen = KYBER768_PRIVATE_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER1024
case KYBER1024:
k = KYBER1024_K;
pubLen = KYBER1024_PUBLIC_KEY_SIZE;
privLen = KYBER1024_PRIVATE_KEY_SIZE;
break;
#endif
#endif
default:
ret = NOT_COMPILED_IN;
break;
}
}
if ((ret == 0) && (len != privLen)) {
ret = BUFFER_E;
}
if (ret == 0) {
mlkem_to_bytes(p, key->priv, (int)k);
p += WC_ML_KEM_POLY_SIZE * k;
ret = wc_KyberKey_EncodePublicKey(key, p, pubLen);
p += pubLen;
}
if ((ret == 0) && ((key->flags & MLKEM_FLAG_H_SET) == 0)) {
ret = MLKEM_HASH_H(&key->hash, p - pubLen, pubLen, key->h);
}
if (ret == 0) {
key->flags |= MLKEM_FLAG_H_SET;
XMEMCPY(p, key->h, sizeof(key->h));
p += WC_ML_KEM_SYM_SZ;
XMEMCPY(p, key->z, sizeof(key->z));
}
return ret;
}
int wc_MlKemKey_EncodePublicKey(MlKemKey* key, unsigned char* out, word32 len)
{
int ret = 0;
unsigned int k = 0;
unsigned int pubLen = 0;
unsigned char* p = out;
if ((key == NULL) || (out == NULL)) {
ret = BAD_FUNC_ARG;
}
if ((ret == 0) &&
((key->flags & MLKEM_FLAG_PUB_SET) != MLKEM_FLAG_PUB_SET)) {
ret = BAD_FUNC_ARG;
}
if (ret == 0) {
switch (key->type) {
#ifndef WOLFSSL_NO_ML_KEM
#ifdef WOLFSSL_WC_ML_KEM_512
case WC_ML_KEM_512:
k = WC_ML_KEM_512_K;
pubLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_768
case WC_ML_KEM_768:
k = WC_ML_KEM_768_K;
pubLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_WC_ML_KEM_1024
case WC_ML_KEM_1024:
k = WC_ML_KEM_1024_K;
pubLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE;
break;
#endif
#endif
#ifdef WOLFSSL_MLKEM_KYBER
#ifdef WOLFSSL_KYBER512
case KYBER512:
k = KYBER512_K;
pubLen = KYBER512_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER768
case KYBER768:
k = KYBER768_K;
pubLen = KYBER768_PUBLIC_KEY_SIZE;
break;
#endif
#ifdef WOLFSSL_KYBER1024
case KYBER1024:
k = KYBER1024_K;
pubLen = KYBER1024_PUBLIC_KEY_SIZE;
break;
#endif
#endif
default:
ret = NOT_COMPILED_IN;
break;
}
}
if ((ret == 0) && (len != pubLen)) {
ret = BUFFER_E;
}
if (ret == 0) {
int i;
mlkem_to_bytes(p, key->pub, (int)k);
p += k * WC_ML_KEM_POLY_SIZE;
for (i = 0; i < WC_ML_KEM_SYM_SZ; i++) {
p[i] = key->pubSeed[i];
}
if ((key->flags & MLKEM_FLAG_H_SET) == 0) {
ret = MLKEM_HASH_H(&key->hash, out, len, key->h);
}
}
if (ret == 0) {
key->flags |= MLKEM_FLAG_H_SET;
}
return ret;
}
#endif