|
55 | 55 | * Key data is assigned into Dilithium key rather than copied. |
56 | 56 | * Life of key data passed in is tightly coupled to life of Dilithium key. |
57 | 57 | * Cannot be used when make key is enabled. |
| 58 | + * WOLFSSL_DILITHIUM_DYNAMIC_KEYS Default: OFF |
| 59 | + * Key buffers (public and private) are dynamically allocated on the heap |
| 60 | + * instead of being static arrays in the key struct. Buffers are right-sized |
| 61 | + * for the key's ML-DSA level and only allocated when needed (e.g. no private |
| 62 | + * key buffer for verify-only keys). Reduces memory footprint significantly. |
| 63 | + * Cannot be used with WOLFSSL_DILITHIUM_ASSIGN_KEY. |
58 | 64 | * WOLFSSL_DILITHIUM_SIGN_SMALL_MEM Default: OFF |
59 | 65 | * Compiles signature implementation that uses smaller amounts of memory but |
60 | 66 | * is considerably slower. |
@@ -218,6 +224,11 @@ void print_data(const char* name, const byte* d, int len) |
218 | 224 | #error "Cannot use assign key when making keys" |
219 | 225 | #endif |
220 | 226 |
|
| 227 | +#if defined(WOLFSSL_DILITHIUM_DYNAMIC_KEYS) && \ |
| 228 | + defined(WOLFSSL_DILITHIUM_ASSIGN_KEY) |
| 229 | + #error "Cannot use both WOLFSSL_DILITHIUM_DYNAMIC_KEYS and WOLFSSL_DILITHIUM_ASSIGN_KEY" |
| 230 | +#endif |
| 231 | + |
221 | 232 |
|
222 | 233 | /* Number of bytes from first block to use for sign. */ |
223 | 234 | #define DILITHIUM_SIGN_BYTES 8 |
@@ -358,6 +369,72 @@ static int dilithium_get_params(int level, const wc_dilithium_params** params) |
358 | 369 | return ret; |
359 | 370 | } |
360 | 371 |
|
| 372 | +#if defined(WOLFSSL_DILITHIUM_DYNAMIC_KEYS) && \ |
| 373 | + defined(WOLFSSL_DILITHIUM_PRIVATE_KEY) |
| 374 | +/* Allocate the private key buffer for the current level if not already |
| 375 | + * allocated. Buffer is sized via wc_dilithium_size(key) and the allocated size |
| 376 | + * is stored in key->kSz for later use (ForceZero, free). On failure key->k may |
| 377 | + * remain NULL; callers must not inspect it. */ |
| 378 | +static int dilithium_alloc_priv_buf(dilithium_key* key) |
| 379 | +{ |
| 380 | + int ret = 0; |
| 381 | + |
| 382 | + if (key->k == NULL) { |
| 383 | + int secSz = wc_dilithium_size(key); |
| 384 | + if (secSz < 0) { |
| 385 | + /* Should not happen, as the level checks have already been |
| 386 | + * performed, but defense-in-depth. */ |
| 387 | + ret = BAD_STATE_E; |
| 388 | + } |
| 389 | + else { |
| 390 | + #ifdef USE_INTEL_SPEEDUP |
| 391 | + secSz += 8; |
| 392 | + #endif |
| 393 | + key->k = (byte*)XMALLOC((word32)secSz, key->heap, |
| 394 | + DYNAMIC_TYPE_DILITHIUM); |
| 395 | + if (key->k == NULL) { |
| 396 | + ret = MEMORY_E; |
| 397 | + } |
| 398 | + else { |
| 399 | + key->kSz = (word32)secSz; |
| 400 | + } |
| 401 | + } |
| 402 | + } |
| 403 | + return ret; |
| 404 | +} |
| 405 | +#endif |
| 406 | + |
| 407 | +#if defined(WOLFSSL_DILITHIUM_DYNAMIC_KEYS) && \ |
| 408 | + defined(WOLFSSL_DILITHIUM_PUBLIC_KEY) |
| 409 | +/* Allocate the public key buffer for the current level if not already |
| 410 | + * allocated. Buffer is sized via wc_dilithium_pub_size(key). On failure, |
| 411 | + * key->p may remain NULL; callers must not inspect it. */ |
| 412 | +static int dilithium_alloc_pub_buf(dilithium_key* key) |
| 413 | +{ |
| 414 | + int ret = 0; |
| 415 | + |
| 416 | + if (key->p == NULL) { |
| 417 | + int pubSz = wc_dilithium_pub_size(key); |
| 418 | + if (pubSz < 0) { |
| 419 | + /* Should not happen, as the level checks have already been |
| 420 | + * performed, but defense-in-depth. */ |
| 421 | + ret = BAD_STATE_E; |
| 422 | + } |
| 423 | + else { |
| 424 | + #ifdef USE_INTEL_SPEEDUP |
| 425 | + pubSz += 8; |
| 426 | + #endif |
| 427 | + key->p = (byte*)XMALLOC((word32)pubSz, key->heap, |
| 428 | + DYNAMIC_TYPE_DILITHIUM); |
| 429 | + if (key->p == NULL) { |
| 430 | + ret = MEMORY_E; |
| 431 | + } |
| 432 | + } |
| 433 | + } |
| 434 | + return ret; |
| 435 | +} |
| 436 | +#endif |
| 437 | + |
361 | 438 | /****************************************************************************** |
362 | 439 | * Hash operations |
363 | 440 | ******************************************************************************/ |
@@ -7654,9 +7731,20 @@ static int dilithium_make_key_from_seed(dilithium_key* key, const byte* seed) |
7654 | 7731 | sword32* s1 = NULL; |
7655 | 7732 | sword32* s2 = NULL; |
7656 | 7733 | sword32* t = NULL; |
7657 | | - byte* pub_seed = key->k; |
| 7734 | + byte* pub_seed = NULL; |
7658 | 7735 | byte kl[2]; |
7659 | 7736 |
|
| 7737 | +#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS |
| 7738 | + ret = dilithium_alloc_priv_buf(key); |
| 7739 | + if (ret == 0) { |
| 7740 | + ret = dilithium_alloc_pub_buf(key); |
| 7741 | + } |
| 7742 | +#endif |
| 7743 | + |
| 7744 | + if (ret == 0) { |
| 7745 | + pub_seed = key->k; |
| 7746 | + } |
| 7747 | + |
7660 | 7748 | /* Allocate memory for large intermediates. */ |
7661 | 7749 | #ifdef WC_DILITHIUM_CACHE_MATRIX_A |
7662 | 7750 | #ifndef WC_DILITHIUM_FIXED_ARRAY |
@@ -7818,11 +7906,22 @@ static int dilithium_make_key_from_seed(dilithium_key* key, const byte* seed) |
7818 | 7906 | sword64* t64 = NULL; |
7819 | 7907 | #endif |
7820 | 7908 | byte* h = NULL; |
7821 | | - byte* pub_seed = key->k; |
| 7909 | + byte* pub_seed = NULL; |
7822 | 7910 | unsigned int r; |
7823 | 7911 | unsigned int s; |
7824 | 7912 | byte kl[2]; |
7825 | 7913 |
|
| 7914 | +#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS |
| 7915 | + ret = dilithium_alloc_priv_buf(key); |
| 7916 | + if (ret == 0) { |
| 7917 | + ret = dilithium_alloc_pub_buf(key); |
| 7918 | + } |
| 7919 | +#endif |
| 7920 | + |
| 7921 | + if (ret == 0) { |
| 7922 | + pub_seed = key->k; |
| 7923 | + } |
| 7924 | + |
7826 | 7925 | /* Allocate memory for large intermediates. */ |
7827 | 7926 | if (ret == 0) { |
7828 | 7927 | unsigned int allocSz; |
@@ -8576,7 +8675,7 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key, |
8576 | 8675 | /* Step 11: Start rejection sampling loop */ |
8577 | 8676 | do { |
8578 | 8677 | byte aseed[DILITHIUM_GEN_A_SEED_SZ]; |
8579 | | - byte w1e[DILITHIUM_MAX_W1_ENC_SZ]; |
| 8678 | + WC_DECLARE_VAR(w1e, byte, DILITHIUM_MAX_W1_ENC_SZ, 0); |
8580 | 8679 | sword32* w = w1; |
8581 | 8680 | byte* commit = sig; |
8582 | 8681 | byte r; |
@@ -8807,11 +8906,17 @@ static int dilithium_sign_with_seed_mu(dilithium_key* key, |
8807 | 8906 | byte* ze = sig + params->lambda / 4; |
8808 | 8907 |
|
8809 | 8908 | /* Step 15: Encode w1. */ |
8810 | | - dilithium_vec_encode_w1(w1, params->k, params->gamma2, w1e); |
8811 | | - /* Step 15: Hash mu and encoded w1. |
8812 | | - * Step 32: Hash is stored in signature. */ |
8813 | | - ret = dilithium_hash256(&key->shake, mu, DILITHIUM_MU_SZ, |
8814 | | - w1e, params->w1EncSz, commit, params->lambda / 4); |
| 8909 | + WC_ALLOC_VAR_EX(w1e, byte, DILITHIUM_MAX_W1_ENC_SZ, |
| 8910 | + key->heap, DYNAMIC_TYPE_DILITHIUM, ret=MEMORY_E); |
| 8911 | + if (WC_VAR_OK(w1e)) { |
| 8912 | + dilithium_vec_encode_w1(w1, params->k, params->gamma2, |
| 8913 | + w1e); |
| 8914 | + /* Step 15: Hash mu and encoded w1. |
| 8915 | + * Step 32: Hash is stored in signature. */ |
| 8916 | + ret = dilithium_hash256(&key->shake, mu, DILITHIUM_MU_SZ, |
| 8917 | + w1e, params->w1EncSz, commit, params->lambda / 4); |
| 8918 | + } |
| 8919 | + WC_FREE_VAR_EX(w1e, key->heap, DYNAMIC_TYPE_DILITHIUM); |
8815 | 8920 | if (ret == 0) { |
8816 | 8921 | /* Step 17: Compute c from first 256 bits of commit. */ |
8817 | 8922 | ret = dilithium_sample_in_ball_ex(params->level, |
@@ -10000,6 +10105,16 @@ static int oqs_dilithium_make_key(dilithium_key* key, WC_RNG* rng) |
10000 | 10105 | ret = SIG_TYPE_E; |
10001 | 10106 | } |
10002 | 10107 |
|
| 10108 | + |
| 10109 | +#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS |
| 10110 | + if (ret == 0) { |
| 10111 | + ret = dilithium_alloc_priv_buf(key); |
| 10112 | + } |
| 10113 | + if (ret == 0) { |
| 10114 | + ret = dilithium_alloc_pub_buf(key); |
| 10115 | + } |
| 10116 | +#endif |
| 10117 | + |
10003 | 10118 | if (ret == 0) { |
10004 | 10119 | ret = wolfSSL_liboqsRngMutexLock(rng); |
10005 | 10120 | if (ret == 0) { |
@@ -10921,6 +11036,19 @@ int wc_dilithium_set_level(dilithium_key* key, byte level) |
10921 | 11036 | #endif |
10922 | 11037 | #endif /* WOLFSSL_WC_DILITHIUM */ |
10923 | 11038 |
|
| 11039 | +#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS |
| 11040 | + if (key->k != NULL) { |
| 11041 | + ForceZero(key->k, key->kSz); |
| 11042 | + XFREE(key->k, key->heap, DYNAMIC_TYPE_DILITHIUM); |
| 11043 | + key->k = NULL; |
| 11044 | + key->kSz = 0; |
| 11045 | + } |
| 11046 | + if (key->p != NULL) { |
| 11047 | + XFREE(key->p, key->heap, DYNAMIC_TYPE_DILITHIUM); |
| 11048 | + key->p = NULL; |
| 11049 | + } |
| 11050 | +#endif |
| 11051 | + |
10924 | 11052 | /* Store level and indicate public and private key are not set. */ |
10925 | 11053 | key->level = level % WC_ML_DSA_DRAFT; |
10926 | 11054 | key->pubKeySet = 0; |
@@ -10991,6 +11119,15 @@ void wc_dilithium_free(dilithium_key* key) |
10991 | 11119 | /* Free the SHAKE-128/256 object. */ |
10992 | 11120 | wc_Shake256_Free(&key->shake); |
10993 | 11121 | #endif |
| 11122 | +#endif |
| 11123 | +#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS |
| 11124 | + if (key->k != NULL) { |
| 11125 | + ForceZero(key->k, key->kSz); |
| 11126 | + XFREE(key->k, key->heap, DYNAMIC_TYPE_DILITHIUM); |
| 11127 | + } |
| 11128 | + if (key->p != NULL) { |
| 11129 | + XFREE(key->p, key->heap, DYNAMIC_TYPE_DILITHIUM); |
| 11130 | + } |
10994 | 11131 | #endif |
10995 | 11132 | /* Ensure all private data is zeroized. */ |
10996 | 11133 | ForceZero(key, sizeof(*key)); |
@@ -11553,12 +11690,19 @@ int wc_dilithium_import_public(const byte* in, word32 inLen, dilithium_key* key) |
11553 | 11690 | } |
11554 | 11691 | } |
11555 | 11692 |
|
| 11693 | + |
| 11694 | +#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS |
| 11695 | + if (ret == 0) { |
| 11696 | + ret = dilithium_alloc_pub_buf(key); |
| 11697 | + } |
| 11698 | +#endif |
| 11699 | + |
11556 | 11700 | if (ret == 0) { |
11557 | 11701 | /* Copy the private key data in or copy pointer. */ |
11558 | | - #ifndef WOLFSSL_DILITHIUM_ASSIGN_KEY |
11559 | | - XMEMCPY(key->p, in, inLen); |
11560 | | - #else |
| 11702 | + #ifdef WOLFSSL_DILITHIUM_ASSIGN_KEY |
11561 | 11703 | key->p = in; |
| 11704 | + #else |
| 11705 | + XMEMCPY(key->p, in, inLen); |
11562 | 11706 | #endif |
11563 | 11707 |
|
11564 | 11708 | #ifdef WC_DILITHIUM_CACHE_PUB_VECTORS |
@@ -11630,23 +11774,35 @@ static int dilithium_set_priv_key(const byte* priv, word32 privSz, |
11630 | 11774 | dilithium_key* key) |
11631 | 11775 | { |
11632 | 11776 | int ret = 0; |
| 11777 | + int expPrivSz; |
11633 | 11778 | #ifdef WC_DILITHIUM_CACHE_MATRIX_A |
11634 | 11779 | const wc_dilithium_params* params = key->params; |
11635 | 11780 | #endif |
11636 | 11781 |
|
11637 | | - /* Validate parameters. */ |
11638 | | - if ((privSz != ML_DSA_LEVEL2_KEY_SIZE) && |
11639 | | - (privSz != ML_DSA_LEVEL3_KEY_SIZE) && |
11640 | | - (privSz != ML_DSA_LEVEL5_KEY_SIZE)) { |
| 11782 | + /* Validate parameters. privSz must match the expected size for the |
| 11783 | + * level set on the key. This is required so that subsequent code |
| 11784 | + * which reads via key->params stays within the (possibly dynamically |
| 11785 | + * sized) buffer. */ |
| 11786 | + expPrivSz = wc_dilithium_size(key); |
| 11787 | + if (expPrivSz < 0) { |
| 11788 | + ret = BAD_FUNC_ARG; |
| 11789 | + } |
| 11790 | + else if (privSz != (word32)expPrivSz) { |
11641 | 11791 | ret = BAD_FUNC_ARG; |
11642 | 11792 | } |
11643 | 11793 |
|
| 11794 | +#ifdef WOLFSSL_DILITHIUM_DYNAMIC_KEYS |
| 11795 | + if (ret == 0) { |
| 11796 | + ret = dilithium_alloc_priv_buf(key); |
| 11797 | + } |
| 11798 | +#endif |
| 11799 | + |
11644 | 11800 | if (ret == 0) { |
11645 | 11801 | /* Copy the private key data in or copy pointer. */ |
11646 | | - #ifndef WOLFSSL_DILITHIUM_ASSIGN_KEY |
11647 | | - XMEMCPY(key->k, priv, privSz); |
11648 | | - #else |
| 11802 | + #ifdef WOLFSSL_DILITHIUM_ASSIGN_KEY |
11649 | 11803 | key->k = priv; |
| 11804 | + #else |
| 11805 | + XMEMCPY(key->k, priv, privSz); |
11650 | 11806 | #endif |
11651 | 11807 | } |
11652 | 11808 |
|
|
0 commit comments