- internal/chain: end-to-end chain verification. Walks head → genesis,
verifies every cert (Ed25519 or STM as appropriate), and checks
continuity at every boundary:
epoch: same or +1 from previous
hash: current.previous_hash == previous.hash
AVK: same epoch → equal aggregate_verification_key
new epoch → matches previous.protocol_message.next_aggregate_verification_key
- cmd: 'verify chain' subcommand + 'verify manifest <dir>' for SHA-checking
downloaded immutable files
- internal/manifest: per-file SHA-256 verification against the digests.json
shipped in the snapshot's digests archive
- MCP: 8th tool 'mithril_verify_chain' for agent-driven full-chain verify
- README: complete rewrite — status table, architecture, gotchas, MCP
tool surface, exit code contract, build instructions
- LICENSE: Apache-2.0 (matches upstream Mithril)
Verified end to end against live networks:
preprod chain 90 certs (89 STM + 1 genesis) 1124 wins ✓
mainnet chain 89 certs (88 STM + 1 genesis) 210921 wins ✓
That's the wrap. Pure-Go consensus-correct Mithril client, single 10 MB
static binary, MCP-native, no CGo, no upstream Rust runtime.
178 lines
6.4 KiB
Markdown
178 lines
6.4 KiB
Markdown
# 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.
|