fips205-slhdsa-verified/verification/Proofs/Audit.lean

285 lines
15 KiB
Text
Raw Normal View History

review round 2: in-Lean exact-cone audit + reproducibility + doc honesty Addresses the round-2 reviewer punch-list. No theorem statement, proof term, or fold definition changed; the eleven cones are unchanged (independent collectAxioms dump in verification/RECORDED-RUN.md). AUDIT GATE (both reviewers, the critical one) - Retire the bash #print-axioms text parser (fail-open on empty/truncated reports, and only a SUBSET check). Replace with verification/Proofs/Audit.lean: reads each certificate's cone from the kernel via collectAxioms and asserts EXACT set equality against its expected boundary. Extra axiom, dropped oracle, renamed/deleted cert, or an axiom/opaque sham each throw -> non-zero Lean exit. No text to misparse; nothing fails open. check.sh Phase 3 now just compiles it (and still requires the explicit PASSED line). - check-selftest.sh rewritten to attack the new gate: dead-file, smuggled extra axiom (named), dropped-oracle (subset would pass, exact must not), and a vanished certificate (the collectAxioms-returns-[] trap). All four rejected. REPRODUCIBILITY (GPT B1.4 / B1.5) - extract.sh refuses a wrong-commit or dirty source tree (fail-closed), takes an optional source-path arg, and pins the source commit. - verification/PROVENANCE.json: single machine-readable pin set (source + charon + aeneas commits/channel + lean + ocaml) with generated-file sha256. - Re-running extract.sh reproduces gen/SlhVerify/{Types,Funs}.lean byte-identically (companion fips205-source commit adds Cargo.lock + rust-toolchain.toml; verified not to perturb the model). DOC HONESTY (both reviewers) - README: fix the self-contradiction (apex "not yet proven" trailer vs the proven apex), the false "oracles kept OUTSIDE every cone" (they are INSIDE, by design), "deployed monomorphic path" and "semantics-identical for every parameter set" overclaims, "only two lines changed", stale snapshot head; retitle the stale future-tense "what will be claimed" section. - TRUSTED-BASE: drop "nothing proven yet"; add base_2b-inner and deployment- bridge non-claims explicitly; current pin. - ChainSpec header: "deployed monomorphic path" -> private verify_mono facade (comment only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 17:13:55 +00:00
/- ──────────────────────────────────────────────────────────────────────────────
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
Proofs/Audit.lean — the axiom / statement / specification / coverage audit.
ROUND 5 (third reviewer, 2026-07-27) demonstrated that the round-4 gate was
closed at the EXPLOITS but not at the MECHANISMS. Three fail-opens, each
executed end-to-end with the button printing ALL GREEN:
NEW-1 `manifestFingerprint` covered `manifest` only — never
`allowedBoundary`, the sole predicate the enumeration tests against.
Adding one name to that list re-opened the `False`-proof completely,
with the committed fingerprint BYTE-IDENTICAL.
NEW-2 the statement fingerprint pinned each certificate's TYPE, which
references its hand-written reference fold BY NAME. Redefining that
fold to *be* the extracted loop left cone and type-hash identical
while the certificate degenerated to "the loop equals the loop" —
100% of the fidelity content lives in those definitions.
(drill) layer-2 enumeration matched `.thmInfo` only, so a `def : False`
passed; and this file's own declarations were enumerated by nothing.
The fix binds the WHOLE audited object, not the parts an attacker happened to
touch. This file emits a canonical AUDIT-MANIFEST block covering:
· the POLICY constants (`allowedBoundary`, `certModules`) — NEW-1;
· every certificate's fully-elaborated STATEMENT (`pp.all`) — F2 properly;
· every hand-written SPECIFICATION constant transitively reachable from
those statements, with its fully-elaborated DEFINITION BODY — NEW-2.
(Proof-valued constants contribute their statement, not their proof term:
proof irrelevance makes the term semantically immaterial.)
`check.sh` binds to the **SHA-256** of that block. This also retires the
32-bit `Expr.hash` as the load-bearing digest (NEW-5): the per-certificate
type hashes below remain, but only as fast, human-legible DIAGNOSTICS that
name which certificate moved — the cryptographic binding is the SHA-256.
Enumeration now covers EVERY declaration kind (`def`, `theorem`, `opaque`,
`axiom`, …) in the eight certificate modules AND every declaration of this
file itself (the auditor is no longer exempt from its own audit — round-5 R1).
Standing limit, stated accurately (see TRUSTED-BASE.md item 11 for the full
trusted computing base): an audit executed by a harness cannot defend against
an author who edits that harness. `verification/lean-guard` is therefore
sha256-pinned by check.sh Phase 0, but `check.sh` itself, the toolchain env,
and `$AENEAS_HOME` remain trusted. The consumer defense is, and always was,
the pinned commit reviewed at the pin.
review round 2: in-Lean exact-cone audit + reproducibility + doc honesty Addresses the round-2 reviewer punch-list. No theorem statement, proof term, or fold definition changed; the eleven cones are unchanged (independent collectAxioms dump in verification/RECORDED-RUN.md). AUDIT GATE (both reviewers, the critical one) - Retire the bash #print-axioms text parser (fail-open on empty/truncated reports, and only a SUBSET check). Replace with verification/Proofs/Audit.lean: reads each certificate's cone from the kernel via collectAxioms and asserts EXACT set equality against its expected boundary. Extra axiom, dropped oracle, renamed/deleted cert, or an axiom/opaque sham each throw -> non-zero Lean exit. No text to misparse; nothing fails open. check.sh Phase 3 now just compiles it (and still requires the explicit PASSED line). - check-selftest.sh rewritten to attack the new gate: dead-file, smuggled extra axiom (named), dropped-oracle (subset would pass, exact must not), and a vanished certificate (the collectAxioms-returns-[] trap). All four rejected. REPRODUCIBILITY (GPT B1.4 / B1.5) - extract.sh refuses a wrong-commit or dirty source tree (fail-closed), takes an optional source-path arg, and pins the source commit. - verification/PROVENANCE.json: single machine-readable pin set (source + charon + aeneas commits/channel + lean + ocaml) with generated-file sha256. - Re-running extract.sh reproduces gen/SlhVerify/{Types,Funs}.lean byte-identically (companion fips205-source commit adds Cargo.lock + rust-toolchain.toml; verified not to perturb the model). DOC HONESTY (both reviewers) - README: fix the self-contradiction (apex "not yet proven" trailer vs the proven apex), the false "oracles kept OUTSIDE every cone" (they are INSIDE, by design), "deployed monomorphic path" and "semantics-identical for every parameter set" overclaims, "only two lines changed", stale snapshot head; retitle the stale future-tense "what will be claimed" section. - TRUSTED-BASE: drop "nothing proven yet"; add base_2b-inner and deployment- bridge non-claims explicitly; current pin. - ChainSpec header: "deployed monomorphic path" -> private verify_mono facade (comment only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 17:13:55 +00:00
────────────────────────────────────────────────────────────────────────────── -/
import Proofs.ChainSpec
import Proofs.WotsSpec
import Proofs.XmssSpec
import Proofs.HtSpec
import Proofs.ForsInnerSpec
import Proofs.ForsOuterSpec
import Proofs.InputPrepSpec
import Proofs.ApexSpec
open Lean Elab Command
namespace SlhVerify.Audit
review round 4: bind the cert set, statements, and model bytes (F1/F2/F3) The third reviewer demonstrated that the round-2 in-Lean exact-cone audit, though sound for LISTED certs, left three fail-opens OUTSIDE the cone check — and made check.sh print ALL GREEN over a repo proving False. All closed; no theorem, proof, or fold changed (the 11 cones are unchanged). F1 — the audited SET was unbound. Audit.lean now (a) enumerates EVERY theorem defined in the eight certificate modules and requires each cone ⊆ boundary, so an un-manifested `theorem _ : False := cheat _` fails regardless of naming (this is the exact exploit the reviewer used); and (b) prints a MANIFEST fingerprint over the whole committed manifest, which check.sh binds to — so deleting/swapping a cert row fails outside Lean too. F2 — only cones were bound, not statements. Each cert now also carries the structural fingerprint (Expr.hash) of its elaborated type; a statement gutted to a tautology of the same cone changes the fingerprint and fails. F3 — the gen/ model bytes were unbound. New check.sh Phase 0 sha256-pins all four gen/SlhVerify/*.lean (incl. the two hand-maintained *External files, now hashed in PROVENANCE.json) BEFORE compiling; a hand-edited model fails first. F4/F5 — docs. README cone diagram now roots honestly at slh_verify_internal and states the pure/prehash domain-separator byte, the ctx>255 check, M' assembly, and deserialization are ABOVE the root and uncovered (new TRUSTED-BASE item 10). The false "rules out a wrong ADRS field" claim is corrected in README + ChainSpec (a transliteration makes the field visible, not excluded). check-selftest.sh: eight attacks, all rejected (dead file; extra axiom; dropped oracle; vanished cert; un-manifested False theorem; gutted statement; hand-edited model; deleted manifest row). Full transcript + green check.sh in verification/RECORDED-RUN.md. Standing limit unchanged and disclosed: an audit cannot defend against an author who edits the manifest AND check.sh AND the proofs together; the consumer defense is the pinned commit reviewed at the pin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 17:47:39 +00:00
/-- Lean's three kernel axioms. -/
review round 2: in-Lean exact-cone audit + reproducibility + doc honesty Addresses the round-2 reviewer punch-list. No theorem statement, proof term, or fold definition changed; the eleven cones are unchanged (independent collectAxioms dump in verification/RECORDED-RUN.md). AUDIT GATE (both reviewers, the critical one) - Retire the bash #print-axioms text parser (fail-open on empty/truncated reports, and only a SUBSET check). Replace with verification/Proofs/Audit.lean: reads each certificate's cone from the kernel via collectAxioms and asserts EXACT set equality against its expected boundary. Extra axiom, dropped oracle, renamed/deleted cert, or an axiom/opaque sham each throw -> non-zero Lean exit. No text to misparse; nothing fails open. check.sh Phase 3 now just compiles it (and still requires the explicit PASSED line). - check-selftest.sh rewritten to attack the new gate: dead-file, smuggled extra axiom (named), dropped-oracle (subset would pass, exact must not), and a vanished certificate (the collectAxioms-returns-[] trap). All four rejected. REPRODUCIBILITY (GPT B1.4 / B1.5) - extract.sh refuses a wrong-commit or dirty source tree (fail-closed), takes an optional source-path arg, and pins the source commit. - verification/PROVENANCE.json: single machine-readable pin set (source + charon + aeneas commits/channel + lean + ocaml) with generated-file sha256. - Re-running extract.sh reproduces gen/SlhVerify/{Types,Funs}.lean byte-identically (companion fips205-source commit adds Cargo.lock + rust-toolchain.toml; verified not to perturb the model). DOC HONESTY (both reviewers) - README: fix the self-contradiction (apex "not yet proven" trailer vs the proven apex), the false "oracles kept OUTSIDE every cone" (they are INSIDE, by design), "deployed monomorphic path" and "semantics-identical for every parameter set" overclaims, "only two lines changed", stale snapshot head; retitle the stale future-tense "what will be claimed" section. - TRUSTED-BASE: drop "nothing proven yet"; add base_2b-inner and deployment- bridge non-claims explicitly; current pin. - ChainSpec header: "deployed monomorphic path" -> private verify_mono facade (comment only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 17:13:55 +00:00
def kernel3 : List Name := [`propext, `Classical.choice, `Quot.sound]
def oracleF : Name := `verify_mono.oracle.f
def oracleH : Name := `verify_mono.oracle.h
def oracleTL : Name := `verify_mono.oracle.t_l
def oracleTLen : Name := `verify_mono.oracle.t_len
def oracleHMsg : Name := `verify_mono.oracle.h_msg
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
/-- The ONLY axioms permitted in any cone anywhere in the audited modules.
POLICY CONSTANT — folded into the SHA-256 digest (round-5 NEW-1): widening
this list changes the digest and fails the build. -/
review round 2: in-Lean exact-cone audit + reproducibility + doc honesty Addresses the round-2 reviewer punch-list. No theorem statement, proof term, or fold definition changed; the eleven cones are unchanged (independent collectAxioms dump in verification/RECORDED-RUN.md). AUDIT GATE (both reviewers, the critical one) - Retire the bash #print-axioms text parser (fail-open on empty/truncated reports, and only a SUBSET check). Replace with verification/Proofs/Audit.lean: reads each certificate's cone from the kernel via collectAxioms and asserts EXACT set equality against its expected boundary. Extra axiom, dropped oracle, renamed/deleted cert, or an axiom/opaque sham each throw -> non-zero Lean exit. No text to misparse; nothing fails open. check.sh Phase 3 now just compiles it (and still requires the explicit PASSED line). - check-selftest.sh rewritten to attack the new gate: dead-file, smuggled extra axiom (named), dropped-oracle (subset would pass, exact must not), and a vanished certificate (the collectAxioms-returns-[] trap). All four rejected. REPRODUCIBILITY (GPT B1.4 / B1.5) - extract.sh refuses a wrong-commit or dirty source tree (fail-closed), takes an optional source-path arg, and pins the source commit. - verification/PROVENANCE.json: single machine-readable pin set (source + charon + aeneas commits/channel + lean + ocaml) with generated-file sha256. - Re-running extract.sh reproduces gen/SlhVerify/{Types,Funs}.lean byte-identically (companion fips205-source commit adds Cargo.lock + rust-toolchain.toml; verified not to perturb the model). DOC HONESTY (both reviewers) - README: fix the self-contradiction (apex "not yet proven" trailer vs the proven apex), the false "oracles kept OUTSIDE every cone" (they are INSIDE, by design), "deployed monomorphic path" and "semantics-identical for every parameter set" overclaims, "only two lines changed", stale snapshot head; retitle the stale future-tense "what will be claimed" section. - TRUSTED-BASE: drop "nothing proven yet"; add base_2b-inner and deployment- bridge non-claims explicitly; current pin. - ChainSpec header: "deployed monomorphic path" -> private verify_mono facade (comment only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 17:13:55 +00:00
def allowedBoundary : List Name :=
kernel3 ++ [oracleF, oracleH, oracleTL, oracleTLen, oracleHMsg]
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
/-- The eight certificate-bearing proof modules. POLICY CONSTANT — also folded
into the digest. (It is additionally cross-checked by `certsSeen` below:
every manifest certificate must be found inside one of these modules.) -/
review round 4: bind the cert set, statements, and model bytes (F1/F2/F3) The third reviewer demonstrated that the round-2 in-Lean exact-cone audit, though sound for LISTED certs, left three fail-opens OUTSIDE the cone check — and made check.sh print ALL GREEN over a repo proving False. All closed; no theorem, proof, or fold changed (the 11 cones are unchanged). F1 — the audited SET was unbound. Audit.lean now (a) enumerates EVERY theorem defined in the eight certificate modules and requires each cone ⊆ boundary, so an un-manifested `theorem _ : False := cheat _` fails regardless of naming (this is the exact exploit the reviewer used); and (b) prints a MANIFEST fingerprint over the whole committed manifest, which check.sh binds to — so deleting/swapping a cert row fails outside Lean too. F2 — only cones were bound, not statements. Each cert now also carries the structural fingerprint (Expr.hash) of its elaborated type; a statement gutted to a tautology of the same cone changes the fingerprint and fails. F3 — the gen/ model bytes were unbound. New check.sh Phase 0 sha256-pins all four gen/SlhVerify/*.lean (incl. the two hand-maintained *External files, now hashed in PROVENANCE.json) BEFORE compiling; a hand-edited model fails first. F4/F5 — docs. README cone diagram now roots honestly at slh_verify_internal and states the pure/prehash domain-separator byte, the ctx>255 check, M' assembly, and deserialization are ABOVE the root and uncovered (new TRUSTED-BASE item 10). The false "rules out a wrong ADRS field" claim is corrected in README + ChainSpec (a transliteration makes the field visible, not excluded). check-selftest.sh: eight attacks, all rejected (dead file; extra axiom; dropped oracle; vanished cert; un-manifested False theorem; gutted statement; hand-edited model; deleted manifest row). Full transcript + green check.sh in verification/RECORDED-RUN.md. Standing limit unchanged and disclosed: an audit cannot defend against an author who edits the manifest AND check.sh AND the proofs together; the consumer defense is the pinned commit reviewed at the pin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 17:47:39 +00:00
def certModules : List Name :=
[`Proofs.ChainSpec, `Proofs.WotsSpec, `Proofs.XmssSpec, `Proofs.HtSpec,
`Proofs.ForsInnerSpec, `Proofs.ForsOuterSpec, `Proofs.InputPrepSpec, `Proofs.ApexSpec]
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
/-- Per-certificate expected cone + a 32-bit `Expr.hash` of the elaborated
statement. The hash is a DIAGNOSTIC ONLY (it names which certificate moved);
the binding digest is the SHA-256 over the canonical block. -/
review round 4: bind the cert set, statements, and model bytes (F1/F2/F3) The third reviewer demonstrated that the round-2 in-Lean exact-cone audit, though sound for LISTED certs, left three fail-opens OUTSIDE the cone check — and made check.sh print ALL GREEN over a repo proving False. All closed; no theorem, proof, or fold changed (the 11 cones are unchanged). F1 — the audited SET was unbound. Audit.lean now (a) enumerates EVERY theorem defined in the eight certificate modules and requires each cone ⊆ boundary, so an un-manifested `theorem _ : False := cheat _` fails regardless of naming (this is the exact exploit the reviewer used); and (b) prints a MANIFEST fingerprint over the whole committed manifest, which check.sh binds to — so deleting/swapping a cert row fails outside Lean too. F2 — only cones were bound, not statements. Each cert now also carries the structural fingerprint (Expr.hash) of its elaborated type; a statement gutted to a tautology of the same cone changes the fingerprint and fails. F3 — the gen/ model bytes were unbound. New check.sh Phase 0 sha256-pins all four gen/SlhVerify/*.lean (incl. the two hand-maintained *External files, now hashed in PROVENANCE.json) BEFORE compiling; a hand-edited model fails first. F4/F5 — docs. README cone diagram now roots honestly at slh_verify_internal and states the pure/prehash domain-separator byte, the ctx>255 check, M' assembly, and deserialization are ABOVE the root and uncovered (new TRUSTED-BASE item 10). The false "rules out a wrong ADRS field" claim is corrected in README + ChainSpec (a transliteration makes the field visible, not excluded). check-selftest.sh: eight attacks, all rejected (dead file; extra axiom; dropped oracle; vanished cert; un-manifested False theorem; gutted statement; hand-edited model; deleted manifest row). Full transcript + green check.sh in verification/RECORDED-RUN.md. Standing limit unchanged and disclosed: an audit cannot defend against an author who edits the manifest AND check.sh AND the proofs together; the consumer defense is the pinned commit reviewed at the pin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 17:47:39 +00:00
def manifest : List (Name × List Name × UInt64) :=
[ (`fips205.chain_free_loop_eq, kernel3 ++ [oracleF], 2535491171),
(`fips205.wots_loop1_eq, kernel3 ++ [oracleF], 2968777228),
(`fips205.xmss_loop_eq, kernel3 ++ [oracleH], 763493610),
(`fips205.ht_loop_eq, kernel3 ++ [oracleF, oracleH, oracleTL], 1071622136),
(`fips205.fors_inner_loop_eq, kernel3 ++ [oracleH], 2102092697),
(`fips205.fors_outer_loop_eq, kernel3 ++ [oracleF, oracleH], 2749583942),
(`fips205.to_int_loop_eq, kernel3, 3797401829),
(`fips205.to_byte_loop_eq, kernel3, 3618049364),
(`fips205.wots_csum_loop_eq, kernel3, 4245103433),
(`fips205.base2b_outer_loop_eq, kernel3, 324621577),
(`fips205.slh_verify_128s_accepts_iff, kernel3 ++ [oracleF, oracleH, oracleTL, oracleTLen, oracleHMsg], 2489587792) ]
Phase 3c: declaration coverage in both directions, and the accounting identity Completes the round-8 hardening of this repository. Round-8 review (Claude, register keys `drv-surface-no-cones` and `accounting-certifies-enumeration`). WHAT PHASE 3 DID NOT PIN. It proves each certificate's cone is exact and that no declaration in scope carries a disallowed axiom. It does not pin WHICH declarations exist: a new one that happens to be clean, and a silently vanished one, both pass it. inventory-allowlist.txt 265 rows — the audited corpus driver-allowlist.txt 35 rows — the audit INSTRUMENT's own surface both as INV|module|name|kind|CONE, diffed in BOTH directions by inventory_gate.sh, the same implementation the ed25519 repositories use, with a tag per surface. The instrument surface carries cones because the reviewer showed enumeration is not audit: a claim planted in an instrument is counted by an accounting identity and then examined by nothing, if its row carries no cone and no allowlist covers it. Here the instrument's 35 declarations are pinned exactly as the corpus's 265 are. INTERNAL NAMES ARE NO LONGER EXEMPT from the environment walk. They were skipped, which was harmless while nothing compared that walk against the kernel's view — and became a hole the moment something did: Phase 3b reads object files, which contain the compiler's auxiliaries. Exempting them would have left the accounting identity permanently short and forced the residual to be "explained" by a constant. That is the shape of the fudge term four-fork data refuted in the ed25519 repositories, and it is refused here before it can start. THE ACCOUNTING IDENTITY, as SET CONTAINMENT and never arithmetic: every constant the kernel holds must appear in one of the two walks. The kernel gate now emits KERNEL-NAME rows so the comparison names what is missing rather than reporting a count that has to be interpreted. kernel 300 = inventory 265 + instrument 35 residual: none Negative-tested, all three rejected by name and the tree restored to green: · a deleted INV row -> UNCLASSIFIED: INV|Proofs.ApexSpec|List.allM.eq_1|theorem| · a deleted DRV row -> UNCLASSIFIED: DRV|Proofs.Audit|SlhVerify.Audit.sortNames|def · a row with no declaration behind it -> STALE: …|fips205.ghost_that_does_not_exist|… Both allowlists join the pinned harness set: not executable, so the executable-bit rule cannot reach them, and an allowlist an attacker may rewrite pins nothing. fips205-slhdsa-verified now has the ed25519 repositories' gate set: 0 hygiene, 0d correspondence, 1 model, 2 proofs, 3 in-Lean audit, 3b kernel-side axiom gate, 3c coverage + accounting. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 15:34:00 +00:00
/-- Declaration kind, in the vocabulary the estate's allowlists already use.
A KIND is part of the record because "the name is still there" and "the
thing behind the name is still the same kind of thing" are different
facts: a theorem quietly replaced by a `def` keeps its name and loses its
meaning. -/
def kindOf : ConstantInfo → String
| .axiomInfo _ => "axiom"
| .thmInfo _ => "theorem"
| .opaqueInfo _ => "opaque"
| .defnInfo _ => "def"
| .quotInfo _ => "quot"
| .inductInfo _ => "inductive"
| .ctorInfo _ => "ctor"
| .recInfo _ => "rec"
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
/-- Deterministic name ordering for the canonical serialization. -/
def sortNames (l : List Name) : List Name :=
((l.map toString).toArray.qsort (· < ·)).toList.map (·.toName)
/-- Whitespace-canonical: every whitespace run collapses to one space, so the
pretty-printer's line wrapping cannot perturb the digest. -/
def normWs (s : String) : String :=
(s.foldl (fun (acc : String × Bool) c =>
let c := if c.isWhitespace then ' ' else c
if c == ' ' then (if acc.2 then acc else (acc.1.push ' ', true))
else (acc.1.push c, false))
("", true)).1
/-- Is `n` a hand-written declaration living in one of the certificate modules?
These are the SPECIFICATION side — the folds the certificates are stated
against — as opposed to the extracted model in `gen/` (pinned by Phase 0). -/
def isSpecConst (env : Environment) (n : Name) : Bool :=
match env.getModuleIdxFor? n with
| some idx => certModules.contains env.header.moduleNames[idx.toNat]!
| none => false
/-- Transitive closure over specification constants, starting from a
certificate's STATEMENT and following DEFINITION bodies (a theorem
contributes its statement only). This discovers the reference folds — and
any future one — automatically, so a new specification definition cannot be
introduced without moving the digest. -/
partial def closureOf (env : Environment) (seen : NameSet) (work : List Name) : NameSet :=
match work with
| [] => seen
| n :: rest =>
if seen.contains n || !isSpecConst env n then closureOf env seen rest
else
let seen := seen.insert n
let more := match env.find? n with
| some (.defnInfo v) => v.value.getUsedConstants.toList ++ v.type.getUsedConstants.toList
| some ci => ci.type.getUsedConstants.toList
| none => []
closureOf env seen (more ++ rest)
/-- Fully-explicit (`pp.all`) rendering, whitespace-canonicalized. -/
def ppAll (e : Expr) : CommandElabM String := do
let s ← Command.liftCoreM <| Meta.MetaM.run' <|
withOptions (fun o => o.setBool `pp.all true) do
return (← Meta.ppExpr e).pretty
return normWs s
review round 2: in-Lean exact-cone audit + reproducibility + doc honesty Addresses the round-2 reviewer punch-list. No theorem statement, proof term, or fold definition changed; the eleven cones are unchanged (independent collectAxioms dump in verification/RECORDED-RUN.md). AUDIT GATE (both reviewers, the critical one) - Retire the bash #print-axioms text parser (fail-open on empty/truncated reports, and only a SUBSET check). Replace with verification/Proofs/Audit.lean: reads each certificate's cone from the kernel via collectAxioms and asserts EXACT set equality against its expected boundary. Extra axiom, dropped oracle, renamed/deleted cert, or an axiom/opaque sham each throw -> non-zero Lean exit. No text to misparse; nothing fails open. check.sh Phase 3 now just compiles it (and still requires the explicit PASSED line). - check-selftest.sh rewritten to attack the new gate: dead-file, smuggled extra axiom (named), dropped-oracle (subset would pass, exact must not), and a vanished certificate (the collectAxioms-returns-[] trap). All four rejected. REPRODUCIBILITY (GPT B1.4 / B1.5) - extract.sh refuses a wrong-commit or dirty source tree (fail-closed), takes an optional source-path arg, and pins the source commit. - verification/PROVENANCE.json: single machine-readable pin set (source + charon + aeneas commits/channel + lean + ocaml) with generated-file sha256. - Re-running extract.sh reproduces gen/SlhVerify/{Types,Funs}.lean byte-identically (companion fips205-source commit adds Cargo.lock + rust-toolchain.toml; verified not to perturb the model). DOC HONESTY (both reviewers) - README: fix the self-contradiction (apex "not yet proven" trailer vs the proven apex), the false "oracles kept OUTSIDE every cone" (they are INSIDE, by design), "deployed monomorphic path" and "semantics-identical for every parameter set" overclaims, "only two lines changed", stale snapshot head; retitle the stale future-tense "what will be claimed" section. - TRUSTED-BASE: drop "nothing proven yet"; add base_2b-inner and deployment- bridge non-claims explicitly; current pin. - ChainSpec header: "deployed monomorphic path" -> private verify_mono facade (comment only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 17:13:55 +00:00
elab "auditCones" : command => do
let env ← getEnv
let mut errs : Array String := #[]
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
-- (0) the manifest's expected cones may reference nothing outside the policy.
review round 4: bind the cert set, statements, and model bytes (F1/F2/F3) The third reviewer demonstrated that the round-2 in-Lean exact-cone audit, though sound for LISTED certs, left three fail-opens OUTSIDE the cone check — and made check.sh print ALL GREEN over a repo proving False. All closed; no theorem, proof, or fold changed (the 11 cones are unchanged). F1 — the audited SET was unbound. Audit.lean now (a) enumerates EVERY theorem defined in the eight certificate modules and requires each cone ⊆ boundary, so an un-manifested `theorem _ : False := cheat _` fails regardless of naming (this is the exact exploit the reviewer used); and (b) prints a MANIFEST fingerprint over the whole committed manifest, which check.sh binds to — so deleting/swapping a cert row fails outside Lean too. F2 — only cones were bound, not statements. Each cert now also carries the structural fingerprint (Expr.hash) of its elaborated type; a statement gutted to a tautology of the same cone changes the fingerprint and fails. F3 — the gen/ model bytes were unbound. New check.sh Phase 0 sha256-pins all four gen/SlhVerify/*.lean (incl. the two hand-maintained *External files, now hashed in PROVENANCE.json) BEFORE compiling; a hand-edited model fails first. F4/F5 — docs. README cone diagram now roots honestly at slh_verify_internal and states the pure/prehash domain-separator byte, the ctx>255 check, M' assembly, and deserialization are ABOVE the root and uncovered (new TRUSTED-BASE item 10). The false "rules out a wrong ADRS field" claim is corrected in README + ChainSpec (a transliteration makes the field visible, not excluded). check-selftest.sh: eight attacks, all rejected (dead file; extra axiom; dropped oracle; vanished cert; un-manifested False theorem; gutted statement; hand-edited model; deleted manifest row). Full transcript + green check.sh in verification/RECORDED-RUN.md. Standing limit unchanged and disclosed: an audit cannot defend against an author who edits the manifest AND check.sh AND the proofs together; the consumer defense is the pinned commit reviewed at the pin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 17:47:39 +00:00
for (cert, cone, _) in manifest do
for a in cone do
unless allowedBoundary.contains a do
throwError "manifest references non-boundary axiom {a} for {cert}"
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
-- (1) NAMED CERTS: exists ∧ is a theorem ∧ exact cone ∧ statement diagnostic.
review round 4: bind the cert set, statements, and model bytes (F1/F2/F3) The third reviewer demonstrated that the round-2 in-Lean exact-cone audit, though sound for LISTED certs, left three fail-opens OUTSIDE the cone check — and made check.sh print ALL GREEN over a repo proving False. All closed; no theorem, proof, or fold changed (the 11 cones are unchanged). F1 — the audited SET was unbound. Audit.lean now (a) enumerates EVERY theorem defined in the eight certificate modules and requires each cone ⊆ boundary, so an un-manifested `theorem _ : False := cheat _` fails regardless of naming (this is the exact exploit the reviewer used); and (b) prints a MANIFEST fingerprint over the whole committed manifest, which check.sh binds to — so deleting/swapping a cert row fails outside Lean too. F2 — only cones were bound, not statements. Each cert now also carries the structural fingerprint (Expr.hash) of its elaborated type; a statement gutted to a tautology of the same cone changes the fingerprint and fails. F3 — the gen/ model bytes were unbound. New check.sh Phase 0 sha256-pins all four gen/SlhVerify/*.lean (incl. the two hand-maintained *External files, now hashed in PROVENANCE.json) BEFORE compiling; a hand-edited model fails first. F4/F5 — docs. README cone diagram now roots honestly at slh_verify_internal and states the pure/prehash domain-separator byte, the ctx>255 check, M' assembly, and deserialization are ABOVE the root and uncovered (new TRUSTED-BASE item 10). The false "rules out a wrong ADRS field" claim is corrected in README + ChainSpec (a transliteration makes the field visible, not excluded). check-selftest.sh: eight attacks, all rejected (dead file; extra axiom; dropped oracle; vanished cert; un-manifested False theorem; gutted statement; hand-edited model; deleted manifest row). Full transcript + green check.sh in verification/RECORDED-RUN.md. Standing limit unchanged and disclosed: an audit cannot defend against an author who edits the manifest AND check.sh AND the proofs together; the consumer defense is the pinned commit reviewed at the pin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 17:47:39 +00:00
for (cert, expected, expFp) in manifest do
review round 2: in-Lean exact-cone audit + reproducibility + doc honesty Addresses the round-2 reviewer punch-list. No theorem statement, proof term, or fold definition changed; the eleven cones are unchanged (independent collectAxioms dump in verification/RECORDED-RUN.md). AUDIT GATE (both reviewers, the critical one) - Retire the bash #print-axioms text parser (fail-open on empty/truncated reports, and only a SUBSET check). Replace with verification/Proofs/Audit.lean: reads each certificate's cone from the kernel via collectAxioms and asserts EXACT set equality against its expected boundary. Extra axiom, dropped oracle, renamed/deleted cert, or an axiom/opaque sham each throw -> non-zero Lean exit. No text to misparse; nothing fails open. check.sh Phase 3 now just compiles it (and still requires the explicit PASSED line). - check-selftest.sh rewritten to attack the new gate: dead-file, smuggled extra axiom (named), dropped-oracle (subset would pass, exact must not), and a vanished certificate (the collectAxioms-returns-[] trap). All four rejected. REPRODUCIBILITY (GPT B1.4 / B1.5) - extract.sh refuses a wrong-commit or dirty source tree (fail-closed), takes an optional source-path arg, and pins the source commit. - verification/PROVENANCE.json: single machine-readable pin set (source + charon + aeneas commits/channel + lean + ocaml) with generated-file sha256. - Re-running extract.sh reproduces gen/SlhVerify/{Types,Funs}.lean byte-identically (companion fips205-source commit adds Cargo.lock + rust-toolchain.toml; verified not to perturb the model). DOC HONESTY (both reviewers) - README: fix the self-contradiction (apex "not yet proven" trailer vs the proven apex), the false "oracles kept OUTSIDE every cone" (they are INSIDE, by design), "deployed monomorphic path" and "semantics-identical for every parameter set" overclaims, "only two lines changed", stale snapshot head; retitle the stale future-tense "what will be claimed" section. - TRUSTED-BASE: drop "nothing proven yet"; add base_2b-inner and deployment- bridge non-claims explicitly; current pin. - ChainSpec header: "deployed monomorphic path" -> private verify_mono facade (comment only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 17:13:55 +00:00
match env.find? cert with
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
| none => errs := errs.push s!"{cert}: NOT FOUND (renamed/deleted?)"
| some (.thmInfo ci) =>
review round 2: in-Lean exact-cone audit + reproducibility + doc honesty Addresses the round-2 reviewer punch-list. No theorem statement, proof term, or fold definition changed; the eleven cones are unchanged (independent collectAxioms dump in verification/RECORDED-RUN.md). AUDIT GATE (both reviewers, the critical one) - Retire the bash #print-axioms text parser (fail-open on empty/truncated reports, and only a SUBSET check). Replace with verification/Proofs/Audit.lean: reads each certificate's cone from the kernel via collectAxioms and asserts EXACT set equality against its expected boundary. Extra axiom, dropped oracle, renamed/deleted cert, or an axiom/opaque sham each throw -> non-zero Lean exit. No text to misparse; nothing fails open. check.sh Phase 3 now just compiles it (and still requires the explicit PASSED line). - check-selftest.sh rewritten to attack the new gate: dead-file, smuggled extra axiom (named), dropped-oracle (subset would pass, exact must not), and a vanished certificate (the collectAxioms-returns-[] trap). All four rejected. REPRODUCIBILITY (GPT B1.4 / B1.5) - extract.sh refuses a wrong-commit or dirty source tree (fail-closed), takes an optional source-path arg, and pins the source commit. - verification/PROVENANCE.json: single machine-readable pin set (source + charon + aeneas commits/channel + lean + ocaml) with generated-file sha256. - Re-running extract.sh reproduces gen/SlhVerify/{Types,Funs}.lean byte-identically (companion fips205-source commit adds Cargo.lock + rust-toolchain.toml; verified not to perturb the model). DOC HONESTY (both reviewers) - README: fix the self-contradiction (apex "not yet proven" trailer vs the proven apex), the false "oracles kept OUTSIDE every cone" (they are INSIDE, by design), "deployed monomorphic path" and "semantics-identical for every parameter set" overclaims, "only two lines changed", stale snapshot head; retitle the stale future-tense "what will be claimed" section. - TRUSTED-BASE: drop "nothing proven yet"; add base_2b-inner and deployment- bridge non-claims explicitly; current pin. - ChainSpec header: "deployed monomorphic path" -> private verify_mono facade (comment only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 17:13:55 +00:00
let got := (← collectAxioms cert).toList
let extras := got.filter (fun a => !expected.contains a)
let missing := expected.filter (fun a => !got.contains a)
unless extras.isEmpty && missing.isEmpty do
review round 4: bind the cert set, statements, and model bytes (F1/F2/F3) The third reviewer demonstrated that the round-2 in-Lean exact-cone audit, though sound for LISTED certs, left three fail-opens OUTSIDE the cone check — and made check.sh print ALL GREEN over a repo proving False. All closed; no theorem, proof, or fold changed (the 11 cones are unchanged). F1 — the audited SET was unbound. Audit.lean now (a) enumerates EVERY theorem defined in the eight certificate modules and requires each cone ⊆ boundary, so an un-manifested `theorem _ : False := cheat _` fails regardless of naming (this is the exact exploit the reviewer used); and (b) prints a MANIFEST fingerprint over the whole committed manifest, which check.sh binds to — so deleting/swapping a cert row fails outside Lean too. F2 — only cones were bound, not statements. Each cert now also carries the structural fingerprint (Expr.hash) of its elaborated type; a statement gutted to a tautology of the same cone changes the fingerprint and fails. F3 — the gen/ model bytes were unbound. New check.sh Phase 0 sha256-pins all four gen/SlhVerify/*.lean (incl. the two hand-maintained *External files, now hashed in PROVENANCE.json) BEFORE compiling; a hand-edited model fails first. F4/F5 — docs. README cone diagram now roots honestly at slh_verify_internal and states the pure/prehash domain-separator byte, the ctx>255 check, M' assembly, and deserialization are ABOVE the root and uncovered (new TRUSTED-BASE item 10). The false "rules out a wrong ADRS field" claim is corrected in README + ChainSpec (a transliteration makes the field visible, not excluded). check-selftest.sh: eight attacks, all rejected (dead file; extra axiom; dropped oracle; vanished cert; un-manifested False theorem; gutted statement; hand-edited model; deleted manifest row). Full transcript + green check.sh in verification/RECORDED-RUN.md. Standing limit unchanged and disclosed: an audit cannot defend against an author who edits the manifest AND check.sh AND the proofs together; the consumer defense is the pinned commit reviewed at the pin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 17:47:39 +00:00
errs := errs.push s!"{cert}: cone extra={extras} missing={missing}"
unless ci.type.hash == expFp do
errs := errs.push s!"{cert}: STATEMENT fingerprint {ci.type.hash} ≠ committed {expFp} (statement changed?)"
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
| some (.axiomInfo _) => errs := errs.push s!"{cert}: is an AXIOM, not a proven theorem"
| some (.opaqueInfo _) => errs := errs.push s!"{cert}: is OPAQUE, not a proven theorem"
| some _ => errs := errs.push s!"{cert}: not a theorem"
-- (2) ENUMERATION over EVERY declaration kind — not just theorems (a
-- `def : False` passed the round-4 gate) — in the eight certificate
-- modules, AND over this file's own declarations (module index is `none`
-- during its own elaboration), so the auditor is not exempt (round-5 R1).
review round 4: bind the cert set, statements, and model bytes (F1/F2/F3) The third reviewer demonstrated that the round-2 in-Lean exact-cone audit, though sound for LISTED certs, left three fail-opens OUTSIDE the cone check — and made check.sh print ALL GREEN over a repo proving False. All closed; no theorem, proof, or fold changed (the 11 cones are unchanged). F1 — the audited SET was unbound. Audit.lean now (a) enumerates EVERY theorem defined in the eight certificate modules and requires each cone ⊆ boundary, so an un-manifested `theorem _ : False := cheat _` fails regardless of naming (this is the exact exploit the reviewer used); and (b) prints a MANIFEST fingerprint over the whole committed manifest, which check.sh binds to — so deleting/swapping a cert row fails outside Lean too. F2 — only cones were bound, not statements. Each cert now also carries the structural fingerprint (Expr.hash) of its elaborated type; a statement gutted to a tautology of the same cone changes the fingerprint and fails. F3 — the gen/ model bytes were unbound. New check.sh Phase 0 sha256-pins all four gen/SlhVerify/*.lean (incl. the two hand-maintained *External files, now hashed in PROVENANCE.json) BEFORE compiling; a hand-edited model fails first. F4/F5 — docs. README cone diagram now roots honestly at slh_verify_internal and states the pure/prehash domain-separator byte, the ctx>255 check, M' assembly, and deserialization are ABOVE the root and uncovered (new TRUSTED-BASE item 10). The false "rules out a wrong ADRS field" claim is corrected in README + ChainSpec (a transliteration makes the field visible, not excluded). check-selftest.sh: eight attacks, all rejected (dead file; extra axiom; dropped oracle; vanished cert; un-manifested False theorem; gutted statement; hand-edited model; deleted manifest row). Full transcript + green check.sh in verification/RECORDED-RUN.md. Standing limit unchanged and disclosed: an audit cannot defend against an author who edits the manifest AND check.sh AND the proofs together; the consumer defense is the pinned commit reviewed at the pin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 17:47:39 +00:00
let manifestNames := manifest.map (·.1)
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
let mut nEnum := 0
review round 4: bind the cert set, statements, and model bytes (F1/F2/F3) The third reviewer demonstrated that the round-2 in-Lean exact-cone audit, though sound for LISTED certs, left three fail-opens OUTSIDE the cone check — and made check.sh print ALL GREEN over a repo proving False. All closed; no theorem, proof, or fold changed (the 11 cones are unchanged). F1 — the audited SET was unbound. Audit.lean now (a) enumerates EVERY theorem defined in the eight certificate modules and requires each cone ⊆ boundary, so an un-manifested `theorem _ : False := cheat _` fails regardless of naming (this is the exact exploit the reviewer used); and (b) prints a MANIFEST fingerprint over the whole committed manifest, which check.sh binds to — so deleting/swapping a cert row fails outside Lean too. F2 — only cones were bound, not statements. Each cert now also carries the structural fingerprint (Expr.hash) of its elaborated type; a statement gutted to a tautology of the same cone changes the fingerprint and fails. F3 — the gen/ model bytes were unbound. New check.sh Phase 0 sha256-pins all four gen/SlhVerify/*.lean (incl. the two hand-maintained *External files, now hashed in PROVENANCE.json) BEFORE compiling; a hand-edited model fails first. F4/F5 — docs. README cone diagram now roots honestly at slh_verify_internal and states the pure/prehash domain-separator byte, the ctx>255 check, M' assembly, and deserialization are ABOVE the root and uncovered (new TRUSTED-BASE item 10). The false "rules out a wrong ADRS field" claim is corrected in README + ChainSpec (a transliteration makes the field visible, not excluded). check-selftest.sh: eight attacks, all rejected (dead file; extra axiom; dropped oracle; vanished cert; un-manifested False theorem; gutted statement; hand-edited model; deleted manifest row). Full transcript + green check.sh in verification/RECORDED-RUN.md. Standing limit unchanged and disclosed: an audit cannot defend against an author who edits the manifest AND check.sh AND the proofs together; the consumer defense is the pinned commit reviewed at the pin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 17:47:39 +00:00
let mut certsSeen : Array Name := #[]
Phase 3c: declaration coverage in both directions, and the accounting identity Completes the round-8 hardening of this repository. Round-8 review (Claude, register keys `drv-surface-no-cones` and `accounting-certifies-enumeration`). WHAT PHASE 3 DID NOT PIN. It proves each certificate's cone is exact and that no declaration in scope carries a disallowed axiom. It does not pin WHICH declarations exist: a new one that happens to be clean, and a silently vanished one, both pass it. inventory-allowlist.txt 265 rows — the audited corpus driver-allowlist.txt 35 rows — the audit INSTRUMENT's own surface both as INV|module|name|kind|CONE, diffed in BOTH directions by inventory_gate.sh, the same implementation the ed25519 repositories use, with a tag per surface. The instrument surface carries cones because the reviewer showed enumeration is not audit: a claim planted in an instrument is counted by an accounting identity and then examined by nothing, if its row carries no cone and no allowlist covers it. Here the instrument's 35 declarations are pinned exactly as the corpus's 265 are. INTERNAL NAMES ARE NO LONGER EXEMPT from the environment walk. They were skipped, which was harmless while nothing compared that walk against the kernel's view — and became a hole the moment something did: Phase 3b reads object files, which contain the compiler's auxiliaries. Exempting them would have left the accounting identity permanently short and forced the residual to be "explained" by a constant. That is the shape of the fudge term four-fork data refuted in the ed25519 repositories, and it is refused here before it can start. THE ACCOUNTING IDENTITY, as SET CONTAINMENT and never arithmetic: every constant the kernel holds must appear in one of the two walks. The kernel gate now emits KERNEL-NAME rows so the comparison names what is missing rather than reporting a count that has to be interpreted. kernel 300 = inventory 265 + instrument 35 residual: none Negative-tested, all three rejected by name and the tree restored to green: · a deleted INV row -> UNCLASSIFIED: INV|Proofs.ApexSpec|List.allM.eq_1|theorem| · a deleted DRV row -> UNCLASSIFIED: DRV|Proofs.Audit|SlhVerify.Audit.sortNames|def · a row with no declaration behind it -> STALE: …|fips205.ghost_that_does_not_exist|… Both allowlists join the pinned harness set: not executable, so the executable-bit rule cannot reach them, and an allowlist an attacker may rewrite pins nothing. fips205-slhdsa-verified now has the ed25519 repositories' gate set: 0 hygiene, 0d correspondence, 1 model, 2 proofs, 3 in-Lean audit, 3b kernel-side axiom gate, 3c coverage + accounting. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 15:34:00 +00:00
let mut invRows : Array String := #[]
let mut drvRows : Array String := #[]
review round 4: bind the cert set, statements, and model bytes (F1/F2/F3) The third reviewer demonstrated that the round-2 in-Lean exact-cone audit, though sound for LISTED certs, left three fail-opens OUTSIDE the cone check — and made check.sh print ALL GREEN over a repo proving False. All closed; no theorem, proof, or fold changed (the 11 cones are unchanged). F1 — the audited SET was unbound. Audit.lean now (a) enumerates EVERY theorem defined in the eight certificate modules and requires each cone ⊆ boundary, so an un-manifested `theorem _ : False := cheat _` fails regardless of naming (this is the exact exploit the reviewer used); and (b) prints a MANIFEST fingerprint over the whole committed manifest, which check.sh binds to — so deleting/swapping a cert row fails outside Lean too. F2 — only cones were bound, not statements. Each cert now also carries the structural fingerprint (Expr.hash) of its elaborated type; a statement gutted to a tautology of the same cone changes the fingerprint and fails. F3 — the gen/ model bytes were unbound. New check.sh Phase 0 sha256-pins all four gen/SlhVerify/*.lean (incl. the two hand-maintained *External files, now hashed in PROVENANCE.json) BEFORE compiling; a hand-edited model fails first. F4/F5 — docs. README cone diagram now roots honestly at slh_verify_internal and states the pure/prehash domain-separator byte, the ctx>255 check, M' assembly, and deserialization are ABOVE the root and uncovered (new TRUSTED-BASE item 10). The false "rules out a wrong ADRS field" claim is corrected in README + ChainSpec (a transliteration makes the field visible, not excluded). check-selftest.sh: eight attacks, all rejected (dead file; extra axiom; dropped oracle; vanished cert; un-manifested False theorem; gutted statement; hand-edited model; deleted manifest row). Full transcript + green check.sh in verification/RECORDED-RUN.md. Standing limit unchanged and disclosed: an audit cannot defend against an author who edits the manifest AND check.sh AND the proofs together; the consumer defense is the pinned commit reviewed at the pin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 17:47:39 +00:00
for (nm, ci) in env.constants.toList do
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
let scope : Option String :=
review round 4: bind the cert set, statements, and model bytes (F1/F2/F3) The third reviewer demonstrated that the round-2 in-Lean exact-cone audit, though sound for LISTED certs, left three fail-opens OUTSIDE the cone check — and made check.sh print ALL GREEN over a repo proving False. All closed; no theorem, proof, or fold changed (the 11 cones are unchanged). F1 — the audited SET was unbound. Audit.lean now (a) enumerates EVERY theorem defined in the eight certificate modules and requires each cone ⊆ boundary, so an un-manifested `theorem _ : False := cheat _` fails regardless of naming (this is the exact exploit the reviewer used); and (b) prints a MANIFEST fingerprint over the whole committed manifest, which check.sh binds to — so deleting/swapping a cert row fails outside Lean too. F2 — only cones were bound, not statements. Each cert now also carries the structural fingerprint (Expr.hash) of its elaborated type; a statement gutted to a tautology of the same cone changes the fingerprint and fails. F3 — the gen/ model bytes were unbound. New check.sh Phase 0 sha256-pins all four gen/SlhVerify/*.lean (incl. the two hand-maintained *External files, now hashed in PROVENANCE.json) BEFORE compiling; a hand-edited model fails first. F4/F5 — docs. README cone diagram now roots honestly at slh_verify_internal and states the pure/prehash domain-separator byte, the ctx>255 check, M' assembly, and deserialization are ABOVE the root and uncovered (new TRUSTED-BASE item 10). The false "rules out a wrong ADRS field" claim is corrected in README + ChainSpec (a transliteration makes the field visible, not excluded). check-selftest.sh: eight attacks, all rejected (dead file; extra axiom; dropped oracle; vanished cert; un-manifested False theorem; gutted statement; hand-edited model; deleted manifest row). Full transcript + green check.sh in verification/RECORDED-RUN.md. Standing limit unchanged and disclosed: an audit cannot defend against an author who edits the manifest AND check.sh AND the proofs together; the consumer defense is the pinned commit reviewed at the pin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 17:47:39 +00:00
match env.getModuleIdxFor? nm with
| some idx =>
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
let m := env.header.moduleNames[idx.toNat]!
if certModules.contains m then some (toString m) else none
Phase 3c: declaration coverage in both directions, and the accounting identity Completes the round-8 hardening of this repository. Round-8 review (Claude, register keys `drv-surface-no-cones` and `accounting-certifies-enumeration`). WHAT PHASE 3 DID NOT PIN. It proves each certificate's cone is exact and that no declaration in scope carries a disallowed axiom. It does not pin WHICH declarations exist: a new one that happens to be clean, and a silently vanished one, both pass it. inventory-allowlist.txt 265 rows — the audited corpus driver-allowlist.txt 35 rows — the audit INSTRUMENT's own surface both as INV|module|name|kind|CONE, diffed in BOTH directions by inventory_gate.sh, the same implementation the ed25519 repositories use, with a tag per surface. The instrument surface carries cones because the reviewer showed enumeration is not audit: a claim planted in an instrument is counted by an accounting identity and then examined by nothing, if its row carries no cone and no allowlist covers it. Here the instrument's 35 declarations are pinned exactly as the corpus's 265 are. INTERNAL NAMES ARE NO LONGER EXEMPT from the environment walk. They were skipped, which was harmless while nothing compared that walk against the kernel's view — and became a hole the moment something did: Phase 3b reads object files, which contain the compiler's auxiliaries. Exempting them would have left the accounting identity permanently short and forced the residual to be "explained" by a constant. That is the shape of the fudge term four-fork data refuted in the ed25519 repositories, and it is refused here before it can start. THE ACCOUNTING IDENTITY, as SET CONTAINMENT and never arithmetic: every constant the kernel holds must appear in one of the two walks. The kernel gate now emits KERNEL-NAME rows so the comparison names what is missing rather than reporting a count that has to be interpreted. kernel 300 = inventory 265 + instrument 35 residual: none Negative-tested, all three rejected by name and the tree restored to green: · a deleted INV row -> UNCLASSIFIED: INV|Proofs.ApexSpec|List.allM.eq_1|theorem| · a deleted DRV row -> UNCLASSIFIED: DRV|Proofs.Audit|SlhVerify.Audit.sortNames|def · a row with no declaration behind it -> STALE: …|fips205.ghost_that_does_not_exist|… Both allowlists join the pinned harness set: not executable, so the executable-bit rule cannot reach them, and an allowlist an attacker may rewrite pins nothing. fips205-slhdsa-verified now has the ed25519 repositories' gate set: 0 hygiene, 0d correspondence, 1 model, 2 proofs, 3 in-Lean audit, 3b kernel-side axiom gate, 3c coverage + accounting. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 15:34:00 +00:00
-- INTERNAL NAMES ARE NO LONGER EXEMPT. They were skipped here, which
-- was harmless while nothing compared this walk against the kernel's
-- view — and became a hole the moment it did: Phase 3b reads the object
-- files, which contain the compiler's auxiliaries, so exempting them
-- here would leave the accounting identity permanently short and force
-- it to be "explained" by a constant. A residual that has to be
-- explained away is the shape of the fudge term four-fork data refuted
-- in the ed25519 repos.
| none => some "Proofs.Audit"
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
match scope with
| none => pure ()
| some where_ =>
nEnum := nEnum + 1
if manifestNames.contains nm then certsSeen := certsSeen.push nm
Phase 3c: declaration coverage in both directions, and the accounting identity Completes the round-8 hardening of this repository. Round-8 review (Claude, register keys `drv-surface-no-cones` and `accounting-certifies-enumeration`). WHAT PHASE 3 DID NOT PIN. It proves each certificate's cone is exact and that no declaration in scope carries a disallowed axiom. It does not pin WHICH declarations exist: a new one that happens to be clean, and a silently vanished one, both pass it. inventory-allowlist.txt 265 rows — the audited corpus driver-allowlist.txt 35 rows — the audit INSTRUMENT's own surface both as INV|module|name|kind|CONE, diffed in BOTH directions by inventory_gate.sh, the same implementation the ed25519 repositories use, with a tag per surface. The instrument surface carries cones because the reviewer showed enumeration is not audit: a claim planted in an instrument is counted by an accounting identity and then examined by nothing, if its row carries no cone and no allowlist covers it. Here the instrument's 35 declarations are pinned exactly as the corpus's 265 are. INTERNAL NAMES ARE NO LONGER EXEMPT from the environment walk. They were skipped, which was harmless while nothing compared that walk against the kernel's view — and became a hole the moment something did: Phase 3b reads object files, which contain the compiler's auxiliaries. Exempting them would have left the accounting identity permanently short and forced the residual to be "explained" by a constant. That is the shape of the fudge term four-fork data refuted in the ed25519 repositories, and it is refused here before it can start. THE ACCOUNTING IDENTITY, as SET CONTAINMENT and never arithmetic: every constant the kernel holds must appear in one of the two walks. The kernel gate now emits KERNEL-NAME rows so the comparison names what is missing rather than reporting a count that has to be interpreted. kernel 300 = inventory 265 + instrument 35 residual: none Negative-tested, all three rejected by name and the tree restored to green: · a deleted INV row -> UNCLASSIFIED: INV|Proofs.ApexSpec|List.allM.eq_1|theorem| · a deleted DRV row -> UNCLASSIFIED: DRV|Proofs.Audit|SlhVerify.Audit.sortNames|def · a row with no declaration behind it -> STALE: …|fips205.ghost_that_does_not_exist|… Both allowlists join the pinned harness set: not executable, so the executable-bit rule cannot reach them, and an allowlist an attacker may rewrite pins nothing. fips205-slhdsa-verified now has the ed25519 repositories' gate set: 0 hygiene, 0d correspondence, 1 model, 2 proofs, 3 in-Lean audit, 3b kernel-side axiom gate, 3c coverage + accounting. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 15:34:00 +00:00
-- THE ROW. Same shape as the corpus walks in the ed25519 repositories:
-- module, name, kind, cone. The originating module is part of the record
-- because two modules may legitimately declare the same name, and keyed
-- on name alone one would be covered by the other's entry.
let rowCone := (← collectAxioms nm).toList
let rowKind := kindOf ci
let rowStr := s!"{where_}|{nm}|{rowKind}|{String.intercalate "," ((sortNames rowCone).map toString)}"
if where_ == "Proofs.Audit" then
drvRows := drvRows.push s!"DRV|{rowStr}"
else
invRows := invRows.push s!"INV|{rowStr}"
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
match ci with
| .axiomInfo _ =>
-- the five oracle axioms live in gen/ (Phase-0 pinned); an axiom
-- DECLARED inside an audited module is never acceptable.
errs := errs.push s!"AXIOM DECLARED in audited scope: {nm} ({where_})"
| _ =>
review round 4: bind the cert set, statements, and model bytes (F1/F2/F3) The third reviewer demonstrated that the round-2 in-Lean exact-cone audit, though sound for LISTED certs, left three fail-opens OUTSIDE the cone check — and made check.sh print ALL GREEN over a repo proving False. All closed; no theorem, proof, or fold changed (the 11 cones are unchanged). F1 — the audited SET was unbound. Audit.lean now (a) enumerates EVERY theorem defined in the eight certificate modules and requires each cone ⊆ boundary, so an un-manifested `theorem _ : False := cheat _` fails regardless of naming (this is the exact exploit the reviewer used); and (b) prints a MANIFEST fingerprint over the whole committed manifest, which check.sh binds to — so deleting/swapping a cert row fails outside Lean too. F2 — only cones were bound, not statements. Each cert now also carries the structural fingerprint (Expr.hash) of its elaborated type; a statement gutted to a tautology of the same cone changes the fingerprint and fails. F3 — the gen/ model bytes were unbound. New check.sh Phase 0 sha256-pins all four gen/SlhVerify/*.lean (incl. the two hand-maintained *External files, now hashed in PROVENANCE.json) BEFORE compiling; a hand-edited model fails first. F4/F5 — docs. README cone diagram now roots honestly at slh_verify_internal and states the pure/prehash domain-separator byte, the ctx>255 check, M' assembly, and deserialization are ABOVE the root and uncovered (new TRUSTED-BASE item 10). The false "rules out a wrong ADRS field" claim is corrected in README + ChainSpec (a transliteration makes the field visible, not excluded). check-selftest.sh: eight attacks, all rejected (dead file; extra axiom; dropped oracle; vanished cert; un-manifested False theorem; gutted statement; hand-edited model; deleted manifest row). Full transcript + green check.sh in verification/RECORDED-RUN.md. Standing limit unchanged and disclosed: an audit cannot defend against an author who edits the manifest AND check.sh AND the proofs together; the consumer defense is the pinned commit reviewed at the pin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 17:47:39 +00:00
let cone := (← collectAxioms nm).toList
let bad := cone.filter (fun a => !allowedBoundary.contains a)
unless bad.isEmpty do
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
errs := errs.push s!"UN-AUDITED declaration {nm} ({where_}) has disallowed axioms {bad}"
review round 4: bind the cert set, statements, and model bytes (F1/F2/F3) The third reviewer demonstrated that the round-2 in-Lean exact-cone audit, though sound for LISTED certs, left three fail-opens OUTSIDE the cone check — and made check.sh print ALL GREEN over a repo proving False. All closed; no theorem, proof, or fold changed (the 11 cones are unchanged). F1 — the audited SET was unbound. Audit.lean now (a) enumerates EVERY theorem defined in the eight certificate modules and requires each cone ⊆ boundary, so an un-manifested `theorem _ : False := cheat _` fails regardless of naming (this is the exact exploit the reviewer used); and (b) prints a MANIFEST fingerprint over the whole committed manifest, which check.sh binds to — so deleting/swapping a cert row fails outside Lean too. F2 — only cones were bound, not statements. Each cert now also carries the structural fingerprint (Expr.hash) of its elaborated type; a statement gutted to a tautology of the same cone changes the fingerprint and fails. F3 — the gen/ model bytes were unbound. New check.sh Phase 0 sha256-pins all four gen/SlhVerify/*.lean (incl. the two hand-maintained *External files, now hashed in PROVENANCE.json) BEFORE compiling; a hand-edited model fails first. F4/F5 — docs. README cone diagram now roots honestly at slh_verify_internal and states the pure/prehash domain-separator byte, the ctx>255 check, M' assembly, and deserialization are ABOVE the root and uncovered (new TRUSTED-BASE item 10). The false "rules out a wrong ADRS field" claim is corrected in README + ChainSpec (a transliteration makes the field visible, not excluded). check-selftest.sh: eight attacks, all rejected (dead file; extra axiom; dropped oracle; vanished cert; un-manifested False theorem; gutted statement; hand-edited model; deleted manifest row). Full transcript + green check.sh in verification/RECORDED-RUN.md. Standing limit unchanged and disclosed: an audit cannot defend against an author who edits the manifest AND check.sh AND the proofs together; the consumer defense is the pinned commit reviewed at the pin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 17:47:39 +00:00
for cert in manifestNames do
unless certsSeen.contains cert do
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
errs := errs.push s!"manifest cert {cert} not found in any certificate module"
review round 2: in-Lean exact-cone audit + reproducibility + doc honesty Addresses the round-2 reviewer punch-list. No theorem statement, proof term, or fold definition changed; the eleven cones are unchanged (independent collectAxioms dump in verification/RECORDED-RUN.md). AUDIT GATE (both reviewers, the critical one) - Retire the bash #print-axioms text parser (fail-open on empty/truncated reports, and only a SUBSET check). Replace with verification/Proofs/Audit.lean: reads each certificate's cone from the kernel via collectAxioms and asserts EXACT set equality against its expected boundary. Extra axiom, dropped oracle, renamed/deleted cert, or an axiom/opaque sham each throw -> non-zero Lean exit. No text to misparse; nothing fails open. check.sh Phase 3 now just compiles it (and still requires the explicit PASSED line). - check-selftest.sh rewritten to attack the new gate: dead-file, smuggled extra axiom (named), dropped-oracle (subset would pass, exact must not), and a vanished certificate (the collectAxioms-returns-[] trap). All four rejected. REPRODUCIBILITY (GPT B1.4 / B1.5) - extract.sh refuses a wrong-commit or dirty source tree (fail-closed), takes an optional source-path arg, and pins the source commit. - verification/PROVENANCE.json: single machine-readable pin set (source + charon + aeneas commits/channel + lean + ocaml) with generated-file sha256. - Re-running extract.sh reproduces gen/SlhVerify/{Types,Funs}.lean byte-identically (companion fips205-source commit adds Cargo.lock + rust-toolchain.toml; verified not to perturb the model). DOC HONESTY (both reviewers) - README: fix the self-contradiction (apex "not yet proven" trailer vs the proven apex), the false "oracles kept OUTSIDE every cone" (they are INSIDE, by design), "deployed monomorphic path" and "semantics-identical for every parameter set" overclaims, "only two lines changed", stale snapshot head; retitle the stale future-tense "what will be claimed" section. - TRUSTED-BASE: drop "nothing proven yet"; add base_2b-inner and deployment- bridge non-claims explicitly; current pin. - ChainSpec header: "deployed monomorphic path" -> private verify_mono facade (comment only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 17:13:55 +00:00
unless errs.isEmpty do
review round 4: bind the cert set, statements, and model bytes (F1/F2/F3) The third reviewer demonstrated that the round-2 in-Lean exact-cone audit, though sound for LISTED certs, left three fail-opens OUTSIDE the cone check — and made check.sh print ALL GREEN over a repo proving False. All closed; no theorem, proof, or fold changed (the 11 cones are unchanged). F1 — the audited SET was unbound. Audit.lean now (a) enumerates EVERY theorem defined in the eight certificate modules and requires each cone ⊆ boundary, so an un-manifested `theorem _ : False := cheat _` fails regardless of naming (this is the exact exploit the reviewer used); and (b) prints a MANIFEST fingerprint over the whole committed manifest, which check.sh binds to — so deleting/swapping a cert row fails outside Lean too. F2 — only cones were bound, not statements. Each cert now also carries the structural fingerprint (Expr.hash) of its elaborated type; a statement gutted to a tautology of the same cone changes the fingerprint and fails. F3 — the gen/ model bytes were unbound. New check.sh Phase 0 sha256-pins all four gen/SlhVerify/*.lean (incl. the two hand-maintained *External files, now hashed in PROVENANCE.json) BEFORE compiling; a hand-edited model fails first. F4/F5 — docs. README cone diagram now roots honestly at slh_verify_internal and states the pure/prehash domain-separator byte, the ctx>255 check, M' assembly, and deserialization are ABOVE the root and uncovered (new TRUSTED-BASE item 10). The false "rules out a wrong ADRS field" claim is corrected in README + ChainSpec (a transliteration makes the field visible, not excluded). check-selftest.sh: eight attacks, all rejected (dead file; extra axiom; dropped oracle; vanished cert; un-manifested False theorem; gutted statement; hand-edited model; deleted manifest row). Full transcript + green check.sh in verification/RECORDED-RUN.md. Standing limit unchanged and disclosed: an audit cannot defend against an author who edits the manifest AND check.sh AND the proofs together; the consumer defense is the pinned commit reviewed at the pin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 17:47:39 +00:00
throwError "AUDIT FAILED (fail-closed):\n{String.intercalate "\n" errs.toList}"
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
-- (3) CANONICAL BLOCK: policy + statements + specification bodies. check.sh
-- binds to the SHA-256 of everything between the markers.
let mut lines : Array String := #[]
lines := lines.push
s!"policy|allowedBoundary={String.intercalate "," ((sortNames allowedBoundary).map toString)}|certModules={String.intercalate "," ((sortNames certModules).map toString)}"
let mut specs : NameSet := {}
for (cert, cone, _) in manifest do
let ci := (env.find? cert).get!
specs := (closureOf env {} ci.type.getUsedConstants.toList).toList.foldl (·.insert ·) specs
lines := lines.push
s!"cert|{cert}|cone={String.intercalate "," ((sortNames cone).map toString)}|type={← ppAll ci.type}"
for nm in sortNames specs.toList do
match env.find? nm with
| none => errs := errs.push s!"specification constant vanished: {nm}"
| some ci =>
let isProp ← Command.liftCoreM <| Meta.MetaM.run' <| Meta.isProp ci.type
-- proof irrelevance: a Prop-valued constant contributes its STATEMENT;
-- a data definition contributes its BODY — that is where fidelity lives.
if isProp then
lines := lines.push s!"spec|{nm}|prop|type={← ppAll ci.type}"
else
match ci with
| .defnInfo v => lines := lines.push s!"spec|{nm}|def|value={← ppAll v.value}"
| _ => lines := lines.push s!"spec|{nm}|other|type={← ppAll ci.type}"
unless errs.isEmpty do
throwError "AUDIT FAILED (fail-closed):\n{String.intercalate "\n" errs.toList}"
logInfo ("AUDIT-MANIFEST-BEGIN\n" ++ String.intercalate "\n" lines.toList ++ "\nAUDIT-MANIFEST-END")
-- check.sh prints the certificate list it gets from HERE, not from a hand-kept
-- bash array (drill finding: the one authoritative claim string was the one
-- thing nothing bound — adding a name to it printed a cert that never existed).
Phase 3c: declaration coverage in both directions, and the accounting identity Completes the round-8 hardening of this repository. Round-8 review (Claude, register keys `drv-surface-no-cones` and `accounting-certifies-enumeration`). WHAT PHASE 3 DID NOT PIN. It proves each certificate's cone is exact and that no declaration in scope carries a disallowed axiom. It does not pin WHICH declarations exist: a new one that happens to be clean, and a silently vanished one, both pass it. inventory-allowlist.txt 265 rows — the audited corpus driver-allowlist.txt 35 rows — the audit INSTRUMENT's own surface both as INV|module|name|kind|CONE, diffed in BOTH directions by inventory_gate.sh, the same implementation the ed25519 repositories use, with a tag per surface. The instrument surface carries cones because the reviewer showed enumeration is not audit: a claim planted in an instrument is counted by an accounting identity and then examined by nothing, if its row carries no cone and no allowlist covers it. Here the instrument's 35 declarations are pinned exactly as the corpus's 265 are. INTERNAL NAMES ARE NO LONGER EXEMPT from the environment walk. They were skipped, which was harmless while nothing compared that walk against the kernel's view — and became a hole the moment something did: Phase 3b reads object files, which contain the compiler's auxiliaries. Exempting them would have left the accounting identity permanently short and forced the residual to be "explained" by a constant. That is the shape of the fudge term four-fork data refuted in the ed25519 repositories, and it is refused here before it can start. THE ACCOUNTING IDENTITY, as SET CONTAINMENT and never arithmetic: every constant the kernel holds must appear in one of the two walks. The kernel gate now emits KERNEL-NAME rows so the comparison names what is missing rather than reporting a count that has to be interpreted. kernel 300 = inventory 265 + instrument 35 residual: none Negative-tested, all three rejected by name and the tree restored to green: · a deleted INV row -> UNCLASSIFIED: INV|Proofs.ApexSpec|List.allM.eq_1|theorem| · a deleted DRV row -> UNCLASSIFIED: DRV|Proofs.Audit|SlhVerify.Audit.sortNames|def · a row with no declaration behind it -> STALE: …|fips205.ghost_that_does_not_exist|… Both allowlists join the pinned harness set: not executable, so the executable-bit rule cannot reach them, and an allowlist an attacker may rewrite pins nothing. fips205-slhdsa-verified now has the ed25519 repositories' gate set: 0 hygiene, 0d correspondence, 1 model, 2 proofs, 3 in-Lean audit, 3b kernel-side axiom gate, 3c coverage + accounting. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 15:34:00 +00:00
-- The two walks, emitted for check.sh to diff against committed allowlists in
-- BOTH directions. A trailer per walk, so a truncated or crashed emission can
-- never pass as an empty diff.
for r in invRows.qsort (· < ·) do IO.println r
IO.println s!"INV-COUNT|{invRows.size}"
for r in drvRows.qsort (· < ·) do IO.println r
IO.println s!"DRV-COUNT|{drvRows.size}"
review round 5: bind the policy, the specification bodies, and the harness The third reviewer demonstrated that the round-4 gate was closed at the EXPLOITS, not the MECHANISMS: it bound the manifest rows while the things he moved sat outside the binding. Three fail-opens, each executed end-to-end with the button printing ALL GREEN. No theorem, proof, fold, or model body changed. NEW-1 — the policy constant was unbound. `manifestFingerprint` covered `manifest` but never `allowedBoundary`, the sole predicate the enumeration tests against; adding one name re-opened the False-proof with the committed fingerprint BYTE-IDENTICAL. NEW-2 — the specification bodies were unbound. The statement fingerprint pinned each certificate's TYPE, which names its reference fold; redefining that fold to *be* the extracted loop left cone and type-hash identical while the certificate degenerated to `loop = loop`. 100% of the fidelity content lives in those defs. NEW-3 — the harness was unbound. Stubbing verification/lean-guard alone, without touching check.sh or the proofs, gave ALL GREEN in 3.6s over destroyed proofs. FIX — one mechanism rather than three patches. Audit.lean now emits a canonical AUDIT-MANIFEST block and check.sh binds to its SHA-256. The block covers the POLICY constants, every certificate's fully-elaborated statement, and every specification constant transitively reachable from those statements with its fully-elaborated BODY (41 constants; the closure is computed, so a new fold cannot appear without moving the digest; Prop-valued constants contribute their statement, by proof irrelevance). This also retires the 32-bit Expr.hash as the binding (NEW-5) — it survives only as a per-certificate diagnostic. Enumeration now covers EVERY declaration kind (a `def : False` passed before) in the eight certificate modules AND in Audit.lean itself — the auditor is no longer exempt (round-5 R1). A bare `axiom` in audited scope is now an error. Phase 0 purges stale .olean (the verdict must depend on committed bytes, not .gitignored build state — NEW-4), forbids any .lean outside gen/ and Proofs/, and sha256-pins the four model files AND lean-guard. lean-guard is KEPT rather than removed (the reviewer's portability advice is declined by operator decision): it is the memory cap and machine-wide lock that protect the build machine after a 12.2GB OOM took the host down. That trade-off is documented. check.sh's "Certificates proven:" line now comes from the audited manifest; the hand-kept CERTS array — the one authoritative claim string nothing bound — is deleted. check-selftest.sh: 14 attacks, all rejected, plus a check that the hashed block literally carries the twelve fold bodies. Attacks 9-14 are the reviewers' and an independent drill's own exploits, turned into regression tests. DOCS. TRUSTED-BASE gains item 11 (the REAL trusted computing base — lean-guard pinned; check.sh, the toolchain env, $AENEAS_HOME, python3 and Lean still trusted) and item 12 (the apex does not compose the ten). README: the audit description rewritten; the XMSS sibling-order claim downgraded from "pins" to "makes visible", with a new blanket non-claim covering all ten loop certificates; the de-plumbing file claim corrected (round 1 touched only verify_mono.rs, round 2 only helpers.rs — which is ON the deployed verify AND sign paths, now disclosed; wots.rs was never patched). RECORDED-RUN: three lines that stood inside a fence were a hand-written summary, not console output — fabricated evidence in the file whose purpose is machine evidence. They are removed and the fabrication is named in place, together with the correction that the "INDEPENDENT RUN" block predates this gate. New rule: nothing goes in a fence unless captured with tee/cat, and every block states its date, pin, and who ran it. The transcripts added here follow it. Also disclosed rather than buried: three bugs in my own test harness this round (an olean-purge build-order break, an attack rejected by the wrong rule, and a coverage assertion looking on the wrong line) — each would have let an attack pass or fail for an unrelated reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 20:57:46 +00:00
logInfo s!"CERTIFICATES: {String.intercalate " " (manifestNames.map toString)}"
logInfo s!"exact-cone audit PASSED: {manifest.length} certificates (cones + statements), {specs.toList.length} specification constants pinned, {nEnum} declarations enumerated clean"
review round 2: in-Lean exact-cone audit + reproducibility + doc honesty Addresses the round-2 reviewer punch-list. No theorem statement, proof term, or fold definition changed; the eleven cones are unchanged (independent collectAxioms dump in verification/RECORDED-RUN.md). AUDIT GATE (both reviewers, the critical one) - Retire the bash #print-axioms text parser (fail-open on empty/truncated reports, and only a SUBSET check). Replace with verification/Proofs/Audit.lean: reads each certificate's cone from the kernel via collectAxioms and asserts EXACT set equality against its expected boundary. Extra axiom, dropped oracle, renamed/deleted cert, or an axiom/opaque sham each throw -> non-zero Lean exit. No text to misparse; nothing fails open. check.sh Phase 3 now just compiles it (and still requires the explicit PASSED line). - check-selftest.sh rewritten to attack the new gate: dead-file, smuggled extra axiom (named), dropped-oracle (subset would pass, exact must not), and a vanished certificate (the collectAxioms-returns-[] trap). All four rejected. REPRODUCIBILITY (GPT B1.4 / B1.5) - extract.sh refuses a wrong-commit or dirty source tree (fail-closed), takes an optional source-path arg, and pins the source commit. - verification/PROVENANCE.json: single machine-readable pin set (source + charon + aeneas commits/channel + lean + ocaml) with generated-file sha256. - Re-running extract.sh reproduces gen/SlhVerify/{Types,Funs}.lean byte-identically (companion fips205-source commit adds Cargo.lock + rust-toolchain.toml; verified not to perturb the model). DOC HONESTY (both reviewers) - README: fix the self-contradiction (apex "not yet proven" trailer vs the proven apex), the false "oracles kept OUTSIDE every cone" (they are INSIDE, by design), "deployed monomorphic path" and "semantics-identical for every parameter set" overclaims, "only two lines changed", stale snapshot head; retitle the stale future-tense "what will be claimed" section. - TRUSTED-BASE: drop "nothing proven yet"; add base_2b-inner and deployment- bridge non-claims explicitly; current pin. - ChainSpec header: "deployed monomorphic path" -> private verify_mono facade (comment only). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 17:13:55 +00:00
end SlhVerify.Audit
open SlhVerify.Audit in
auditCones