llbc: commit the artifact the claim depended on, and verify the pin block

Round-9 review (GPT-5.6, R9-F2, BLOCKER). TRUSTED-BASE said:

    "The .llbc is committed, so the SECOND step can be re-run by anyone with
     the pinned Aeneas and this repository"

.gitignore excluded it. `git ls-files` had no LLBC. The file existed only on
the author's disk. I ran `ls`, saw it, and wrote the claim without running
`git ls-files` — so a sentence that reads as an independent-reproducibility
guarantee was true for exactly one person. The experiment itself was real:
re-running Aeneas on that LLBC did reproduce Types.lean and Funs.lean
byte-identically. What was false is that anyone else could repeat it.

CHASING IT FOUND WORSE. `generated_artifacts_sha256` was read by NOTHING —
check.sh had zero references to it. Its Types.lean and Funs.lean entries
matched only because those files are ALSO pinned in model_integrity_sha256,
which is checked. The .llbc entry, the one nothing else covered, had been
stale since review round 2 (522d8b2): the source was re-extracted on
2026-07-28, the model files and their pins were updated, and this pin was not.
It named d8ec0b00…, an artifact that did NOT produce the committed model. The
file that did is 69666ddc… — timestamped nine seconds before Types.lean and
Funs.lean, and demonstrably regenerating them byte-for-byte.

A pin nothing verifies drifts, and nobody notices. That is the finding, and it
is a sharper instance of the pattern than the one the reviewer reported.

  · .gitignore no longer excludes SlhVerify.llbc; it is committed (1.6 MB)
  · its pin corrected to the artifact that actually produced the model
  · check.sh Phase 0 now verifies generated_artifacts_sha256, so the block
    stops being decorative. Negative-tested: one appended byte gives
    `✗ SlhVerify.llbc: sha256 dd5925770bc7 ≠ pinned 69666ddc43a4`, exit 1
  · TRUSTED-BASE item 3 rewritten. It now says what committing the LLBC does
    and does NOT buy: the Lean model is the faithful Aeneas image of THAT
    intermediate, and whether the intermediate is the faithful Charon image of
    fips205-source@a3ce8e8 rests on the author alone. Verifying the committed
    LLBC against itself establishes nothing about Charon.
    "Do not read the second half as evidence for the first."
  · README qualified AT THE CLAIM SITE, not via a later link

Button green after every edit; accounting still closes at 300 with no residual.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
mrwulf 2026-08-03 20:36:19 +02:00
parent 851e976450
commit 1b430dfd68
6 changed files with 44 additions and 11 deletions

5
.gitignore vendored
View file

@ -4,4 +4,7 @@ target/
# *_Template.lean is NO LONGER ignored: it is Aeneas's own statement of what # *_Template.lean is NO LONGER ignored: it is Aeneas's own statement of what
# the extraction needs from outside, and it is the only artifact against which # the extraction needs from outside, and it is the only artifact against which
# "does the model ANSWER the extraction" can be asked. Committed and pinned. # "does the model ANSWER the extraction" can be asked. Committed and pinned.
SlhVerify.llbc # SlhVerify.llbc is NO LONGER ignored. It is the intermediate Charon produces
# and Aeneas consumes, and committing it is what makes the LLBC->Lean half of
# extraction independently re-runnable. Round-9 review (GPT-5.6) found
# TRUSTED-BASE claiming it was committed while .gitignore excluded it.

View file

@ -360,7 +360,10 @@ gracefully**: when `systemd-run` is unavailable it falls back to Lean's own
`-M` cap, so the button runs on a stock Linux box without cgroup support — an `-M` cap, so the button runs on a stock Linux box without cgroup support — an
external reviewer has run it green that way. Note also that the *empirical external reviewer has run it green that way. Note also that the *empirical
bridge* (`cargo test` in the snapshot repo) needs no Lean toolchain at all and bridge* (`cargo test` in the snapshot repo) needs no Lean toolchain at all and
runs on stable Rust. Extraction is reproducible: the runs on stable Rust. Extraction is reproducible **in its second stage only**
(see TRUSTED-BASE item 3: the committed `.llbc` lets anyone re-run Aeneas and
reproduce the model byte-identically; re-running Charon against the Rust
requires charon and has never been done by anyone but the author): the
full pin set (source commit, Charon/Aeneas commits + toolchain channel, Lean full pin set (source commit, Charon/Aeneas commits + toolchain channel, Lean
and OCaml versions) is in [verification/PROVENANCE.json](verification/PROVENANCE.json); and OCaml versions) is in [verification/PROVENANCE.json](verification/PROVENANCE.json);
`verification/extract.sh` refuses to run against a wrong-commit or dirty `verification/extract.sh` refuses to run against a wrong-commit or dirty

View file

@ -22,14 +22,30 @@ proceeds and is part of every claim.
model is trusted base. model is trusted base.
**What is now reproducible, and what is not.** Extraction is two steps: **What is now reproducible, and what is not.** Extraction is two steps:
`Rust --charon--> SlhVerify.llbc --aeneas--> gen/SlhVerify/*.lean`. The `Rust --charon--> SlhVerify.llbc --aeneas--> gen/SlhVerify/*.lean`.
`.llbc` is committed, so the SECOND step can be re-run by anyone with the
pinned Aeneas and this repository, and on 2026-08-03 doing so reproduced The `.llbc` is committed **as of 2026-08-03** and byte-pinned in
`Types.lean` and `Funs.lean` **byte-identically**. The FIRST step still `generated_artifacts_sha256`, which `check.sh` Phase 0 now verifies. So the
requires charon, which no reviewer has yet had available. So: the SECOND step can be re-run by anyone with the pinned Aeneas and this
LLBC → Lean half is reproducible on demand; the Rust → LLBC half rests on repository, and doing so reproduces `Types.lean` and `Funs.lean`
the author's attestation alone, and continues to do so until a third party byte-identically.
runs it. Do not read the first half as evidence for the second.
THE FIRST STEP CANNOT BE. It requires charon, which no reviewer has yet had
available, and this repository ships no charon output anyone can check
against — the committed `.llbc` IS that output, so verifying it against
itself establishes nothing. What the committed `.llbc` gives a reader is
this and only this: the Lean model in `gen/` is the faithful Aeneas image of
THAT intermediate. Whether that intermediate is the faithful Charon image of
`fips205-source@a3ce8e8` rests on the author's attestation alone, and
continues to do so until a third party runs Charon. **Do not read the second
half as evidence for the first.**
This paragraph previously said the `.llbc` was committed while `.gitignore`
excluded it — round-9 review (GPT-5.6) — so the claim was false for every
reader and true only on the author's disk. Chasing it found the larger
defect: `generated_artifacts_sha256` was read by nothing, and its `.llbc`
entry had been stale since review round 2, naming an artifact that did not
produce the committed model.
3b. **The correspondence check is textual, not a Lean query.** Phase 0d parses 3b. **The correspondence check is textual, not a Lean query.** Phase 0d parses
`FunsExternal_Template.lean` and the hand-written model as SOURCE TEXT. It `FunsExternal_Template.lean` and the hand-written model as SOURCE TEXT. It

View file

@ -28,7 +28,7 @@
"aeneas": "aeneas -backend lean -split-files -subdir SlhVerify -dest gen SlhVerify.llbc" "aeneas": "aeneas -backend lean -split-files -subdir SlhVerify -dest gen SlhVerify.llbc"
}, },
"generated_artifacts_sha256": { "generated_artifacts_sha256": {
"SlhVerify.llbc": "d8ec0b00593eee1778bc4cc0cc1801fb6415bb294425f01384434849c6443f58", "SlhVerify.llbc": "69666ddc43a4d5e02ca8eaa64eb740f8849eac64e0cd9df76506ab4f68f2af55",
"gen/SlhVerify/Types.lean": "db720b4a30f512e6048212a472e6853b24931a8121cb94c4cf7e6489754d6384", "gen/SlhVerify/Types.lean": "db720b4a30f512e6048212a472e6853b24931a8121cb94c4cf7e6489754d6384",
"gen/SlhVerify/Funs.lean": "7b7de55fd0206142f2678a079a6ed4462292356bc7de08ecd55cac0c76a1da9f" "gen/SlhVerify/Funs.lean": "7b7de55fd0206142f2678a079a6ed4462292356bc7de08ecd55cac0c76a1da9f"
}, },

File diff suppressed because one or more lines are too long

View file

@ -110,6 +110,16 @@ import json, sys, hashlib, os
prov = json.load(open(sys.argv[1])); here = sys.argv[2] prov = json.load(open(sys.argv[1])); here = sys.argv[2]
files = {k: v for k, v in prov.get("model_integrity_sha256", {}).items() if not k.startswith("_")} files = {k: v for k, v in prov.get("model_integrity_sha256", {}).items() if not k.startswith("_")}
files.update({k: v for k, v in prov.get("harness_integrity_sha256", {}).items() if not k.startswith("_")}) files.update({k: v for k, v in prov.get("harness_integrity_sha256", {}).items() if not k.startswith("_")})
# generated_artifacts_sha256 WAS NEVER READ BY THIS SCRIPT. Round-9 review
# (GPT-5.6) found TRUSTED-BASE claiming the LLBC was committed while
# .gitignore excluded it; chasing that turned up the larger defect: this whole
# pin block was decorative. Its Types.lean/Funs.lean entries matched only
# because those files are ALSO pinned in model_integrity_sha256, which is
# checked. The LLBC entry — the one nothing else covered — had been stale since
# review round 2 (522d8b2): the source was re-extracted, the model files and
# their pins were updated, and this pin was not. A pin nothing verifies drifts,
# and nobody notices. It is verified here now.
files.update({k: v for k, v in prov.get("generated_artifacts_sha256", {}).items() if not k.startswith("_")})
if not files: if not files:
print(" no integrity map in PROVENANCE.json (fail-closed)"); sys.exit(1) print(" no integrity map in PROVENANCE.json (fail-closed)"); sys.exit(1)
bad = 0 bad = 0