mirror of https://github.com/wolfSSL/wolfssl.git
Merge pull request #8412 from SparkiDev/mlkem_kyber_small_mem
ML-KEM/Kyber: small memory usagepull/8422/head
commit
f0b3c2955e
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue