# mithril-go Pure-Go client for the Cardano [Mithril](https://mithril.network) protocol. Mithril is Cardano's stake-based certified-snapshot system — it lets a new node bootstrap the chain from a cryptographically-verified snapshot instead of replaying every block from genesis. The official [`mithril-client`](https://github.com/input-output-hk/mithril) is Rust. `mithril-go` is a pure-Go reimplementation that produces a single static binary with no CGo, no upstream Rust runtime, and an MCP-native tool surface for AI agents — useful for: - Embedding Mithril bootstrap into Go-based Cardano tooling (alongside `gouroboros`, `dingo`, etc.) - Constrained ARM/embedded targets where shipping the Rust binary + its deps is overkill - Operators who prefer a single `go install`-able helper - AI agents (Claude Code, Cursor, Zed, ...) that want to verify Mithril certs as a callable tool ## Status **Working consensus-correct verification against live mainnet and preprod.** | Capability | Status | |---|---| | Aggregator REST client | ✅ list, show, cert, walk-chain | | Resumable HTTP download (SHA hook + progress) | ✅ | | Streamed zstd+tar extract (tar-slip defended) | ✅ | | Genesis Ed25519 verification | ✅ live mainnet + preprod | | STM BLS12-381 aggregate verification | ✅ live mainnet + preprod | | Lottery-win threshold (Taylor series, big.Rat) | ✅ | | Merkle batch-proof verification (Blake2b-256) | ✅ | | AVK chaining + epoch + hash continuity | ✅ | | **Full chain verification (genesis → head)** | ✅ live mainnet + preprod | | Per-immutable SHA manifest verification | ✅ | | MCP stdio server (8 tools) | ✅ | | Full immutables-download loop (8000+ files) | ⏳ | ## Quick start ```bash go build ./cmd/mithril-go # produces a 9.5 MB single static binary mithril-go info -network mainnet mithril-go list -network mainnet mithril-go show -network mainnet latest mithril-go cert -network mainnet head mithril-go cert -network mainnet -chain head # walk to genesis mithril-go download -network preprod -out ./snap latest mithril-go verify -network preprod manifest ./snap # SHA-check downloaded files mithril-go verify -network mainnet genesis # Ed25519 mithril-go verify -network mainnet head # STM BLS aggregate mithril-go verify -network mainnet chain # full walk + every cert ``` Every query command supports `-json` for structured output. ## Architecture ``` cmd/mithril-go/ main.go CLI entrypoint, subcommand dispatch mcp.go MCP tool registration json.go Structured-output helpers internal/ aggregator/ REST client (list, get, cert, walk-chain) artifact/ Resumable HTTP download + streamed zstd-tar extract chain/ End-to-end chain verify (genesis → head, AVK chaining) manifest/ Per-immutable SHA-256 verification against digests.json mcp/ Minimal JSON-RPC 2.0 stdio MCP server (no deps) networks/ Per-network aggregator URLs + genesis verify keys stm/ STM BLS12-381 verification: types, BLS, aggregation, lottery, Merkle, top-level Verify verify/ Genesis Ed25519 verification ``` ## What was non-obvious (so future-you doesn't have to dig) Three things in the upstream Rust that aren't documented anywhere prominent: 1. **DST is empty.** Mithril's BLS hash-to-G1 uses an empty domain separation tag, not the IETF standard `BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_`. The Rust calls `blst.verify(sig, msg, &[], &[], pk, ...)` — the `&[]` is the empty DST. 2. **The signed message is `signed_message_bytes || mt_root_bytes`**, not `signed_message` alone. The Merkle commitment root is appended before BLS verify. 3. **Aggregation is MuSig-style scalar-weighted, not plain.** `t_i = Blake2b-128(Blake2b-128(σ_0‖…‖σ_{n-1}) ‖ be_u64(i))`, then `aggr_sig = Σ t_i·sig_i` and `aggr_vk = Σ t_i·vk_i`. Plain summation does not interop with blst. Plus the `protocol_message` hash is SHA-256 over key-then-value, with keys ordered by **Rust enum declaration order**, not alphabetical. ## Machine / LLM usage Every query command accepts `-json`: ``` mithril-go verify -network mainnet -json chain | jq '.steps[] | select(.kind=="genesis")' ``` Stable exit codes: | Code | Meaning | |---|---| | 0 | success | | 1 | generic error | | 2 | usage error | | 3 | network / aggregator error | | 4 | integrity failure (SHA, tar-slip, truncated archive) | | 5 | signature verification failure (genesis or STM) | | 130 | canceled (SIGINT) | These are the contract — existing codes won't renumber. ### MCP server `mithril-go mcp` brings up a Model Context Protocol stdio server. Compatible with any MCP client (Claude Code, Cursor, Zed, custom agents). Tools exposed: | Tool | Purpose | |---|---| | `mithril_info` | Network + aggregator + genesis verify key | | `mithril_list_snapshots` | Newest-first list of cardano-database snapshots | | `mithril_show_snapshot` | Detail for a snapshot (or `latest`) | | `mithril_get_certificate` | Cert by hash (or `head`) | | `mithril_walk_cert_chain` | Walk previous_hash from head to genesis | | `mithril_verify_certificate` | Ed25519 OR STM BLS verify, dispatched by cert kind | | `mithril_verify_chain` | Full chain verify with per-step report | | `mithril_verify_genesis` | Walk to genesis + Ed25519 verify (legacy single-purpose tool) | Example agent flow: ``` agent: tools/call mithril_verify_chain {network: mainnet} → {verified: true, length: 89, genesis_hash: "...", steps: [...]} ``` ## Dependencies - `github.com/consensys/gnark-crypto` — pure Go BLS12-381 (audited) - `golang.org/x/crypto/blake2b` — stdlib-adjacent Blake2b - `github.com/klauspost/compress/zstd` — pure Go zstd No CGo. No `blst`. `go build ./cmd/mithril-go` produces a single static binary. Cross-compile with `GOOS=linux GOARCH=arm64 go build`. ## Building ```bash go build -o mithril-go ./cmd/mithril-go go test ./... go test -tags live ./... # hits live preprod aggregator ``` ## Verified against live networks (latest run) ``` mainnet chain 89 STM + 1 genesis ✓ mainnet head 59 signers, 1972 wins ✓ mainnet genesis Ed25519 ✓ preprod chain 89 STM + 1 genesis ✓ preprod head 2 signers, 11 wins ✓ preprod genesis Ed25519 ✓ ``` ## License Apache-2.0. See `LICENSE`. Matches the upstream Mithril project.