Commit graph

72 commits

Author SHA1 Message Date
3153988c4e tests: NIST ACVP SHA2-128s verification KATs + a real differential bridge
External review flagged across rounds 4-6 that the empirical evidence tying the
proved model to the deployed code had not moved by a single data point in six
rounds: the sole bridge was nine assertion points (3 rounds, one fixed seed,
corruption always at byte 100), and the ACVP vectors vendored here contain NO
SLH-DSA-SHA2-128s sigVer group at all — the one parameter set this verification
campaign is about had zero NIST known-answer verification coverage.

VECTORS. tests/nist_acvp_vectors/SLH-DSA-sigVer-FIPS205/sha2_128s_extracted.json
carries the three SHA2-128s sigVer groups extracted verbatim from the official
NIST ACVP-Server vector set (source URL, upstream file sha256 and extraction
method recorded in the file's own _provenance block; per-test private keys
dropped as unnecessary to verify). 42 tests: 2 valid and 12 negative per group,
the negatives spread over structurally distinct corruption sites — modified R,
modified SIGFORS, modified SIGHT, modified message, too-small and too-large
signatures.

TESTS (all in src/verify_mono.rs, so they exercise the monomorphic path the Lean
certificates are about):

- mono_matches_nist_acvp_128s_internal — NIST's `internal` group carries M'
  directly, which is exactly what slh_verify_128s consumes, so these are true
  known-answer tests OF THE PROVED PATH: 10 executed, 4 attributed to
  deserialization (wrong-length signatures, rejected above the extraction root).
  Accounting is exact — all 14 are accounted for, nothing silently skipped.
- mono_matches_nist_acvp_128s_external_pure — builds M' the way lib.rs does and
  requires mono, the deployed verifier and NIST to agree: 10 executed, 9 of them
  with a NON-EMPTY context. This is the first empirical check of the
  domain-separator byte and context-length prefix that TRUSTED-BASE item 10
  declares outside every proof.
- deployed_matches_nist_acvp_128s_prehash — validates the deployed prehash path
  for 128s: 3 executed, 4 wrong-length, and 7 skipped because NIST exercises
  prehash functions (SHA3-*, truncated SHA2) this crate's `Ph` enum does not
  implement. Counted and reported rather than hidden.
- mono_matches_deployed_randomized — replaces the fixed-seed/fixed-byte bridge:
  12 rounds, varying message lengths including empty, corruption spread across
  the WHOLE 7856-byte signature, plus wrong-public-key and wrong-context cases
  that were never exercised before. 108 assertion points, each requiring mono
  and deployed to agree.

Bridge coverage: 9 assertion points -> 131, of which 20 are NIST known-answer
tests on the proved path where there were previously none.

No change to any verify-path function: this commit touches test code and test
data only, so the Charon/Aeneas extraction is unaffected (verified separately by
re-running extract.sh and diffing the generated model).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 09:42:56 +02:00
797b4ef263 reproducibility: commit Cargo.lock + pin rust-toolchain (review round 2)
External review round 2 (GPT B1.5) flagged that no Cargo.lock was committed
and the extraction toolchain was undocumented. Fixes:

- Un-ignore and commit Cargo.lock (this is a verification-pinned snapshot, not
  a library — a locked dependency graph is part of the reproducible artifact).
- Add rust-toolchain.toml pinning nightly-2026-06-01, the exact channel the
  Charon/Aeneas transpiler uses, so `charon cargo` extraction and the `cargo
  test` differential harness agree on one compiler.

Verified: re-running verification/extract.sh against this tree reproduces
gen/SlhVerify/{Types,Funs}.lean BYTE-IDENTICALLY (sha256 unchanged) — these
additions do not perturb the extracted Lean model.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 19:08:47 +02:00
bea105195b helpers: de-plumb round 2 — to_int & base_2b iterators to index loops
Removes the last two untranslatable iterator adapters on the verify path so
their loops extract to real definitions (no Take/IterMut axioms in any cone):

- to_int: `for item in x.iter().take(n)` -> `for i in 0..n { ... x[i] }`. The
  Take adapter was the LAST non-oracle, non-zeroize axiom in the model.
- base_2b: `for item in baseb.iter_mut()` -> `for out in 0..out_len { ...;
  baseb[out] = ... }`. The IterMut adapter carried a next_back write-back
  closure as loop state (a function-typed fixpoint), painful to reason about.

Both are semantics-identical for every FIPS 205 parameter set: the asserts
already pin x.len()==n and out_len==baseb.len(), so the index ranges visit
exactly the same elements/slots in the same order with the same values. The
inner `while bits < b` loop of base_2b was already clean and is untouched.

Validation: cargo test --features slh_dsa_sha2_128s --lib green — all 12
parameter-set round trips AND mono_matches_deployed_verify (mono == deployed
generic verify on valid / corrupted / wrong-message inputs).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 08:47:15 +02:00
6f6a9d65e7 verify_mono: de-plumb Result/iterator idioms (8 sites, semantics identical)
Aeneas translates the affected core-library instances only as axioms
(TryFrom/unwrap Result plumbing, iterator adapters, the &u32 Sub instance),
which would put transpiler axioms into certificate cones. Each site is
replaced by a construct that extracts to a real definition, with identical
semantics for every FIPS 205 parameter set:

- wots/xmss/ht/fors/slh const-generic preps: u32::try_from(X).unwrap() ->
  X as u32 (every parameter <= 63; cast lossless).
- wots checksum loop: msg.iter().take(2*N) with &u32 subtraction -> index
  loop over 0..2*N with value reads (same iteration space, same values).
- ht per-layer idx_leaf and slh idx_leaf: u32::try_from + is_err/unwrap ->
  plain cast. Both values are pre-masked to hp' resp. h/d bits, and hp',
  h/d <= 9 for every FIPS 205 parameter set, so the conversion cannot
  fail: the removed error branch is dead code.

Validation: cargo test --features slh_dsa_sha2_128s --lib green — all 12
parameter-set round trips AND the differential test
mono_matches_deployed_verify (mono verify == deployed generic verify on
valid / corrupted / wrong-message inputs).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 17:04:52 +02:00
2d89ee3fd7 Aeneas-compat: single-slice M' + is_err idiom in mono verify
Two further transpiler-compat refinements found while extracting (Aeneas
reported one Unimplemented in slh_verify_internal_free):

- h_msg / slh_verify take the message-digest input M' as a SINGLE
  contiguous &[u8] instead of &[&[u8]] (nested slices are untranslatable;
  the dalek verify_sha512 single-message-slice lesson). H_msg hashes the
  byte concatenation, so a pre-concatenated M' is bit-identical — the
  differential test builds M' = toByte(0,1)||toByte(0,1)||<>||msg and
  still agrees with the deployed verifier.
- the one let-else (u32::try_from(idx_leaf) else return false) rewritten
  to the translatable is_err/unwrap idiom already used in ht_verify.

Result: charon + aeneas both exit 0 on the verify cone; the extracted
Lean model type-checks. Differential test still passes; default-feature
build still clean (additive).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 22:20:36 +02:00
b4e2293d96 Aeneas-compat: monomorphic SHA2-128s verify path (additive)
The generic verify path threads the six hash primitives through
crate::hashers::Hashers, a struct of fn() POINTERS, which the Aeneas
Rust->Lean transpiler cannot translate (the sole gate-0 obstruction).

This adds src/verify_mono.rs: the verify cone (chain, wots_pk_from_sig,
xmss_pk_from_sig, ht_verify, fors_pk_from_sig, slh_verify_internal)
reproduced with the hash suite reached through NAMED free functions in a
verify_mono::oracle module (the deliberate SHA-2 opaque boundary of the
proof) instead of fn-pointer dereferences, plus a monomorphic entry
slh_verify_128s fixing the SLH-DSA-SHA2-128s constants. Function bodies
are copied verbatim from wots/xmss/hypertree/fors/slh so the extracted
Lean model stays faithful to the deployed algorithm.

Additive and inert: gated behind feature slh_dsa_sha2_128s; the only
change to existing code is two lines declaring the module. All twelve
parameter sets build unchanged (cargo build default features: clean).

Fidelity is pinned by an in-crate differential unit test that pits
slh_verify_128s against the deployed Verifier::verify on freshly
generated signatures — valid (both accept), corrupted (both reject),
and wrong-message (both reject), across three keypairs. Passes.

Same pattern as the curve25519-dalek-source verify_sha512 shim. This is
a frozen snapshot for the formal-verification campaign; no affiliation
with, and no changes proposed to, the upstream project.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 22:12:04 +02:00
5dca0db7e9 snapshot hygiene: strip upstream CI workflows
This is a frozen snapshot for the SLH-DSA verification campaign, pinned
at upstream 30bac08. Upstream's CI does not belong in this namespace
(and must not run here); removing .github is the only deviation from
verbatim. Upstream history is fully preserved beneath this commit.
No affiliation with, and no changes proposed to, the upstream project.
2026-07-22 20:58:59 +02:00
integritychain
30bac08580
Update package.json 2025-09-01 18:34:31 -05:00
eschorn1
a9b02e92cd 0.4.1 RC1 2024-12-22 20:46:43 -06:00
eschorn1
6f0f48eaee fuzz up 2024-12-22 18:32:27 -06:00
eschorn1
e77284a10d v0.4.0 RC1 2024-10-04 11:02:10 -05:00
eschorn1
5f8a96c02b docs, bench stats 2024-10-03 14:48:53 -05:00
eschorn1
49bebd533e audit/coverage/ffi 2024-10-03 12:39:25 -05:00
eschorn1
59314dc043 dudect, workflows 2024-10-03 12:24:28 -05:00
eschorn1
e68fb16221 much tighter clippy 2024-10-02 16:02:02 -05:00
eschorn1
834e75b603 align comments with released spec 2024-10-02 14:50:54 -05:00
eschorn1
f0576386fc hashing 2024-10-01 17:17:27 -05:00
eschorn1
899179a1e1 clippy/benches: shaky, shaky 2024-10-01 14:56:50 -05:00
eschorn1
ab0f62369a shaky, shaky 2024-10-01 14:29:06 -05:00
eschorn1
8c03d1f9c3 prep update 2024-10-01 09:30:20 -05:00
integritychain
fca844d470
Merge pull request #3 from jonmon6691/add-acvp-tests
Add test module for ACVP known answer tests
2024-09-29 19:01:56 -05:00
eschorn1
628656a3a0 clippy: starting update 2024-09-29 18:26:45 -05:00
eschorn1
7542bb2d80 starting update 2024-09-29 18:05:16 -05:00
Jon Wallace
2c027b3f6d Add test module for ACVP known answer tests 2024-09-15 19:55:08 -07:00
eschorn1
bf62d98c42 python binding 2024-03-15 11:36:47 -05:00
eschorn1
4a8c3d215f python binding 2024-03-15 10:17:14 -05:00
eschorn1
8e4ebfec1a rust ffi 2024-03-14 13:35:26 -05:00
eschorn1
20a8263d42 wasm 2024-03-14 08:46:53 -05:00
eschorn1
98fc10359f benchmarks 2024-03-10 18:07:57 -05:00
eschorn1
bdd49221e4 minor clippy 2024-03-10 08:15:56 -05:00
eschorn1
f4bd328bf1 unwound generic-array 2024-03-09 15:58:29 -06:00
eschorn1
aaf3b57066 clippy 2024-03-08 18:25:57 -06:00
eschorn1
db92cdfabd msrv 1.70 2024-03-08 17:22:43 -06:00
eschorn1
b8b3a192dd gitignore nit 2024-02-10 14:44:09 -06:00
eschorn1
6bab551ffb dudect 2024-02-10 14:26:37 -06:00
eschorn1
6cec1182c7 cargo deny2 2024-02-10 09:26:34 -06:00
eschorn1
19d280b50e cargo deny 2024-02-10 09:03:01 -06:00
eschorn1
f1991a2282 ga2 2024-02-09 18:32:05 -06:00
eschorn1
d8bdfbb883 ga 2024-02-09 18:22:35 -06:00
eschorn1
6b94ff1aa0 msrv 1.73 2024-02-09 17:50:05 -06:00
eschorn1
b0213416c8 fips205 prep 2024-02-09 17:43:59 -06:00
eschorn1
ddfabeb6ac source split 2024-02-09 16:31:05 -06:00
eschorn1
6c449f3e36 working traits 2024-02-09 15:28:59 -06:00
eschorn1
69f94c55fe clippy and test clean 2024-02-08 06:42:28 -06:00
eschorn1
569374a055 polish 2024-02-07 17:22:26 -06:00
eschorn1
4f8f03546c diet1 2024-02-07 16:30:42 -06:00
eschorn1
a6ff2130de not 2024-02-07 15:31:17 -06:00
eschorn1
7bb838973b vectors passing 2024-02-07 12:17:59 -06:00
integritychain
44ab28ef08 inst sha2 2024-02-06 18:25:57 -06:00
integritychain
846ac8b92d sha2 is progress 2024-02-03 18:18:18 -06:00