Skip to content

[WIP] Rename Dilithium API to ML-DSA and make CI track latest wolfSSL stable#33

Open
aidangarske wants to merge 7 commits into
wolfSSL:mainfrom
aidangarske:mldsa-rename
Open

[WIP] Rename Dilithium API to ML-DSA and make CI track latest wolfSSL stable#33
aidangarske wants to merge 7 commits into
wolfSSL:mainfrom
aidangarske:mldsa-rename

Conversation

@aidangarske
Copy link
Copy Markdown
Member

@aidangarske aidangarske commented May 30, 2026

Description

Move the wolfCrypt-facing post-quantum surface from the legacy
wc_dilithium_* / dilithium_key naming to the canonical FIPS 204
wc_MlDsaKey API, mirroring wolfSSL/wolfTPM PR #509. The COSE algorithm
and curve constants (WOLFCOSE_ALG_ML_DSA_*, WOLFCOSE_CRV_ML_DSA_*) were
already ML-DSA named and are unchanged.

Renames:
- Public API wc_CoseKey_SetDilithium -> wc_CoseKey_SetMlDsa
- WOLFCOSE_KEY union field .dilithium (dilithium_key*) -> .mldsa (wc_MlDsaKey*)
- All wc_dilithium_* calls -> wc_MlDsaKey_* (note the new key-first argument
  order for Init/SignCtx/VerifyCtx/ImportPubRaw/ImportKey)
- Build guard HAVE_DILITHIUM -> WOLFSSL_HAVE_MLDSA
- WOLFSSL_DILITHIUM_NO_CTX -> WOLFSSL_MLDSA_NO_CTX
- Test failure-injection enums WOLF_FAIL_DILITHIUM_* -> WOLF_FAIL_MLDSA_*

The wc_MlDsaKey API requires wolfSSL newer than v5.9.1-stable built with
--enable-dilithium --enable-experimental; PQC paths compile out under the
WOLFSSL_HAVE_MLDSA guard on older wolfSSL, so the rest of wolfCOSE still
builds against the v5.8.0-stable minimum.
Make CI follow upstream wolfSSL automatically instead of pinning master,
modeled on wolfSSL/wolfProvider PR #400 (resolve-version) and wolfTPM
PR #509 (PQC-aware version gating).

- Add reusable .github/workflows/_resolve-wolfssl.yml (workflow_call) that
  resolves the latest v*-stable tag at run time and emits a matrix of
  master + latest-stable, plus a refs array for cross-product use. PQC is
  marked eligible only when the resolved stable is strictly newer than the
  v5.9.1-stable floor (the release line where the wc_MlDsaKey API the rename
  now targets becomes available); otherwise only master builds PQC.
- wolfssl-versions.yml: keep the v5.8.0-stable backward-compat floor +
  latest-stable + master, now with a per-row pqc flag; wolfSSL configure
  gates --enable-dilithium --enable-experimental on matrix.pqc.
- Fan out the wolfSSL-building workflows over master + latest-stable via the
  reusable workflow with the same PQC gating: build-test (x OS), coverage,
  comprehensive-tests, examples, scenarios, sanitizer, multi-compiler
  (x compiler), coverity.
- minimal-build, static-analysis, and the MISRA workflows stay on master
  (feature-gating / source-analysis, where a version axis adds little) but
  gain --enable-experimental next to --enable-dilithium.
- Rename the analysis -DHAVE_DILITHIUM macro to -DWOLFSSL_HAVE_MLDSA in
  misra-2012/misra-2023 so cppcheck/clang-tidy keep covering the renamed
  ML-DSA code paths.

wolfCOSE sources include <wolfssl/options.h>, so the WOLFSSL_HAVE_MLDSA guard
flows from the installed wolfSSL for normal builds; non-PQC legs compile the
ML-DSA paths out cleanly and still exercise the rest of the surface.
Copilot AI review requested due to automatic review settings May 30, 2026 20:02
@aidangarske aidangarske marked this pull request as ready for review May 30, 2026 20:04
@aidangarske aidangarske changed the title Rename Dilithium API to ML-DSA and make CI track latest wolfSSL stable [WIP] Rename Dilithium API to ML-DSA and make CI track latest wolfSSL stable May 30, 2026

This comment was marked as resolved.

CI failures on PR wolfSSL#33 were runtime, not compile: the Examples and
Scenarios jobs built the demo/scenario binaries (linked against the
shared libwolfssl) but ran them without LD_LIBRARY_PATH, so they failed
with "libwolfssl.so.44: cannot open shared object file". Export
LD_LIBRARY_PATH in the run step for both workflows.

Review follow-ups:
- multi-compiler.yml: make the compiler list a real matrix axis so it
  cross-products with the wolfSSL ref (6 compilers x 2 refs) instead of
  collapsing via include-merge.
- sanitizer.yml: drop the "|| true" that masked forced-failure / ASan
  regressions in the coverage-force-failure step.
- tools/wolfcose_tool.c: check wc_MlDsaKey_Init / wc_MlDsaKey_SetParams
  return codes in keygen/sign/verify before using the key instead of
  proceeding on a possibly-uninitialized key.
- tools/wolfcose_tool.c: the verify command returned 1 on the success
  path (pre-existing); return 0 so a successful ML-DSA verify exits zero.
The previous matrix used wolfssl-ref as an axis plus an include: list of
compilers, which GitHub Actions merges instead of cross-producting, so
only a couple legs ran. Make cc a real matrix axis (gcc-11/12/13,
clang-14/15/17) crossed with the resolved wolfSSL refs (latest-stable +
master) for the full 12-leg matrix, like wolfTPM does.
tool_verify probed each wolfCrypt key type in sequence against one
WOLFCOSE_KEY whose .key is a union: it set e.g. coseKey.key.ecc = &ecc
(a ~300B stack ecc_key) then called wc_CoseKey_Decode on the key file.
For an ML-DSA key, decode dispatched on the file's kty/crv and wrote a
~7900B wc_MlDsaKey through the aliased union pointer into the small
ecc_key, smashing the stack and crashing in the subsequent wc_ecc_free.

Fix (zero allocation, tooling only — core src/ ML-DSA path untouched):
peek the COSE_Key metadata with an empty key union (every wolfCrypt
importer is gated on a non-NULL union member, so none runs), read
kty/crv, then instantiate exactly one correctly-typed stack key and
decode/verify. Only one key struct is ever live, which also drops the
function's stack usage.

Also harden the ML-DSA verify path with a wc_MlDsaKey_Init return check.

Add scripts/cli-test.sh: drives the built binary through every
subcommand (keygen/sign/verify, enc/dec, mac/macverify, self-test) for
all sign/AEAD/MAC algorithms, plus tamper-detection and usage-error
checks. Algorithms whose keygen fails (not built) are skipped, so it is
safe on minimal builds. Wired in as `make cli-test` and run in
build-test CI across every OS and wolfSSL ref. This is the coverage gap
that let the ML-DSA verify crash reach CI green: tool-test only
exercised ES256.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants