Commit graph

66 commits

Author SHA1 Message Date
920485eb83 web: unlisted operator-dropped documents from <log>/site/
Generic mechanism: bare-name PDFs placed in the log directory's site/
folder are served by name, checked LAST in the route chain (can never
shadow an API route), traversal-safe, noindex, and deliberately absent
from the endpoint index and the docs page - the operator decides who
receives a link. Tested: serve, unlisted-in-404, traversal rejected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 14:17:39 +02:00
3aa8d4b2bf LTL front page: display the trust anchor in full, above the fold
The provider public key is the one thing a consumer takes on trust;
hiding it behind /log-public-key inverted the page's priorities. New
'The trust anchor - pin this key' section at the top of the docs page
shows the PEM in full with its SHA-256 fingerprint, the mirror-compare
instruction, and the raw endpoint for scripts. Honest 'missing' card if
a deployment lacks the key. Test asserts the page renders the key.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 09:45:35 +02:00
be9a39cd2b paper rigor pass: fix three claims that failed verification; serve the trust anchor
Socratic audit findings, all verified against artifacts:
- 'zero lines between structurally identical forks' was FALSE: risc0 vs
  betrusted differ by 27 lines (all annotation, documenting the risc0
  fork's black_box trusted-base entry). Corrected to the true number.
- '~64 Lean files per fork' over-rounded anza's 58. Now '58-64'.
- completeness parenthetical now states both hypotheses (a=-1 square, d
  non-square), not just d.
- 'key published in two independent locations' was ASPIRATIONAL: the
  site served only a fingerprint. New /log-public-key endpoint serves
  the key bytes; docs-page artifact-1 row links both copies; test added.
Verified exactly and kept: 215-line parser diff (FromBytesSpec), 121-line
signature-glue diff (SigApexSpec), byte-identical x4 math files incl. the
carry-telescope file, 11-axiom upstream boundary, 16 certs/leaf, 153-line
mirror verifier, leaf fields (toolchain + machine_protection), all 17 refs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 09:28:55 +02:00
8aa228d2fe paper: retitle + author block per publication decision
- Title: 'LTL: Lean Transparency Log'; subtitle now 'Distributing
  Machine-Checked Proof Evidence through a Recursively Self-Certifying
  Merkle Log' (the log carries the certificates of the code that signs
  the log - recursion named, marketing dropped)
- Author: Olaf Horvath, contact Olaf.Horvath@zkdefi.org, single URL
  ltl.zkdefi.org (redundant zkdefi.org line removed)
- PDF rebuilt (4 pages), page 1 visually inspected
- title echoes updated: llms.txt, LTL docs-page paper card

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 08:45:49 +02:00
231d5dfafa LTL docs: site-wide nav (notes / code / cv) in the header line
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:05:05 +02:00
9acb078844 Serve the paper at /paper; witness mirror must be independently operated
- web.py: /paper (and /paper/ltl.pdf) serve the committed PDF, loaded
  once at startup from the repo checkout; listed in the 404 endpoint
  index; covered by the web roundtrip test
- docs page: 'The paper' card linking the PDF
- DEPLOY.md: the second witness mirror belongs on a host the operator
  does NOT control (a self-hosted mirror adds no equivocation defense)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:44:06 +02:00
47dfb61a7f Move the log service to ltl.zkdefi.org (root path); keep path-mount support
- serve/webdocs/cli default to base_path='' (own subdomain, root serving)
- webdocs link builder handles the empty base like web.py already did
- all docs, paper, notebook 06b, and published-mirror README point at
  https://ltl.zkdefi.org; DEPLOY.md rewritten for subdomain + redirect
- tests: root mount is the production shape; one test keeps exercising
  the path-mounted variant

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:14:52 +02:00
a651a3b58c The LTL website: the accumulator drawn live, artifacts named unambiguously
The /docs route is now a real landing site (still one self-contained
HTML, inline CSS + inline SVG, zero external assets):

- One-sentence definition up top: what the LTL is and the cost
  asymmetry it exists for (one signature + a few hashes in
  milliseconds vs hours of theorem proving).
- THE GRAPHIC: the accumulator itself, rendered server-side from the
  LIVE log at page load - real leaf hashes, real internal nodes, the
  real root and signature. Green leaves are boundary-exact verified
  attestations; grey leaves are the historical audit-failure entries,
  labeled "kept forever - an append-only ledger does not erase its bad
  day". The signature box names the dogfood backend and the provider's
  self-inclusion check (the signature vouches for the code; the tree
  vouches for the signature's code).
- "What do I download?" - exactly three artifacts, numbered, each with
  what-it-is and where: (1) provider.ed25519.pub, the sole trust
  anchor, cross-checkable between this site and the GitHub mirror;
  (2) the attestation = the claim; (3) the receipt = the proof of
  inclusion. Plus the maximal-benefit path: clone the mirror, run
  verify.py --all, become a witness.
- Three usage lanes (quick check / zero-install audit / autonomous
  agent), the API, and the means / does-NOT-mean cards.

Rendered against the real 8-leaf log and content-asserted in tests'
presence. 54/54 green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 16:38:37 +02:00
9092f032e0 Public-exposure self-audit: genericize DEPLOY.md, scrub provider paths
Socratic pass over everything this public repo reveals, adversary-first:

- DEPLOY.md no longer names the hosting provider or the server's other
  software inventory (that sentence was NEW public information - the
  site's front page does not advertise it). It now states its own
  redaction policy up front, leads with a Caddy proxy config (matching
  what the target site actually fronts with), adds rate-limiting and
  proxy timeouts for the stdlib backend, generalizes the second-mirror
  section, and gains an explicit key-hygiene section (the signing key
  never touches the public server; a compromised box has nothing to
  rotate).
- Future attestations stop leaking provider-machine paths: the
  machine_protection guard path is recorded repo-relative and the Lean
  project dir is recorded in its configured env-var form, never
  machine-resolved. (The 12 already-published leaves containing local
  home paths are immutable by design - severity assessed low: a local
  username on a non-addressable dev box, no credentials - and an
  append-only log does not rewrite its history.)

Audited clean: no keys, tokens, or credential-named files anywhere in
git history; no public IPs; loopback-only binds; commit identity is the
owner's long-standing public one. 54/54 tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 16:16:10 +02:00
fbe40c3dfe The log goes public: git-published mirror, online service, witnesses
Three synchronized faces of one log - transport orthogonal to trust:

- PUBLISHED GIT MIRROR: log-publish exports the public face (one file
  per leaf so git history mirrors log history; the FULL STH history as
  the witness channel; per-component attestations + receipts; the
  provider public key; a standalone stdlib-only verify.py and customer
  README). Live at github.com/saymrwulf/lean-transparency-log (genesis:
  8 leaves incl. the honest failed-run entries, dogfood-signed head).
- ONLINE SERVICE (pacta_provider serve): read-only, zero-dependency
  HTTP with CT-style endpoints under a base path for
  zkdefi.org/lean-transparency-log - /v1/sth, /v1/sth-history,
  /v1/sth-consistency?first=N, /v1/proof, /v1/attestation, /v1/entries,
  /v1/metadata, /healthz - plus self-contained customer documentation
  at /docs (current state, attested components, API, the verify-
  without-trusting-this-site path, and the means/does-NOT-mean
  boundary). The process never loads private keys: heads are signed
  offline; a compromised server can withhold or replay (pinning +
  freshness detect both) but never forge. STH history now recorded
  append-only by the provider (with a backfill head signed for the
  existing log).
- AGENT ONLINE CLIENT: pacta log-fetch (download evidence; explicitly
  UNVERIFIED until receipt-verify runs - transport is not trust) and
  pacta sth-refresh (fetch head, verify signature, advance the pin via
  an online consistency proof from the pinned size; fail closed).
- WITNESSES: pacta witness-audit over a clone of the published mirror
  recomputes every prefix root from the public leaves and checks every
  historical head + signature - no consistency proofs needed when the
  leaves are public. Tampering one published entry trips both the
  leaf-hash check and the prefix-root check (tested). verify.py gives
  customers the same audit with zero installation.
- DEPLOY.md: the complete server-session checklist for zkdefi.org -
  reconstruct the servable log FROM the published mirror (the server
  stays in witness trust-position), hardened systemd unit, nginx/Caddy
  path routing, Forgejo mirror setup, the provider->world update
  cycle, and remote smoke tests.

Validated end-to-end on the REAL log: all 10 endpoints, online-fetched
proof re-verified locally through the dogfood verifier with pinning,
online pin refresh, publish + witness audit green, tamper caught,
standalone verify.py green in the published clone. 54/54 tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 16:05:20 +02:00
b8ffbafa7f The provider eats its own dogfood: root signatures via the merkleized library
The dogfood principle now runs in BOTH directions. Agents already
verified signatures through the proven dalek path; now the provider
SIGNS with it too, and proves to itself that the signing code is in its
own log before every signature:

- dogfood binary gains a `sign` mode (seed over stdin, never argv;
  ed25519_dalek::SigningKey from the same pinned merkleized workspace).
  Honesty ledger unchanged: the library's VERIFY path is
  certificate-covered; its signing path is declared trusted base - but
  it is the ATTESTED artifact, not an un-attested third implementation.
- sign_payload_ed25519_detailed: signing dispatch mirroring the verify
  dispatch; the backend that actually signed is recorded in every
  attestation signature block and STH.
- THE SELF-REFERENTIAL CHECK: before signing any tree head, the
  provider runs the SAME Merkle inclusion verification an agent runs -
  against the very tree it is about to sign - for the newest leaf
  attesting the signing library itself, and embeds the result in the
  signature block:
    signing_provenance:
      signing_backend: verified-dalek-serial
      signing_library_component: dalek-ed25519-verified
      signing_library_source_commit: aa0f6ab...
      self_inclusion: verified
      signing_library_leaf_index: 4
      signing_library_certificates_proven: 16/16
  A root signature that names the leaf vouching for the code that
  produced it. First-append chicken-and-egg is handled honestly
  (self_inclusion: library_not_in_log).
- Evidence refreshed: all four receipts re-issued under dogfood-signed
  STHs; the full agent verify loop re-run green.

50/50 tests (new signing roundtrip test, skip-safe where unbuilt).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 15:21:17 +02:00
5b0158ecef Machine protection: route all pacta Lean compiles through lean-guard
pacta's replay invoked `lake env lean` bare - on the reference machine
that is exactly the pattern that once OOM-crashed the host (see the
corpus' POSTMORTEM). New RepoConfig.lean_guard (set for all five repos
in examples/repos.yaml: verification/lean-guard): when configured,
every compile and axiom audit runs `lake env <guard> <file> --root=...`
instead of bare lean - hard memory cap via systemd scope + lean -M,
core pinning, timeout, single-flight lock, free-RAM preflight with the
Guard-3a retry ladder, all tuned via LEAN_MEM_MB / LEAN_MIN_FREE_MB /
LEAN_MEM_WAIT_SEC / LEAN_TIMEOUT / LEAN_MAX_CORES. Provider
attestations now record a machine_protection block naming the guard
(or "UNGUARDED"). Smoke-tested live on the real dalek repo: clamping
trace visible, compile green. 49/49 tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 10:42:59 +02:00
7c717d03fc Log accountability: STH pinning, consistency enforcement, freshness, monitor
A transparency log without split-view defense is just a signature with
extra steps: the provider could serve one tree to the agent and another
to the world, or roll the log back, and standalone receipt verification
would never notice. The primitives (RFC 9162 consistency proofs) were
already implemented and correct; this closes the loop on the AGENT side.

- src/pacta/sthstore.py: a local STH pin store. Unknown log -> pin
  (trust-on-first-use, recorded as such). Same tree size -> the root
  must match the pin byte-for-byte; a mismatch is named EQUIVOCATION
  and is a hard rejection. Larger tree -> a consistency proof FROM THE
  PINNED SIZE is required and verified before the pin advances
  (receipts already embed a from-previous anchor; the anchor's root is
  itself checked against the pin so a lying anchor cannot bridge a
  split view). Smaller tree -> LOG ROLLBACK, hard rejection.
- Freshness policy: --max-sth-age-seconds rejects stale (or
  future-dated) tree heads - an old-but-valid STH can hide later
  entries.
- Wired into receipt-verify, claims, and agent (--sth-store,
  --consistency-proof, --max-sth-age-seconds); evidence records the
  pin action; any accountability failure fails the receipt closed.
- Provider: log-consistency --from-size N (serve proofs for pinning
  agents whose pin is older than the receipt's embedded anchor) and
  log-audit (monitor self-check: recompute the tree, verify the stored
  STH and per-entry leaf hashes).

Live drill in this commit's validation: pin-on-first-use -> matched ->
grown-with-proof advance -> a real forged same-size split view REJECTED
with the equivocation diagnostic -> freshness rejection -> clean
self-audit. tests/test_sthstore.py covers pin/match/equivocation,
growth-without-proof, lying consistency anchors, rollback, freshness.
45/45 tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 10:08:34 +02:00
caa864a749 Estate sync: boundary-axiom vocabulary + the four-tier apex reality (R4)
The verified corpus completed its phase 2 on 2026-07-06: every ed25519
fork now carries FOUR button-enforced apex tiers up to the full lift
(accept <=> decompress(R) = [k](-A)+[s]B as points), the complete scalar
layer, and the constructive encoding/decoding chain. pacta was calibrated
to the pre-apex corpus and - worse - had no vocabulary for
boundary-audited certificates: its axiom audit knew only "clean = exactly
the three standard axioms", so the apex tiers would have scored dirty.

New vocabulary:
- Profile.certificate_axioms: per-certificate ALLOWED axiom sets;
  expected_axioms_for(cert) resolves each certificate's own boundary.
- RepoConfig.apex_boundary: a simple per-fork key (dalek-wrappers /
  hash3 / anza) expanded by the ed25519 profile into the exact
  per-tier allowed sets. AUTHORITY NOTE in profiles/ed25519.py: each
  repo's check.sh Phase 3b is the enforcement point; if the button and
  this table disagree, the button wins.
- run_axiom_audit compares each certificate against ITS allowed set;
  deviation in EITHER direction (extra axiom or missing boundary
  axiom) is dirty.

New risk reality:
- R4 is now reachable: full four-tier apex + constructive chain +
  scalar arithmetic, all proven with cones pinned to their documented
  boundaries. R4 always carries explicit residual blockers (SHA-512
  oracle, hypothesis-parametric wire parses, translation faithfulness,
  no side-channel/build assurance - those gate R5).
- R3 unchanged (arithmetic pair) and now explains exactly which apex
  certificates are missing for R4.

Attestation trust model hardened:
- The provider is trusted for its OBSERVATION, never its VERDICT:
  axiom_status is re-derived locally from observed_axioms against the
  agent's own boundary policy. A provider that labels a dirty cone
  "clean" gains nothing; "proven" with no observed axioms is
  "unverifiable".
- Partial attestations degrade instead of being rejected: uncovered
  certificates stay unproven and the score caps accordingly (an
  arithmetic-only attestation still authorizes an R3 library capsule,
  never a wallet).

Also: scripts/mini_pytest.py - a dependency-free test runner (tmp_path,
raises, monkeypatch, capsys) for hosts without pytest; examples
regenerated FROM the tool (dalek/anza fixtures now R4, 16 certs; new
full four-tier attestation example); tests updated + new
tests/test_boundaries.py (lying-provider, missing-boundary-axiom,
partial-coverage cases). 40/40 tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 10:04:43 +02:00
0461d2f997 add transparency log trust provider 2026-07-03 14:09:34 +02:00
0522cdfdca add nested proof check provider 2026-07-03 13:03:58 +02:00