Fix Dilithium signing when WC_DILITHIUM_CACHE_MATRIX_A is enabled#10400
Fix Dilithium signing when WC_DILITHIUM_CACHE_MATRIX_A is enabled#10400dgarske merged 3 commits intowolfSSL:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes the Dilithium/ML-DSA signing path when matrix-A caching is enabled, addressing the cached-matrix allocation bug described in #10383. It updates the core signing implementation and adds a regression test in the wolfCrypt test suite to keep this cache-allocation path covered.
Changes:
- Fix
dilithium_sign_with_seed_mu()so the cached matrix-A allocation is stored onkey->ainstead of a transient local pointer. - Zero-initialize the newly allocated cache buffer before use, matching other cached-allocation paths.
- Add
dilithium_sign_cache_alloc_test()and run it for ML-DSA 44/65/87 to exercise the sign-after-cache-reset path.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
wolfcrypt/src/dilithium.c |
Fixes cached matrix-A allocation in the Dilithium signing path. |
wolfcrypt/test/test.c |
Adds a regression test that clears the cache, signs, and verifies for all supported ML-DSA levels. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #10400
Scan targets checked: wolfcrypt-bugs, wolfcrypt-src
No new issues found in the changed files. ✅
Frauschi
left a comment
There was a problem hiding this comment.
As ML-DSA is now added to Wconversion testing, you will need type casts on the XMALLOC() and XMEMSET() calls for the params->aSz argument.
…-compat shims
The post-quantum signature algorithm originally implemented as Dilithium
was standardized by NIST as ML-DSA in FIPS 204. This commit renames the
implementation file pair, the public API surface, and every internal
helper to the canonical ML-DSA names, mirroring the earlier Kyber ->
ML-KEM migration in wc_mlkem.{h,c}.
This commit deliberately scopes the change to the rename + compatibility
surface only. **No in-tree consumer call sites are converted.** Existing
in-tree consumers (TLS layer, ASN.1 / EVP / cryptocb wrappers, tests,
benchmark, examples, Rust wrapper) keep using the legacy spelling and
compile through the dilithium.h compatibility shim, which provides both
the legacy macro / inline name aliases and the bi-directional sub-config
build-gate translation in a single header. New consumer code can
include <wolfssl/wolfcrypt/wc_mldsa.h> directly and use the canonical
names. See doc/dilithium-to-mldsa-migration.md for the full migration
guide.
Rebased onto current master (7d1516f). The rebase pulls in three
upstream fixes:
- PR wolfSSL#10399 (commit 2833a4b, ~220 (sword32)/(byte)/(word32) casts in
dilithium.c plus three cast hunks in asn.c) -- inherited into the
new wc_mldsa.c via the file rename.
- PR wolfSSL#10400 (commit 4191d46, "Fix Dilithium signing when
WC_DILITHIUM_CACHE_MATRIX_A is enabled") -- backported into
wc_mldsa.c with canonical gate names; assigns to key->a (not local
a), adds (size_t) cast on params->aSz, and zero-initializes after
successful allocation in mldsa_sign_with_seed_mu.
- PR wolfSSL#10420 (commit 55d7ed8, "ML-DSA fixes: small vfy key object,
small SHA-3, fix test") -- the verify-only k[] gate was manually
backported from master's struct dilithium_key into our renamed
struct MlDsaKey in wc_mldsa.h (same #if !defined(WOLFSSL_MLDSA_VERIFY_ONLY)
structure for both INTEL_SPEEDUP and non-INTEL paths). The
test_mldsa.c WOLFSSL_NO_ML_DSA_44/65/87 test gates auto-merged
cleanly.
File layout
-----------
wolfcrypt/src/dilithium.c -> wolfcrypt/src/wc_mldsa.c
wolfssl/wolfcrypt/dilithium.h -> wolfssl/wolfcrypt/wc_mldsa.h
The legacy <wolfssl/wolfcrypt/dilithium.h> path is reborn as a thin
compatibility shim that #include's wc_mldsa.h and provides macro /
inline aliases for every legacy linkage symbol. The shim also hosts
the bi-directional sub-config build-gate translation block (the parent
gate HAVE_DILITHIUM <-> WOLFSSL_HAVE_MLDSA is mapped earlier in
settings.h, since some files read it before dilithium.h is included).
Build-gate rename
-----------------
HAVE_DILITHIUM -> WOLFSSL_HAVE_MLDSA
WOLFSSL_DILITHIUM_* -> WOLFSSL_MLDSA_* (~25 sub-config gates)
WC_DILITHIUM_CACHE_* -> WC_MLDSA_CACHE_*
WC_DILITHIUM_FIXED_ARRAY -> WC_MLDSA_FIXED_ARRAY
WC_DILITHIUMKEY_TYPE_DEFINED -> WC_MLDSAKEY_TYPE_DEFINED
Build-system options
--------------------
CMake:
WOLFSSL_MLDSA -- new canonical option.
WOLFSSL_DILITHIUM -- preserved as a legacy alias; either being set
enables -DWOLFSSL_HAVE_MLDSA.
BUILD_DILITHIUM (cmake/automake conditional) -> BUILD_MLDSA.
Autotools:
--enable-mldsa -- canonical configure switch.
--enable-dilithium -- preserved as a convenience alias.
Internal shell variables ENABLED_DILITHIUM* renamed to ENABLED_MLDSA*.
The configure summary echoes "ML-DSA: yes" rather than "DILITHIUM: yes".
Public API rename
-----------------
Type:
dilithium_key -> MlDsaKey
wc_dilithium_params -> MlDsaParams
Init / lifecycle (3-arg Init matching wc_MlKemKey_Init):
wc_dilithium_init -> wc_MlDsaKey_Init (was 1-arg, now 3-arg
with heap + devId; legacy 1-arg form is
supplied by the shim's static-inline
wrapper that defaults heap=NULL,
devId=INVALID_DEVID).
wc_dilithium_init_ex -> wc_MlDsaKey_Init (3-arg)
wc_dilithium_init_id -> wc_MlDsaKey_InitId
wc_dilithium_init_label -> wc_MlDsaKey_InitLabel
wc_dilithium_new -> wc_MlDsaKey_New
wc_dilithium_delete -> wc_MlDsaKey_Delete
wc_dilithium_free -> wc_MlDsaKey_Free
Parameters / sizing:
wc_dilithium_set_level -> wc_MlDsaKey_SetParams
wc_dilithium_get_level -> wc_MlDsaKey_GetParams
wc_dilithium_size -> wc_MlDsaKey_Size
wc_dilithium_priv_size -> wc_MlDsaKey_PrivSize
wc_dilithium_pub_size -> wc_MlDsaKey_PubSize
wc_dilithium_sig_size -> wc_MlDsaKey_SigSize
wc_dilithium_check_key -> wc_MlDsaKey_CheckKey
Key generation:
wc_dilithium_make_key -> wc_MlDsaKey_MakeKey
wc_dilithium_make_key_from_seed -> wc_MlDsaKey_MakeKeyFromSeed
Raw export (no argument reorder):
wc_dilithium_export_public -> wc_MlDsaKey_ExportPubRaw
wc_dilithium_export_private[_only] -> wc_MlDsaKey_ExportPrivRaw
wc_dilithium_export_key -> wc_MlDsaKey_ExportKey
Raw import / sign / verify / DER decode (FIPS 204 / ML-KEM
convention puts the key first; legacy form put it last):
wc_dilithium_import_public(in, inLen, key)
-> wc_MlDsaKey_ImportPubRaw(key, in, inLen)
wc_dilithium_import_private[_only](priv, privSz, key)
-> wc_MlDsaKey_ImportPrivRaw(key, priv, privSz)
wc_dilithium_import_key(priv, privSz, pub, pubSz, key)
-> wc_MlDsaKey_ImportKey(key, priv, privSz, pub, pubSz)
wc_dilithium_sign_msg / sign_ctx_msg / sign_ctx_hash / *_with_seed
-> wc_MlDsaKey_Sign / SignCtx / SignCtxHash / *WithSeed
wc_dilithium_verify_msg / verify_ctx_msg / verify_ctx_hash / verify_mu
-> wc_MlDsaKey_Verify / VerifyCtx / VerifyCtxHash / VerifyMu
wc_Dilithium_PrivateKeyDecode(in, idx, key, sz)
-> wc_MlDsaKey_PrivateKeyDecode(key, in, sz, idx)
wc_Dilithium_PublicKeyDecode(in, idx, key, sz)
-> wc_MlDsaKey_PublicKeyDecode(key, in, sz, idx)
ASN.1 encode (no reorder):
wc_Dilithium_PublicKeyToDer -> wc_MlDsaKey_PublicKeyToDer
wc_Dilithium_PrivateKeyToDer -> wc_MlDsaKey_PrivateKeyToDer
wc_Dilithium_KeyToDer -> wc_MlDsaKey_KeyToDer
Type forward declaration in wolfssl/wolfcrypt/asn_public.h:
typedef struct MlDsaKey MlDsaKey added (guarded by
WC_MLDSAKEY_TYPE_DEFINED). The legacy `typedef struct MlDsaKey
dilithium_key` typedef alias is also exposed from this header
(guarded by !WOLFSSL_NO_DILITHIUM_LEGACY_NAMES) so application
code that included only asn_public.h on master keeps compiling.
OpenSSL-compat enum (wolfssl/openssl/evp.h):
Unchanged in this PR -- WC_EVP_PKEY_DILITHIUM = 301 / EVP_PKEY_DILITHIUM
are kept as-is. Aligning the enum value with OpenSSL 3.5+'s actual
NID_ML_DSA_44/65/87 (1457/1458/1459) is planned for a follow-up PR.
Struct field in wolfssl/wolfcrypt/asn.h:
Unchanged in this PR -- SignatureCtx::dilithium remains a `struct
dilithium_key*`, and the surrounding gates remain on HAVE_DILITHIUM.
The legacy struct tag resolves to the canonical type via the shim
macro `#define dilithium_key MlDsaKey`.
Internal helper rename
----------------------
All ~80 lower-case static / file-scope helpers in wc_mldsa.{h,c} and
wc_mldsa_asm.S are renamed dilithium_* -> mldsa_* for consistency with
ML-KEM's mlkem_* convention. The two WOLFSSL_TEST_VIS encoders
wc_dilithium_encode_w1_88/32 become wc_mldsa_encode_w1_88/32. The
struct typedef wc_dilithium_params becomes MlDsaParams.
The FIPS 204 spec-derived constants (DILITHIUM_Q, DILITHIUM_N,
DILITHIUM_LEVEL{2,3,5}_*, DILITHIUM_ML_DSA_{44,65,87}_*) are kept under
their existing names; renaming those public macro constants is
out of scope for this PR.
Compatibility surface
---------------------
A single shim header at wolfssl/wolfcrypt/dilithium.h. It provides
two independent compatibility services, each suppressible via its
own opt-out:
- Macro / static-inline aliases for the legacy linkage names. Direct
one-to-one #defines for the no-reorder APIs and static-inline
function wrappers for the 16 arg-reorder APIs (so the legacy names
remain addressable, not just preprocessor expansions). Suppressed
by defining WOLFSSL_NO_DILITHIUM_LEGACY_NAMES.
- Bi-directional translation of all 31 sub-config build gates
(legacy WOLFSSL_DILITHIUM_* / WC_DILITHIUM_* <-> canonical
WOLFSSL_MLDSA_* / WC_MLDSA_*). The block runs before the shim's
#include of wc_mldsa.h so the canonical implementation reads its
conditional declarations correctly regardless of which spelling
user_settings.h or the build system used. Suppressed by defining
WOLFSSL_NO_DILITHIUM_LEGACY_GATES.
The parent gate HAVE_DILITHIUM <-> WOLFSSL_HAVE_MLDSA is mapped in
settings.h (forward arm unconditional, reverse arm honors the opt-out)
because some files (notably memory.h via types.h) need the parent gate
visible before they have a chance to include dilithium.h.
A small block of internal-helper aliases inside dilithium.h covers
WOLFSSL_LOCAL `dilithium_get_oid_sum` and the WOLFSSL_TEST_VIS
`wc_dilithium_encode_w1_*` encoders that this branch's unmigrated
in-tree consumers (src/ssl_load.c, tests/api/test_mldsa.c) still call.
Two wolfSSL-internal infrastructure files have their sub-gate
references migrated to canonical names because neither pulls in the
dilithium.h shim:
- wolfssl/wolfcrypt/memory.h reads 4 sub-gates for LARGEST_MEM_BUCKET
sizing. Reachable from <types.h> very early, before any TU has a
chance to include dilithium.h.
- wolfssl/certs_test.h is auto-generated from gencertbuf.pl and has
zero #include directives. Reachable from external TUs that include
only <wolfssl/ssl.h>, which does not transitively pull in
dilithium.h.
For both files, configure now emits canonical -DWOLFSSL_MLDSA_*
defines, so canonical sub-gate references are correct without
relying on the bidirectional shim. gencertbuf.pl was updated
accordingly so future regenerations stay on canonical.
Tests / verification
--------------------
A compile-time validation block at the bottom of wc_mldsa.c (under
!WOLFSSL_NO_DILITHIUM_LEGACY_NAMES suppression) exercises every legacy
macro / inline alias. A parallel block exercises every canonical
declaration in wc_mldsa.h. The bodies sit inside `if (0)` so the
compiler parses and type-checks the expansions without emitting any
runtime call. A missing or misordered alias produces an immediate
compile error.
Wconversion preservation: master's PR wolfSSL#10399 added 220 `(sword32)`
casts (and several `(byte)` / `(word32)` casts) inside dilithium.c.
After the file rename, the new wc_mldsa.c has all 220 `(sword32)`
casts intact (count verified equal between master's dilithium.c and
our new wc_mldsa.c).
Builds clean with --enable-mldsa, --enable-dilithium (legacy alias),
and --enable-mldsa with -DWOLFSSL_MLDSA_VERIFY_ONLY. make check
passes; testwolfcrypt DILITHIUM test passes.
https://claude.ai/code/session_01N9vLeZw4Gsfb11N4BU1Mbe
Description
dilithium_sign_with_seed_mu()allocated matrix A into a local variable a, then immediately overwrote it with a = key->aFixes #10383
Testing
Added
dilithium_sign_cache_alloc_testWC_DILITHIUM_CACHE_MATRIX_Ais enabled in Debian RPM testsChecklist