[PATCH 10/10] dilithium: use strong random for signature nonce
Jussi Kivilinna <[email protected]> Sun, 2 Aug 2026 12:55:15 +0300
| Newsgroups | gmane.comp.encryption.gpg.libgcrypt.devel |
|---|---|
| Message-ID | <[email protected]> |
* cipher/pubkey-dilithium.c (randombytes): Add 'level' parameter.
(mldsa_generate): Use GCRY_VERY_STRONG_RANDOM for key seed.
(mldsa_sign): Use GCRY_STRONG_RANDOM for per signature value.
--
'randombytes' used GCRY_VERY_STRONG_RANDOM for both key seed and hedged
signing nonce. Nonce is per signature ephemeral value, same as ECDSA,
DSA and GOST nonces, all of which use GCRY_STRONG_RANDOM. Level 2
request forces jitterentropy gathering costing about 2 ms, which
dominated signing time. Key seed keeps level 2.
Benchmark on AMD Ryzen 9 9950X3D, signing usec/operation, quick random
disabled:
before after speedup
ML-DSA-44 2108.52 140.37 15.02x
ML-DSA-65 2144.04 223.50 9.59x
ML-DSA-87 2234.45 272.85 8.19x
Signed-off-by: Jussi Kivilinna <[email protected]>
---
cipher/pubkey-dilithium.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/cipher/pubkey-dilithium.c b/cipher/pubkey-dilithium.c
index 9d13aad3..92c64d91 100644
--- a/cipher/pubkey-dilithium.c
+++ b/cipher/pubkey-dilithium.c
@@ -121,9 +121,10 @@ mldsa_compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam)
static void
-randombytes (unsigned char *out, size_t outlen)
+randombytes (unsigned char *out, size_t outlen,
+ enum gcry_random_level level)
{
- _gcry_randomize (out, outlen, GCRY_VERY_STRONG_RANDOM);
+ _gcry_randomize (out, outlen, level);
}
static gcry_err_code_t
@@ -151,7 +152,8 @@ mldsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
rc = sexp_extract_param (genparms, NULL, "/S", &seed_mpi, NULL);
if (rc == GPG_ERR_NOT_FOUND)
{
- randombytes (seed, SEEDBYTES);
+ /* Long term key material. */
+ randombytes (seed, SEEDBYTES, GCRY_VERY_STRONG_RANDOM);
rc = 0;
}
else if (rc)
@@ -255,7 +257,10 @@ mldsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
memcpy (rnd, ctx.rnd, RNDBYTES);
}
else
- randombytes (rnd, RNDBYTES);
+ {
+ /* Per signature value, same level as ECDSA nonce. */
+ randombytes (rnd, RNDBYTES, GCRY_STRONG_RANDOM);
+ }
if (ctx.flags & PUBKEY_FLAG_NO_PREFIX)
rc = dilithium_sign (info->algo, sig, info->sig_len, data, data_len,
NULL, -1, sk, rnd);
--
2.53.0