Skip to content

SLH-DSA (FIPS-205) native verify is non-conformant — rejects the authoritative NIST ACVP vector #137

Description

@icellan

Summary

The native SLH-DSA (FIPS-205) verify implementation is not standard-conformant: it self-consistently round-trips its own signatures but rejects the authoritative NIST ACVP vector. This is the same failure mode as BUG-101 (BLAKE3) — self-consistent but non-standard — surfaced now that we vendor an independent official KAT (post-mortem remediation #2).

Evidence

Both tests are in packages/runar-go/crypto_kat_test.go:

  • TestSLHDSA_SelfConsistency passesSLHKeygenSLHSignSLHVerify round-trips fine. This proves the KAT harness (API/args/format) is correct.
  • TestOfficialKAT_SLHDSA_ACVP shows native SLHVerify rejects the NIST ACVP SLH-DSA-SHA2-128s (internal) sigVer vector (tcId 422, testPassed=true), vendored verbatim at conformance/runtime-vectors/slh-dsa-acvp-kat.json.

Same API + format on both sides → the vector is authoritative and the implementation is at fault, not the harness.

Root cause (partial)

compilers/go/.../slh_dsa.go slhHmsg: the H_msg MGF1 seed is SHA256(R ‖ PK.seed ‖ PK.root ‖ M), omitting the R ‖ PK.seed prefix that FIPS-205 §11.2 mandates (added to mitigate multi-target long-message 2nd-preimage attacks). A temporary patch applying only the H_msg fix did not make the ACVP vector verify, so further verify-path deviations remain — a full FIPS-205 audit is required.

Scope

  • Native verify in all real-crypto tiers (Go confirmed; Rust slh_dsa.rs, Python slhdsa_impl.py share the design and should be audited).
  • The on-chain SLH-DSA codegen almost certainly shares the deviation (packages/runar-compiler/src/passes/slh-dsa-codegen.ts + the 6 peer modules). A native-only fix would silently diverge the off-chain test helper from the on-chain script — the codegen must be audited against the same NIST vector.
  • SLH-DSA is documented as experimental, but this is a real correctness bug: a script that "verifies" an SLH-DSA signature does not implement FIPS-205.

Regression gate (already in place)

The vendored NIST ACVP vector is the gate. While the bug exists, crypto_kat_test.go:286 t.Skipfs with a loud "KNOWN FIPS-205 NON-CONFORMANCE" message (documented in docs/test-skips.md as a Gap row) so the suite stays green. The moment SLHVerify accepts the vector, the skip is bypassed and the accept/reject assertions enforce automatically — delete the guard on fix.

Remediation

  1. Full FIPS-205 conformance audit of native SLH-DSA verify (H_msg §11.2 prefix + the remaining deviations), across Go / Rust / Python.
  2. Audit the on-chain SLH-DSA codegen for the same deviations against the NIST ACVP vector.
  3. Delete the xfail guard at crypto_kat_test.go:286 once conformant.

Found by post-mortem remediation #2 (independent official KATs). WOTS+ is a related but separate case — the native wots.go uses a custom simplified hash, not RFC 8391, so no published KAT applies (documented, not vendored).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions