mirror of
https://github.com/saymrwulf/proof-aware-crypto-tooling-agent.git
synced 2026-09-09 20:50:38 +00:00
course refresh: the notebooks enter the SLH-DSA era
The 14-notebook course predated the post-quantum campaign entirely (coherence findings 10, 11). Now, authored in the GENERATOR and regenerated (AGENTS.md rule): - notebook 06: new section 'The second signature that actually shipped: SLH-DSA' — the deterministic co-signature since tree size 14, chosen because the log attests its own parameter set's verify path (leaf 18, 11 certs); absent-not-failed for older heads; determinism as an audit primitive; verify-only always. Plus a runnable keygen/sign/verify/ re-sign-byte-equality demo (honest skip below OpenSSL 3.5) and the --slhdsa-public-key consumer flag in the policy list. - notebook 09: the 'post-quantum line' is now three-legged — Ed25519 proven-verify dogfood, SLH-DSA shipped-and-attested, ML-DSA required- but-honest-unavailable — with the closing point that a slot stops being aspirational the day its verify path enters the log; stale 16/16 provenance count -> 44/44 (leaf 13 re-attestation). - notebook 07: policy exercise extended with the co-signature question; 00 course map goal updated; README course listing for 06/09. - GENERATOR DRIFT REPAIRED in passing: notebook 10's cockpit cell had been added to the .ipynb but never backported to the generator — regeneration would have silently dropped it; the cell is now IN the generator and round-trips (19 cells, content identical). Suite 157 green.
This commit is contained in:
parent
31a9dee10a
commit
1086a3ba02
8 changed files with 893 additions and 801 deletions
|
|
@ -125,11 +125,11 @@ The `notebooks/` directory contains a zero-to-hero teaching sequence for undergr
|
|||
- `03_lean_replay_and_axiom_audit.ipynb`: replay versus transpilation, Lean invocation, axiom audits.
|
||||
- `04_proof_hygiene_and_boundaries.ipynb`: `sorry`, local axioms, trivial targets, manifest coverage.
|
||||
- `05_third_party_attestation_provider.ipynb`: provider trust transformation and signed attestations.
|
||||
- `06_merkle_transparency_logs.ipynb`: RFC 9162-style Merkle proofs, STHs, Ed25519/ML-DSA policy.
|
||||
- `06_merkle_transparency_logs.ipynb`: RFC 9162-style Merkle proofs, STHs, the dual-signature head policy (Ed25519 + the shipped SLH-DSA co-signature) and the fail-closed ML-DSA slot.
|
||||
- `06a_provider_build_the_log.ipynb` / `06b_agent_verify_inclusion.ipynb`: the MIRRORED PAIR - one provider (builds, Lean-verifies, signs with the merkleized library, self-checks its own inclusion), many agents (verify inclusion from scratch in ~25 lines, no Lean); the domain separation is the design and the lecture structure mirrors it.
|
||||
- `07_agent_consequences.ipynb`: receipt-gated artifact builds and wallet-denial policy.
|
||||
- `08_capstone_research_program.ipynb`: audit the shipped R4 evidence; design the R5 discharge plan.
|
||||
- `09_dogfood_verified_crypto.ipynb`: the proven-path verifier in the agent's own loop; hybrid-PQC posture.
|
||||
- `09_dogfood_verified_crypto.ipynb`: the proven-path verifier in the agent's own loop; the three-legged PQ posture (Ed25519 dogfood, shipped SLH-DSA, honest ML-DSA slot).
|
||||
- `10_verified_custody_wallet.ipynb`: warden - the quorum custody boundary and signing firewall, ratchet-rule (toy 3-of-3, then the real four proven forks), plus the counterparty recomputing a custody card's inclusion proof.
|
||||
- `11_the_customers_eye_view.ipynb`: the counterparty's seat - what a customer can and cannot recompute about someone else's wallet from its custody card and the public log.
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
"- Perform a proof hygiene scan and explain why `sorry`, local axioms, and trivial theorem targets are dangerous.\n",
|
||||
"- Explain how a third-party proof-checking provider changes the trusted base.\n",
|
||||
"- Implement and verify RFC 9162-style Merkle inclusion and consistency proofs.\n",
|
||||
"- Explain why Signed Tree Heads need accountable signatures, why Ed25519 is useful here, and why ML-DSA requires a real backend.\n",
|
||||
"- Explain why Signed Tree Heads need accountable signatures, why Ed25519 is useful here, why ML-DSA requires a real backend, and how the shipped SLH-DSA co-signature differs from both.\n",
|
||||
"- Design policy gates that convert verification evidence into consequences.\n",
|
||||
"- Read R4 four-tier apex evidence, name its residual blockers, and write a research plan toward R5 production assurance.\n"
|
||||
]
|
||||
|
|
@ -150,26 +150,6 @@
|
|||
"- NIST FIPS 204, Module-Lattice-Based Digital Signature Standard: https://csrc.nist.gov/pubs/fips/204/final\n",
|
||||
"- PACTA README: `../README.md`\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## The course's operational twin: the cockpit and the lab manual\n",
|
||||
"\n",
|
||||
"These notebooks are the *code-level* track: you build the machinery with your own hands.\n",
|
||||
"Two sibling surfaces teach the *operational* track on the very same system:\n",
|
||||
"\n",
|
||||
"- **The custody cockpit** — `pacta wallet cockpit --demo` serves a read-only bridge of six\n",
|
||||
" role stations (proposer, quorum bench, operator, cryptographer, architect, newcomer) over\n",
|
||||
" live evidence, with a tmux-style deck (`/deck`) showing every station in parallel.\n",
|
||||
"- **The lab manual** (`docs/warden-lab-manual.md`, served at `/manual`) — a study-club course\n",
|
||||
" that teaches each *role* hands-on: labs with checkpoints, a safe ledger-tamper drill,\n",
|
||||
" self-tests, and a capstone incident walked through all six chairs.\n",
|
||||
"\n",
|
||||
"Recommended weave: notebooks 00–09 first (build it), then the lab manual (run it as a crew),\n",
|
||||
"with notebook 10 and the manual's warden sessions read side by side."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
|
|
|||
|
|
@ -128,7 +128,8 @@
|
|||
"Policy matters:\n",
|
||||
"\n",
|
||||
"- `require-signatures ed25519`: verify Ed25519 and allow ML-DSA to be unavailable.\n",
|
||||
"- `require-signatures both`: require Ed25519 and ML-DSA verified. If ML-DSA is unavailable, fail closed.\n"
|
||||
"- `require-signatures both`: require Ed25519 and ML-DSA verified. If ML-DSA is unavailable, fail closed.\n",
|
||||
"- `--slhdsa-public-key <pem>`: additionally verify the second (post-quantum) SLH-DSA co-signature on the head; heads before tree size 14 report `absent` (allowed), a present-but-wrong signature fails closed.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -156,6 +157,59 @@
|
|||
"ML-DSA adds post-quantum robustness for the accumulator signature layer. But it must be a real signature, not an aspirational label. If a host lacks ML-DSA, the correct result is an explicit blocker.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## The second signature that actually shipped: SLH-DSA\n",
|
||||
"\n",
|
||||
"Since tree size 14, every head of the LIVE log carries a second,\n",
|
||||
"deterministic **SLH-DSA-SHA2-128s** (FIPS 205) signature beside the\n",
|
||||
"required Ed25519 one. This is not the ML-DSA slot above - it is a\n",
|
||||
"hash-based scheme, and it was chosen because the estate has PROVEN\n",
|
||||
"its verify path (eleven certificates, log leaf 18): the log\n",
|
||||
"co-signs with the parameter set whose verification path it itself\n",
|
||||
"attests. Three design facts worth internalizing:\n",
|
||||
"\n",
|
||||
"1. Heads published before size 14 carry no co-signature, and\n",
|
||||
" verifiers report them `ABSENT` rather than failing them - an\n",
|
||||
" append-only log keeps the history of its own signature-scheme\n",
|
||||
" upgrades.\n",
|
||||
"2. The co-signature is deterministic on purpose: re-signing the\n",
|
||||
" same payload is byte-comparable, so \"same input, same\n",
|
||||
" signature\" becomes a diff you can run, not an assurance you\n",
|
||||
" must trust.\n",
|
||||
"3. Signing is still never proven - here, as everywhere in this\n",
|
||||
" estate, certificates cover the VERIFY path only.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Runnable where OpenSSL >= 3.5 is present; honest skip otherwise.\n",
|
||||
"import tempfile\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"from pacta import slhdsa\n",
|
||||
"\n",
|
||||
"tmp = Path(tempfile.mkdtemp(prefix=\"nb06-slhdsa-\"))\n",
|
||||
"try:\n",
|
||||
" slhdsa.generate_slhdsa_keypair(tmp / \"slh.key\", tmp / \"slh.pub\")\n",
|
||||
"except Exception as exc:\n",
|
||||
" print(\"SLH-DSA unavailable on this host (OpenSSL >= 3.5 needed):\", exc)\n",
|
||||
"else:\n",
|
||||
" payload = b\"canonical STH payload bytes\"\n",
|
||||
" block = slhdsa.slh_dsa_signature_block(payload, tmp / \"slh.key\", tmp / \"slh.pub\")\n",
|
||||
" ok, err = slhdsa.verify_payload_slhdsa(payload, block[\"signature_base64\"], tmp / \"slh.pub\")\n",
|
||||
" print(\"co-signature verifies:\", ok, err or \"\")\n",
|
||||
" block2 = slhdsa.slh_dsa_signature_block(payload, tmp / \"slh.key\", tmp / \"slh.pub\")\n",
|
||||
" print(\"deterministic (byte-equal re-sign):\",\n",
|
||||
" block[\"signature_base64\"] == block2[\"signature_base64\"])\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
|
|||
|
|
@ -201,6 +201,7 @@
|
|||
"- Modify a claim card to R2 and show that `build-library` is refused.\n",
|
||||
"- Explain why a denial artifact is useful for auditability.\n",
|
||||
"- Design a policy where an agent requires `both` Ed25519 and ML-DSA signatures for production deployment but allows Ed25519-only in a local lab.\n",
|
||||
"- Extend it: when should the agent also require the SLH-DSA co-signature, given that heads before tree size 14 legitimately lack it?\n",
|
||||
"- Write a downstream Rust pseudo-code snippet that imports the generated capsule before enabling a code path.\n"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
"- State precisely which parts of the dogfood verifier are certificate-covered and which are its trusted base.\n",
|
||||
"- Extract a raw Ed25519 key from an OpenSSL PEM by hand (napkin) and mechanically (real).\n",
|
||||
"- Demonstrate backend dispatch and the fail-closed `--require-verified-verifier` policy.\n",
|
||||
"- Defend the hybrid post-quantum posture: one proven-classical signature plus one required-but-honest ML-DSA slot.\n"
|
||||
"- Defend the three-legged post-quantum posture: proven-classical Ed25519, the shipped SLH-DSA co-signature with its attested verify path, and a required-but-honest ML-DSA slot.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -122,7 +122,8 @@
|
|||
"leaf, against the very tree it is about to sign. The verdict is\n",
|
||||
"embedded in the signature block (`signing_provenance`: backend,\n",
|
||||
"library commit, leaf index, `self_inclusion: verified`,\n",
|
||||
"certificates 16/16). Lectures 6a/6b walk both sides of this.\n",
|
||||
"certificates 44/44 - the signer's source family was re-attested at 44\n",
|
||||
"certificates as leaf 13). Lectures 6a/6b walk both sides of this.\n",
|
||||
"Honesty note unchanged: the library's VERIFY path is\n",
|
||||
"certificate-covered; the signing path is declared trusted base -\n",
|
||||
"but it is the attested artifact, not an un-attested third\n",
|
||||
|
|
@ -130,12 +131,13 @@
|
|||
"\n",
|
||||
"## The post-quantum line, held honestly\n",
|
||||
"\n",
|
||||
"The dogfood loop deliberately does NOT extend to ML-DSA. There is no formally verified ML-DSA implementation in this corpus, and pretending otherwise would poison the whole posture. The hybrid strategy is therefore asymmetric on purpose:\n",
|
||||
"The posture has three legs now, and each is exactly as strong as it claims:\n",
|
||||
"\n",
|
||||
"- **Ed25519 (classical): proven path.** The signature everyone can check today runs on certificate-covered code.\n",
|
||||
"- **ML-DSA-65 (post-quantum): required, honest, unavailable-until-real.** The tree-head slot exists in every signed structure; `--require-signatures both` fails CLOSED on hosts without a real FIPS 204 backend; and when a real backend lands, the policy flips on without a schema change.\n",
|
||||
"- **Ed25519 (classical): proven verify path, dogfooded.** The signature everyone can check today runs on certificate-covered code.\n",
|
||||
"- **SLH-DSA-SHA2-128s (post-quantum): shipped and attested.** Since tree size 14 every live head carries a second, deterministic SLH-DSA co-signature. The estate proved the VERIFY path of a pinned Rust FIPS 205 implementation (eleven certificates) and appended that attestation as leaf 18 - so the co-signature uses exactly the parameter set the log itself attests. Consumers check it with `pacta receipt-verify ... --slhdsa-public-key provider.slhdsa.pub` or the mirror's `verify.py`. Signing remains unproven - verify paths only, always.\n",
|
||||
"- **ML-DSA-65 (lattice PQ): required, honest, unavailable-until-real.** The tree-head slot exists in every signed structure; `--require-signatures both` fails CLOSED on hosts without a real FIPS 204 backend; when a real backend lands, the policy flips on without a schema change.\n",
|
||||
"\n",
|
||||
"A migration strategy that records \"we cannot do this yet\" as a deployment blocker is strictly stronger than one that ships a placeholder. Blockers get fixed; placeholders get trusted.\n"
|
||||
"A migration strategy that records \"we cannot do this yet\" as a deployment blocker is strictly stronger than one that ships a placeholder. Blockers get fixed; placeholders get trusted. And the SLH-DSA leg shows the endgame: a slot stops being aspirational the day its verify path enters the log.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
"## Why a quorum, when one proof would do?\n",
|
||||
"\n",
|
||||
"Each member is *proven* to decide the same predicate,\n",
|
||||
"`accept(A,m,R,s) ⇔ decompress(R) = [k](−A) + [s]B`. So on the\n",
|
||||
"`accept(A,m,R,s) \u21d4 decompress(R) = [k](\u2212A) + [s]B`. So on the\n",
|
||||
"proven domain they cannot disagree about *meaning*. Classic\n",
|
||||
"N-version programming hopes independent code won't share a bug;\n",
|
||||
"we do not hope - we know the semantics coincide, so a runtime\n",
|
||||
|
|
@ -343,8 +343,8 @@
|
|||
"\n",
|
||||
"Open `/deck` for all six role stations live in parallel (the quorum bench you built is the\n",
|
||||
"indigo pane; the ledger you hash-chained is re-verified on every page load), and `/manual`\n",
|
||||
"for the lab-manual sessions that teach each role — Session 4's tamper drill breaks a *copy*\n",
|
||||
"of a ledger exactly like this notebook's and watches two independent surfaces catch it."
|
||||
"for the lab-manual sessions that teach each role \u2014 Session 4's tamper drill breaks a *copy*\n",
|
||||
"of a ledger exactly like this notebook's and watches two independent surfaces catch it.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Lecture 11: The Customer's-Eye View — You Hold the Ruler\n",
|
||||
"# Lecture 11: The Customer's-Eye View \u2014 You Hold the Ruler\n",
|
||||
"\n",
|
||||
"Every earlier lecture looked at the log from the *operator's*\n",
|
||||
"side: replaying proofs, signing attestations, building the\n",
|
||||
"tree. This one flips the telescope. You are now a customer — an\n",
|
||||
"agent, a wallet, a developer — who wants to trust one of the\n",
|
||||
"tree. This one flips the telescope. You are now a customer \u2014 an\n",
|
||||
"agent, a wallet, a developer \u2014 who wants to trust one of the\n",
|
||||
"four verified Ed25519 forks and has no theorem prover, no Lean,\n",
|
||||
"no desire to spend hours re-checking anything. What actually\n",
|
||||
"happens on your side? The answer reframes the whole system, and\n",
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
"\n",
|
||||
"- Separate the three roles that a verification touches:\n",
|
||||
" *measurement* (operator), *publication* (the log), and\n",
|
||||
" *judgment* (you) — and see that only the last is yours.\n",
|
||||
" *judgment* (you) \u2014 and see that only the last is yours.\n",
|
||||
"- Understand the \"allowed axioms\" list as a **requirements\n",
|
||||
" card** you own, can read, and could write yourself.\n",
|
||||
"- Explain why a self-written card meeting the supply *exactly*\n",
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## The card is a requirements card — and ideally you write it\n",
|
||||
"## The card is a requirements card \u2014 and ideally you write it\n",
|
||||
"\n",
|
||||
"The list of axioms a certificate is *allowed* to rest on is not\n",
|
||||
"handed to you by the operator at verification time. It ships\n",
|
||||
|
|
@ -85,12 +85,12 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Wish meets supply — and it is no accident\n",
|
||||
"## Wish meets supply \u2014 and it is no accident\n",
|
||||
"\n",
|
||||
"Now compare your self-written card against what the four forks\n",
|
||||
"actually declare. They match. That convergence is *engineered*:\n",
|
||||
"the supply was deliberately shrunk — every axiom made to justify\n",
|
||||
"its existence — so that any reasonable person's independently\n",
|
||||
"the supply was deliberately shrunk \u2014 every axiom made to justify\n",
|
||||
"its existence \u2014 so that any reasonable person's independently\n",
|
||||
"written card lands on the same minimal list. When the wish meets\n",
|
||||
"the supply exactly, it is because the supplier spent months\n",
|
||||
"making the supply as small as honesty allows.\n"
|
||||
|
|
@ -131,20 +131,20 @@
|
|||
"\n",
|
||||
"Only judgment is yours, and it is the only step that involves an\n",
|
||||
"opinion. The operator is trusted to *copy down what the kernel\n",
|
||||
"printed* — never to interpret it.\n"
|
||||
"printed* \u2014 never to interpret it.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## If you are happy — you are already finished\n",
|
||||
"## If you are happy \u2014 you are already finished\n",
|
||||
"\n",
|
||||
"If your card covers the observed cone, verification is: check\n",
|
||||
"one signature, walk ~4 hashes to the signed root, compare cones\n",
|
||||
"to your card. Milliseconds, standard library, no Lean. Done.\n",
|
||||
"\n",
|
||||
"## If you are NOT happy — there is nothing to negotiate\n",
|
||||
"## If you are NOT happy \u2014 there is nothing to negotiate\n",
|
||||
"\n",
|
||||
"Suppose your card is stricter: *\"I require SHA-512 itself\n",
|
||||
"proven, not an oracle.\"* The system has no sales pitch for you.\n",
|
||||
|
|
@ -152,7 +152,7 @@
|
|||
"*not in supply; SHA-512-proven is the R5 frontier; here is the\n",
|
||||
"exact list of what you would be accepting if you proceed\n",
|
||||
"anyway.* Your decision is never \"lower my standards\" in the\n",
|
||||
"abstract — it is a named line item: *SHA-512 as oracle: yes/no.*\n",
|
||||
"abstract \u2014 it is a named line item: *SHA-512 as oracle: yes/no.*\n",
|
||||
"Informed compromise, not diffuse trust.\n"
|
||||
]
|
||||
},
|
||||
|
|
@ -180,7 +180,7 @@
|
|||
"\n",
|
||||
"The gap between anyone's dream card and today's supply is a\n",
|
||||
"to-do list, not a wall. Prove SHA-512, certify the wire\n",
|
||||
"parsers, and the new certificates enter the same log — and\n",
|
||||
"parsers, and the new certificates enter the same log \u2014 and\n",
|
||||
"stricter cards start passing. The log is additive in exactly\n",
|
||||
"the way requirements are.\n",
|
||||
"\n",
|
||||
|
|
@ -211,19 +211,6 @@
|
|||
" card and the supply)? What single action by a customer\n",
|
||||
" settles the argument in their favor?\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Do it in the cockpit: the Inspect instrument\n",
|
||||
"\n",
|
||||
"The recomputation this notebook performs by hand is exactly what the cockpit's **Inspect**\n",
|
||||
"instrument (`/inspect`) runs on paste — same deployed verifier, verbatim diagnostics —\n",
|
||||
"and what the lab manual's Cryptographer session drills: verify the sample evidence, then\n",
|
||||
"deliberately corrupt one character and learn the distinct failure surfaces.\n",
|
||||
"`pacta wallet cockpit --demo`, then Inspect → “Load the sample evidence”."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ COURSE = {
|
|||
- Perform a proof hygiene scan and explain why `sorry`, local axioms, and trivial theorem targets are dangerous.
|
||||
- Explain how a third-party proof-checking provider changes the trusted base.
|
||||
- Implement and verify RFC 9162-style Merkle inclusion and consistency proofs.
|
||||
- Explain why Signed Tree Heads need accountable signatures, why Ed25519 is useful here, and why ML-DSA requires a real backend.
|
||||
- Explain why Signed Tree Heads need accountable signatures, why Ed25519 is useful here, why ML-DSA requires a real backend, and how the shipped SLH-DSA co-signature differs from both.
|
||||
- Design policy gates that convert verification evidence into consequences.
|
||||
- Read R4 four-tier apex evidence, name its residual blockers, and write a research plan toward R5 production assurance.
|
||||
"""
|
||||
|
|
@ -1029,6 +1029,7 @@ COURSE = {
|
|||
|
||||
- `require-signatures ed25519`: verify Ed25519 and allow ML-DSA to be unavailable.
|
||||
- `require-signatures both`: require Ed25519 and ML-DSA verified. If ML-DSA is unavailable, fail closed.
|
||||
- `--slhdsa-public-key <pem>`: additionally verify the second (post-quantum) SLH-DSA co-signature on the head; heads before tree size 14 report `absent` (allowed), a present-but-wrong signature fails closed.
|
||||
"""
|
||||
),
|
||||
code(
|
||||
|
|
@ -1050,6 +1051,53 @@ COURSE = {
|
|||
ML-DSA adds post-quantum robustness for the accumulator signature layer. But it must be a real signature, not an aspirational label. If a host lacks ML-DSA, the correct result is an explicit blocker.
|
||||
"""
|
||||
),
|
||||
md(
|
||||
"""
|
||||
## The second signature that actually shipped: SLH-DSA
|
||||
|
||||
Since tree size 14, every head of the LIVE log carries a second,
|
||||
deterministic **SLH-DSA-SHA2-128s** (FIPS 205) signature beside the
|
||||
required Ed25519 one. This is not the ML-DSA slot above - it is a
|
||||
hash-based scheme, and it was chosen because the estate has PROVEN
|
||||
its verify path (eleven certificates, log leaf 18): the log
|
||||
co-signs with the parameter set whose verification path it itself
|
||||
attests. Three design facts worth internalizing:
|
||||
|
||||
1. Heads published before size 14 carry no co-signature, and
|
||||
verifiers report them `ABSENT` rather than failing them - an
|
||||
append-only log keeps the history of its own signature-scheme
|
||||
upgrades.
|
||||
2. The co-signature is deterministic on purpose: re-signing the
|
||||
same payload is byte-comparable, so "same input, same
|
||||
signature" becomes a diff you can run, not an assurance you
|
||||
must trust.
|
||||
3. Signing is still never proven - here, as everywhere in this
|
||||
estate, certificates cover the VERIFY path only.
|
||||
"""
|
||||
),
|
||||
code(
|
||||
"""
|
||||
# Runnable where OpenSSL >= 3.5 is present; honest skip otherwise.
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
from pacta import slhdsa
|
||||
|
||||
tmp = Path(tempfile.mkdtemp(prefix="nb06-slhdsa-"))
|
||||
try:
|
||||
slhdsa.generate_slhdsa_keypair(tmp / "slh.key", tmp / "slh.pub")
|
||||
except Exception as exc:
|
||||
print("SLH-DSA unavailable on this host (OpenSSL >= 3.5 needed):", exc)
|
||||
else:
|
||||
payload = b"canonical STH payload bytes"
|
||||
block = slhdsa.slh_dsa_signature_block(payload, tmp / "slh.key", tmp / "slh.pub")
|
||||
ok, err = slhdsa.verify_payload_slhdsa(payload, block["signature_base64"], tmp / "slh.pub")
|
||||
print("co-signature verifies:", ok, err or "")
|
||||
block2 = slhdsa.slh_dsa_signature_block(payload, tmp / "slh.key", tmp / "slh.pub")
|
||||
print("deterministic (byte-equal re-sign):",
|
||||
block["signature_base64"] == block2["signature_base64"])
|
||||
"""
|
||||
),
|
||||
md(
|
||||
"""
|
||||
## Two domains, two notebooks - by design
|
||||
|
|
@ -1749,6 +1797,7 @@ COURSE = {
|
|||
- Modify a claim card to R2 and show that `build-library` is refused.
|
||||
- Explain why a denial artifact is useful for auditability.
|
||||
- Design a policy where an agent requires `both` Ed25519 and ML-DSA signatures for production deployment but allows Ed25519-only in a local lab.
|
||||
- Extend it: when should the agent also require the SLH-DSA co-signature, given that heads before tree size 14 legitimately lack it?
|
||||
- Write a downstream Rust pseudo-code snippet that imports the generated capsule before enabling a code path.
|
||||
"""
|
||||
),
|
||||
|
|
@ -1770,7 +1819,7 @@ COURSE = {
|
|||
- State precisely which parts of the dogfood verifier are certificate-covered and which are its trusted base.
|
||||
- Extract a raw Ed25519 key from an OpenSSL PEM by hand (napkin) and mechanically (real).
|
||||
- Demonstrate backend dispatch and the fail-closed `--require-verified-verifier` policy.
|
||||
- Defend the hybrid post-quantum posture: one proven-classical signature plus one required-but-honest ML-DSA slot.
|
||||
- Defend the three-legged post-quantum posture: proven-classical Ed25519, the shipped SLH-DSA co-signature with its attested verify path, and a required-but-honest ML-DSA slot.
|
||||
"""
|
||||
),
|
||||
md(
|
||||
|
|
@ -1858,7 +1907,8 @@ COURSE = {
|
|||
leaf, against the very tree it is about to sign. The verdict is
|
||||
embedded in the signature block (`signing_provenance`: backend,
|
||||
library commit, leaf index, `self_inclusion: verified`,
|
||||
certificates 16/16). Lectures 6a/6b walk both sides of this.
|
||||
certificates 44/44 - the signer's source family was re-attested at 44
|
||||
certificates as leaf 13). Lectures 6a/6b walk both sides of this.
|
||||
Honesty note unchanged: the library's VERIFY path is
|
||||
certificate-covered; the signing path is declared trusted base -
|
||||
but it is the attested artifact, not an un-attested third
|
||||
|
|
@ -1866,12 +1916,13 @@ COURSE = {
|
|||
|
||||
## The post-quantum line, held honestly
|
||||
|
||||
The dogfood loop deliberately does NOT extend to ML-DSA. There is no formally verified ML-DSA implementation in this corpus, and pretending otherwise would poison the whole posture. The hybrid strategy is therefore asymmetric on purpose:
|
||||
The posture has three legs now, and each is exactly as strong as it claims:
|
||||
|
||||
- **Ed25519 (classical): proven path.** The signature everyone can check today runs on certificate-covered code.
|
||||
- **ML-DSA-65 (post-quantum): required, honest, unavailable-until-real.** The tree-head slot exists in every signed structure; `--require-signatures both` fails CLOSED on hosts without a real FIPS 204 backend; and when a real backend lands, the policy flips on without a schema change.
|
||||
- **Ed25519 (classical): proven verify path, dogfooded.** The signature everyone can check today runs on certificate-covered code.
|
||||
- **SLH-DSA-SHA2-128s (post-quantum): shipped and attested.** Since tree size 14 every live head carries a second, deterministic SLH-DSA co-signature. The estate proved the VERIFY path of a pinned Rust FIPS 205 implementation (eleven certificates) and appended that attestation as leaf 18 - so the co-signature uses exactly the parameter set the log itself attests. Consumers check it with `pacta receipt-verify ... --slhdsa-public-key provider.slhdsa.pub` or the mirror's `verify.py`. Signing remains unproven - verify paths only, always.
|
||||
- **ML-DSA-65 (lattice PQ): required, honest, unavailable-until-real.** The tree-head slot exists in every signed structure; `--require-signatures both` fails CLOSED on hosts without a real FIPS 204 backend; when a real backend lands, the policy flips on without a schema change.
|
||||
|
||||
A migration strategy that records "we cannot do this yet" as a deployment blocker is strictly stronger than one that ships a placeholder. Blockers get fixed; placeholders get trusted.
|
||||
A migration strategy that records "we cannot do this yet" as a deployment blocker is strictly stronger than one that ships a placeholder. Blockers get fixed; placeholders get trusted. And the SLH-DSA leg shows the endgame: a slot stops being aspirational the day its verify path enters the log.
|
||||
"""
|
||||
),
|
||||
code(
|
||||
|
|
@ -2310,6 +2361,23 @@ COURSE = {
|
|||
trusted for after you do.
|
||||
"""
|
||||
),
|
||||
md(
|
||||
"""
|
||||
## The human surface: see this wallet through the cockpit
|
||||
|
||||
Everything this notebook built programmatically has a read-only human console:
|
||||
|
||||
```
|
||||
pacta wallet cockpit --demo # throwaway demo wallet, zero setup
|
||||
pacta wallet cockpit --wallet DIR # the wallet you just sealed here
|
||||
```
|
||||
|
||||
Open `/deck` for all six role stations live in parallel (the quorum bench you built is the
|
||||
indigo pane; the ledger you hash-chained is re-verified on every page load), and `/manual`
|
||||
for the lab-manual sessions that teach each role — Session 4's tamper drill breaks a *copy*
|
||||
of a ledger exactly like this notebook's and watches two independent surfaces catch it.
|
||||
"""
|
||||
),
|
||||
]
|
||||
),
|
||||
"11_the_customers_eye_view.ipynb": notebook(
|
||||
|
|
|
|||
Loading…
Reference in a new issue