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 passes — SLHKeygen → SLHSign → SLHVerify 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
- Full FIPS-205 conformance audit of native SLH-DSA verify (H_msg §11.2 prefix + the remaining deviations), across Go / Rust / Python.
- Audit the on-chain SLH-DSA codegen for the same deviations against the NIST ACVP vector.
- 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).
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_SelfConsistencypasses —SLHKeygen→SLHSign→SLHVerifyround-trips fine. This proves the KAT harness (API/args/format) is correct.TestOfficialKAT_SLHDSA_ACVPshows nativeSLHVerifyrejects the NIST ACVPSLH-DSA-SHA2-128s(internal) sigVer vector (tcId 422,testPassed=true), vendored verbatim atconformance/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.goslhHmsg: the H_msg MGF1 seed isSHA256(R ‖ PK.seed ‖ PK.root ‖ M), omitting theR ‖ PK.seedprefix 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
slh_dsa.rs, Pythonslhdsa_impl.pyshare the design and should be audited).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.Regression gate (already in place)
The vendored NIST ACVP vector is the gate. While the bug exists,
crypto_kat_test.go:286t.Skipfs with a loud "KNOWN FIPS-205 NON-CONFORMANCE" message (documented indocs/test-skips.mdas a Gap row) so the suite stays green. The momentSLHVerifyaccepts the vector, the skip is bypassed and the accept/reject assertions enforce automatically — delete the guard on fix.Remediation
crypto_kat_test.go:286once conformant.Found by post-mortem remediation #2 (independent official KATs). WOTS+ is a related but separate case — the native
wots.gouses a custom simplified hash, not RFC 8391, so no published KAT applies (documented, not vendored).