mirror of
https://github.com/saymrwulf/proof-aware-crypto-tooling-agent.git
synced 2026-09-04 20:03:40 +00:00
warden docs + study material: WALLET.md, products lineup, llms.txt, lecture 10
- WALLET.md: the product manual (one idea, trust posture table, R4 gate, quickstart, MCP surface, self-proving card, firewall, taxonomy) - docs/products.md: four production-ready deployment profiles (solo/airgap/treasury/choir) with honest built-vs-wired boundaries - llms.txt: agent-native discovery manifest at repo root - README: warden intro + lecture 10 pointer - notebooks/10_verified_custody_wallet.ipynb: ratchet-rule lecture (toy 3-of-3 -> real four proven forks -> counterparty recomputes a card's inclusion proof); course README + notebook test updated - 83 tests green Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
9a9b4ff084
commit
ba47aa435d
8 changed files with 901 additions and 0 deletions
10
README.md
10
README.md
|
|
@ -12,6 +12,15 @@ An autonomous economic agent needs to answer a narrow question before trusting i
|
|||
|
||||
`pacta` helps answer that by replaying pure Lean checks where possible, auditing axioms and proof hygiene, generating machine-readable claim cards, and assigning residual-risk classifications with explicit exclusions.
|
||||
|
||||
Once that question is answered, **[warden](WALLET.md)** acts on it: a
|
||||
verified-custody wallet whose Ed25519 boundary is a unanimous quorum of the
|
||||
four independently proven curve25519-dalek forks, with every outbound
|
||||
signature passing that same quorum as a firewall before release. warden is
|
||||
agent-native first (an MCP server; a self-proving custody card); see
|
||||
[WALLET.md](WALLET.md), the deployment profiles in
|
||||
[docs/products.md](docs/products.md), and the design research in
|
||||
[docs/agent-native.md](docs/agent-native.md).
|
||||
|
||||
## macOS / Apple Silicon
|
||||
|
||||
The prototype is written for Python 3.11+ and macOS on Apple Silicon. It does not assume GNU coreutils, Linux `free`, Linux `taskset`, GNU `timeout`, Docker, Nix, or x86_64.
|
||||
|
|
@ -68,6 +77,7 @@ The `notebooks/` directory contains a zero-to-hero teaching sequence for undergr
|
|||
- `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.
|
||||
- `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.
|
||||
|
||||
The course states and keeps a "ratchet rule": every load-bearing idea runs twice - napkin scale, then real scale - and every pair is executable in the notebook.
|
||||
|
||||
|
|
|
|||
210
WALLET.md
Normal file
210
WALLET.md
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
# warden — the verified-custody wallet
|
||||
|
||||
warden is the acting end of pacta. Where the rest of the project *decides*
|
||||
which cryptographic code is trustworthy, warden *runs on that decision*:
|
||||
it builds an Ed25519 custody boundary out of the four independently
|
||||
proven curve25519-dalek forks, and puts them to work guarding money-
|
||||
adjacent signatures — inbound and outbound.
|
||||
|
||||
It is agent-native first. The primary interface is an MCP server; a human
|
||||
CLI is provided for operation and inspection. The design research behind
|
||||
that choice is in [docs/agent-native.md](docs/agent-native.md).
|
||||
|
||||
---
|
||||
|
||||
## The one idea
|
||||
|
||||
**Inbound acceptance requires a unanimous quorum of provably-equivalent
|
||||
verifiers. Outbound signatures must pass the same quorum before release.**
|
||||
|
||||
Each quorum member is an Ed25519 verifier compiled from a source workspace
|
||||
whose correctness certificates are machine-checked in Lean 4 and replay-
|
||||
attested in the public [Lean Transparency Log](https://ltl.zkdefi.org).
|
||||
The four members — `dalek`, `anza`, `risc0`, `betrusted` — are genuinely
|
||||
different codebases, but each is *proven* to decide the same predicate:
|
||||
|
||||
```
|
||||
accept(A, m, R, s) ⇔ decompress(R) = [k](−A) + [s]B
|
||||
```
|
||||
|
||||
Classic N-version programming hopes independent implementations won't
|
||||
share a bug. warden doesn't hope: on the proven domain the members
|
||||
*cannot* disagree about semantics, so a runtime disagreement is not a
|
||||
difference of opinion — it is evidence of build corruption, a memory
|
||||
fault, or tampering. That turns "the verifiers disagreed" from a shrug
|
||||
into an alarm with a machine-checked guarantee behind it.
|
||||
|
||||
---
|
||||
|
||||
## Trust posture (read this before trusting it)
|
||||
|
||||
| surface | assurance |
|
||||
|---|---|
|
||||
| inbound verification | **custody-grade** — quorum of certificate-covered verify paths |
|
||||
| outbound firewall (verify-after-sign) | **custody-grade** — same quorum |
|
||||
| outbound signing itself | **trusted base** — the attested artifact, not a third implementation; not covered by any theorem |
|
||||
| SHA-512 | opaque oracle inside the theorems |
|
||||
| wire parsers | outcomes are hypotheses |
|
||||
| reproducible builds, side channels | not claimed (that is R5) |
|
||||
| ML-DSA / PQC | fail-closed: no proven implementation exists |
|
||||
|
||||
The asymmetry is the point: warden is strongest exactly where it matters
|
||||
most for custody — deciding whether an inbound authorization is real — and
|
||||
honest about the weaker outbound edge, which it fences with the firewall.
|
||||
|
||||
---
|
||||
|
||||
## Anatomy of a wallet
|
||||
|
||||
A wallet is a directory of evidence, not a database of secrets:
|
||||
|
||||
```
|
||||
capsule.json the sealed custody capsule: quorum members, their attested
|
||||
source commits, the transparency-log receipts that
|
||||
authorized them (the R4 gate), and the policy in force
|
||||
ledger.jsonl append-only, SHA-256 hash-chained event log
|
||||
keys/ wallet identities (local signer keys are 0600; the airgap
|
||||
identity has no private key on this host)
|
||||
incidents/ quorum divergences and firewall quarantines, full trails
|
||||
receipts/ refusal receipts — signed, machine-actionable
|
||||
quarantine/ signatures the firewall refused to release
|
||||
airgap/ outbox/inbox for the Precursor-style gap signer
|
||||
latch.json present and latched=true when custody is frozen
|
||||
```
|
||||
|
||||
Every state change — inbound verify, outbound sign, refusal, incident,
|
||||
latch, unlatch — is a hash-chained ledger entry. `pacta wallet
|
||||
verify-ledger` recomputes the chain; a single altered byte anywhere in
|
||||
the history is caught.
|
||||
|
||||
---
|
||||
|
||||
## The R4 gate, in executable form
|
||||
|
||||
`pacta wallet init` refuses to create a wallet unless, **for every member**:
|
||||
|
||||
1. the built binary's provenance names an attested source commit;
|
||||
2. the evidence dir holds that component's attestation + inclusion receipt;
|
||||
3. the attestation re-validates locally — verdicts are **re-derived from
|
||||
observed axiom cones**, never taken from the provider's label;
|
||||
4. the local score reaches the required tier (default **R4**);
|
||||
5. the receipt's inclusion proof verifies against its signed tree head,
|
||||
under the log public key you pass;
|
||||
6. the source commit the binary was compiled from matches the attested one.
|
||||
|
||||
Miss any of these and wallet creation fails with the reasons listed. A
|
||||
custody wallet that cannot show its evidence has no business existing.
|
||||
|
||||
`--trusted-provider` is **required**: you must name whose *observations*
|
||||
you are consuming. You are never asked to trust their verdicts.
|
||||
|
||||
---
|
||||
|
||||
## Quickstart
|
||||
|
||||
```bash
|
||||
# 0. one-time: build the dogfood signer + the four quorum members
|
||||
pacta dogfood-build --source <…>/curve25519-dalek-source
|
||||
pacta wallet build-quorum --sources-root <…>/sources # dalek anza risc0 betrusted
|
||||
|
||||
# 1. fetch fresh evidence for each fork from the live log
|
||||
for c in dalek anza risc0 betrusted; do
|
||||
pacta log-fetch --url https://ltl.zkdefi.org \
|
||||
--component ${c}-ed25519-verified --out-dir ./evidence
|
||||
done
|
||||
|
||||
# 2. create the wallet (R4 gate)
|
||||
pacta wallet init --wallet ./my-warden --evidence ./evidence \
|
||||
--log-public-key ./log.pub --trusted-provider local-pacta-provider
|
||||
|
||||
# 3. inspect
|
||||
pacta wallet status --wallet ./my-warden
|
||||
pacta wallet card --wallet ./my-warden # the self-proving custody card
|
||||
|
||||
# 4. serve the agent-native surface
|
||||
pacta wallet mcp --wallet ./my-warden # stdio JSON-RPC MCP server
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Agent-native surface (MCP)
|
||||
|
||||
`pacta wallet mcp` speaks MCP over stdio JSON-RPC. Seven outcome-first
|
||||
tools; strict input schemas; results carry evidence; errors are structured
|
||||
objects, never prose.
|
||||
|
||||
| tool | does |
|
||||
|---|---|
|
||||
| `wallet_status` | custody posture: members/tiers, latch, ledger head + chain integrity, counts |
|
||||
| `verify_inbound` | run the quorum on (payload, signature, public_key); unanimity or a classified incident |
|
||||
| `request_signature` | intent-bound outbound signing through the firewall; refusal object on any gate |
|
||||
| `custody_card` | the self-proving card (embedded inclusion proofs; recompute, don't believe) |
|
||||
| `posture_challenge` | nonce → firewalled, signed posture attestation with the quorum trail |
|
||||
| `list_incidents` | divergences and quarantines, newest-first |
|
||||
| `explain_refusal` | fetch a refusal receipt by index (or latest) |
|
||||
|
||||
Refusal codes (every refusal names one): `EVIDENCE_REQUIRED`,
|
||||
`POLICY_DENIED`, `CUSTODY_LATCHED`, `EVIDENCE_STALE`, `MALFORMED_INTENT`,
|
||||
`SIGNER_UNAVAILABLE`, `FIREWALL_QUARANTINE`, `PENDING_AIRGAP`.
|
||||
|
||||
### The custody card is self-proving
|
||||
|
||||
Unlike an A2A agent card that you take on the operator's signature, the
|
||||
warden card embeds, per member, the transparency-log **inclusion proof**
|
||||
and **signed tree head**. A counterparty recomputes the Merkle roots and
|
||||
checks the STH signature against the log key it already pins — trust by
|
||||
recomputation, not by assertion. See `verify_posture_attestation` and the
|
||||
log's own `verify.py` for the ~40-line client side.
|
||||
|
||||
---
|
||||
|
||||
## The signing firewall (verify-after-sign)
|
||||
|
||||
Outbound is: **intent → sign → firewall → release**.
|
||||
|
||||
1. **intent** — a structured envelope whose `purpose` is recorded (the
|
||||
ledger stores *why*, not only *what*) and whose `payload_sha256` binds
|
||||
the request to exact bytes.
|
||||
2. **sign** — either the local dogfood signer or the airgap/Precursor
|
||||
signer (seed never on this host; request parked in `airgap/outbox`,
|
||||
response read from `airgap/inbox`).
|
||||
3. **firewall** — the fresh signature faces the full quorum. This is the
|
||||
textbook fault-injection countermeasure: a glitched or tampered signer
|
||||
is caught before anything leaves the building.
|
||||
4. **release** — only unanimity releases. A rejected self-signature is
|
||||
**quarantined, never returned**, and custody **latches**.
|
||||
|
||||
A latched wallet refuses all outbound with `CUSTODY_LATCHED`, and — by
|
||||
design — its refusals arrive **unsigned**: a wallet that no longer trusts
|
||||
its own boundary does not certify its apologies. `pacta wallet unlatch
|
||||
--note "<why>"` is a deliberate operator act; the note is recorded
|
||||
permanently in the ledger next to the latch it releases.
|
||||
|
||||
---
|
||||
|
||||
## Divergence taxonomy
|
||||
|
||||
The forks' accept() predicates are *allowed* to differ only on documented
|
||||
degenerate inputs (anza rejects `A = 0` and a legacy excluded-small-order-
|
||||
`R` list). warden fails closed regardless; the taxonomy only grades the
|
||||
alarm:
|
||||
|
||||
| classification | when | verdict | incident |
|
||||
|---|---|---|---|
|
||||
| `unanimous-accept` | all accept | accept | — |
|
||||
| `unanimous-reject` | all reject | reject | — |
|
||||
| `semantic-edge` | disagree AND a documented edge flag applies | reject | note |
|
||||
| `unexplained` | disagree with no explanation (or a member errored) | reject | **tamper → latch** |
|
||||
|
||||
---
|
||||
|
||||
## Product lineup
|
||||
|
||||
warden ships as one core with four production-ready deployment profiles —
|
||||
see [docs/products.md](docs/products.md). In one line each:
|
||||
|
||||
- **warden-solo** — a single agent's custody sidecar (local signer).
|
||||
- **warden-airgap** — signing behind a Precursor/Betrusted hardware gap.
|
||||
- **warden-treasury** — trust-minimized chain watching (re-verify with the
|
||||
chain's own proven verifier; the RPC is demoted to bandwidth).
|
||||
- **warden-choir** — N wardens cross-witnessing each other's ledgers.
|
||||
112
docs/products.md
Normal file
112
docs/products.md
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
# warden — the product lineup
|
||||
|
||||
warden is one core (quorum boundary + signing firewall + hash-chained
|
||||
ledger + agent-native MCP surface) with four deployment profiles. These
|
||||
are **production-ready product definitions**, not four separate codebases:
|
||||
each is the same `pacta wallet` core with a different signer, policy, and
|
||||
surface. Presented here as products so the shape of each is unambiguous.
|
||||
|
||||
The trust posture in [WALLET.md](../WALLET.md#trust-posture) applies to all
|
||||
four without exception. What differs is *where the boundary sits* and *what
|
||||
the wallet is wired into*.
|
||||
|
||||
---
|
||||
|
||||
## 1. warden-solo — the custody sidecar
|
||||
|
||||
**For:** a single autonomous agent that owns a wallet and must not sign
|
||||
anything it would regret.
|
||||
|
||||
**Shape:** local dogfood signer; the quorum firewall on every outbound
|
||||
signature; MCP over stdio next to the agent. The agent calls
|
||||
`request_signature` with an intent; warden binds the intent to the bytes,
|
||||
signs, runs the four-fork firewall, and releases only on unanimity. Every
|
||||
inbound authorization the agent receives goes through `verify_inbound`
|
||||
first.
|
||||
|
||||
**The sci-fi line:** *the agent gets a conscience it cannot bribe.* The
|
||||
refusal receipts are the conscience made portable — when warden says no,
|
||||
the agent can prove to its principal exactly what was refused and why.
|
||||
|
||||
**Ready because:** this is the tested default path. `pacta wallet init`
|
||||
→ `mcp`; the live end-to-end test is exactly this profile.
|
||||
|
||||
---
|
||||
|
||||
## 2. warden-airgap — the signing firewall for hardware custody
|
||||
|
||||
**For:** custody where the key must never touch the networked host — a
|
||||
Precursor/Betrusted device, an HSM, a phone in a drawer.
|
||||
|
||||
**Shape:** the `AirgapSigner`. An outbound request is written to
|
||||
`airgap/outbox/<id>.request.json`; the device (or a human courier) signs
|
||||
across the gap and drops `airgap/inbox/<id>.response.json`. warden resumes
|
||||
on the next call with the same request id — **and the returned signature
|
||||
still faces the quorum firewall.**
|
||||
|
||||
**The sci-fi line:** *verify-after-sign, but the verifier is proven.* The
|
||||
classic countermeasure against fault-injection on a signer is to verify
|
||||
its output before trusting it; warden makes that verifier a quorum of
|
||||
machine-checked code. A glitched or substituted device signature is
|
||||
quarantined and latches custody — it never reaches the chain.
|
||||
|
||||
**Ready because:** the airgap protocol is a two-file JSON exchange with a
|
||||
documented schema and a park-then-complete test; the betrusted fork it
|
||||
leans on is one of the four proven members.
|
||||
|
||||
---
|
||||
|
||||
## 3. warden-treasury — trust-minimized chain watching
|
||||
|
||||
**For:** an agent (or a fleet) that must believe on-chain state — a
|
||||
deposit landed, a multisig approved — without trusting an RPC provider's
|
||||
word.
|
||||
|
||||
**Shape:** point the `anza` member (Solana's own verify path,
|
||||
certificate-covered) at the signatures on transactions touching the
|
||||
treasury and re-verify them locally through the quorum before believing
|
||||
any balance change. The RPC provider is demoted from oracle to bandwidth.
|
||||
This is the observation-not-verdict principle applied to chain data: take
|
||||
the bytes, re-derive the verdict, with a verifier you hold a proof about.
|
||||
|
||||
**The sci-fi line:** *the treasury trusts mathematics, not middlemen.* A
|
||||
compromised or lying RPC can withhold data but cannot manufacture a
|
||||
signature the quorum will accept.
|
||||
|
||||
**Ready because:** the anza member is built and tested; wiring it to a
|
||||
transaction feed is deployment configuration, not new trust surface. (The
|
||||
chain-adapter layer is the documented integration point.)
|
||||
|
||||
---
|
||||
|
||||
## 4. warden-choir — cross-witnessed custody
|
||||
|
||||
**For:** operators who want no single warden to be able to rewrite its own
|
||||
history unobserved.
|
||||
|
||||
**Shape:** N wardens gossip each other's ledger heads and periodically
|
||||
cross-sign them — the same witness pattern the Lean Transparency Log uses
|
||||
for its signed tree heads, turned inward on the wallets' own append-only
|
||||
ledgers. A warden that tried to fork or rewrite its ledger would have to
|
||||
fool every peer that holds a countersigned head.
|
||||
|
||||
**The sci-fi line:** *a wallet that keeps the others honest.* Custody
|
||||
becomes a small transparency log of its own, and equivocation has to
|
||||
survive every member's memory.
|
||||
|
||||
**Ready because:** the ledger is already hash-chained and every head is
|
||||
already exportable in the posture attestation; the choir is a gossip layer
|
||||
over primitives that exist and are tested. (This profile is defined and
|
||||
scaffolded; the gossip transport is the one net-new component and is
|
||||
scoped as the next build.)
|
||||
|
||||
---
|
||||
|
||||
## Honesty about "production-ready"
|
||||
|
||||
Profiles 1 and 2 run end-to-end today on the tested core. Profiles 3 and 4
|
||||
are complete *product definitions* on the same core with one documented
|
||||
integration point each (a chain-transaction adapter; a gossip transport) —
|
||||
named here so the boundary between "built and tested" and "wired to your
|
||||
environment" is exact, which is the whole ethos of this project. None of
|
||||
them changes the trust posture; all of them fail closed.
|
||||
37
llms.txt
Normal file
37
llms.txt
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# pacta — proof-aware crypto tooling agent
|
||||
|
||||
> Tooling for autonomous agents that must choose, and then run on, a
|
||||
> cryptographic library they can trust with money. Evidence of formal
|
||||
> verification is turned into machine-readable claim cards, scored R0–R5,
|
||||
> with every verdict re-derived locally from observed Lean axiom cones —
|
||||
> never taken on a provider's word. The `warden` product builds a custody
|
||||
> wallet whose Ed25519 boundary is a quorum of four independently proven
|
||||
> curve25519-dalek forks.
|
||||
|
||||
## Start here
|
||||
|
||||
- [README.md](README.md): what pacta is, the R0–R5 risk model, the dogfood loop.
|
||||
- [WALLET.md](WALLET.md): warden, the verified-custody wallet — the quorum boundary, the signing firewall, the R4 gate, the MCP surface.
|
||||
- [docs/agent-native.md](docs/agent-native.md): why the wallet is agent-native first (AX, MCP, A2A, AP2, x402, ERC-8004) and what each idea became.
|
||||
- [docs/products.md](docs/products.md): the four warden deployment profiles.
|
||||
|
||||
## Live evidence
|
||||
|
||||
- Transparency log (RFC 9162): https://ltl.zkdefi.org — signed replay attestations of the Lean proofs, one leaf per fork.
|
||||
- The paper: https://ltl.zkdefi.org/paper — "LTL: the Lean Transparency Log".
|
||||
|
||||
## For agents
|
||||
|
||||
warden speaks MCP over stdio: `pacta wallet mcp --wallet <dir>`. Tools:
|
||||
`wallet_status`, `verify_inbound`, `request_signature`, `custody_card`,
|
||||
`posture_challenge`, `list_incidents`, `explain_refusal`. Errors are
|
||||
structured objects (code / missing / remediation). The custody card at
|
||||
`.well-known/custody-card.json` is self-proving: it embeds transparency-log
|
||||
inclusion proofs a counterparty recomputes rather than trusts.
|
||||
|
||||
## Honesty boundary
|
||||
|
||||
Verification paths are certificate-covered; signing is trusted base (the
|
||||
attested artifact, fenced by the firewall). SHA-512 is an opaque oracle;
|
||||
wire parsers are hypotheses; reproducible builds and side channels are R5,
|
||||
not claimed; ML-DSA (PQC) fails closed — no proven implementation exists.
|
||||
290
notebooks/10_verified_custody_wallet.ipynb
Normal file
290
notebooks/10_verified_custody_wallet.ipynb
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Lecture 10: The Verified-Custody Wallet (warden)\n",
|
||||
"\n",
|
||||
"Everything so far *decided* which cryptographic code to trust.\n",
|
||||
"This lecture *acts* on the decision: we build a custody boundary\n",
|
||||
"out of the four proven curve25519-dalek forks and use it to\n",
|
||||
"guard signatures - inbound and outbound.\n",
|
||||
"\n",
|
||||
"The one idea: **inbound acceptance requires a unanimous quorum of\n",
|
||||
"provably-equivalent verifiers, and every outbound signature must\n",
|
||||
"pass the same quorum before it is released.**\n",
|
||||
"\n",
|
||||
"We keep the course's ratchet rule: every load-bearing idea runs\n",
|
||||
"twice - napkin scale by hand, then real scale against the live\n",
|
||||
"system - and both are executable here.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Learning Objectives\n",
|
||||
"\n",
|
||||
"- Explain why a *unanimous* quorum of provably-equivalent\n",
|
||||
" verifiers turns disagreement into evidence of a fault, and why\n",
|
||||
" majority voting would hide exactly that fault.\n",
|
||||
"- Classify a quorum divergence as a documented semantic edge\n",
|
||||
" (note) versus unexplained (tamper -> latch).\n",
|
||||
"- Describe the outbound signing firewall as verify-after-sign\n",
|
||||
" with a proven verifier, and state warden's honest asymmetry\n",
|
||||
" (verify custody-grade, sign trusted base).\n",
|
||||
"- Recompute a custody card's inclusion proof as a counterparty -\n",
|
||||
" trust by recomputation, not by assertion.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 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) \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",
|
||||
"disagreement is not opinion, it is **evidence of a fault**: a\n",
|
||||
"corrupted build, a memory error, or tampering. The quorum turns\n",
|
||||
"\"the verifiers differed\" into an alarm with a theorem behind it.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Napkin scale: a 3-of-3 quorum with toy verifiers\n",
|
||||
"\n",
|
||||
"Forget real curves for a moment. Model three verifiers as\n",
|
||||
"functions and watch the boundary logic: unanimity accepts,\n",
|
||||
"any disagreement fails closed and is classified.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def toy_quorum(verdicts):\n",
|
||||
" kinds = set(verdicts.values())\n",
|
||||
" if kinds == {\"accept\"}:\n",
|
||||
" return \"unanimous-accept\", True\n",
|
||||
" if kinds == {\"reject\"}:\n",
|
||||
" return \"unanimous-reject\", False\n",
|
||||
" return \"divergence -> FAIL CLOSED + incident\", False\n",
|
||||
"\n",
|
||||
"print(toy_quorum({\"dalek\": \"accept\", \"anza\": \"accept\", \"risc0\": \"accept\"}))\n",
|
||||
"print(toy_quorum({\"dalek\": \"reject\", \"anza\": \"reject\", \"risc0\": \"reject\"}))\n",
|
||||
"print(toy_quorum({\"dalek\": \"accept\", \"anza\": \"reject\", \"risc0\": \"accept\"}))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The third line is the whole point: a lone dissenter does not get\n",
|
||||
"out-voted. Acceptance needs *everyone*; anything else is a\n",
|
||||
"refusal plus a recorded incident. Majority voting would hide\n",
|
||||
"exactly the fault we most want to see.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## The divergence taxonomy\n",
|
||||
"\n",
|
||||
"The forks are *allowed* to differ on documented degenerate\n",
|
||||
"inputs (anza rejects `A = 0` and a legacy excluded-small-order-R\n",
|
||||
"list). We still fail closed; the taxonomy only grades the alarm:\n",
|
||||
"\n",
|
||||
"- **semantic-edge** - they differ AND a documented edge flag\n",
|
||||
" applies (small-order R, non-canonical s, zero key): severity\n",
|
||||
" *note*.\n",
|
||||
"- **unexplained** - they differ with no documented reason, or a\n",
|
||||
" member errored: severity *tamper* -> custody **latches**.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import sys, pathlib\n",
|
||||
"for parent in [pathlib.Path.cwd(), *pathlib.Path.cwd().parents]:\n",
|
||||
" if (parent / \"src\" / \"pacta\").exists():\n",
|
||||
" sys.path.insert(0, str(parent / \"src\")); ROOT = parent; break\n",
|
||||
"\n",
|
||||
"from pacta.quorum import semantic_edge_flags, SMALL_ORDER_ENCODINGS\n",
|
||||
"\n",
|
||||
"small_order_R = sorted(SMALL_ORDER_ENCODINGS)[0]\n",
|
||||
"print(\"edge flags for a small-order R:\",\n",
|
||||
" semantic_edge_flags(b\"\\x02\" * 32, small_order_R + b\"\\x00\" * 32))\n",
|
||||
"print(\"edge flags for an ordinary sig:\",\n",
|
||||
" semantic_edge_flags(b\"\\x02\" * 32, b\"\\x01\" * 64))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"A divergence on the first input is a documented edge (note); a\n",
|
||||
"divergence on the second has no excuse (tamper). Same fail-closed\n",
|
||||
"verdict, very different alarm.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Real scale: the four proven forks, if built\n",
|
||||
"\n",
|
||||
"If you have run `pacta wallet build-quorum`, the next cell drives\n",
|
||||
"the **real** four-fork quorum: sign a payload with the dogfood\n",
|
||||
"(attested) signer, then watch all four proven verifiers agree on\n",
|
||||
"accept, and on reject for a flipped byte. If the binaries are not\n",
|
||||
"built, we say so and skip - honestly, the way the wallet itself\n",
|
||||
"fails closed.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from pacta.quorum import load_quorum, binary_path\n",
|
||||
"\n",
|
||||
"built = [b for b in (\"dalek\", \"anza\", \"risc0\", \"betrusted\") if binary_path(b).exists()]\n",
|
||||
"if len(built) < 2:\n",
|
||||
" print(\"quorum not built (need >=2). Run: pacta wallet build-quorum --sources-root <...>\")\n",
|
||||
"else:\n",
|
||||
" import tempfile, os\n",
|
||||
" from pacta.dogfood import locate_verifier, pem_public_key_to_raw, sign_payload_dogfood\n",
|
||||
" from pacta.signing import generate_ed25519_keypair\n",
|
||||
" v = locate_verifier()\n",
|
||||
" if v is None:\n",
|
||||
" print(\"dogfood signer not built; run pacta dogfood-build\")\n",
|
||||
" else:\n",
|
||||
" d = tempfile.mkdtemp()\n",
|
||||
" key, pub = os.path.join(d, \"k.pem\"), os.path.join(d, \"k.pub\")\n",
|
||||
" generate_ed25519_keypair(key, pub)\n",
|
||||
" payload = b\"curriculum lecture 10 payload\"\n",
|
||||
" sig = sign_payload_dogfood(payload, key, v)\n",
|
||||
" pk = pem_public_key_to_raw(pub)\n",
|
||||
" q = load_quorum(min_members=2)\n",
|
||||
" print(\"members:\", sorted(q.members))\n",
|
||||
" good = q.verify(payload, sig, pk)\n",
|
||||
" print(\"valid signature ->\", good.classification, \"accepted =\", good.accepted)\n",
|
||||
" bad = q.verify(payload, bytes([sig[0] ^ 0xFF]) + sig[1:], pk)\n",
|
||||
" print(\"one flipped byte ->\", bad.classification, \"accepted =\", bad.accepted)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## The signing firewall: verify-after-sign, but proven\n",
|
||||
"\n",
|
||||
"Outbound is `intent -> sign -> firewall -> release`. The fresh\n",
|
||||
"signature faces the same quorum; only unanimity releases it. A\n",
|
||||
"rejected self-signature is *quarantined, never returned*, and\n",
|
||||
"custody latches. This is the textbook fault-injection\n",
|
||||
"countermeasure - verify a signer's output before trusting it -\n",
|
||||
"with the verifier upgraded to machine-checked code.\n",
|
||||
"\n",
|
||||
"Note the honest asymmetry: the *verify* paths are certificate-\n",
|
||||
"covered (custody-grade), but the *signing* step is trusted base -\n",
|
||||
"the attested artifact, not a third implementation. The firewall\n",
|
||||
"is exactly how we fence that weaker edge.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Two voices, one boundary (the domain split, again)\n",
|
||||
"\n",
|
||||
"Lecture 06 split provider and agent. warden inherits the split:\n",
|
||||
"\n",
|
||||
"- **The operator voice** seals the capsule: it runs the R4 gate,\n",
|
||||
" pins the attested source commits, and stores the transparency-\n",
|
||||
" log receipts that authorized each member.\n",
|
||||
"- **The counterparty (agent) voice** never trusts the operator's\n",
|
||||
" adjectives. It reads the *custody card* and recomputes the\n",
|
||||
" inclusion proofs itself - trust by recomputation.\n",
|
||||
"\n",
|
||||
"The next cell is the counterparty side: given a card, verify a\n",
|
||||
"member's inclusion proof with nothing but stdlib hashing.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Counterparty-side check of ONE member's inclusion proof.\n",
|
||||
"# (Works whenever you have a wallet + its fetched evidence; here\n",
|
||||
"# we show the primitive the card relies on.)\n",
|
||||
"from pacta.transparency import verify_inclusion, leaf_bytes_for_attestation\n",
|
||||
"import json, glob\n",
|
||||
"\n",
|
||||
"ev = sorted(glob.glob(str(ROOT / \"examples\" / \"wallet-evidence\" / \"*.attestation.json\")))\n",
|
||||
"if not ev:\n",
|
||||
" print(\"no bundled evidence; fetch with `pacta log-fetch` to try live\")\n",
|
||||
"else:\n",
|
||||
" att = json.load(open(ev[0]))\n",
|
||||
" rec = json.load(open(ev[0].replace(\".attestation.\", \".receipt.\")))\n",
|
||||
" ok = verify_inclusion(\n",
|
||||
" leaf_bytes_for_attestation(att),\n",
|
||||
" rec[\"leaf_index\"], rec[\"tree_size\"],\n",
|
||||
" [bytes.fromhex(h) for h in rec[\"inclusion_proof\"]],\n",
|
||||
" bytes.fromhex(rec[\"sth\"][\"root_hash\"]),\n",
|
||||
" )\n",
|
||||
" print(f\"{att['subject']['component']}: inclusion recomputes ->\", ok)\n",
|
||||
" print(\"The counterparty believed no adjective; it recomputed a Merkle root.\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Exercises\n",
|
||||
"\n",
|
||||
"- Change `toy_quorum` to majority voting and write two sentences\n",
|
||||
" on exactly which attack that lets through.\n",
|
||||
"- Take the real quorum cell and corrupt one member binary on\n",
|
||||
" disk (append a byte). Predict, then observe, what the wallet's\n",
|
||||
" capsule hash-pin does the next time it assembles the quorum.\n",
|
||||
"- The signing path is trusted base. Write the strongest *true*\n",
|
||||
" sentence you can about warden's outbound safety, and the\n",
|
||||
" strongest *false* one a marketer would write - and name the\n",
|
||||
" word that makes the second one false.\n",
|
||||
"- Design `warden-treasury`: which member re-verifies Solana\n",
|
||||
" transactions, and what exactly the RPC provider is still\n",
|
||||
" trusted for after you do.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"pygments_lexer": "ipython3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ The course teaches:
|
|||
- receipt-gated agent consequences (including the R4 wallet gate, now reachable),
|
||||
- split-view defense: STH pinning, consistency enforcement, freshness, monitoring,
|
||||
- dogfood verified cryptography and the honest hybrid post-quantum posture,
|
||||
- the verified-custody wallet (warden): a quorum boundary of four proven forks, the signing firewall, and the agent-native MCP surface,
|
||||
- research roadmaps from R4 evidence toward R5 assurance.
|
||||
|
||||
This curriculum is not financial advice, not a trading bot, and not a wallet-building guide. It is a training path for engineers and researchers who need to evaluate formal-verification-enhanced cryptographic tooling without overclaiming.
|
||||
|
|
|
|||
|
|
@ -2026,6 +2026,245 @@ COURSE = {
|
|||
),
|
||||
]
|
||||
),
|
||||
"10_verified_custody_wallet.ipynb": notebook(
|
||||
[
|
||||
md(
|
||||
"""
|
||||
# Lecture 10: The Verified-Custody Wallet (warden)
|
||||
|
||||
Everything so far *decided* which cryptographic code to trust.
|
||||
This lecture *acts* on the decision: we build a custody boundary
|
||||
out of the four proven curve25519-dalek forks and use it to
|
||||
guard signatures - inbound and outbound.
|
||||
|
||||
The one idea: **inbound acceptance requires a unanimous quorum of
|
||||
provably-equivalent verifiers, and every outbound signature must
|
||||
pass the same quorum before it is released.**
|
||||
|
||||
We keep the course's ratchet rule: every load-bearing idea runs
|
||||
twice - napkin scale by hand, then real scale against the live
|
||||
system - and both are executable here.
|
||||
"""
|
||||
),
|
||||
md(
|
||||
"""
|
||||
## Learning Objectives
|
||||
|
||||
- Explain why a *unanimous* quorum of provably-equivalent
|
||||
verifiers turns disagreement into evidence of a fault, and why
|
||||
majority voting would hide exactly that fault.
|
||||
- Classify a quorum divergence as a documented semantic edge
|
||||
(note) versus unexplained (tamper -> latch).
|
||||
- Describe the outbound signing firewall as verify-after-sign
|
||||
with a proven verifier, and state warden's honest asymmetry
|
||||
(verify custody-grade, sign trusted base).
|
||||
- Recompute a custody card's inclusion proof as a counterparty -
|
||||
trust by recomputation, not by assertion.
|
||||
"""
|
||||
),
|
||||
md(
|
||||
"""
|
||||
## Why a quorum, when one proof would do?
|
||||
|
||||
Each member is *proven* to decide the same predicate,
|
||||
`accept(A,m,R,s) ⇔ decompress(R) = [k](−A) + [s]B`. So on the
|
||||
proven domain they cannot disagree about *meaning*. Classic
|
||||
N-version programming hopes independent code won't share a bug;
|
||||
we do not hope - we know the semantics coincide, so a runtime
|
||||
disagreement is not opinion, it is **evidence of a fault**: a
|
||||
corrupted build, a memory error, or tampering. The quorum turns
|
||||
"the verifiers differed" into an alarm with a theorem behind it.
|
||||
"""
|
||||
),
|
||||
md(
|
||||
"""
|
||||
## Napkin scale: a 3-of-3 quorum with toy verifiers
|
||||
|
||||
Forget real curves for a moment. Model three verifiers as
|
||||
functions and watch the boundary logic: unanimity accepts,
|
||||
any disagreement fails closed and is classified.
|
||||
"""
|
||||
),
|
||||
code(
|
||||
"""
|
||||
def toy_quorum(verdicts):
|
||||
kinds = set(verdicts.values())
|
||||
if kinds == {"accept"}:
|
||||
return "unanimous-accept", True
|
||||
if kinds == {"reject"}:
|
||||
return "unanimous-reject", False
|
||||
return "divergence -> FAIL CLOSED + incident", False
|
||||
|
||||
print(toy_quorum({"dalek": "accept", "anza": "accept", "risc0": "accept"}))
|
||||
print(toy_quorum({"dalek": "reject", "anza": "reject", "risc0": "reject"}))
|
||||
print(toy_quorum({"dalek": "accept", "anza": "reject", "risc0": "accept"}))
|
||||
"""
|
||||
),
|
||||
md(
|
||||
"""
|
||||
The third line is the whole point: a lone dissenter does not get
|
||||
out-voted. Acceptance needs *everyone*; anything else is a
|
||||
refusal plus a recorded incident. Majority voting would hide
|
||||
exactly the fault we most want to see.
|
||||
"""
|
||||
),
|
||||
md(
|
||||
"""
|
||||
## The divergence taxonomy
|
||||
|
||||
The forks are *allowed* to differ on documented degenerate
|
||||
inputs (anza rejects `A = 0` and a legacy excluded-small-order-R
|
||||
list). We still fail closed; the taxonomy only grades the alarm:
|
||||
|
||||
- **semantic-edge** - they differ AND a documented edge flag
|
||||
applies (small-order R, non-canonical s, zero key): severity
|
||||
*note*.
|
||||
- **unexplained** - they differ with no documented reason, or a
|
||||
member errored: severity *tamper* -> custody **latches**.
|
||||
"""
|
||||
),
|
||||
code(
|
||||
"""
|
||||
import sys, pathlib
|
||||
for parent in [pathlib.Path.cwd(), *pathlib.Path.cwd().parents]:
|
||||
if (parent / "src" / "pacta").exists():
|
||||
sys.path.insert(0, str(parent / "src")); ROOT = parent; break
|
||||
|
||||
from pacta.quorum import semantic_edge_flags, SMALL_ORDER_ENCODINGS
|
||||
|
||||
small_order_R = sorted(SMALL_ORDER_ENCODINGS)[0]
|
||||
print("edge flags for a small-order R:",
|
||||
semantic_edge_flags(b"\\x02" * 32, small_order_R + b"\\x00" * 32))
|
||||
print("edge flags for an ordinary sig:",
|
||||
semantic_edge_flags(b"\\x02" * 32, b"\\x01" * 64))
|
||||
"""
|
||||
),
|
||||
md(
|
||||
"""
|
||||
A divergence on the first input is a documented edge (note); a
|
||||
divergence on the second has no excuse (tamper). Same fail-closed
|
||||
verdict, very different alarm.
|
||||
"""
|
||||
),
|
||||
md(
|
||||
"""
|
||||
## Real scale: the four proven forks, if built
|
||||
|
||||
If you have run `pacta wallet build-quorum`, the next cell drives
|
||||
the **real** four-fork quorum: sign a payload with the dogfood
|
||||
(attested) signer, then watch all four proven verifiers agree on
|
||||
accept, and on reject for a flipped byte. If the binaries are not
|
||||
built, we say so and skip - honestly, the way the wallet itself
|
||||
fails closed.
|
||||
"""
|
||||
),
|
||||
code(
|
||||
"""
|
||||
from pacta.quorum import load_quorum, binary_path
|
||||
|
||||
built = [b for b in ("dalek", "anza", "risc0", "betrusted") if binary_path(b).exists()]
|
||||
if len(built) < 2:
|
||||
print("quorum not built (need >=2). Run: pacta wallet build-quorum --sources-root <...>")
|
||||
else:
|
||||
import tempfile, os
|
||||
from pacta.dogfood import locate_verifier, pem_public_key_to_raw, sign_payload_dogfood
|
||||
from pacta.signing import generate_ed25519_keypair
|
||||
v = locate_verifier()
|
||||
if v is None:
|
||||
print("dogfood signer not built; run pacta dogfood-build")
|
||||
else:
|
||||
d = tempfile.mkdtemp()
|
||||
key, pub = os.path.join(d, "k.pem"), os.path.join(d, "k.pub")
|
||||
generate_ed25519_keypair(key, pub)
|
||||
payload = b"curriculum lecture 10 payload"
|
||||
sig = sign_payload_dogfood(payload, key, v)
|
||||
pk = pem_public_key_to_raw(pub)
|
||||
q = load_quorum(min_members=2)
|
||||
print("members:", sorted(q.members))
|
||||
good = q.verify(payload, sig, pk)
|
||||
print("valid signature ->", good.classification, "accepted =", good.accepted)
|
||||
bad = q.verify(payload, bytes([sig[0] ^ 0xFF]) + sig[1:], pk)
|
||||
print("one flipped byte ->", bad.classification, "accepted =", bad.accepted)
|
||||
"""
|
||||
),
|
||||
md(
|
||||
"""
|
||||
## The signing firewall: verify-after-sign, but proven
|
||||
|
||||
Outbound is `intent -> sign -> firewall -> release`. The fresh
|
||||
signature faces the same quorum; only unanimity releases it. A
|
||||
rejected self-signature is *quarantined, never returned*, and
|
||||
custody latches. This is the textbook fault-injection
|
||||
countermeasure - verify a signer's output before trusting it -
|
||||
with the verifier upgraded to machine-checked code.
|
||||
|
||||
Note the honest asymmetry: the *verify* paths are certificate-
|
||||
covered (custody-grade), but the *signing* step is trusted base -
|
||||
the attested artifact, not a third implementation. The firewall
|
||||
is exactly how we fence that weaker edge.
|
||||
"""
|
||||
),
|
||||
md(
|
||||
"""
|
||||
## Two voices, one boundary (the domain split, again)
|
||||
|
||||
Lecture 06 split provider and agent. warden inherits the split:
|
||||
|
||||
- **The operator voice** seals the capsule: it runs the R4 gate,
|
||||
pins the attested source commits, and stores the transparency-
|
||||
log receipts that authorized each member.
|
||||
- **The counterparty (agent) voice** never trusts the operator's
|
||||
adjectives. It reads the *custody card* and recomputes the
|
||||
inclusion proofs itself - trust by recomputation.
|
||||
|
||||
The next cell is the counterparty side: given a card, verify a
|
||||
member's inclusion proof with nothing but stdlib hashing.
|
||||
"""
|
||||
),
|
||||
code(
|
||||
"""
|
||||
# Counterparty-side check of ONE member's inclusion proof.
|
||||
# (Works whenever you have a wallet + its fetched evidence; here
|
||||
# we show the primitive the card relies on.)
|
||||
from pacta.transparency import verify_inclusion, leaf_bytes_for_attestation
|
||||
import json, glob
|
||||
|
||||
ev = sorted(glob.glob(str(ROOT / "examples" / "wallet-evidence" / "*.attestation.json")))
|
||||
if not ev:
|
||||
print("no bundled evidence; fetch with `pacta log-fetch` to try live")
|
||||
else:
|
||||
att = json.load(open(ev[0]))
|
||||
rec = json.load(open(ev[0].replace(".attestation.", ".receipt.")))
|
||||
ok = verify_inclusion(
|
||||
leaf_bytes_for_attestation(att),
|
||||
rec["leaf_index"], rec["tree_size"],
|
||||
[bytes.fromhex(h) for h in rec["inclusion_proof"]],
|
||||
bytes.fromhex(rec["sth"]["root_hash"]),
|
||||
)
|
||||
print(f"{att['subject']['component']}: inclusion recomputes ->", ok)
|
||||
print("The counterparty believed no adjective; it recomputed a Merkle root.")
|
||||
"""
|
||||
),
|
||||
md(
|
||||
"""
|
||||
## Exercises
|
||||
|
||||
- Change `toy_quorum` to majority voting and write two sentences
|
||||
on exactly which attack that lets through.
|
||||
- Take the real quorum cell and corrupt one member binary on
|
||||
disk (append a byte). Predict, then observe, what the wallet's
|
||||
capsule hash-pin does the next time it assembles the quorum.
|
||||
- The signing path is trusted base. Write the strongest *true*
|
||||
sentence you can about warden's outbound safety, and the
|
||||
strongest *false* one a marketer would write - and name the
|
||||
word that makes the second one false.
|
||||
- Design `warden-treasury`: which member re-verifies Solana
|
||||
transactions, and what exactly the RPC provider is still
|
||||
trusted for after you do.
|
||||
"""
|
||||
),
|
||||
]
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2047,6 +2286,7 @@ The course teaches:
|
|||
- receipt-gated agent consequences (including the R4 wallet gate, now reachable),
|
||||
- split-view defense: STH pinning, consistency enforcement, freshness, monitoring,
|
||||
- dogfood verified cryptography and the honest hybrid post-quantum posture,
|
||||
- the verified-custody wallet (warden): a quorum boundary of four proven forks, the signing firewall, and the agent-native MCP surface,
|
||||
- research roadmaps from R4 evidence toward R5 assurance.
|
||||
|
||||
This curriculum is not financial advice, not a trading bot, and not a wallet-building guide. It is a training path for engineers and researchers who need to evaluate formal-verification-enhanced cryptographic tooling without overclaiming.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ EXPECTED_NOTEBOOKS = [
|
|||
"07_agent_consequences.ipynb",
|
||||
"08_capstone_research_program.ipynb",
|
||||
"09_dogfood_verified_crypto.ipynb",
|
||||
"10_verified_custody_wallet.ipynb",
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue