diff --git a/paper/check-paper.sh b/paper/check-paper.sh index 755fd94..4624af8 100755 --- a/paper/check-paper.sh +++ b/paper/check-paper.sh @@ -69,6 +69,14 @@ VERSION=$(grep -oP '\\date\{[^}]*---\s*\Kv[0-9.]+' ltl.tex || true) pdftotext -f 1 -l 1 ltl.pdf - | grep -q "$VERSION" || fail "title page does not carry $VERSION" ! pdftotext ltl.pdf - | grep -q '??' || fail "unresolved ?? reference in PDF" +# --- 5b. site claim binding: the webdocs paper card's page count --------- +WEBDOCS=../provider/src/pacta_provider/webdocs.py +if [[ -f "$WEBDOCS" ]]; then + STATED=$(grep -oP '\(PDF, \K[0-9]+(?= pages)' "$WEBDOCS" || true) + [[ -n "$STATED" ]] || fail "webdocs paper card lost its '(PDF, N pages' claim" + [[ "$STATED" -eq "$NPAGES" ]] || fail "webdocs says $STATED pages, PDF has $NPAGES" +fi + # --- 6. render for the mandatory eye pass -------------------------------- rm -rf "$PAGES_DIR"; mkdir -p "$PAGES_DIR" pdftoppm -png -r 110 ltl.pdf "$PAGES_DIR/p" diff --git a/paper/ltl.pdf b/paper/ltl.pdf index 1935968..6921d7d 100644 Binary files a/paper/ltl.pdf and b/paper/ltl.pdf differ diff --git a/provider/src/pacta_provider/webdocs.py b/provider/src/pacta_provider/webdocs.py index 394028e..f7a6080 100644 --- a/provider/src/pacta_provider/webdocs.py +++ b/provider/src/pacta_provider/webdocs.py @@ -138,16 +138,16 @@ proof subject of leaf 18.
slh_block = "" return f"""This key is the sole cryptographic identity anchor: it -authenticates that these statements were made by the operator. It does not, by itself, make +authenticates that these statements were made by the operator (the same party the artifacts call “the provider”). It does not, by itself, make those statements true — each attestation's truth additionally rests on the replay, theorem, -extraction and toolchain assumptions stated in that leaf. Every tree head and attestation is +extraction and toolchain assumptions stated in that leaf (one signed entry of the tree below). Every tree head and attestation is signature-checked against this key. -Pin it, and compare this copy byte-for-byte with the independently hosted -mirror copy; they must be identical.
+Pin it (save your own copy; from then on trust only what checks against that copy), and compare this copy byte-for-byte with the independently hosted +mirror copy; they must be identical. The first fetch is trust-on-first-use; the two-host byte-comparison is what bounds it.{pem}
SHA-256 fingerprint {escape(fingerprint)}
· raw: {base or ''}/log-public-key
- · curl -s ltl.zkdefi.org/log-public-key
curl -s https://ltl.zkdefi.org/log-public-key
{slh_block}One sentence: a public, append-only Merkle -accumulator of signed statements that the Lean 4 formal proofs of specific -cryptographic Rust libraries, at specific git commits, machine-re-check with exactly +accumulator (a hash tree that only ever grows) of signed statements that the Lean 4 formal proofs of specific +cryptographic Rust libraries, at specific git commits, re-check by machine with exactly their documented assumptions — so that you can trust a proof result by checking -one required signature (Ed25519; heads from tree 14 add an additive post-quantum -SLH-DSA signature) and ~{max(1,(latest.get('tree_size') or 1).bit_length())} hashes in +one required signature (Ed25519) and ~{max(1,(latest.get('tree_size') or 1).bit_length())} hashes in milliseconds, instead of running a theorem prover for hours.
verified attestation (all certificates proven, axiom cones boundary-exact) -historical audit-failure attestation — kept forever; an append-only ledger does not erase its bad day +historical audit-failure attestation — kept forever; an append-only ledger does not erase its bad day (leaves 0–3: an early audit round that failed; leaves 4–7 re-attest the same four libraries cleanly)
Every box above is computed from the live log at page render — leaf hashes, -internal nodes, the root, and the signature are the real ones. Before signing this +internal nodes, the root, and the signature are the real ones. The code that signs the log is itself an entry in the log — and checks its own entry before signing. In detail: before signing this root, the provider Merkle-verified its own signing library's leaf (index {provenance.get('signing_library_leaf_index','?')}, certificates {escape(str(provenance.get('signing_library_certificates_proven','?')))}) @@ -237,12 +236,12 @@ identical.
<library>.attestation.jsonentries/entries/<library>.receipt.jsonopenssl binary).receipts/verify.py wraps that core with full fail-closed binding checks (stdlib hashing; signature checks shell out to the openssl binary).
+receipts/verify.py (Python stdlib + the openssl binary for
@@ -257,17 +256,19 @@ consumers.)| component | artifact 2 | artifact 3 | status |
|---|
One certificate = one machine-checked theorem together with its exact assumption set (its axiom cone).
+pacta receipt-verify --attestation … --receipt … --log-public-key provider.ed25519.pub
---sth-store pins.json for split-view defense.git clone {mirror} && python3 verify.py --all
-pacta CLI ships in the pacta repository (pip install . from a clone). Add --sth-store pins.json to remember every Signed Tree Head (STH) you accept — your defense against a split view (the operator showing different histories to different consumers).git clone {mirror} && cd lean-transparency-log && python3 verify.py --all
+openssl binary (signature checks fail closed without it). You become a witness of the whole history.--require-verified-verifier).attestation.json. Honesty about the boundary is the product.
sth-history.jsonl. Everything
-since is additive: the four Ed25519 corpora re-attested at 44 certificates each
-(leaves 13–16), the accumulator's hardened model (leaf 17), the first post-quantum
-subject (leaf 18), and dual-signed heads from tree 14 on.
-python3 verify.py --all re-verifies the paper-era prefix together with everything
-after it.python3 verify.py --all
+re-verifies all of it, paper-era and after, from a clone of the mirror.Log heads are signed offline; this service is read-only and holds no key material. Provider tooling, agent tooling, and the full Jupyter course live in the pacta repository.
diff --git a/tests/test_web_and_witness.py b/tests/test_web_and_witness.py index 30995e4..27870a5 100644 --- a/tests/test_web_and_witness.py +++ b/tests/test_web_and_witness.py @@ -159,3 +159,25 @@ def test_standalone_verify_py_runs(tmp_path): assert result.returncode == 0, result.stdout + result.stderr # hardened verifier: full mode (signatures verified) must report exactly this assert "RESULT: OK [full]" in result.stdout + + +def test_webdocs_source_carries_no_stale_paper_claims(): + # Regression for the 2026-08-16 operator finding: the paper card said + # "23 pages" and the July-snapshot card survived a silently failed + # replace (an invisible NBSP defeated the pattern). Guard the shipped + # STRINGS, not just version markers. + from pathlib import Path + + source = Path(__file__).resolve().parents[1] / "provider" / "src" / "pacta_provider" / "webdocs.py" + text = source.read_text(encoding="utf-8") + for stale in ("snapshot", "thirteen leaves", "16 July", "16 July", + "16\xa0July", "v0.9", "v0.10", "23 pages"): + assert stale not in text, f"stale marker {stale!r} in webdocs" + # printed commands must work as printed: curl needs the scheme + # (http->https redirect yields empty output), the clone one-liner + # needs the cd into the cloned directory + assert "curl -s ltl.zkdefi.org" not in text + assert "cd lean-transparency-log" in text + # first-use glosses the page promised: STH and axiom cones + assert "Signed Tree Head (STH)" in text + assert "axiom cones (the exact set of assumptions" in text