site rewrite v2 + OpenAPI: the undergrad-first page

Operator critique, all points: no narrative opener (the page now begins
'This site is a public notary for machine-checked proofs...'); subjects
stated symmetrically and completely (signature-CHECKING code in four
Ed25519 libraries, an SLH-DSA implementation, and the log's own Merkle
machinery — the accumulator leaf was missing before); the redundant
'same thing, in one precise sentence' paragraph is gone; every ladder
rung now labels its preconditions ('You need: ...') before any command
and explains what the command does and what a green result means; no
forward references to the paper before its own section; the key card
opens 'Two keys sign everything in this log' — never again 'This key'
— with Key 1/Key 2 structure; the API box is REMOVED from the page and
replaced the industry-standard way: an OpenAPI 3 document served at
/openapi.json (new route + test), one footer line points to it; the
footer carries no commands; the paper card references rung 1 instead
of dropping a bare command. Suite 155 green.
This commit is contained in:
mrwulf 2026-08-17 10:02:06 +02:00
parent 6c65a53775
commit 42c244374a
3 changed files with 135 additions and 99 deletions

View file

@ -20,6 +20,39 @@ from .transparency_log import TransparencyLog
API_VERSION = "v1" API_VERSION = "v1"
def _openapi_document(base: str) -> dict:
"""The machine interface, described the industry-standard way (OpenAPI 3)
instead of a hand-written endpoint box on the human docs page."""
q = lambda name, desc, req=True: {"name": name, "in": "query", "required": req,
"description": desc, "schema": {"type": "string"}}
ok = {"200": {"description": "success"}}
return {
"openapi": "3.0.3",
"info": {"title": "Lean Transparency Log",
"description": "Read-only CT-style interface of the LTL. "
"Heads are signed offline; this service holds no key material.",
"version": API_VERSION},
"servers": [{"url": "https://ltl.zkdefi.org" + base}],
"paths": {
"/log-public-key": {"get": {"summary": "Required Ed25519 public key (PEM)", "responses": ok}},
"/log-slhdsa-public-key": {"get": {"summary": "Additive post-quantum SLH-DSA public key (PEM)", "responses": ok}},
"/healthz": {"get": {"summary": "Liveness and current tree size", "responses": ok}},
"/paper": {"get": {"summary": "The current paper (PDF)", "responses": ok}},
f"/{API_VERSION}/metadata": {"get": {"summary": "Log identity", "responses": ok}},
f"/{API_VERSION}/sth": {"get": {"summary": "Latest Signed Tree Head", "responses": ok}},
f"/{API_VERSION}/sth-history": {"get": {"summary": "Every Signed Tree Head ever issued (witness material)", "responses": ok}},
f"/{API_VERSION}/sth-consistency": {"get": {"summary": "Consistency proof from a pinned size",
"parameters": [q("first", "your pinned old tree size")], "responses": ok}},
f"/{API_VERSION}/proof": {"get": {"summary": "Inclusion proof (freshly issued receipt)",
"parameters": [q("component", "component name", False), q("leaf_hash", "leaf hash (hex)", False)], "responses": ok}},
f"/{API_VERSION}/attestation": {"get": {"summary": "Newest attestation for a component",
"parameters": [q("component", "component name")], "responses": ok}},
f"/{API_VERSION}/entries": {"get": {"summary": "Raw leaves in [start, end)",
"parameters": [q("start", "first index", False), q("end", "one past last index", False)], "responses": ok}},
},
}
def make_handler(log: TransparencyLog, base_path: str, docs_html: str, paper_pdfs: dict[str, bytes] | None = None): def make_handler(log: TransparencyLog, base_path: str, docs_html: str, paper_pdfs: dict[str, bytes] | None = None):
paper_pdfs = paper_pdfs or {} paper_pdfs = paper_pdfs or {}
@ -78,6 +111,8 @@ def make_handler(log: TransparencyLog, base_path: str, docs_html: str, paper_pdf
self.send_header("Content-Length", str(len(body))) self.send_header("Content-Length", str(len(body)))
self.end_headers() self.end_headers()
self.wfile.write(body) self.wfile.write(body)
elif route == "/openapi.json":
self._send(200, _openapi_document(base))
elif route == "/healthz": elif route == "/healthz":
self._send(200, {"ok": True, "tree_size": len(log.entries())}) self._send(200, {"ok": True, "tree_size": len(log.entries())})
elif route == f"/{API_VERSION}/metadata": elif route == f"/{API_VERSION}/metadata":
@ -153,6 +188,7 @@ def make_handler(log: TransparencyLog, base_path: str, docs_html: str, paper_pdf
f"{base}/log-public-key", f"{base}/log-public-key",
f"{base}/log-slhdsa-public-key", f"{base}/log-slhdsa-public-key",
f"{base}/healthz", f"{base}/healthz",
f"{base}/openapi.json",
f"{base}/{API_VERSION}/metadata", f"{base}/{API_VERSION}/metadata",
f"{base}/{API_VERSION}/sth", f"{base}/{API_VERSION}/sth",
f"{base}/{API_VERSION}/sth-history", f"{base}/{API_VERSION}/sth-history",

View file

@ -150,11 +150,11 @@ def _trust_anchor_html(log: TransparencyLog, metadata: dict[str, Any], base: str
slh_pem = escape(slh_path.read_text(encoding="utf-8").strip()) slh_pem = escape(slh_path.read_text(encoding="utf-8").strip())
slh_fp = _h.sha256(slh_path.read_bytes()).hexdigest() slh_fp = _h.sha256(slh_path.read_bytes()).hexdigest()
slh_block = f"""<hr style="border:none;border-top:1px solid #ddd;margin:.8rem 0"> slh_block = f"""<hr style="border:none;border-top:1px solid #ddd;margin:.8rem 0">
<p style="margin-top:0"><strong>Second, additive anchor post-quantum.</strong> Heads from <p style="margin-top:0"><strong>Key&nbsp;2 SLH-DSA-SHA2-128s (FIPS&nbsp;205), additive
tree&nbsp;14 on additionally carry a deterministic <strong>SLH-DSA-SHA2-128s</strong> (FIPS&nbsp;205) post-quantum.</strong> Heads from tree size&nbsp;14 on carry a second signature from this key;
signature over the same payload. The Ed25519 signature above remains the one every consumer must older heads legitimately have none an append-only log keeps its history. Check it where your
check; this one is checked where tooling allows (OpenSSL&nbsp;&nbsp;3.5). Its verify path is the tooling allows (OpenSSL&nbsp;&nbsp;3.5). The kind of code that verifies such signatures is itself
proof subject of leaf&nbsp;18.</p> a proof subject of this log (leaf&nbsp;18).</p>
<pre style="margin-bottom:.4rem">{slh_pem}</pre> <pre style="margin-bottom:.4rem">{slh_pem}</pre>
<p class="muted" style="margin:.2rem 0 0">SHA-256 fingerprint <code>{slh_fp}</code> <p class="muted" style="margin:.2rem 0 0">SHA-256 fingerprint <code>{slh_fp}</code>
&nbsp;·&nbsp; raw: <a href="{base}/log-slhdsa-public-key"><code>{base or ''}/log-slhdsa-public-key</code></a> &nbsp;·&nbsp; raw: <a href="{base}/log-slhdsa-public-key"><code>{base or ''}/log-slhdsa-public-key</code></a>
@ -162,13 +162,14 @@ proof subject of leaf&nbsp;18.</p>
else: else:
slh_block = "" slh_block = ""
return f"""<div class="card"> return f"""<div class="card">
<p style="margin-top:0">This key is the <strong>required cryptographic identity anchor</strong> the one every consumer must check: it <p style="margin-top:0"><strong>Two keys sign everything in this log.</strong> Neither makes a
authenticates that these statements were made by the operator (the same party the artifacts call the provider). It does not, by itself, make claim <em>true</em>; they prove a claim comes from this operator, unchanged. Save your own copy
those statements true each attestation's truth additionally rests on the replay, theorem, of both that is called <em>pinning</em>: from then on you trust only what verifies against
extraction and toolchain assumptions stated in that leaf (one signed entry of the tree below). Every tree head and attestation is your saved copies. Fetch each key from this page AND from the independently hosted mirror and
signature-checked against this key. compare byte-for-byte; the copies must be identical. (The first fetch is trust-on-first-use;
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 comparing two independent hosts is what bounds it.)</p>
<a href="{mirror}/blob/main/provider.ed25519.pub">mirror copy</a>; they must be identical. The first fetch is trust-on-first-use; the two-host byte-comparison is what bounds it.</p> <p><strong>Key&nbsp;1 Ed25519, required.</strong> Every signed head and every attestation must
verify against it.</p>
<pre style="margin-bottom:.4rem">{pem}</pre> <pre style="margin-bottom:.4rem">{pem}</pre>
<p class="muted" style="margin:.2rem 0 0">SHA-256 fingerprint <code>{escape(fingerprint)}</code> <p class="muted" style="margin:.2rem 0 0">SHA-256 fingerprint <code>{escape(fingerprint)}</code>
&nbsp;·&nbsp; raw: <a href="{base}/log-public-key"><code>{base or ''}/log-public-key</code></a> &nbsp;·&nbsp; raw: <a href="{base}/log-public-key"><code>{base or ''}/log-public-key</code></a>
@ -221,93 +222,91 @@ def render_docs(log: TransparencyLog, base_path: str) -> str:
· <a href="https://zkdefi.org/saymrwulf">code</a> · <a href="https://zkdefi.org/saymrwulf">code</a>
· <a href="https://zkdefi.com/">cv</a></p> · <a href="https://zkdefi.com/">cv</a></p>
<h1>LTL the Lean Transparency Log</h1> <h1>LTL the Lean Transparency Log</h1>
<p><strong>What happened here, in plain terms:</strong> we took real cryptographic <p>This site is a <strong>public notary for machine-checked proofs about cryptographic
code four production Ed25519 signature libraries and the verification path of software</strong>. A proof assistant <a href="https://lean-lang.org">Lean&nbsp;4</a>, a program
SLH-DSA (FIPS&nbsp;205), the post-quantum signature standard and machine-checked that checks mathematical proofs mechanically has verified precise statements about the code
mathematical proofs about it with the <a href="https://lean-lang.org">Lean&nbsp;4</a> that <em>checks signatures</em>: in four widely deployed <strong>Ed25519</strong> libraries, in an
proof assistant. Re-checking those proofs yourself takes a toolchain and about half implementation of <strong>SLH-DSA</strong> (FIPS&nbsp;205, the hash-based post-quantum signature
an hour of compute per library. This site is the shortcut that does not ask for standard), and in <strong>the Merkle-tree machinery of this log itself</strong>. Every completed
blind trust: a public, tamper-evident ledger of signed statements about every proof proof check is recorded here as a signed, numbered entry that can never be altered or removed
check we ran so you decide how much of our work you re-verify, from a millisecond {len(entries)} entries so far, drawn live further down this page.</p>
signature check to redoing everything.</p>
<p class="tagline"><strong>The same thing, in one precise sentence:</strong> a public, append-only Merkle <p>Re-checking such proofs yourself takes a toolchain and real compute time. This log gives you
accumulator (a hash tree that only ever grows) of <em>signed statements that the Lean&nbsp;4 formal proofs of specific cheaper positions to stand on: in milliseconds you can verify that the operator is permanently
cryptographic Rust libraries, at specific git commits, re-check by machine with exactly bound to every claim he ever made and you can escalate, step by step, up to redoing
their documented assumptions</em> so that you can trust a proof result by checking everything yourself. The ladder below lists every position, cheapest first.</p>
<strong>one required signature (Ed25519) and ~{max(1,(latest.get('tree_size') or 1).bit_length())} hashes in
milliseconds</strong>, instead of running a theorem prover for hours.</p>
<h2>Choose where you stand the trust ladder</h2> <h2>Choose where you stand the trust ladder</h2>
<p>Every rung below is a legitimate place to stand. Each states what you still take
on trust, what you do, what it costs, and what you know afterwards. Climb one rung
at a time the whole service is built so that you can.</p>
<div class="steps"> <div class="steps">
<div class="card"><strong>&ldquo;I just want the history held honest.&rdquo;</strong> anyone, one minute.<br> <div class="card"><strong>Hold a copy of the history.</strong> anyone; one minute.<br>
Still trusted: everything but lying becomes attributable. You still trust: the content of every claim. You defeat: silent rewriting.<br>
You need: Python&nbsp;3 and the <code>openssl</code> command (preinstalled on most Linux and macOS systems).
<pre>git clone https://github.com/saymrwulf/lean-transparency-log &amp;&amp; cd lean-transparency-log &amp;&amp; python3 verify.py --all</pre> <pre>git clone https://github.com/saymrwulf/lean-transparency-log &amp;&amp; cd lean-transparency-log &amp;&amp; python3 verify.py --all</pre>
<span class="muted">Python plus the system <code>openssl</code> binary; fails closed without it. <span class="muted">This fetches the log&rsquo;s public mirror a git repository holding every entry
Afterwards you hold every leaf and every Signed Tree Head (STH) ever issued. If the and every signed head ever issued and re-computes every hash and signature in it. A green
operator ever shows anyone a conflicting history, your copy exposes it you are a result means the history you now hold is internally consistent and signed. Keep the folder:
witness. A split view (the operator showing different histories to different if the operator ever shows a different history to anyone else, your copy proves it. A log
consumers) survives only until two witnesses compare.</span></div> that shows different histories to different people (a &ldquo;split view&rdquo;) survives only until
two holders compare.</span></div>
<div class="card"><strong>&ldquo;I trust the operator&rsquo;s reports; bind him to them.&rdquo;</strong> milliseconds.<br> <div class="card"><strong>Check that a claim is real and binding.</strong> milliseconds.<br>
Still trusted: that the recorded observations are honest. You still trust: that the operator&rsquo;s recorded observation is honest.<br>
Download the three artifacts (key, claim, inclusion proof table below), then: You need: four small files from the tables below the two public keys, plus one library&rsquo;s
claim file (&ldquo;attestation&rdquo;) and its proof of inclusion (&ldquo;receipt&rdquo;).
<pre>pacta receipt-verify --attestation --receipt --log-public-key provider.ed25519.pub</pre> <pre>pacta receipt-verify --attestation --receipt --log-public-key provider.ed25519.pub</pre>
<span class="muted">The <code>pacta</code> CLI ships in the <span class="muted">Your machine checks one Ed25519 signature and
~{max(1,(latest.get('tree_size') or 1).bit_length())} hashes no proof assistant involved.
The <code>pacta</code> tool ships in the
<a href="https://github.com/saymrwulf/proof-aware-crypto-tooling-agent">pacta repository</a> <a href="https://github.com/saymrwulf/proof-aware-crypto-tooling-agent">pacta repository</a>
(<code>pip install .</code> from a clone); a one-page Python core (the paper&rsquo;s (<code>pip install .</code> from a clone); about forty lines of ordinary Python do the same
Appendix&nbsp;C) does the same check without it. Add <code>--sth-store pins.json</code> to check, and the mirror&rsquo;s <code>verify.py</code> contains exactly that core. Afterwards the
remember every head you accept. Afterwards the exact claim repository, commit, claim which repository, which exact source version, which theorems, which assumptions
theorems, assumptions is cryptographically pinned to the operator&rsquo;s key inside an is bound to the operator&rsquo;s key inside a history he can neither rewrite nor deny.</span></div>
append-only history: he can never rewrite or deny it. What he <em>observed</em>, you
have not yet checked.</span></div>
<div class="card"><strong>&ldquo;I accept his observations not his judgment.&rdquo;</strong> minutes; the rung most people miss.<br> <div class="card"><strong>Judge by your own standards.</strong> minutes.<br>
Still trusted: the recorded axiom lists; <em>not</em> the operator&rsquo;s pass/fail labels. Every entry records more than pass/fail: it lists the exact assumptions each proof rests on
Compare each attestation&rsquo;s recorded assumption cones against a requirements card (its <em>axiom cone</em>). So you may ignore the operator&rsquo;s verdicts entirely: write down
you write yourself <code>pacta</code> automates the comparison, and lecture&nbsp;11 of the which assumptions <em>you</em> accept, and have your tooling compare list against list, name
<a href="https://github.com/saymrwulf/proof-aware-crypto-tooling-agent">Jupyter course</a> by name. <code>pacta</code> automates the comparison; lecture&nbsp;11 of the Jupyter course (same
walks through it. repository) teaches it step by step.
<span class="muted">Afterwards every verdict is <em>your</em> verdict, re-derived from your <span class="muted">Afterwards every verdict is your verdict the operator&rsquo;s labels can at
own ruler; operator labels can veto but never grant acceptance (details in most veto, never grant. The section &ldquo;You hold the ruler&rdquo; below is this rung in full.</span></div>
&ldquo;You hold the ruler&rdquo; below).</span></div>
<div class="card"><strong>&ldquo;I don&rsquo;t trust his observations I&rsquo;ll run the proofs myself.&rdquo;</strong> about 30&nbsp;minutes per library.<br> <div class="card"><strong>Re-run the proof check yourself.</strong> about 30&nbsp;minutes per library.<br>
Still trusted: the published Lean sources and the extraction that produced them; You still trust: that the published Lean statements mean what they say.<br>
<em>not</em> the operator&rsquo;s execution. Clone the attested repository at its pinned You need: a Lean&nbsp;4 toolchain (free).
commit and press its check button (<code>verification/check.sh</code>) with a Lean&nbsp;4 <span class="muted">Every attested repository ships one script, <code>verification/check.sh</code>.
toolchain: the kernel re-checks every certificate on your machine and the axiom Clone the repository at the exact source version recorded in its log entry and run the script:
audit prints the exact assumption cones. the proof assistant re-checks every theorem on your machine and prints every assumption list.
<span class="muted">Afterwards the theorem prover accepted on <em>your</em> hardware The operator is now out of the loop entirely.</span></div>
the operator is out of the loop entirely.</span></div>
<div class="card"><strong>&ldquo;I trust none of it I&rsquo;ll rebuild the whole path.&rdquo;</strong> weeks.<br> <div class="card"><strong>Rebuild everything from source.</strong> weeks.<br>
Still trusted: Lean&rsquo;s kernel, the extraction tools, and your compiler the floor, What remains trusted: Lean&rsquo;s proof kernel, the Rust-to-Lean translation tools (Charon and
which we name rather than hide. Pin the upstream Rust source yourself, extract it to Aeneas), and your compiler the floor, which we name rather than hide.
Lean with Charon/Aeneas (every repository ships its <code>extract.sh</code>, pinned <span class="muted">Every repository documents its full path: the pinned upstream Rust code,
toolchain versions, and byte-pinned generated models for comparison), re-read the the extraction script that regenerates the Lean definitions byte-for-byte, and the theorem
theorem statements against FIPS&nbsp;205 / RFC&nbsp;9162 / the curve equations, and re-prove statements to read against the standards themselves (FIPS&nbsp;205, RFC&nbsp;9162, the curve
or audit each certificate. equations). Reproduce any part; compare with what is published. After this rung you no longer
<span class="muted">Afterwards you have reproduced the estate and no longer need us need this site that is the point. There is no rung&nbsp;6: even here you trust a kernel, a
which is the point. There is no rung above this one: even here you trust a kernel, a compiler, and your hardware.</span></div>
compiler, and your silicon. Anyone offering zero trust is selling something.</span></div>
</div> </div>
<h2>The trust anchors pin these keys (one required, one additive)</h2> <h2>Two keys sign this log pin these keys</h2>
{_trust_anchor_html(log, metadata, base, mirror)} {_trust_anchor_html(log, metadata, base, mirror)}
<h2>The accumulator, live</h2> <h2>The accumulator, live</h2>
<p>The log is a <strong>Merkle tree</strong>: every entry (&ldquo;leaf&rdquo;) 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. This
picture is computed from the live log at page render the leaf hashes, nodes, root, and
signature are the real ones:</p>
{tree_svg} {tree_svg}
<p class="legend"> <p class="legend">
<span><span class="sw" style="background:#e2f2e9;border:1px solid #1e7f4f"></span>verified attestation (all certificates proven, axiom cones boundary-exact)</span> <span><span class="sw" style="background:#e2f2e9;border:1px solid #1e7f4f"></span>verified attestation (all certificates proven, axiom cones boundary-exact)</span>
<span><span class="sw" style="background:#f4f4f6;border:1px solid #8a93a0"></span>historical audit-failure attestation kept forever; an append-only ledger does not erase its bad day (leaves&nbsp;03: an early audit round that failed; leaves&nbsp;47 re-attest the same four libraries cleanly)</span> <span><span class="sw" style="background:#f4f4f6;border:1px solid #8a93a0"></span>historical audit-failure attestation kept forever; an append-only ledger does not erase its bad day (leaves&nbsp;03: an early audit round that failed; leaves&nbsp;47 re-attest the same four libraries cleanly)</span>
</p> </p>
<p class="muted">Every box above is computed from the live log at page render leaf hashes, <p class="muted">The library that signs the log is itself an entry in the log what that entry proves is its <em>verify</em> path (no signing code is proven, here or anywhere) and it checks its own entry before signing. In detail: before signing this
internal nodes, the root, and the signature are the real ones. The library that signs the log is itself an entry in the log what that entry proves is its <em>verify</em> 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 root, the provider Merkle-verified its own signing library's leaf
(index {provenance.get('signing_library_leaf_index','?')}, (index {provenance.get('signing_library_leaf_index','?')},
certificates {escape(str(provenance.get('signing_library_certificates_proven','?')))}) certificates {escape(str(provenance.get('signing_library_certificates_proven','?')))})
@ -335,7 +334,9 @@ which observed axiom cones (the exact set of assumptions each proof ultimately r
<td>table below, or <a href="{mirror}">mirror</a> <code>entries/</code></td></tr> <td>table below, or <a href="{mirror}">mirror</a> <code>entries/</code></td></tr>
<tr><td><b>3</b></td><td><code>&lt;library&gt;.receipt.json</code></td> <tr><td><b>3</b></td><td><code>&lt;library&gt;.receipt.json</code></td>
<td><strong>The proof of inclusion.</strong> Binds artifact&nbsp;2 into the signed tree: <td><strong>The proof of inclusion.</strong> Binds artifact&nbsp;2 into the signed tree:
leaf index, sibling hashes, the Signed Tree Head (STH). A one-page Python core verifies it printed as Appendix&nbsp;C of the paper; the shipped <code>verify.py</code> wraps that core with full fail-closed binding checks (stdlib hashing; signature checks shell out to the <code>openssl</code> binary).</td> leaf index, sibling hashes, the Signed Tree Head (STH). About forty lines of ordinary
Python verify it; the mirror&rsquo;s <code>verify.py</code> contains exactly that core, wrapped in
fail-closed safety checks (stdlib hashing; signature checks shell out to the <code>openssl</code> binary).</td>
<td>table below, or <a href="{mirror}">mirror</a> <code>receipts/</code></td></tr> <td>table below, or <a href="{mirror}">mirror</a> <code>receipts/</code></td></tr>
<tr><td>+</td><td>the full mirror clone</td> <tr><td>+</td><td>the full mirror clone</td>
<td><strong>Maximal benefit: become a witness.</strong> Every leaf + every signed head <td><strong>Maximal benefit: become a witness.</strong> Every leaf + every signed head
@ -387,24 +388,6 @@ into this same log. <strong>If your ruler is stricter than our supply, your rule
our roadmap.</strong> (The full walk-through is lecture&nbsp;11 of the Jupyter course in the our roadmap.</strong> (The full walk-through is lecture&nbsp;11 of the Jupyter course in the
<a href="https://github.com/saymrwulf/proof-aware-crypto-tooling-agent">pacta repo</a>.)</div> <a href="https://github.com/saymrwulf/proof-aware-crypto-tooling-agent">pacta repo</a>.)</div>
<h2>For your tooling the raw API</h2>
<p>Humans never need these directly; every link on this page already uses them. They
exist so that <em>your software</em> a CI job, an autonomous agent, a package
resolver can consume the log without scraping HTML. The <code>pacta</code> CLI
builds on them: STH pinning, freshness policy, risk scoring (R0R5, six named
residual-risk classes) with policy-gated consequences, and optionally
<code>--require-verified-verifier</code>, which checks every signature through the
proof-attested Ed25519 code path itself.</p>
<pre>GET {base}/v1/sth latest Signed Tree Head
GET {base}/v1/sth-history the published head history (witness material)
GET {base}/v1/sth-consistency?first=N consistency proof from your pinned size
GET {base}/v1/proof?component=NAME inclusion proof (artifact 3, freshly issued)
GET {base}/v1/attestation?component=NAME the claim (artifact 2)
GET {base}/v1/entries?start=N&amp;end=M raw leaves
GET {base}/v1/metadata log identity
GET {base}/healthz</pre>
<h2>The paper</h2> <h2>The paper</h2>
<div class="card"><a href="{base}/paper"><strong>Accountable Distribution of Machine-Checked <div class="card"><a href="{base}/paper"><strong>Accountable Distribution of Machine-Checked
Correctness Evidence: A Transparency Model and the Lean Transparency Log</strong></a> Correctness Evidence: A Transparency Model and the Lean Transparency Log</strong></a>
@ -428,9 +411,13 @@ Ed25519 tiers.</div>
describes this deployment as it runs nineteen leaves, dual-signed heads, the describes this deployment as it runs nineteen leaves, dual-signed heads, the
post-quantum verify path as leaf&nbsp;18 with its own certificate appendix. The log is post-quantum verify path as leaf&nbsp;18 with its own certificate appendix. The log is
append-only and keeps growing past any paper revision; every number the paper states append-only and keeps growing past any paper revision; every number the paper states
stays checkable against the retained history: <code>python3 verify.py --all</code> stays checkable against the retained history: the mirror clone from rung&nbsp;1 of the
re-verifies all of it, paper-era and after, from a clone of the mirror.</div> ladder re-verifies all of it, paper-era and after.</div>
<p class="muted">Log heads are signed offline; this service is read-only and holds no <p class="muted">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 <a href="https://github.com/saymrwulf/proof-aware-crypto-tooling-agent">pacta repository</a>.</p> key material. Provider tooling, agent tooling, and the full Jupyter course live in the
<a href="https://github.com/saymrwulf/proof-aware-crypto-tooling-agent">pacta repository</a>.
Software integrators: the machine interface behind every link on this page is described by the
OpenAPI document at <a href="{base}/openapi.json"><code>/openapi.json</code></a> the
<code>pacta</code> tool builds on it (head pinning, freshness policy, risk scoring R0R5).</p>
</body></html>""" </body></html>"""

View file

@ -210,3 +210,16 @@ def test_svg_tree_boxes_never_overlap_or_spill():
head = re.search(r'<rect x="[-0-9.]+" y="[0-9.]+" width="([0-9.]+)" height="46"', svg) head = re.search(r'<rect x="[-0-9.]+" y="[0-9.]+" width="([0-9.]+)" height="46"', svg)
title = re.search(r'font-weight="bold">([^<]+)</text>', svg).group(1) title = re.search(r'font-weight="bold">([^<]+)</text>', svg).group(1)
assert len(title) * 7.0 <= float(head.group(1)), "head title spills" assert len(title) * 7.0 <= float(head.group(1)), "head title spills"
def test_openapi_document_served_and_valid():
# The machine interface is published the industry-standard way
# (operator order 2026-08-16: no endpoint box on the human page).
import json as _json
from pacta_provider.web import _openapi_document
doc = _openapi_document("")
assert doc["openapi"].startswith("3.")
assert "/v1/sth" in doc["paths"] and "/log-public-key" in doc["paths"]
_json.dumps(doc) # serializable