Merge pull request #8412 from SparkiDev/mlkem_kyber_small_mem

ML-KEM/Kyber: small memory usage
pull/8422/head
David Garske 2025-02-04 11:45:01 -08:00 committed by GitHub
commit f0b3c2955e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 431 additions and 39 deletions

View File

@ -676,6 +676,8 @@ WOLFSSL_MAKE_SYSTEM_NAME_LINUX
WOLFSSL_MAKE_SYSTEM_NAME_WSL
WOLFSSL_MDK5
WOLFSSL_MEM_FAIL_COUNT
WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
WOLFSSL_MONT_RED_CT
WOLFSSL_MP_COND_COPY
WOLFSSL_MP_INVMOD_CONSTANT_TIME

View File

@ -24,6 +24,20 @@
* https://csrc.nist.gov/Projects/post-quantum-cryptography/post-quantum-cryptography-standardization/round-3-submissions
*/
/* Possible Kyber options:
*
* WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM Default: OFF
* Uses less dynamic memory to perform key generation.
* Has a small performance trade-off.
* Only usable with C implementation.
*
* WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM Default: OFF
* Uses less dynamic memory to perform encapsulation.
* Affects decapsulation too as encapsulation called.
* Has a small performance trade-off.
* Only usable with C implementation.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@ -42,6 +56,14 @@
#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
#ifdef WOLFSSL_WC_KYBER
/******************************************************************************/
@ -225,7 +247,8 @@ int wc_KyberKey_MakeKey(KyberKey* key, WC_RNG* rng)
* Make a Kyber key object using random data.
*
* @param [in, out] key Kyber key ovject.
* @param [in] rng Random number generator.
* @param [in] rand Random data.
* @param [in] len Length of random data in bytes.
* @return 0 on success.
* @return BAD_FUNC_ARG when key or rand is NULL.
* @return BUFFER_E when length is not KYBER_MAKEKEY_RAND_SZ.
@ -239,11 +262,17 @@ int wc_KyberKey_MakeKeyWithRandom(KyberKey* key, const unsigned char* rand,
byte* pubSeed = buf;
byte* noiseSeed = buf + KYBER_SYM_SZ;
#ifndef WOLFSSL_NO_MALLOC
sword16* a = NULL;
#else
sword16 a[(KYBER_MAX_K + 1) * KYBER_MAX_K * KYBER_N];
#endif
sword16* e = NULL;
#else
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
sword16 e[(KYBER_MAX_K + 1) * KYBER_MAX_K * KYBER_N];
#else
sword16 e[KYBER_MAX_K * KYBER_N];
#endif
#endif
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
sword16* a = NULL;
#endif
int ret = 0;
int kp = 0;
@ -302,9 +331,14 @@ int wc_KyberKey_MakeKeyWithRandom(KyberKey* key, const unsigned char* rand,
#ifndef WOLFSSL_NO_MALLOC
if (ret == 0) {
/* Allocate dynamic memory for matrix and error vector. */
a = (sword16*)XMALLOC((kp + 1) * kp * KYBER_N * sizeof(sword16),
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
e = (sword16*)XMALLOC((kp + 1) * kp * KYBER_N * sizeof(sword16),
key->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (a == NULL) {
#else
e = (sword16*)XMALLOC(kp * KYBER_N * sizeof(sword16),
key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#endif
if (e == NULL) {
ret = MEMORY_E;
}
}
@ -312,8 +346,10 @@ int wc_KyberKey_MakeKeyWithRandom(KyberKey* key, const unsigned char* rand,
if (ret == 0) {
const byte* d = rand;
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
/* Error vector allocated at end of a. */
e = a + (kp * kp * KYBER_N);
a = e + (kp * KYBER_N);
#endif
#if defined(WOLFSSL_KYBER_ORIGINAL) && !defined(WOLFSSL_NO_ML_KEM)
if (key->type & KYBER_ORIGINAL)
@ -344,20 +380,29 @@ int wc_KyberKey_MakeKeyWithRandom(KyberKey* key, const unsigned char* rand,
/* Cache the z value for decapsulation and encoding private key. */
XMEMCPY(key->z, z, sizeof(key->z));
/* Generate the matrix A. */
ret = kyber_gen_matrix(&key->prf, a, kp, pubSeed, 0);
}
if (ret == 0) {
/* Initialize PRF for use in noise generation. */
kyber_prf_init(&key->prf);
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
/* Generate noise using PRF. */
ret = kyber_get_noise(&key->prf, kp, key->priv, e, NULL, noiseSeed);
}
if (ret == 0) {
/* Generate the matrix A. */
ret = kyber_gen_matrix(&key->prf, a, kp, pubSeed, 0);
}
if (ret == 0) {
/* Generate key pair from random data. */
kyber_keygen(key->priv, key->pub, e, a, kp);
#else
/* Generate noise using PRF. */
ret = kyber_get_noise(&key->prf, kp, key->priv, NULL, NULL, noiseSeed);
}
if (ret == 0) {
ret = kyber_keygen_seeds(key->priv, key->pub, &key->prf, e, kp,
pubSeed, noiseSeed);
}
if (ret == 0) {
#endif
/* Private and public key are set/available. */
key->flags |= KYBER_FLAG_PRIV_SET | KYBER_FLAG_PUB_SET;
}
@ -365,7 +410,7 @@ int wc_KyberKey_MakeKeyWithRandom(KyberKey* key, const unsigned char* rand,
#ifndef WOLFSSL_NO_MALLOC
/* Free dynamic memory allocated in function. */
if (key != NULL) {
XFREE(a, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(e, key->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
@ -470,15 +515,25 @@ static int kyberkey_encapsulate(KyberKey* key, const byte* msg, byte* coins,
{
int ret = 0;
sword16* sp = NULL;
sword16* ep = NULL;
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
sword16* k = NULL;
sword16* ep = NULL;
sword16* epp = NULL;
#endif
unsigned int kp = 0;
unsigned int compVecSz = 0;
#ifndef WOLFSSL_NO_MALLOC
sword16* at = NULL;
#else
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
sword16 at[((KYBER_MAX_K + 3) * KYBER_MAX_K + 3) * KYBER_N];
#else
sword16 at[3 * KYBER_MAX_K * KYBER_N];
#endif
#endif
#ifdef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
sword16* bp;
sword16* v;
#endif
/* Establish parameters based on key type. */
@ -532,8 +587,13 @@ static int kyberkey_encapsulate(KyberKey* key, const byte* msg, byte* coins,
#ifndef WOLFSSL_NO_MALLOC
if (ret == 0) {
/* Allocate dynamic memory for all matrices, vectors and polynomials. */
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
at = (sword16*)XMALLOC(((kp + 3) * kp + 3) * KYBER_N * sizeof(sword16),
key->heap, DYNAMIC_TYPE_TMP_BUFFER);
#else
at = (sword16*)XMALLOC(3 * kp * KYBER_N * sizeof(sword16), key->heap,
DYNAMIC_TYPE_TMP_BUFFER);
#endif
if (at == NULL) {
ret = MEMORY_E;
}
@ -541,36 +601,58 @@ static int kyberkey_encapsulate(KyberKey* key, const byte* msg, byte* coins,
#endif
if (ret == 0) {
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
/* Assign allocated dynamic memory to pointers.
* at (m) | k (p) | sp (v) | sp (v) | epp (v) | bp (p) | v (v) */
* at (m) | k (p) | sp (v) | ep (p) | epp (v) | bp (v) | v (p) */
k = at + KYBER_N * kp * kp;
sp = k + KYBER_N;
ep = sp + KYBER_N * kp;
epp = ep + KYBER_N * kp;
#else
/* Assign allocated dynamic memory to pointers.
* at (v) | sp (v) | bp (v) */
sp = at + KYBER_N * kp;
#endif
/* Initialize the PRF for use in the noise generation. */
kyber_prf_init(&key->prf);
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
/* Convert msg to a polynomial. */
kyber_from_msg(k, msg);
/* Generate the transposed matrix. */
ret = kyber_gen_matrix(&key->prf, at, kp, key->pubSeed, 1);
}
if (ret == 0) {
/* Initialize the PRF for use in the noise generation. */
kyber_prf_init(&key->prf);
/* Generate noise using PRF. */
ret = kyber_get_noise(&key->prf, kp, sp, ep, epp, coins);
}
if (ret == 0) {
/* Generate the transposed matrix. */
ret = kyber_gen_matrix(&key->prf, at, kp, key->pubSeed, 1);
}
if (ret == 0) {
sword16* bp;
sword16* v;
/* Assign remaining allocated dynamic memory to pointers.
* at (m) | k (p) | sp (v) | sp (v) | epp (v) | bp (p) | v (v)*/
* at (m) | k (p) | sp (v) | ep (p) | epp (v) | bp (v) | v (p)*/
bp = epp + KYBER_N;
v = bp + KYBER_N * kp;
/* Perform encapsulation maths. */
kyber_encapsulate(key->pub, bp, v, at, sp, ep, epp, k, kp);
#else
/* Generate noise using PRF. */
ret = kyber_get_noise(&key->prf, kp, sp, NULL, NULL, coins);
}
if (ret == 0) {
/* Assign remaining allocated dynamic memory to pointers.
* at (v) | sp (v) | bp (v) */
bp = sp + KYBER_N * kp;
v = at;
ret = kyber_encapsulate_seeds(key->pub, &key->prf, bp, at, sp, kp, msg,
key->pubSeed, coins);
}
if (ret == 0) {
#endif
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
if (kp == KYBER512_K) {
@ -848,7 +930,7 @@ static KYBER_NOINLINE int kyberkey_decapsulate(KyberKey* key,
#if !defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC)
sword16* bp = NULL;
#else
sword16 bp[(KYBER_MAX_K + 2) * KYBER_N];
sword16 bp[(KYBER_MAX_K + 1) * KYBER_N];
#endif
/* Establish parameters based on key type. */
@ -901,8 +983,8 @@ static KYBER_NOINLINE int kyberkey_decapsulate(KyberKey* key,
#if !defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC)
if (ret == 0) {
/* Allocate dynamic memory for a vector and two polynomials. */
bp = (sword16*)XMALLOC((kp + 2) * KYBER_N * sizeof(sword16), key->heap,
/* Allocate dynamic memory for a vector and a polynomial. */
bp = (sword16*)XMALLOC((kp + 1) * KYBER_N * sizeof(sword16), key->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (bp == NULL) {
ret = MEMORY_E;
@ -911,9 +993,9 @@ static KYBER_NOINLINE int kyberkey_decapsulate(KyberKey* key,
#endif
if (ret == 0) {
/* Assign allocated dynamic memory to pointers.
* bp (v) | v (p) | mp (p) */
* bp (v) | v (p) */
v = bp + kp * KYBER_N;
mp = v + KYBER_N;
mp = bp;
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
if (kp == KYBER512_K) {

View File

@ -81,6 +81,16 @@
#include <wolfcrypt/src/misc.c>
#endif
#if defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) || \
defined(WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM)
static int kyber_gen_matrix_i(KYBER_PRF_T* prf, sword16* a, int kp, byte* seed,
int i, int transposed);
static int kyber_get_noise_i(KYBER_PRF_T* prf, int kp, sword16* vec2,
byte* seed, int i, int make);
static int kyber_get_noise_eta2_c(KYBER_PRF_T* prf, sword16* p,
const byte* seed);
#endif
/* Declared in wc_kyber.c to stop compiler optimizer from simplifying. */
extern volatile sword16 kyber_opt_blocker;
@ -1088,10 +1098,16 @@ static void kyber_pointwise_acc_mont(sword16* r, const sword16* a,
unsigned int i;
kyber_basemul_mont(r, a, b);
#ifdef WOLFSSL_KYBER_SMALL
for (i = 1; i < kp; ++i) {
kyber_basemul_mont_add(r, a + i * KYBER_N, b + i * KYBER_N);
}
#else
for (i = 1; i < kp - 1; ++i) {
kyber_basemul_mont_add(r, a + i * KYBER_N, b + i * KYBER_N);
}
kyber_basemul_mont_add(r, a + (kp - 1) * KYBER_N, b + (kp - 1) * KYBER_N);
#endif
}
/******************************************************************************/
@ -1281,6 +1297,7 @@ void kyber_decapsulate(const sword16* priv, sword16* mp, sword16* bp,
#else
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
/* Generate a public-private key pair from randomly generated data.
*
* @param [in, out] priv Private key vector of polynomials.
@ -1344,6 +1361,67 @@ void kyber_keygen(sword16* priv, sword16* pub, sword16* e, const sword16* a,
}
}
#else
/* Generate a public-private key pair from randomly generated data.
*
* @param [in, out] priv Private key vector of polynomials.
* @param [out] pub Public key vector of polynomials.
* @param [in] prf XOF object.
* @param [in] tv Temporary vector of polynomials.
* @param [in] kp Number of polynomials in vector.
* @param [in] seed Random seed to generate matrix A from.
* @param [in] noiseSeed Random seed to generate noise from.
*/
int kyber_keygen_seeds(sword16* priv, sword16* pub, KYBER_PRF_T* prf,
sword16* tv, int kp, byte* seed, byte* noiseSeed)
{
int i;
int ret = 0;
/* Transform private key. All of result used in public key calculation */
for (i = 0; i < kp; ++i) {
kyber_ntt(priv + i * KYBER_N);
}
/* For each polynomial in the vectors. */
for (i = 0; i < kp; ++i) {
unsigned int j;
/* Generate a vector of matrix A. */
ret = kyber_gen_matrix_i(prf, tv, kp, seed, i, 0);
if (ret != 0) {
break;
}
/* Multiply a by private into public polynomial. */
kyber_pointwise_acc_mont(pub + i * KYBER_N, tv, priv, kp);
/* Convert public polynomial to Montgomery form. */
for (j = 0; j < KYBER_N; ++j) {
sword32 t = pub[i * KYBER_N + j] * (sword32)KYBER_F;
pub[i * KYBER_N + j] = KYBER_MONT_RED(t);
}
/* Generate noise using PRF. */
ret = kyber_get_noise_i(prf, kp, tv, noiseSeed, i, 1);
if (ret != 0) {
break;
}
/* Transform error values polynomial. */
kyber_ntt(tv);
/* Add errors to public key and reduce. */
for (j = 0; j < KYBER_N; ++j) {
sword16 t = pub[i * KYBER_N + j] + tv[j];
pub[i * KYBER_N + j] = KYBER_BARRETT_RED(t);
}
}
return ret;
}
#endif
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
/* Encapsulate message.
*
* @param [in] pub Public key vector of polynomials.
@ -1394,7 +1472,6 @@ static void kyber_encapsulate_c(const sword16* pub, sword16* bp, sword16* v,
}
}
/* Encapsulate message.
*
* @param [in] pub Public key vector of polynomials.
@ -1423,6 +1500,85 @@ void kyber_encapsulate(const sword16* pub, sword16* bp, sword16* v,
}
}
#else
/* Encapsulate message.
*
* @param [in] pub Public key vector of polynomials.
* @param [in] prf XOF object.
* @param [out] bp Vector of polynomials.
* @param [in, out] tp Polynomial.
* @param [in] sp Vector of polynomials.
* @param [in] kp Number of polynomials in vector.
* @param [in] msg Message to encapsulate.
* @param [in] seed Random seed to generate matrix A from.
* @param [in] coins Random seed to generate noise from.
*/
int kyber_encapsulate_seeds(const sword16* pub, KYBER_PRF_T* prf, sword16* bp,
sword16* tp, sword16* sp, int kp, const byte* msg, byte* seed, byte* coins)
{
int ret = 0;
int i;
sword16* at = tp;
sword16* ep = tp;
sword16* v = tp;
sword16* epp = tp + KYBER_N;
sword16* m = sp;
/* Transform sp. All of result used in calculation of bp and v. */
for (i = 0; i < kp; ++i) {
kyber_ntt(sp + i * KYBER_N);
}
/* For each polynomial in the vectors. */
for (i = 0; i < kp; ++i) {
unsigned int j;
/* Generate a vector of matrix A. */
ret = kyber_gen_matrix_i(prf, at, kp, seed, i, 1);
if (ret != 0) {
break;
}
/* Multiply at by sp into bp polynomial. */
kyber_pointwise_acc_mont(bp + i * KYBER_N, at, sp, kp);
/* Inverse transform bp polynomial. */
kyber_invntt(bp + i * KYBER_N);
/* Generate noise using PRF. */
ret = kyber_get_noise_i(prf, kp, ep, coins, i, 0);
if (ret != 0) {
break;
}
/* Add errors to bp and reduce. */
for (j = 0; j < KYBER_N; ++j) {
sword16 t = bp[i * KYBER_N + j] + ep[j];
bp[i * KYBER_N + j] = KYBER_BARRETT_RED(t);
}
}
/* Multiply public key by sp into v polynomial. */
kyber_pointwise_acc_mont(v, pub, sp, kp);
/* Inverse transform v. */
kyber_invntt(v);
kyber_from_msg(m, msg);
/* Generate noise using PRF. */
coins[KYBER_SYM_SZ] = 2 * kp;
ret = kyber_get_noise_eta2_c(prf, epp, coins);
if (ret == 0) {
/* Add errors and message to v and reduce. */
for (i = 0; i < KYBER_N; ++i) {
sword16 t = v[i] + epp[i] + m[i];
tp[i] = KYBER_BARRETT_RED(t);
}
}
return ret;
}
#endif
/* Decapsulate message.
*
* @param [in] priv Private key vector of polynomials.
@ -2362,6 +2518,9 @@ static unsigned int kyber_rej_uniform_c(sword16* p, unsigned int len,
}
#endif
#if !defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) || \
!defined(WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM)
#if !(defined(WOLFSSL_ARMASM) && defined(__aarch64__))
/* Deterministically generate a matrix (or transpose) of uniform integers mod q.
*
@ -2379,7 +2538,7 @@ static unsigned int kyber_rej_uniform_c(sword16* p, unsigned int len,
static int kyber_gen_matrix_c(KYBER_PRF_T* prf, sword16* a, int kp, byte* seed,
int transposed)
{
#ifdef WOLFSSL_SMALL_STACK
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
byte* rand;
#else
byte rand[GEN_MATRIX_SIZE + 2];
@ -2390,7 +2549,7 @@ static int kyber_gen_matrix_c(KYBER_PRF_T* prf, sword16* a, int kp, byte* seed,
XMEMCPY(extSeed, seed, KYBER_SYM_SZ);
#ifdef WOLFSSL_SMALL_STACK
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
/* Allocate large amount of memory to hold random bytes to be samples. */
rand = (byte*)XMALLOC(GEN_MATRIX_SIZE + 2, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (rand == NULL) {
@ -2441,7 +2600,7 @@ static int kyber_gen_matrix_c(KYBER_PRF_T* prf, sword16* a, int kp, byte* seed,
}
}
#ifdef WOLFSSL_SMALL_STACK
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
/* Dispose of temporary buffer. */
XFREE(rand, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
@ -2534,6 +2693,97 @@ int kyber_gen_matrix(KYBER_PRF_T* prf, sword16* a, int kp, byte* seed,
return ret;
}
#endif
#if defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) || \
defined(WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM)
/* Deterministically generate a matrix (or transpose) of uniform integers mod q.
*
* Seed used with XOF to generate random bytes.
*
* @param [in] prf XOF object.
* @param [out] a Matrix of uniform integers.
* @param [in] kp Number of dimensions. kp x kp polynomials.
* @param [in] seed Bytes to seed XOF generation.
* @param [in] i Index of vector to generate.
* @param [in] transposed Whether A or A^T is generated.
* @return 0 on success.
* @return MEMORY_E when dynamic memory allocation fails. Only possible when
* WOLFSSL_SMALL_STACK is defined.
*/
static int kyber_gen_matrix_i(KYBER_PRF_T* prf, sword16* a, int kp, byte* seed,
int i, int transposed)
{
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
byte* rand;
#else
byte rand[GEN_MATRIX_SIZE + 2];
#endif
byte extSeed[KYBER_SYM_SZ + 2];
int ret = 0;
int j;
XMEMCPY(extSeed, seed, KYBER_SYM_SZ);
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
/* Allocate large amount of memory to hold random bytes to be samples. */
rand = (byte*)XMALLOC(GEN_MATRIX_SIZE + 2, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (rand == NULL) {
ret = MEMORY_E;
}
#endif
#if !defined(WOLFSSL_KYBER_SMALL) && defined(WC_64BIT_CPU)
/* Loading 64 bits, only using 48 bits. Loading 2 bytes more than used. */
if (ret == 0) {
rand[GEN_MATRIX_SIZE+0] = 0xff;
rand[GEN_MATRIX_SIZE+1] = 0xff;
}
#endif
/* Generate each polynomial in vector from seed with indices. */
for (j = 0; (ret == 0) && (j < kp); j++) {
if (transposed) {
extSeed[KYBER_SYM_SZ + 0] = i;
extSeed[KYBER_SYM_SZ + 1] = j;
}
else {
extSeed[KYBER_SYM_SZ + 0] = j;
extSeed[KYBER_SYM_SZ + 1] = i;
}
/* Absorb the index specific seed. */
ret = kyber_xof_absorb(prf, extSeed, sizeof(extSeed));
if (ret == 0) {
/* Create out based on the seed. */
ret = kyber_xof_squeezeblocks(prf, rand, GEN_MATRIX_NBLOCKS);
}
if (ret == 0) {
unsigned int ctr;
/* Sample random bytes to create a polynomial. */
ctr = kyber_rej_uniform_c(a + j * KYBER_N, KYBER_N, rand,
GEN_MATRIX_SIZE);
/* Create more blocks if too many rejected. */
while (ctr < KYBER_N) {
kyber_xof_squeezeblocks(prf, rand, 1);
ctr += kyber_rej_uniform_c(a + j * KYBER_N + ctr,
KYBER_N - ctr, rand, XOF_BLOCK_SIZE);
}
}
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
/* Dispose of temporary buffer. */
XFREE(rand, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return ret;
}
#endif
/******************************************************************************/
/* Subtract one 2 bit value from another out of a larger number.
@ -3276,6 +3526,7 @@ static int kyber_get_noise_c(KYBER_PRF_T* prf, int kp, sword16* vec1, int eta1,
/* Increment value of appended byte. */
seed[KYBER_SYM_SZ]++;
}
if ((ret == 0) && (vec2 != NULL)) {
/* Generate noise for error. */
for (i = 0; (ret == 0) && (i < kp); i++) {
/* Generate noise for each dimension of vector. */
@ -3283,6 +3534,10 @@ static int kyber_get_noise_c(KYBER_PRF_T* prf, int kp, sword16* vec1, int eta1,
/* Increment value of appended byte. */
seed[KYBER_SYM_SZ]++;
}
}
else {
seed[KYBER_SYM_SZ] = 2 * kp;
}
if ((ret == 0) && (poly != NULL)) {
/* Generating random error polynomial. */
ret = kyber_get_noise_eta2_c(prf, poly, seed);
@ -3382,6 +3637,45 @@ int kyber_get_noise(KYBER_PRF_T* prf, int kp, sword16* vec1,
return ret;
}
#if defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) || \
defined(WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM)
/* Get the noise/error by calculating random bytes and sampling to a binomial
* distribution.
*
* @param [in, out] prf Pseudo-random function object.
* @param [in] kp Number of polynomials in vector.
* @param [out] vec2 Second Vector of polynomials.
* @param [in] seed Seed to use when calculating random.
* @param [in] i Index of vector to generate.
* @param [in] make Indicates generation is for making a key.
* @return 0 on success.
*/
static int kyber_get_noise_i(KYBER_PRF_T* prf, int kp, sword16* vec2,
byte* seed, int i, int make)
{
int ret;
/* Initialize the PRF (generating matrix A leaves it in uninitialized
* state). */
kyber_prf_init(prf);
/* Set index of polynomial of second vector into seed. */
seed[KYBER_SYM_SZ] = kp + i;
#if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512)
if ((kp == KYBER512_K) && make) {
ret = kyber_get_noise_eta1_c(prf, vec2, seed, KYBER_CBD_ETA3);
}
else
#endif
{
ret = kyber_get_noise_eta1_c(prf, vec2, seed, KYBER_CBD_ETA2);
}
(void)make;
return ret;
}
#endif
/******************************************************************************/
#if !(defined(__aarch64__) && defined(WOLFSSL_ARMASM))

View File

@ -145,13 +145,27 @@ struct KyberKey {
WOLFSSL_LOCAL
void kyber_init(void);
#ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
WOLFSSL_LOCAL
void kyber_keygen(sword16* priv, sword16* pub, sword16* e, const sword16* a,
int kp);
#else
WOLFSSL_LOCAL
int kyber_keygen_seeds(sword16* priv, sword16* pub, KYBER_PRF_T* prf,
sword16* e, int kp, byte* seed, byte* noiseSeed);
#endif
#ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
WOLFSSL_LOCAL
void kyber_encapsulate(const sword16* pub, sword16* bp, sword16* v,
const sword16* at, sword16* sp, const sword16* ep, const sword16* epp,
const sword16* m, int kp);
#else
WOLFSSL_LOCAL
int kyber_encapsulate_seeds(const sword16* pub, KYBER_PRF_T* prf, sword16* bp,
sword16* tp, sword16* sp, int kp, const byte* msg, byte* seed,
byte* coins);
#endif
WOLFSSL_LOCAL
void kyber_decapsulate(const sword16* priv, sword16* mp, sword16* bp,
const sword16* v, int kp);