mithril-go/README.md
Kayos 326d75d91a json output + stable exit codes (M2M / LLM contract)
- -json on info, list, show, cert (+ -chain): emit structured JSON ready
  for jq / agent consumption
- exit codes are now stable + documented: 0/1/2/3/4/5/130 with distinct
  meanings for network vs integrity vs signature failures
- help text enumerates the contract
- readme: machine-usage section explains both

MCP stdio server (for Claude Code / Cursor etc.) planned, not wired yet
2026-04-23 15:25:09 -07:00

5.2 KiB

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. This project is a pure-Go reimplementation that produces a single static binary with no runtime dependencies — useful for:

  • Embedding a Mithril bootstrap into Go-based Cardano tooling (alongside gouroboros, dingo, and friends)
  • Running on constrained ARM/embedded targets where shipping the Rust binary + its deps is overkill
  • Operators who prefer a single go install-able helper

Status

Download + extract pipeline working. Verification is the next milestone.

Piece Status
Aggregator REST client list, get, cert, chain
list / show / info / cert commands working against mainnet + preprod
Resumable HTTP download (single stream, SHA hook)
Streamed zstd+tar extract (tar-slip defended)
download — digests + ancillary (immutables loop pending)
Genesis Ed25519 verification ⚠️ stubbed, needs signed_message derivation wired
STM BLS12-381 aggregate verification the sprint — see below

Usage

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 ./db latest   # digests + ancillary

Verification sprint plan

The verification story splits into two layers:

1. Genesis Ed25519 verification

The genesis certificate (terminates the chain; its previous_hash is empty and genesis_signature is non-empty) is signed by a static Ed25519 key baked into this client per network (internal/networks).

  • Key encoding: the Mithril genesis key is serialized as an ASCII- representation of a 32-byte array literal (e.g. "[191,66,...]") then hex-encoded. Decoder needs to unwrap both levels before handing 32 raw bytes to ed25519.Verify.
  • Signed payload: signed_message field (32 bytes hex) is the output of hashing the serialized protocol_message — the exact hash function and canonicalization must match the Rust reference (mithril-common/src/protocol/ in the upstream repo). Likely Blake2b-256 over a deterministic CBOR or JSON encoding; needs confirming against upstream.
  • Wire location: internal/verify/verify.goGenesis(...).

2. STM BLS12-381 aggregate verification

Every non-genesis certificate carries a multi_signature that is an STM (Stake-based Threshold Multi-signature) aggregate proof over BLS12-381.

  • Scheme: Chotard/Kiayias/Peters "Stake-based Threshold Multisignatures" (Mithril paper §5-6).
  • Library: github.com/supranational/blst Go bindings (IETF-draft BLS12-381 operations; production-grade, consensus layers use it).
  • Inputs:
    • next_aggregate_verification_key from the previous-epoch cert's protocol_message (the "trust handoff" between certs)
    • multi_signature bytes (CBOR-encoded STM aggregate signature)
    • signed_message (what was signed)
  • Output: pass/fail, plus the epoch-boundary decision to promote that cert's next_aggregate_verification_key for use by the NEXT verification.
  • Wire location: internal/verify/verify.goSTM(...).

Downstream once verification lands

  • verify subcommand: takes a snapshot directory, walks the cert chain, verifies genesis Ed25519 + each STM signature in order, validates the merkle_root against the digests manifest's computed root, reports per-stage pass/fail.
  • Per-immutable SHA check against the digests.json manifest (already downloaded — 16836 entries for preprod as of epoch 284).
  • Full immutables loop for the download -immutables path.

Machine / LLM usage

Every query command accepts -json for structured output:

mithril-go list   -network mainnet -json      # snapshot array
mithril-go show   -network mainnet latest -json
mithril-go cert   -network mainnet head -json
mithril-go cert   -network mainnet head -chain -json
mithril-go info   -network mainnet -json

Exit codes are stable:

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.

Planned: mithril-go mcp stdio server (Model Context Protocol) so MCP-native agents (Claude Code, Cursor, etc.) can discover + call commands without shelling out. Not yet implemented.

Dependencies

  • github.com/klauspost/compress/zstd — pure Go zstd decoder
  • (pending) BLS12-381: github.com/supranational/blst via its Go bindings

Building

go build -o mithril-go ./cmd/mithril-go

Produces a single static binary (~9.5 MB). CGo is not used; cross- compilation is GOOS=linux GOARCH=arm64 go build ./cmd/mithril-go.

License

TBD