"""The LTL website, served at the log's base path — one self-contained HTML page (inline CSS + inline SVG, no external assets: works air-gapped behind any reverse proxy). Rendered from the LIVE log state, so the graphic and every number on the page are the accumulator, not a brochure about it.""" from __future__ import annotations from html import escape from typing import Any from pacta.transparency import node_hash from .transparency_log import LogEntry, TransparencyLog _STYLE = """ :root{--ink:#1c2430;--ink2:#5a6675;--line:#dde2e9;--ok:#1e7f4f;--okbg:#e2f2e9; --warn:#a86a10;--warnbg:#fdf0da;--accent:#3b4d8f;--accentbg:#eef0f7;--bg:#f8f9fa} *{box-sizing:border-box} body{font-family:system-ui,sans-serif;max-width:66rem;margin:0 auto;padding:2rem 1.2rem 4rem; color:var(--ink);line-height:1.6;background:var(--bg)} h1{font-size:2rem;margin:.2rem 0 0;letter-spacing:-.01em} h2{font-size:1.2rem;margin-top:2.6rem;border-bottom:2px solid var(--line);padding-bottom:.3rem} .tagline{font-size:1.05rem;color:var(--ink2);max-width:46rem} code,pre{font-family:ui-monospace,Menlo,Consolas,monospace;background:#eef0f3;border-radius:4px} code{padding:.1rem .3rem;font-size:.9em;overflow-wrap:anywhere} pre{padding:.9rem;overflow-x:auto;font-size:.85rem;max-width:100%} table{border-collapse:collapse;width:100%;font-size:.93rem;background:#fff} td,th{border:1px solid var(--line);padding:.5rem .7rem;text-align:left;vertical-align:top} th{background:var(--accentbg)} .pill{display:inline-block;border-radius:9px;padding:.08rem .6rem;font-size:.78rem;font-weight:600} .ok{background:var(--okbg);color:var(--ok)} .warn{background:var(--warnbg);color:var(--warn)} .acc{background:var(--accentbg);color:var(--accent)} .muted{color:var(--ink2);font-size:.9rem} .card{background:#fff;border:1px solid var(--line);border-radius:8px;padding:1rem 1.2rem;margin:.8rem 0} .steps{counter-reset:s} .steps .card{position:relative;padding-left:3.2rem} .steps .card::before{counter-increment:s;content:counter(s);position:absolute;left:1rem;top:1rem; width:1.6rem;height:1.6rem;border-radius:50%;background:var(--accent);color:#fff; display:flex;align-items:center;justify-content:center;font-weight:700;font-size:.9rem} svg{max-width:100%;height:auto;display:block;margin:1rem auto;background:#fff; border:1px solid var(--line);border-radius:8px} a{color:var(--accent)} .legend{display:flex;gap:1.4rem;flex-wrap:wrap;font-size:.85rem;color:var(--ink2);justify-content:center} .sw{display:inline-block;width:.8rem;height:.8rem;border-radius:3px;vertical-align:-1px;margin-right:.3rem} """ def _leaf_ok(entry: LogEntry) -> bool: certificates = ((entry.leaf.get("attestation") or {}).get("certificates")) or [] return bool(certificates) and all( certificate.get("status") == "proven" and certificate.get("axiom_status") == "clean" for certificate in certificates ) def _leaf_short(component: str) -> str: """Compact display name for a leaf box at small spans.""" return (component.replace("-ed25519-verified", "") .replace("ltl-accumulator-verified", "accum") .replace("fips205-slhdsa-verified", "slh-dsa")) def _svg_tree(entries: list[LogEntry], root_hex: str, signing_backend: str, head_label: str = "Ed25519") -> str: """The accumulator, drawn from its real leaves.""" if not entries: return "
(log is empty)
" hashes = [bytes.fromhex(entry.leaf_hash) for entry in entries] levels: list[list[bytes]] = [hashes] while len(levels[-1]) > 1: level = levels[-1] nxt = [node_hash(level[i], level[i + 1]) for i in range(0, len(level) - 1, 2)] if len(level) % 2: nxt.append(level[-1]) levels.append(nxt) width, level_gap = 1000, 86 height = 150 + level_gap * len(levels) out = [f'") return "".join(out) def _trust_anchor_html(log: TransparencyLog, metadata: dict[str, Any], base: str, mirror: str) -> str: """The provider public key, displayed in full on the front page. The key is the one thing a consumer takes on trust, once - hiding it behind a path would invert the page's priorities.""" key_path = log.log_dir / "provider.ed25519.pub" fingerprint = str(metadata.get("ed25519_public_key_fingerprint_sha256", "")) if not key_path.is_file(): return ( 'Key 2 — SLH-DSA (FIPS 205), post-quantum. Heads from tree size 14 on carry a second signature from this key; older heads legitimately have none — an append-only log keeps its history. Check it where your tooling allows (OpenSSL ≥ 3.5). The kind of code that verifies such signatures is itself a proof subject of this log (entry 18).
{slh_pem}
SHA-256 fingerprint {slh_fp}
· raw: {base or ''}/log-slhdsa-public-key
· mirror: provider.slhdsa.pub
Two keys sign everything in this log. Neither makes a claim true; they prove a claim comes from this operator, unchanged. Save your own copy of both — that is called pinning: from then on you trust only what verifies against your saved copies. Fetch each key from this page AND from the independently hosted mirror and compare byte-for-byte; the copies must be identical. (The first fetch is trust-on-first-use; comparing two independent hosts is what bounds it.)
Key 1 — Ed25519, required. Every signed head and every attestation must verify against it.
{pem}
SHA-256 fingerprint {escape(fingerprint)}
· raw: {base or ''}/log-public-key
· curl -s https://ltl.zkdefi.org/log-public-key
{escape(c)}This site is a public notary for machine-checked proofs about cryptographic software. A proof assistant — Lean 4, a program that checks mathematical proofs mechanically — has verified precise statements about the code that checks signatures: in four widely deployed Ed25519 libraries, in an implementation of SLH-DSA (FIPS 205, the hash-based post-quantum signature standard), and in the Merkle-tree machinery of this log itself. Every completed proof check is recorded here as a signed, numbered entry that can never be altered or removed — {len(entries)} entries so far, drawn live further down this page.
Re-checking such proofs yourself takes a toolchain and real compute time. This log gives you cheaper positions to stand on: in milliseconds you can verify that the operator is permanently bound to every claim he ever made — and you can escalate, step by step, up to redoing everything yourself. The ladder below lists every position, cheapest first.
openssl command (preinstalled on most Linux and macOS systems).
git clone https://github.com/saymrwulf/lean-transparency-log && cd lean-transparency-log && python3 verify.py --allThis fetches the log’s public mirror — a git repository holding every entry and every signed head ever issued (a head is the signed root fingerprint of the tree at a given size) — and re-computes every hash and signature in it. A green result means the history you now hold is internally consistent and signed. Keep the folder: if the operator ever shows a different history to anyone else, your copy proves it. A log that shows different histories to different people (a “split view”) survives only until two holders compare.
pacta receipt-verify --attestation … --receipt … --log-public-key provider.ed25519.pub --slhdsa-public-key provider.slhdsa.pubYour machine checks the required Ed25519 signature, the second (post-quantum) signature (needs OpenSSL ≥ 3.5; drop the second flag to skip it), and ~{max(1,(latest.get('tree_size') or 1).bit_length())} hashes — no proof assistant involved. The
pacta tool ships in the
pacta repository
(pip install . from a clone); about forty lines of ordinary Python do the same
check, and the mirror’s verify.py contains exactly that core. Afterwards the
claim — which repository, which exact source version, which theorems, which assumptions —
is bound to the operator’s key inside a history he can neither rewrite nor deny.pacta automates the comparison; lecture 11 of the Jupyter course (same
repository) teaches it step by step.
Afterwards every verdict is your verdict — the operator’s labels can at
most veto, never grant. The section “You hold the ruler” below is this rung in full.verification/check.sh.
Clone the repository at the exact source version recorded in its log entry and run the script:
the proof assistant re-checks every theorem on your machine and prints every assumption list.
The operator is now out of the loop entirely.The log is a Merkle tree: every entry (“leaf”) is hashed, hashes pair up level by level, and a single 32-byte root fingerprints the entire history; the operator signs that root. Changing any past entry would change the root — that is the tamper evidence. Each leaf records one proof run: a batch of certificates — one machine-checked theorem each, together with its exact assumption list. This picture is computed from the live log at page render — the leaf hashes, nodes, root, and signature are the real ones:
{tree_svg}verified attestation — every certificate proven, every assumption list exactly as declared 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)
The library that signs the log is itself an entry in the log — what that entry proves is its verify path (no signing code is proven, here or anywhere) — and it 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','?')))})
against this very tree — so the signed tree contains an attestation of the source the
operator reports its signing binary was built from. (An Ed25519 signature cannot by itself prove
which binary generated it; execution provenance is reported, not proven, and the provenance
fields live in the unsigned signature metadata.) Tree size {latest.get('tree_size',0)},
log id {escape(str(metadata.get('log_id',''))[:16])}….
To benefit from the accumulator you need exactly three files per
library, plus optionally the post-quantum key
(provider.slhdsa.pub) and the whole mirror. Nothing else.
| # | Artifact | What it is | Where |
|---|---|---|---|
| 1 | provider.ed25519.pub |
The identity anchor. The provider's public key — the required cryptographic identity you pin. It authenticates the operator's statements; their truth rests on each leaf's stated assumptions. Fetch it from BOTH independent locations and compare; the copies must be identical. | this site · mirror |
| 2 | <library>.attestation.json |
The claim. Which repo, which exact git commit, which theorems, which observed axiom cones (the exact set of assumptions each proof ultimately rests on), what machine protection — signed by the provider. | table below, or mirror entries/ |
| 3 | <library>.receipt.json |
The proof of inclusion. Binds the claim into the signed tree:
leaf index, sibling hashes, the Signed Tree Head (STH). About forty lines of ordinary
Python verify it; the mirror’s verify.py contains exactly that core, wrapped in
fail-closed safety checks (stdlib hashing; signature checks shell out to the openssl binary). |
table below, or mirror receipts/ |
| + | the full mirror clone | Maximal benefit: hold the complete history yourself (rung 1 of the ladder). Every leaf + every signed head
ever issued + verify.py (Python stdlib + the openssl binary for
signatures; fails closed without them). python3 verify.py --all
recomputes the entire tree and every historical head — you then hold a retained view that can
later EXPOSE a conflicting head shown to someone else. (A single clone cannot by itself prove the
log never split its view toward another consumer; that requires comparing heads across
consumers.) |
git clone {mirror} |
| library | claim (attestation) | proof of inclusion (receipt) | certificates proven |
|---|
attestation.json. Honesty about the boundary is the product.sn = 0),
zero divergences after the one-line restoration, confirmed by a three-way regression.
New in the August 2026 revisions: the deployment evaluated to its current nineteen-leaf, dual-signed state, an
instantiation section for the SLH-DSA (FIPS 205) verify path — eleven certificates,
five uninterpreted hash oracles, exact cones — and a certificate appendix mirroring the
Ed25519 tiers.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.
Software integrators: the machine interface behind every link on this page is described by the
OpenAPI document at /openapi.json — the
pacta tool builds on it (head pinning, freshness policy, risk scoring R0–R5).