mirror of
https://github.com/saymrwulf/proof-aware-crypto-tooling-agent.git
synced 2026-09-03 19:53:43 +00:00
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.
184 lines
9.8 KiB
Text
184 lines
9.8 KiB
Text
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Lecture 9: Eat Your Own Dogfood - Verified Crypto in the Agent's Own Loop\n",
|
|
"\n",
|
|
"Every lecture so far had the agent consume EVIDENCE about a verified Ed25519 implementation while checking that evidence's signatures with OpenSSL - an unverified implementation of the very primitive the evidence is about. That is a defensible bootstrap, but it leaves an ironic gap. This lecture closes it: pacta can build a verifier binary from the PINNED, PROVEN source workspace - the exact commit the dalek certificates pin, serial backend pinned exactly as the verified extraction pins it - and route its own signature checks through it.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Learning Objectives\n",
|
|
"\n",
|
|
"- 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 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"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## What \"verified\" means here - the honest ledger\n",
|
|
"\n",
|
|
"The binary calls `ed25519_dalek::VerifyingKey::verify` in the pinned workspace. The certificates cover `verify_sha512`, the extraction-refactored image of that same path (the delta is the documented hash-wrapper refactor in the pinned source). Certificate-covered: field arithmetic, the group law, scalars, encoding/decoding, constructive decompression, and the four-tier acceptance criterion. Trusted base: SHA-512 (an oracle in the theorems - the proofs hold for whatever bytes it produces), roughly fifteen lines of wire glue, rustc, and the extraction pipeline. The provenance sidecar written at build time records the source commit, the backend cfg, and this exact coverage note - the dogfood claim is itself a claim card.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Napkin: read a PEM with your eyes\n",
|
|
"\n",
|
|
"An OpenSSL Ed25519 public key PEM is a base64-wrapped DER SubjectPublicKeyInfo (RFC 8410), and for this one algorithm the DER is FIXED: twelve prefix bytes `302a300506032b6570032100`, then the raw 32-byte key. Decode one by hand:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from pathlib import Path\n",
|
|
"import base64, subprocess, sys, tempfile\n",
|
|
"\n",
|
|
"repo_root = Path.cwd()\n",
|
|
"if not (repo_root / \"src\" / \"pacta\").exists():\n",
|
|
" repo_root = repo_root.parent\n",
|
|
"sys.path.insert(0, str(repo_root / \"src\"))\n",
|
|
"\n",
|
|
"from pacta.signing import generate_ed25519_keypair\n",
|
|
"\n",
|
|
"tmp = Path(tempfile.mkdtemp(prefix=\"dogfood-lecture-\"))\n",
|
|
"generate_ed25519_keypair(tmp / \"k.key\", tmp / \"k.pub\")\n",
|
|
"pem = (tmp / \"k.pub\").read_text()\n",
|
|
"print(pem)\n",
|
|
"body = \"\".join(line for line in pem.splitlines() if \"-----\" not in line)\n",
|
|
"der = base64.b64decode(body)\n",
|
|
"print(\"DER length:\", len(der), \"(should be 12 + 32 = 44)\")\n",
|
|
"print(\"prefix: \", der[:12].hex(), \"(the fixed Ed25519 SPKI header)\")\n",
|
|
"print(\"raw key: \", der[12:].hex())\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# REAL: the same extraction, mechanically, with validation - and the\n",
|
|
"# dispatch that prefers the proven-path binary when it exists.\n",
|
|
"from pacta.dogfood import locate_verifier, pem_public_key_to_raw\n",
|
|
"from pacta.signing import sign_payload_ed25519, verify_payload_ed25519_detailed\n",
|
|
"\n",
|
|
"raw = pem_public_key_to_raw(tmp / \"k.pub\")\n",
|
|
"assert raw == der[12:]\n",
|
|
"print(\"mechanical extraction matches the napkin:\", raw.hex()[:16], \"...\")\n",
|
|
"\n",
|
|
"payload = b\"the agent checks its own evidence\"\n",
|
|
"signature = sign_payload_ed25519(payload, tmp / \"k.key\")\n",
|
|
"ok, error, backend = verify_payload_ed25519_detailed(payload, signature, tmp / \"k.pub\")\n",
|
|
"print(\"valid:\", ok, \"| backend:\", backend)\n",
|
|
"binary = locate_verifier()\n",
|
|
"print(\"dogfood binary:\", binary or \"not built (OpenSSL fallback in effect - a recorded downgrade)\")\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Build the proven-path verifier once per machine (it needs a local checkout of the pinned source workspace and cargo):\n",
|
|
"\n",
|
|
"```bash\n",
|
|
"pacta dogfood-build --source ~/GitClone/FormalVerification/sources/curve25519-dalek-source\n",
|
|
"pacta dogfood-status\n",
|
|
"```\n",
|
|
"\n",
|
|
"With the binary in place, every receipt and attestation check reports `ed25519_backend: verified-dalek-serial`, and policies can DEMAND it:\n",
|
|
"\n",
|
|
"```bash\n",
|
|
"pacta receipt-verify ... --require-verified-verifier # fails closed on OpenSSL fallback\n",
|
|
"pacta agent ... --require-verified-verifier ...\n",
|
|
"```\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Dogfood in BOTH directions\n",
|
|
"\n",
|
|
"Since this lecture was first written the loop closed on the\n",
|
|
"provider's side too: the binary gained a `sign` mode, so the\n",
|
|
"transparency log's tree heads are now SIGNED by the merkleized\n",
|
|
"library - and before every signature the provider runs the same\n",
|
|
"Merkle inclusion check an agent runs, on its own signing library's\n",
|
|
"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 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",
|
|
"implementation.\n",
|
|
"\n",
|
|
"## The post-quantum line, held honestly\n",
|
|
"\n",
|
|
"The posture has three legs now, and each is exactly as strong as it claims:\n",
|
|
"\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. And the SLH-DSA leg shows the endgame: a slot stops being aspirational the day its verify path enters the log.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from pacta.postquantum import detect_ml_dsa\n",
|
|
"\n",
|
|
"capability = detect_ml_dsa()\n",
|
|
"print(\"ml-dsa available:\", capability.available)\n",
|
|
"print(\"reason:\", capability.reason)\n",
|
|
"print(\"slot as recorded in every STH:\", capability.to_signature_slot())\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Exercises\n",
|
|
"\n",
|
|
"- Flip one byte of a signature and verify through both backends; confirm both reject and that the BACKEND that rejected is recorded.\n",
|
|
"- The dogfood binary's trusted base includes rustc. The certificates' trusted base includes Charon/Aeneas. Draw the two trust diagrams side by side; which assumptions are shared?\n",
|
|
"- Napkin, then real: decode a second PEM by hand; then corrupt its DER prefix and confirm `pem_public_key_to_raw` rejects it.\n",
|
|
"- Policy design: when should an agent REFUSE to fall back to OpenSSL? Write the deployment rule and its recovery path.\n",
|
|
"- Research checkpoint: what would a proof-carrying SHA-512 change about the coverage note in the provenance sidecar?\n"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"name": "python",
|
|
"pygments_lexer": "ipython3"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|