Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/pq-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ jobs:
'--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,1024 --enable-tls-mlkem-standalone --disable-pqc-hybrids --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"',
'--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium=yes,no-ctx --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"',
'--enable-intelasm --enable-sp-asm --enable-mlkem=yes,kyber,ml-kem,cache-a CPPFLAGS="-DWOLFSSL_MLKEM_DYNAMIC_KEYS"',
'--enable-intelasm --enable-sp-asm --enable-dilithium=yes CPPFLAGS="-DWOLFSSL_DILITHIUM_DYNAMIC_KEYS"',
'--disable-intelasm --enable-dilithium=yes,small CPPFLAGS="-DWOLFSSL_DILITHIUM_DYNAMIC_KEYS"',
'--disable-intelasm --enable-dilithium=44,65,87,verify-only CPPFLAGS="-DWOLFSSL_DILITHIUM_DYNAMIC_KEYS"',
]
name: make check
if: github.repository_owner == 'wolfssl'
Expand Down
192 changes: 174 additions & 18 deletions wolfcrypt/src/dilithium.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@
* Key data is assigned into Dilithium key rather than copied.
* Life of key data passed in is tightly coupled to life of Dilithium key.
* Cannot be used when make key is enabled.
* WOLFSSL_DILITHIUM_DYNAMIC_KEYS Default: OFF
* Key buffers (public and private) are dynamically allocated on the heap
* instead of being static arrays in the key struct. Buffers are right-sized
* for the key's ML-DSA level and only allocated when needed (e.g. no private
* key buffer for verify-only keys). Reduces memory footprint significantly.
* Cannot be used with WOLFSSL_DILITHIUM_ASSIGN_KEY.
* WOLFSSL_DILITHIUM_SIGN_SMALL_MEM Default: OFF
* Compiles signature implementation that uses smaller amounts of memory but
* is considerably slower.
Expand Down Expand Up @@ -218,6 +224,11 @@ void print_data(const char* name, const byte* d, int len)
#error "Cannot use assign key when making keys"
#endif

#if defined(WOLFSSL_DILITHIUM_DYNAMIC_KEYS) && \
defined(WOLFSSL_DILITHIUM_ASSIGN_KEY)
#error "Cannot use both WOLFSSL_DILITHIUM_DYNAMIC_KEYS and WOLFSSL_DILITHIUM_ASSIGN_KEY"
#endif


/* Number of bytes from first block to use for sign. */
#define DILITHIUM_SIGN_BYTES 8
Expand Down Expand Up @@ -358,6 +369,72 @@ static int dilithium_get_params(int level, const wc_dilithium_params** params)
return ret;
}

#if defined(WOLFSSL_DILITHIUM_DYNAMIC_KEYS) && \
defined(WOLFSSL_DILITHIUM_PRIVATE_KEY)
/* Allocate the private key buffer for the current level if not already
* allocated. Buffer is sized via wc_dilithium_size(key) and the allocated size
* is stored in key->kSz for later use (ForceZero, free). On failure key->k may
* remain NULL; callers must not inspect it. */
static int dilithium_alloc_priv_buf(dilithium_key* key)
{
int ret = 0;

if (key->k == NULL) {
int secSz = wc_dilithium_size(key);
if (secSz < 0) {
/* Should not happen, as the level checks have already been
* performed, but defense-in-depth. */
ret = BAD_STATE_E;
}
else {
#ifdef USE_INTEL_SPEEDUP
secSz += 8;
#endif
key->k = (byte*)XMALLOC((word32)secSz, key->heap,
DYNAMIC_TYPE_DILITHIUM);
if (key->k == NULL) {
ret = MEMORY_E;
}
else {
key->kSz = (word32)secSz;
}
}
}
return ret;
}
#endif

#if defined(WOLFSSL_DILITHIUM_DYNAMIC_KEYS) && \
defined(WOLFSSL_DILITHIUM_PUBLIC_KEY)
/* Allocate the public key buffer for the current level if not already
* allocated. Buffer is sized via wc_dilithium_pub_size(key). On failure,
* key->p may remain NULL; callers must not inspect it. */
static int dilithium_alloc_pub_buf(dilithium_key* key)
{
int ret = 0;

if (key->p == NULL) {
int pubSz = wc_dilithium_pub_size(key);
if (pubSz < 0) {
/* Should not happen, as the level checks have already been
* performed, but defense-in-depth. */
ret = BAD_STATE_E;
}
else {
#ifdef USE_INTEL_SPEEDUP
pubSz += 8;
#endif
key->p = (byte*)XMALLOC((word32)pubSz, key->heap,
DYNAMIC_TYPE_DILITHIUM);
if (key->p == NULL) {
ret = MEMORY_E;
}
}
}
return ret;
}
#endif

/******************************************************************************
* Hash operations
******************************************************************************/
Expand Down Expand Up @@ -7654,9 +7731,20 @@ static int dilithium_make_key_from_seed(dilithium_key* key, const byte* seed)
sword32* s1 = NULL;
sword32* s2 = NULL;
sword32* t = NULL;
byte* pub_seed = key->k;
byte* pub_seed = NULL;
byte kl[2];

#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS
ret = dilithium_alloc_priv_buf(key);
if (ret == 0) {
ret = dilithium_alloc_pub_buf(key);
}
#endif

if (ret == 0) {
pub_seed = key->k;
}

/* Allocate memory for large intermediates. */
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
#ifndef WC_DILITHIUM_FIXED_ARRAY
Expand Down Expand Up @@ -7818,11 +7906,22 @@ static int dilithium_make_key_from_seed(dilithium_key* key, const byte* seed)
sword64* t64 = NULL;
#endif
byte* h = NULL;
byte* pub_seed = key->k;
byte* pub_seed = NULL;
unsigned int r;
unsigned int s;
byte kl[2];

#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS
ret = dilithium_alloc_priv_buf(key);
if (ret == 0) {
ret = dilithium_alloc_pub_buf(key);
}
#endif

if (ret == 0) {
pub_seed = key->k;
}

/* Allocate memory for large intermediates. */
if (ret == 0) {
unsigned int allocSz;
Expand Down Expand Up @@ -8576,7 +8675,7 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
/* Step 11: Start rejection sampling loop */
do {
byte aseed[DILITHIUM_GEN_A_SEED_SZ];
byte w1e[DILITHIUM_MAX_W1_ENC_SZ];
WC_DECLARE_VAR(w1e, byte, DILITHIUM_MAX_W1_ENC_SZ, 0);
sword32* w = w1;
byte* commit = sig;
byte r;
Expand Down Expand Up @@ -8807,11 +8906,17 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key,
byte* ze = sig + params->lambda / 4;

/* Step 15: Encode w1. */
dilithium_vec_encode_w1(w1, params->k, params->gamma2, w1e);
/* Step 15: Hash mu and encoded w1.
* Step 32: Hash is stored in signature. */
ret = dilithium_hash256(&key->shake, mu, DILITHIUM_MU_SZ,
w1e, params->w1EncSz, commit, params->lambda / 4);
WC_ALLOC_VAR_EX(w1e, byte, DILITHIUM_MAX_W1_ENC_SZ,
key->heap, DYNAMIC_TYPE_DILITHIUM, ret=MEMORY_E);
if (WC_VAR_OK(w1e)) {
dilithium_vec_encode_w1(w1, params->k, params->gamma2,
w1e);
/* Step 15: Hash mu and encoded w1.
* Step 32: Hash is stored in signature. */
ret = dilithium_hash256(&key->shake, mu, DILITHIUM_MU_SZ,
w1e, params->w1EncSz, commit, params->lambda / 4);
}
WC_FREE_VAR_EX(w1e, key->heap, DYNAMIC_TYPE_DILITHIUM);
if (ret == 0) {
/* Step 17: Compute c from first 256 bits of commit. */
ret = dilithium_sample_in_ball_ex(params->level,
Expand Down Expand Up @@ -10000,6 +10105,16 @@ static int oqs_dilithium_make_key(dilithium_key* key, WC_RNG* rng)
ret = SIG_TYPE_E;
}


#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS
Comment thread
SparkiDev marked this conversation as resolved.
if (ret == 0) {
ret = dilithium_alloc_priv_buf(key);
}
if (ret == 0) {
ret = dilithium_alloc_pub_buf(key);
}
#endif

if (ret == 0) {
ret = wolfSSL_liboqsRngMutexLock(rng);
if (ret == 0) {
Expand Down Expand Up @@ -10921,6 +11036,19 @@ int wc_dilithium_set_level(dilithium_key* key, byte level)
#endif
#endif /* WOLFSSL_WC_DILITHIUM */

#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS
Comment thread
SparkiDev marked this conversation as resolved.
if (key->k != NULL) {
ForceZero(key->k, key->kSz);
XFREE(key->k, key->heap, DYNAMIC_TYPE_DILITHIUM);
key->k = NULL;
key->kSz = 0;
}
if (key->p != NULL) {
XFREE(key->p, key->heap, DYNAMIC_TYPE_DILITHIUM);
key->p = NULL;
}
#endif

/* Store level and indicate public and private key are not set. */
key->level = level % WC_ML_DSA_DRAFT;
key->pubKeySet = 0;
Comment thread
Frauschi marked this conversation as resolved.
Expand Down Expand Up @@ -10991,6 +11119,15 @@ void wc_dilithium_free(dilithium_key* key)
/* Free the SHAKE-128/256 object. */
wc_Shake256_Free(&key->shake);
#endif
#endif
#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS
if (key->k != NULL) {
ForceZero(key->k, key->kSz);
XFREE(key->k, key->heap, DYNAMIC_TYPE_DILITHIUM);
}
if (key->p != NULL) {
XFREE(key->p, key->heap, DYNAMIC_TYPE_DILITHIUM);
}
#endif
/* Ensure all private data is zeroized. */
ForceZero(key, sizeof(*key));
Comment thread
Frauschi marked this conversation as resolved.
Expand Down Expand Up @@ -11553,12 +11690,19 @@ int wc_dilithium_import_public(const byte* in, word32 inLen, dilithium_key* key)
}
}


#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS
if (ret == 0) {
ret = dilithium_alloc_pub_buf(key);
}
#endif

if (ret == 0) {
/* Copy the private key data in or copy pointer. */
#ifndef WOLFSSL_DILITHIUM_ASSIGN_KEY
XMEMCPY(key->p, in, inLen);
#else
#ifdef WOLFSSL_DILITHIUM_ASSIGN_KEY
key->p = in;
#else
XMEMCPY(key->p, in, inLen);
#endif

#ifdef WC_DILITHIUM_CACHE_PUB_VECTORS
Expand Down Expand Up @@ -11630,23 +11774,35 @@ static int dilithium_set_priv_key(const byte* priv, word32 privSz,
dilithium_key* key)
{
int ret = 0;
int expPrivSz;
#ifdef WC_DILITHIUM_CACHE_MATRIX_A
const wc_dilithium_params* params = key->params;
#endif

/* Validate parameters. */
if ((privSz != ML_DSA_LEVEL2_KEY_SIZE) &&
(privSz != ML_DSA_LEVEL3_KEY_SIZE) &&
(privSz != ML_DSA_LEVEL5_KEY_SIZE)) {
/* Validate parameters. privSz must match the expected size for the
* level set on the key. This is required so that subsequent code
* which reads via key->params stays within the (possibly dynamically
* sized) buffer. */
expPrivSz = wc_dilithium_size(key);
if (expPrivSz < 0) {
ret = BAD_FUNC_ARG;
}
else if (privSz != (word32)expPrivSz) {
ret = BAD_FUNC_ARG;
}

#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS
if (ret == 0) {
ret = dilithium_alloc_priv_buf(key);
}
#endif

if (ret == 0) {
/* Copy the private key data in or copy pointer. */
#ifndef WOLFSSL_DILITHIUM_ASSIGN_KEY
XMEMCPY(key->k, priv, privSz);
#else
#ifdef WOLFSSL_DILITHIUM_ASSIGN_KEY
key->k = priv;
#else
XMEMCPY(key->k, priv, privSz);
#endif
}

Expand Down
7 changes: 6 additions & 1 deletion wolfcrypt/src/wc_pkcs11.c
Original file line number Diff line number Diff line change
Expand Up @@ -2247,10 +2247,15 @@ int wc_Pkcs11StoreKey(Pkcs11Token* token, int type, int clear, void* key)
session.func->C_DestroyObject(session.handle, privKey);
}
}
#ifndef WOLFSSL_DILITHIUM_ASSIGN_KEY
#if !defined(WOLFSSL_DILITHIUM_ASSIGN_KEY) && \
!defined(WOLFSSL_DILITHIUM_DYNAMIC_KEYS)
if (ret == 0 && clear) {
ForceZero(mldsaKey->k, sizeof(mldsaKey->k));
}
#elif defined(WOLFSSL_DILITHIUM_DYNAMIC_KEYS)
if (ret == 0 && clear && mldsaKey->k != NULL) {
ForceZero(mldsaKey->k, mldsaKey->kSz);
}
Comment thread
Frauschi marked this conversation as resolved.
#endif
break;
}
Expand Down
8 changes: 7 additions & 1 deletion wolfssl/wolfcrypt/dilithium.h
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,9 @@ struct dilithium_key {
byte pubKeySet;
byte prvKeySet;
byte level; /* 2,3 or 5 */
#if defined(WOLFSSL_DILITHIUM_DYNAMIC_KEYS)
word32 kSz; /* allocated size of secret key buffer */
#endif

void* heap; /* heap hint */

Expand All @@ -734,7 +737,10 @@ struct dilithium_key {
int labelLen;
#endif

#ifndef WOLFSSL_DILITHIUM_ASSIGN_KEY
#if defined(WOLFSSL_DILITHIUM_DYNAMIC_KEYS)
byte* p; /* heap-allocated, right-sized public key */
byte* k; /* heap-allocated, right-sized secret key */
#elif !defined(WOLFSSL_DILITHIUM_ASSIGN_KEY)
#ifdef USE_INTEL_SPEEDUP
byte p[DILITHIUM_MAX_PUB_KEY_SIZE+8];
byte k[DILITHIUM_MAX_KEY_SIZE+8];
Expand Down
Loading