Acceptance test report flagged three cosmetic JSON-schema gaps: 1. 'list -json' had no top-level 'count' — caller had to use .snapshots|length. Added 'count' alongside 'snapshots'. 2. 'verify -json chain' top-level 'kind' was reported null — actually a missing field rather than null. Chain results have per-step kind in .steps[]; chain-level kind would be misleading. Documented intent in README rather than adding the field. 3. MCP 'mithril_verify_certificate' returned 'cert_hash' but agents often look for 'hash'. Added 'hash' alias alongside 'cert_hash' in both genesis and STM result paths so either lookup works. End-to-end loop test on mainnet+preprod: full PASS (89-cert mainnet chain + 90-cert preprod chain both verified, MCP all 8 tools work, exit codes correct, manifest detection clean). v1-tag-able now. |
||
|---|---|---|
| cmd/mithril-go | ||
| internal | ||
| .gitignore | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| README.md | ||
| STM-SPRINT.md | ||
mithril-go
Pure-Go client for the Cardano Mithril 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
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
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:
- 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 callsblst.verify(sig, msg, &[], &[], pk, ...)— the&[]is the empty DST. - The signed message is
signed_message_bytes || mt_root_bytes, notsigned_messagealone. The Merkle commitment root is appended before BLS verify. - Aggregation is MuSig-style scalar-weighted, not plain.
t_i = Blake2b-128(Blake2b-128(σ_0‖…‖σ_{n-1}) ‖ be_u64(i)), thenaggr_sig = Σ t_i·sig_iandaggr_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 Blake2bgithub.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
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.