The ZK-CosmWasm Book
Active development. This guide is under active development. Small invariants in accuracy—gas numbers, capability names, circuit paths, and ecosystem status—are still being identified and tuned. Prefer linked source code and upstream docs when you need production certainty.
Builder documentation for the proof-verification CosmWasm stack: host APIs, circuits, cw-orch + ict-rs test/deploy paths, then ecosystem light clients and applications.
Parts
| Part | Focus |
|---|---|
| I — Using ZK-CosmWasm | Proof VM · Cw-Orch / ict-rs tooling · reference |
| II — Ecosystem | Light clients · applications (vote-sdk, auth, bounties, demos) |
| III — Community Program | Thin public residual links (audit / hackathon) |
Build Path
Start here when writing contracts or tests:
- Proof VM
- Architecture
- Circuits And Verifying Keys
- Cw-Orch Testing And Scripting — circuits + Docker e2e
Then Light Clients / Applications as needed.
Who This Guide Is For
This guide is for developers integrating or extending the ZK-CosmWasm stack:
- Building contracts that verify proofs or use native cryptographic hosts
- Integrating light-client designs that track Zcash (and, later, other ecosystems)
- Using application-layer libraries (vote-sdk, smart-account auth, related surfaces)
- Testing and scripting with cw-orch
For generic CosmWasm contract basics (entry points, multitest, funds), see The CosmWasm Book.
| If you are… | Start here |
|---|---|
| Verifying proofs in contracts | Proof VM |
| Tracking Zcash tips / finality | Light Clients |
| Building product protocols | Applications |
| Writing tests and deploy scripts | Cw-Orch Testing And Scripting |
| Following the residual community program | Community Program |
Relationship To CosmWasm Book
| CosmWasm Book | This book | |
|---|---|---|
| Site | https://book.cosmwasm.com/ | https://zk.permissionless.money/ (when published) |
| Focus | Writing CosmWasm contracts | ZK-CosmWasm extensions, light clients, ecosystem applications |
| Upstream API docs | https://docs.cosmwasm.com/ | Plus engineering specs in this CosmWasm fork (ZK_*.md, docs/*) |
Versioning note
This fork tracks CosmWasm packages with ZK extensions. Always check Cargo.toml versions in packages/* for the release you deploy; do not assume crates.io stock CosmWasm includes the ZK host import.
Proof VM
ZK-CosmWasm extends CosmWasm so contracts can verify zero-knowledge proofs on-chain through a host import, with verifying keys (VKs) stored and cached like Wasm modules.
What you get
| Concern | Stock CosmWasm | ZK-CosmWasm |
|---|---|---|
| Crypto hosts | secp256k1, ed25519, BLS12-381, … | Same, plus Halo2/PLONK-style proof verification |
| Circuit selection | Smart-Contract Specific | Application-assigned zkid → circuit metadata / key |
| Storage of VKs | Smart-Contract Specific | Content-addressed blob (params + constraint system + VK + footer) |
| Contract API | api.secp256k1_verify, … | api.proof_instance_verify(zkid, proof, instances) (feature zk) |
Contracts do not re-implement proving systems in Wasm. They pass proof bytes and public inputs; the host resolves the circuit, loads the verifying key, and returns success/failure.
Mental model
- Upload / register a circuit verifying key (often with contract code via
store_code_with_circuit, or as a standalone circuit viastore_circuit). - Map an application
zkidto the circuit’s content-addressed key (consensus/app state). - Verify from a contract:
#![allow(unused)]
fn main() {
// feature = "zk" on cosmwasm-std
let code = api.proof_instance_verify(zkid, &proof_bytes, &instance_bytes)?;
// 0 = valid proof, 1 = invalid proof
// Err = missing circuit, bad encoding, gas, or host error
}
Public instances are fixed-size field elements (length must be a multiple of 32 bytes per instance scalar encoding). Curve routing uses the circuit footer’s curve_id, not the numeric zkid.
Host crypto surface
Contract Wasm imports under env (wired in packages/vm). Highlighted rows are entrypoints added in this fork (not stock CosmWasm). Feature flags must be enabled on the host build for those imports to exist.
| Import / API | Kind | Feature | Notes |
|---|---|---|---|
secp256k1_verify |
Signature | — | ECDSA over secp256k1 (Cosmos default) |
secp256k1_recover_pubkey |
Signature | — | Pubkey recovery from compact signature |
secp256r1_verify |
Signature | — | ECDSA over P-256 (CosmWasm 2.1+) |
secp256r1_recover_pubkey |
Signature | — | P-256 recovery |
ed25519_verify |
Signature | — | EdDSA over ed25519 |
ed25519_batch_verify |
Signature | — | Batch Ed25519 verify |
bls12_381_aggregate_g1 |
Pairing curve | — | Aggregate G1 points (48-byte elements) |
bls12_381_aggregate_g2 |
Pairing curve | — | Aggregate G2 points (96-byte elements) |
bls12_381_pairing_equality |
Pairing curve | — | Multi-pairing equality check |
bls12_381_hash_to_g1 |
Hash-to-curve | — | Map message → G1 (HashFunction + DST) |
bls12_381_hash_to_g2 |
Hash-to-curve | — | Map message → G2 |
proof_instance_verify NEW |
ZK proof | zk |
Halo2 / Groth16 verify via zkid → circuit key |
blake2b_256 NEW |
Hash | hash-blake |
BLAKE2b digest truncated/output 32 bytes |
blake3_256 NEW |
Hash | hash-blake |
BLAKE3 256-bit digest |
bn254_add NEW |
Pairing curve | bn254 |
EIP-196 ECADD on alt_bn128 G1 |
bn254_scalar_mul NEW |
Pairing curve | bn254 |
EIP-196 ECMUL on alt_bn128 G1 |
bn254_pairing_equality NEW |
Pairing curve | bn254 |
EIP-197 pairing check (also used by Groth16 path) |
Hash functions
| Function | Output | Host import | Status |
|---|---|---|---|
| SHA-256 (BLS hash-to-curve mode) | via HashFunction |
inside bls12_381_hash_to_g* |
Stock CosmWasm |
blake2b_256 NEW |
32 bytes | env.blake2b_256 |
feature hash-blake |
blake3_256 NEW |
32 bytes | env.blake3_256 |
feature hash-blake |
blake2b_512 |
64 bytes | — | Library helper in cosmwasm-crypto only (not a host import) |
Curves (signature & pairing hosts)
Existing CosmWasm curve families used by the stock signature / BLS APIs:
| Curve / group | APIs | Typical use |
|---|---|---|
| secp256k1 | secp256k1_verify, secp256k1_recover_pubkey |
Tendermint / Cosmos account signatures |
| secp256r1 (P-256) | secp256r1_verify, secp256r1_recover_pubkey |
WebAuthn / passkey-style credentials |
| ed25519 | ed25519_verify, ed25519_batch_verify |
Consensus / validator-style EdDSA; light-client batches |
| BLS12-381 (G1 / G2) | bls12_381_* |
Aggregate signatures, pairings, hash-to-curve |
Curves for proof verification (curve_id)
Footer field curve_id routes proof_instance_verify (independent of app zkid):
curve_id |
Curve | Circuit family | Proving system |
|---|---|---|---|
0 NEW |
Pasta (Vesta) | Generic Plonkish | Halo2 |
1 NEW |
Pasta (Vesta) | Vote delegation (ZKP #1) | Halo2 |
2 NEW |
Pasta (Vesta) | Vote commitment (ZKP #2) | Halo2 |
3 NEW |
Pasta (Vesta) | Share reveal (ZKP #3) | Halo2 |
4 NEW |
BN254 (alt_bn128) | Generic Groth16 | Groth16 (feature bn254) |
Stack layers
Contract (cosmwasm-std, feature "zk")
→ host import proof_instance_verify
→ resolve zkid → circuit_key (WasmQuery::CircuitInfo)
→ load VK (host cache / cold path Circuit query)
→ AnyVerifyingKey::verify(proof, instances)
Relevant crates in this repository:
| Crate | Role |
|---|---|
packages/std | Contract-facing API and Wasm imports |
packages/vm | Host import, gas, cache integration |
packages/zk | Footer, serialization, AnyVerifyingKey |
packages/zk-vote-bridge | Example: vote-sdk circuits → CosmWasm footer format |
packages/crypto | Shared crypto primitives used by the VM |
Go hosts typically consume this via a wasmvm build linked against the fork (e.g. monorepo crates/zk-wasmvm).
Feature flags
- Enable
zkoncosmwasm-std/ contract crates that callproof_instance_verify. - Host environments must wire circuit queries (
CircuitInfo/Circuit) and the VM circuit cache loader.
See Gas and capabilities for negotiation and metering.
Next Chapters
- Architecture
- Circuits And Verifying Keys
- Storage And Caching
- Gas And Capabilities
- Ecosystem: Light Clients
Architecture
This chapter describes how multi-circuit proof verification works in the CosmWasm VM for integrators and contract authors.
Engineering source of truth: ZK_PROOF_VERIFICATION_ARCHITECTURE.md, ZK_COSMWASM_ZKVM_SPEC.md (repo root).
Two-level identity
| Layer | Identifier | What it stores |
|---|---|---|
| App / consensus | zkid (u64 / u32 at the Wasm boundary) | Logical circuit id → content key / checksum mapping |
| VM cache | Circuit key (72 bytes) or component keys (36 bytes) | Actual serialized params, constraint system, VK |
Think of zkid as a virtual address and the circuit key as a physical page: contracts only ever pass zkid; operators and keepers manage content-addressed blobs.
Historically the mapping was described as zk_circuits:{zkid} → checksum. The host path used today resolves WasmQuery::CircuitInfo { zk_id } for metadata (including the 72-byte circuit_key), then loads bytes from the host circuit cache (Path A). On cache miss it falls back to WasmQuery::Circuit for the full blob (cold path).
Host import
do_proof_instance_verify(zkid, proof_ptr, proof_len, instances_ptr, instances_len) → u32
Implemented in packages/vm/src/imports.rs:
- Charge host-call gas and read proof / instance regions from Wasm memory
- Proof max size: 2 MiB
- Instances max size: 64 KiB
- Charge
halo2_proof_instance_verifygas (linear cost model). - Query CircuitInfo for
zkid→circuit_key(72 bytes). - Load verifying key:
- Prefer host cache loader (no full circuit over the querier)
- Else cold path: Circuit query → deserialize footer + body →
AnyVerifyingKey
- Decode instances with
footer.curve_id(never withzkidas a curve hint). - Verify; return codes:
0— cryptographic verification succeeded1— proof does not verify (not a host crash)Err— missing registry entry, parse/format errors, gas, system query failure
Contract sketch:
#![allow(unused)]
fn main() {
match api.proof_instance_verify(zkid, &proof, &instances) {
Ok(0) => { /* accept */ }
Ok(1) => { /* reject invalid proof */ }
Ok(_) => { /* unexpected */ }
Err(e) => { /* registry / encoding / gas */ }
}
}
Upload path
| API (VM cache) | Purpose |
|---|---|
store_code_with_circuit(code_bundle, checked, persist) | Validate Wasm + VK; store both; pin VK by default; returns checksums |
store_circuit(vk_bytes, persist) | Store / pin a circuit blob alone |
App layer responsibilities:
- Persist
zkid→ circuit key / metadata in consensus state - Ensure mappings exist before contracts verify against that
zkid - Optionally re-pin hot circuits after node restart (disk survives; pinned memory does not)
Virtual-memory analogy
| OS concept | ZK-CosmWasm |
|---|---|
| Virtual address | zkid |
| Page table | App mapping / CircuitInfo |
| Physical frame | Deserialized VK in pinned memory |
| Page fault | Cache miss → disk or Circuit query |
| Wired pages | Pinned circuits |
| Page cache | File-system .bin under zk_* dirs |
Roadmap note (zkVM)
ZK_COSMWASM_ZKVM_SPEC.md describes an evolution from programmable circuit verification (what ships today: upload VKs, verify proofs) toward a Turing-complete WASM execution prover (trace capture, late-binding commit/batch/claim, nested sub-commitments). That is design-forward material for protocol builders. Day-to-day contract integration only needs the multi-circuit verify path above.
Error patterns operators see
| Symptom | Likely cause |
|---|---|
| “circuit not found” / CircuitInfo error | zkid never registered or wrong chain state |
| Deserialization / footer errors | Corrupt blob, wrong format version, truncated file |
Ok(1) | Valid host path, invalid proof or wrong public inputs |
| Instance length errors | Instances not multiple of 32-byte field elements |
Implementation map
| Area | Path |
|---|---|
| Host import | packages/vm/src/imports.rs |
| Gas / env | packages/vm/src/environment.rs |
| Cache | packages/vm/src/cache.rs, packages/vm/src/zk.rs |
| Serialization | packages/zk/ |
Circuits And Verifying Keys
How verifying keys are packaged for the CosmWasm VM, and how circuit developers produce compatible blobs.
Sources: ZK_CIRCUIT_QUICK_REFERENCE.md, ZK_CIRCUIT_SERIALIZATION_FORMAT.md, ZK_COSMWASM_CIRCUIT_MACRO.md.
Goals
- Circuit-agnostic verification: host deserializes params + full constraint system + VK without the original Rust circuit type.
- Param / VK separation: commitment parameters (~60–70+ KiB for modest
k) are shared across circuits with the samekand not duplicated per pinned entry when split storage is used. - Content addressing + integrity: dual SHA-256 checksums in an 80-byte footer.
Binary layout (monolithic)
[ Halo2 commitment params ] param_len
[ Constraint system ] cs_len
[ Verifying key ] vk_len
[ CircuitFooter 80 bytes ]
Footer fields (80 bytes)
| Offset | Size | Field |
|---|---|---|
| 0 | 1 | prover_id (0 = Plonkish) |
| 1 | 1 | curve_id (e.g. Pasta; BN254 uses a distinct id) |
| 2 | 1 | k |
| 3 | 1 | i (public input scalar count) |
| 4–7 | 4 | param_len (u32 LE) |
| 8–11 | 4 | cs_len (u32 LE) |
| 12–15 | 4 | vk_len (u32 LE) |
| 16–47 | 32 | param_checksum = SHA256(params) |
| 48–79 | 32 | vk_checksum = SHA256(cs ‖ vk) |
appstate_key = u32::from_be_bytes([prover_id, curve_id, k, 0]) — used when deriving file keys.
Content-addressed keys
param_key = appstate_key_le (4) ‖ param_checksum (32) → 36 bytes
vk_key = appstate_key_le (4) ‖ vk_checksum (32) → 36 bytes
circuit_key = param_key ‖ vk_key → 72 bytes
Types live in packages/zk (CircuitFooter, CwVerifyingKey, AnyVerifyingKey, …).
Split on-disk layout
Under the Wasm state base directory:
zk_param/<36-byte-hex>.bin # params only
zk_vk/<36-byte-hex>.bin # cs + vk (no footer)
zk_circuit/<72-byte-hex>.bin # full blob including footer
Load prefers split files when both param and vk bodies exist; otherwise falls back to the monolithic circuit file. Every load re-checks both checksums.
Contract-facing instances
- Encode public inputs as concatenated field elements (typically 32 bytes each).
- Host builds
AnyInstancefromcurve_idin the footer, so a singlezkidspace can hold circuits on different curves without remapping ids to curve enums.
#[cosmwasm_circuit] macro (circuit authors)
The derive/attribute machinery under packages/vm-derive helps produce VM-compatible serialization:
- Analyzes
Circuit::configure()for columns, gates, selectors, lookups, permutations - Emits footer metadata and
to_bytes_with_cs/ serialize-for-VM helpers - Compile-time checks for CS properties
Typical attributes:
| Attribute | Meaning |
|---|---|
k | Circuit size (2^k rows); common range 11–20 |
instances | Number of public input scalars |
footer_version | ≥ 2 for CS-inclusive format |
analyze_cs | Default true — full analysis |
Exact attribute surface may evolve; treat root ZK_COSMWASM_CIRCUIT_MACRO.md and the derive crate as SoT for macro details.
Workflow checklist
- Implement Halo2 (or supported) circuit; keygen VK with matching params.
- Serialize params, CS, VK; build footer with dual checksums (or use macro helpers).
- Store via
store_circuit/store_code_with_circuiton the host. - Register
zkid→circuit_keyin app state. - From contracts, call
proof_instance_verifywith matching public inputs. - Optionally pin hot circuits after restart for latency.
Bridging external circuits
packages/zk-vote-bridge shows how vote-sdk Halo2 artifacts (possibly different crate versions) can be re-wrapped with a CosmWasm CircuitFooter so the VM’s AnyVerifyingKey path can verify them. Pattern: serialize bytes in the expected section order → attach footer → store → assign zkid.
Quick doc map (repo root)
| Audience | Document |
|---|---|
| Circuit implementers | ZK_COSMWASM_CIRCUIT_MACRO.md |
| Byte format | ZK_CIRCUIT_SERIALIZATION_FORMAT.md |
| Index | ZK_CIRCUIT_QUICK_REFERENCE.md |
Storage And Caching
How the VM stores circuit material and serves hot verifying keys without re-deserializing on every tx.
Source: ZK_STORAGE_AND_CACHING.md.
Why tiers exist
Commitment parameters are large and shared across circuits with the same k. Pinning a full params copy next to every VK wastes memory. The cache therefore:
- Stores params and cs+vk under separate content-addressed keys
- Keeps a monolithic circuit blob for integrity and fallback
- Serves deserialized VKs from pinned memory or a weight-bounded LRU
Cache hierarchy
| Tier | Key | Eviction | Persistence |
|---|---|---|---|
| Pinned memory | 72-byte circuit / 36-byte param | Manual pin/unpin only | Lost on process restart |
| In-memory LRU | Unified CacheKey (module / partial / circuit) | Weight-based LRU | Lost on restart |
| File system | Hex filenames under zk_* | Manual remove | Survives restart |
Unified LRU entries:
#![allow(unused)]
fn main() {
// Conceptual — see packages/vm cache module
enum CacheKey {
Checksum(Checksum), // Wasm modules
PartialKey([u8; 36]), // param or vk body
CircuitKey([u8; 72]), // full circuit
}
}
On-disk layout
base_dir/state/wasm/
<checksum>.wasm
zk_param/<36-hex>.bin
zk_vk/<36-hex>.bin
zk_circuit/<72-hex>.bin
base_dir/cache/modules/<version>/<target>/<checksum>.module
Keys derive from the footer (to_param_key, to_vk_key, to_circuit_key).
Lifecycle
Store
serialized [params|cs|vk|footer]
→ check_circuit() (dual SHA-256)
→ save_circuit_parts() → zk_param + zk_vk + zk_circuit
→ pin_circuit(circuit_key) (typical default after store)
Load
pinned hit → CachedCircuit (~µs)
LRU hit → CachedCircuit
FS hit → deserialize, promote to LRU
miss → split param+vk load, or monolithic fallback
Pin / unpin / remove
| Call | Effect |
|---|---|
pin_circuit | Ensure deserialized VK is in pinned map (idempotent) |
unpin_circuit | Drop pinned entry (disk may remain) |
remove_circuit | Unpin and delete circuit artifacts as implemented |
Exact semantics of unpin vs FS module removal are implementation-defined in the cache module; do not assume unpin alone deletes all three on-disk parts without checking current packages/vm behavior.
Memory accounting
| Level | Use |
|---|---|
Per-VK size_estimate | Weighting, metrics |
| Pinned / LRU totals | Observability, optional limits |
| Global pinned circuit memory | Optional host limits |
Pinned circuits are not automatically evicted. Treat pin as a performance wire for production hot paths.
Operator tips
- After restart, re-pin circuits that appear on every block.
- Watch pinned hit rate vs FS loads (deserialization is expensive).
- Prefer split layout so many circuits share param files for the same
k. - Keep consensus
zkidmappings correct; cache cannot invent missing registry entries.
Metrics (illustrative)
Hosts expose cache stats (hits on pinned/FS, misses, sizes). Use them when tuning memory limits for nodes that verify many distinct circuits.
Gas And Capabilities
How contracts declare what they need, and how the host meters ZK verification.
Sources: docs/CAPABILITIES.md, docs/CAPABILITIES-BUILT-IN.md, docs/FEATURES.md, docs/GAS.md, plus GasConfig in packages/vm.
Capabilities (not Cargo features)
Capabilities negotiate functionality between a Wasm contract and the chain environment. They are not the same as Rust Cargo features (the old name “features” for this idea was retired; see docs/FEATURES.md).
Contract side
Export a no-arg marker whose name starts with requires_:
#![allow(unused)]
fn main() {
#[cfg(feature = "iterator")]
#[no_mangle]
extern "C" fn requires_iterator() {}
}
If the host’s available capability set does not include every required marker, store fails early — better than discovering a missing host only at execute time.
Capabilities signal availability; they do not hard-block a contract from calling an import if the author ignores markers. Hosts still enforce import allow-lists and gas.
Host side
CacheOptions.available_capabilities is set by the embedding chain (wasmvm / wasmd-style keepers), often from a CSV list.
Built-in examples
| Capability | Rough meaning |
|---|---|
iterator | Range queries on storage |
staking | Staking module messages/queries |
stargate | Protobuf / IBC-era messages |
ibc2 | IBC v2 surfaces |
cosmwasm_1_1 … cosmwasm_3_0 | Versioned query/message sets |
Chains may define additional capabilities. For ZK, enable the zk Cargo feature on cosmwasm-std for the import; ensure the linked wasmvm build implements proof_instance_verify and circuit queries. Treat ZK as a host + std feature concern; do not assume a universal requires_zk string without checking your chain’s capability list.
Gas model (CosmWasm gas)
Upstream CosmWasm documents gas at docs.cosmwasm.com — gas. This fork keeps the same philosophy:
- Target order of magnitude: ~10¹² CosmWasm gas per second of wall time on reference hardware (see comments in
GasConfiganddocs/GAS.md). - That maps to
GAS_PER_US = 1_000_000— about 10⁶ gas per microsecond. - Host crypto is charged via fixed costs or
LinearGasCost:base + n * per_item.
SDK / Cosmos gas conversion is a chain embedding concern (wasmd / app multipliers). Contract authors and integrators should reason in CosmWasm gas units unless their chain docs say otherwise.
Proof verification cost
GasConfig::halo2_proof_instance_verify_cost is a LinearGasCost charged inside do_proof_instance_verify (packages/vm/src/imports.rs).
Size units (not “number of proofs” alone):
units = 1 + ceil(proof_bytes / 1024) + ceil(instance_bytes / 32)
cost = base + units * per_item
Default coefficients in tree (subject to re-calibration; always verify against your release):
base: 2_700 * GAS_PER_US // ~2.7 ms fixed @ 10^6 gas/µs
per_item: 200 * GAS_PER_US // ~200 µs per size unit
These defaults were set from host calibration (verify_gas_calibrate binary on the zk-cosmwasm package, BN254 path) with safety margin: measured square-circuit Groth16 p95 ≈ 2.0 ms → ~2.7 ms fixed at ~1.35× headroom; per_item scales with proof KiB and public-input limbs so large proofs cannot cheap-DoS the host. Re-run calibrate on validator-class CPUs after prover or layout changes.
Additionally (always charged for the call path):
- Generic host call cost
- Region read costs for proof and instance buffers (
read_region_*, size-dependent)
Invalid proofs that complete verification return Ok(1) after gas is charged for the work done. Missing circuits / parse failures return errors (gas already spent for work attempted).
Other crypto hosts (context)
Default config also meters secp256k1, secp256r1, ed25519 (incl. batch), and BLS12-381 operations with the same µs × GAS_PER_US style. ZK verification is one more host path in that framework. For comparison, BLS12-381 pairing equality uses per_item: 163 * GAS_PER_US — that number is not the Halo2 proof default (older docs sometimes confused the two).
Practical advice for developers
- Budget gas for worst-case proof size and cold-path circuit load (first verify after restart may be heavier operationally even if gas is fixed by config).
- Prefer pinned circuits on validators that serve many ZK txs.
- Keep public inputs small and well-typed; oversized instance regions fail or waste gas.
- When targeting multiple chains, document required CosmWasm version capabilities and that the chain’s wasmvm must be ZK-enabled.
- After changing circuits or host crypto, re-run:
cargo run -p zk-cosmwasm --features bn254 --bin verify_gas_calibrate --release
References in this repo
| Path | Content |
|---|---|
docs/CAPABILITIES.md | Negotiation model |
docs/CAPABILITIES-BUILT-IN.md | Built-in list |
docs/GAS.md | Points to upstream gas docs |
packages/vm/src/environment.rs | GasConfig defaults |
packages/vm/src/imports.rs | do_proof_instance_verify unit formula |
packages/zk/src/bin/verify_gas_calibrate.rs | Calibration harness |
Cw-Orch Testing And Scripting
cw-orch (cw-orchestrator) is the typed Rust layer for testing, scripting, and deploying CosmWasm contracts. In this monorepo the fork under crates/cw-orchestrator/ adds first-class circuit artifacts so the same workflow covers ZK verifying keys and proof-host contracts, not only Wasm.
Upstream docs: orchestrator.abstract.money · docs.rs/cw-orch.
Terp/ZK notes: crates/cw-orchestrator/TERP_FORK.md.
What You Use It For
| Layer | Capability |
|---|---|
| Contracts | #[interface(...)] + Uploadable → upload / instantiate / execute / query on mock or chain |
| Circuits (Terp fork) | circuit_interface / CircuitUploadable → store VKs (store-circuit path), query by zkid |
| Same code, many envs | Mock → local daemon → Docker-spawned chain via ict-rs |
| E2E suites | Compose contract + circuit + optional sidecars (e.g. Nostr) under one test runtime |
Circuit Compatibility (Terp Fork)
Stock cw-orch targets contracts. This fork extends the core so circuits live next to contract artifacts and share workspace helpers.
| Piece | Role |
|---|---|
cw_orch_circuit_derive::circuit_interface | Macro parallel to contract interface |
CircuitUploadable | Trait for circuit binary paths (VK / zk blob) |
circuits_dir_from_workspace! | Resolve artifacts/ (or circuit subdirs) from workspace root |
| Artifact naming | {name}_vk.bin / {name}_zk.bin under artifacts/ |
| Halo2 keys | PK = params + proving material; VK carries terpvm circuit footer metadata expected by zk-wasmvm |
| Daemon | upload_circuit / upload_circuit_with_access_config → chain MsgStoreCircuit-style flow; poll until _circuit(zk_id) succeeds |
use cw_orch::prelude::*;
// circuit_interface + CircuitUploadable from the Terp-extended prelude
// After upload: host can resolve zkid → VK; contracts call proof_instance_verify.
Builder flow:
- Compile / export circuit VK (and optional zk package) into
artifacts/. - Implement
CircuitUploadable(or generatedcircuit_interface) for that artifact name. - On a chain env: upload circuit then upload + instantiate the verifier / app contract.
- Prove off-chain; submit proof + public inputs; assert host verify via contract execute/query.
See also: Circuits And Verifying Keys, Proof VM.
Environments: Mock → Daemon → Docker (Ict-Rs)
┌─────────────┐ ┌──────────────────┐ ┌────────────────────────────┐
│ Mock │ → │ Daemon │ → │ ict-rs QuickSpawn / Docker│
│ multi-test │ │ live RPC/keys │ │ real terpd + optional │
│ fast unit │ │ local/testnet │ │ sidecars (e.g. Nostr) │
└─────────────┘ └──────────────────┘ └────────────────────────────┘
same cw-orch interfaces (TxHandler / QueryHandler / Environment)
Mock
Mock::new(...)for pure in-process multi-test.- Fast feedback for message shapes and basic execute paths.
- Circuit host behavior depends on mock wiring; full zk-wasmvm host fidelity is for chain envs.
Daemon (local or remote RPC)
let daemon = cw_orch::daemon::Daemon::builder()
.chain(/* ChainInfo */)
.build()?;
// contract + circuit uploads against a running node
Ict-Rs: Live Containers, E2E Suites
ict-rs (crates/ict-rs) is the interchain / Docker test framework that plugs into cw-orch:
| API | Purpose |
|---|---|
| QuickSpawn / SnapshotStore | Snapshot a chain (genesis + keys), spawn a Docker terpd (or configured binary), wait for block 1, map ports |
Daemon::builder().chain(spawned.to_chain_info()) | Attach cw-orch daemon to the container RPC |
QuickSpawnEnv | Wraps manager + daemon as Environment<Daemon> — drop-in for existing cw-orch tests; Drop stops the container |
ict-rs-cw-orch | Crate glue between ict-rs and cw-orch |
chain::terp (feature terp) | Traits for Circuit + Contract + TerpVmSuite: keygen/prove/verify lifecycle and on-chain store-circuit deploy against zk-wasmvm |
| Sidecars | e.g. Nostr relay in Docker for chain→event e2e |
// Conceptual e2e shape — see crates/ict-rs/ict-rs/README.md
let (spawned, _registry) = manager
.spawn(&snapshot_id, &chain_config, "test-net")
.await?;
let daemon = cw_orch::daemon::Daemon::builder()
.chain(spawned.to_chain_info())
.build()?;
// 1) upload_circuit via daemon / suite
// 2) upload + instantiate verifier contract
// 3) prove off-chain; execute verify path on-chain
// 4) manager.stop(&spawned).await? (or QuickSpawnEnv drop)
TerpVmSuite (ict-rs terp feature) layers on cw-orch circuit types (UploadableCircuit, CircuitPath, CwOrchCircuitUpload, …) so a suite can:
- load/save proving & verifying keys
- prove / verify off-chain
- deploy VK on-chain (
store-circuit) - bind an embedded Wasm verifier to that circuit
Concrete demos (e.g. No Rick-style suites) implement those traits per circuit.
Packages (Monorepo)
| Path | Role |
|---|---|
crates/cw-orchestrator/cw-orch | Interfaces, prelude, circuit_interface re-export |
crates/cw-orchestrator/cw-orch-daemon | Live chain + upload_circuit |
crates/cw-orchestrator/packages/cw-orch-core | circuits module, CircuitUploadable |
crates/cw-orchestrator/packages/macros/cw-orch-circuit-derive | Derive macros for circuits |
crates/ict-rs/ict-rs | Docker spawn, QuickSpawnEnv, Terp ZK suite traits |
crates/ict-rs/ict-rs-cw-orch | Adapter package |
Recommended Test Ladder
- Unit — mock cw-orch interfaces for contract messages.
- Circuit artifacts — generate VK/zk into
artifacts/; unit-test serialize/footer if needed. - Integration — daemon against local
terpdwith zk-wasmvm. - E2E — ict-rs Docker spawn + upload circuit + contract + proof path; optional sidecars.
- CI — pin images/snapshots; always
stop/ Drop containers.
See Also
- Proof VM
- Circuits And Verifying Keys
- Applications
- ict-rs README:
crates/ict-rs/ict-rs/README.md - Fork notes:
crates/cw-orchestrator/TERP_FORK.md
Source Document Map
Map engineering source-of-truth documents → reader chapters. Prefer the chapters for how to build; keep full specs in the linked sources when you need exhaustive detail.
This Crate (permissionlessweb/cosmwasm)
| Repository path | Book chapter |
|---|---|
README.md | Introduction, Proof VM |
ZCASH_INTEGRATION.md | Proof VM (context only; no TZE design dump) |
ZK_COSMWASM_ZKVM_SPEC.md | Architecture |
ZK_PROOF_VERIFICATION_ARCHITECTURE.md | Architecture |
ZK_CIRCUIT_QUICK_REFERENCE.md | Circuits And Verifying Keys |
ZK_CIRCUIT_SERIALIZATION_FORMAT.md | Circuits And Verifying Keys |
ZK_COSMWASM_CIRCUIT_MACRO.md | Circuits And Verifying Keys |
ZK_STORAGE_AND_CACHING.md | Storage And Caching |
docs/CAPABILITIES*.md, GAS.md, FEATURES.md | Gas And Capabilities |
packages/vm/src/environment.rs | Gas And Capabilities (GasConfig) |
Tooling
| Path | Book chapter |
|---|---|
crates/cw-orchestrator/ (+ circuit macros) | Cw-Orch Testing And Scripting |
crates/ict-rs/ (Docker spawn, QuickSpawnEnv, terp ZK suite) | Cw-Orch Testing And Scripting |
Ecosystem
| Path / repo | Book chapter |
|---|---|
| zebra-crosslink, cw-ics08-wasm-crosslink | Light Clients, Crosslink, Pure PoW |
| ibc-go 08-wasm, solidity-ibc-eureka | Design Survey |
| valargroup/vote-sdk | Vote-Sdk |
terp-rs smart-accounts, Terp x/smart-account | Smart-Account Authenticators |
crates/zec-bounties/ | Dao Bounties Embed |
Glossary
| Term | Meaning |
|---|---|
| ZK-CosmWasm | CosmWasm stack with proof-verification-oriented host support and circuit caching |
| zkid | Application-assigned logical circuit id resolved to a content-addressed circuit key |
| VK | Verifying key (with embedded constraint system in this stack’s version-2 format) |
| CircuitFooter | 80-byte trailer: prover/curve/k/instances, section lengths, dual SHA-256 checksums |
| circuit_key | 72-byte content key: param_key ‖ vk_key |
| params | Halo2 (or similar) commitment parameters; often shared for a given k |
| Path A | Host-cache load of VK after CircuitInfo (avoids pulling full blob over querier) |
| Cold path | Circuit query + deserialize when cache misses |
| Crosslink | Hybrid finality light-client / node path over Zcash PoW |
| Pure PoW | Confirmation-depth light-client path on Zcash headers only |
| 08-wasm | IBC light client whose logic runs as CosmWasm Wasm bytecode |
| Capability | Contract/host negotiation via requires_* Wasm exports (not Cargo features) |
| vote-sdk | Shielded voting appchain and circuits (monorepo) |
| terp-rs smart-accounts | Grant-aligned authenticator contracts + suite under contracts/smart-accounts/ |
| FlyClient | Succinct PoW light-client approach (ZIP-221 lineage) |
| Cw-Orch | cw-orchestrator: typed CosmWasm testing and scripting |
| Ecosystem | Application-layer and light-client designs beyond the core VM |
Light Clients
Light clients in this stack are consumer-side programs (often IBC 08-wasm CosmWasm clients) that track Zcash-related consensus and privacy-adjacent state without running a full Zcash node on every appchain.
This chapter is ecosystem-level: which designs exist, how they use Zcash zero-knowledge and consensus primitives, and when to pick one. Implementation repos are maintained by their respective teams—we integrate and document; we do not claim authorship of those libraries.
Credits And Upstream Sources
Libraries and specs below are curated by their upstream teams. Prefer their repositories for correctness, releases, and contribution norms.
| Project | Curated by / origin | Repository |
|---|---|---|
| ICS-08 Wasm light clients (IBC-Go) | Cosmos / IBC-Go maintainers | cosmos/ibc-go — 08-wasm |
| IBC light-client architecture | IBC community | IBC docs, cosmos/ibc (specs including client semantics) |
| IBC v2 / Eureka-oriented programs | Cosmos Solidity IBC Eureka contributors | cosmos/solidity-ibc-eureka |
| cw-ics08-wasm-crosslink | Eureka programs tree (+ monorepo packaging) | programs/cw-ics08-wasm-crosslink |
| cw-ics08-wasm-eth (structural peer) | Same Eureka tree | programs/cw-ics08-wasm-eth |
| Zebra / Crosslink node stack | Shielded Labs / Zebra lineage; permissionlessweb fork for integration | ShieldedLabs/zebra-crosslink, permissionlessweb/zebra-crosslink |
| ics08-wasm client crates (Rust) | IBC-rs maintainers / forks | permissionlessweb/ibc-rs — ics08-wasm (upstream CosmWasm / IBC-rs ecosystem) |
| Tendermint light client crates | Informal / tendermint-rs maintainers | Tendermint-rs light-client packages in the monorepo vendor path |
| CosmWasm contract & host model | CosmWasm core teams | CosmWasm/cosmwasm, book.cosmwasm.com, docs.cosmwasm.com |
Spec-oriented reading for integrators:
- IBC light clients overview (docs site may version-shift; follow current IBC-Go version).
- ICS-08 Wasm module README and ADR notes in ibc-go.
- IBC v2 / multi-hop and Eureka design notes in solidity-ibc-eureka (
docs/, program READMEs) and related monorepo notes such as Mercurydocs/ibc-v2.mdwhen present.
What “Powered By Zcash ZK Primitives” Means
Zcash contributes more than “a hash chain.” Light-client designs in this ecosystem can draw on:
| Primitive family | Role for light clients |
|---|---|
| Proof-of-work headers | Canonical chain work, confirmation depth, pure PoW clients — see Pure PoW Path |
| Crosslink / hybrid finality | Faster finality certificates layered on Zcash work — Crosslink Path |
| ZIP-221 FlyClient-style ideas | Succinct PoW header verification patterns for sparse sampling |
| Halo2 / Orchard-class proving | Validity proofs over batch state, selective disclosure, circuit VKs on the host |
| Nullifiers / note commitments (conceptually) | Privacy-preserving membership and spend-auth adjacent app protocols (via VM + composition, not always inside the LC Wasm) |
The proof VM verifies circuits on the consumer chain; light clients provide verification ability of which Zcash (or hybrid) tip and roots to trust. Together they enable “verify Zcash-grade crypto and headers in CosmWasm.”
Design Families (Summary)
| Design | Trust model | ZK / crypto angle | Status (honest) |
|---|---|---|---|
| Crosslink path | Hybrid finality over PoW | Finality + parent PoW; often paired with app-level Halo2 | Primary implemented LC path in monorepo |
| Pure PoW path | Confirmation depth only | Header work, no Crosslink committee — details & fixtures | Second trust dial; dual-path narrative |
| FlyClient / sparse PoW | Probabilistic PoW proofs | Succinct work proofs (ZIP-221 lineage) | Design / research adjacency for ingress |
| 08-wasm CosmWasm LC | On-chain Wasm client | Host may verify signatures/proofs depending on client | Deployment shape for Crosslink (and peers) |
| IBC v1 classic + IBC v2 / Eureka | Channel / client models per IBC version | Same Wasm packaging; different wire and routing assumptions | Choose stack by consumer chain IBC version |
| App-gated roots via proofs | Application policy | proof_instance_verify on VM after LC tip advances | Composition pattern, not a separate LC binary |
Details: Design Survey. Paths: Crosslink Path, Pure PoW Path, Headers And Ingress.
Integrator Checklist
- Choose a trust dial (pure PoW vs hybrid Crosslink vs future succinct PoW).
- Pin the Wasm checksum / store flow for the 08-wasm client.
- Define ingress (who feeds headers / certificates).
- Separate header advancement from application ZK verification (proof host).
- Align with IBC v1 vs v2 capabilities on the consumer chain.
- Plan for multi-source ecosystems later—the LC section is Zcash-first, not Zcash-only forever.
Next
- Design Survey
- Proof VM for on-chain circuit verify
Design Survey
Survey of light-client and tip-tracking designs used or planned with this stack, emphasizing how they use Zcash consensus and zero-knowledge primitives, plus the IBC / CosmWasm packaging primitives that make them deployable. This is an ecosystem map, not a full protocol specification.
Upstream implementations and specs are curated by their teams—see links and Light Clients.
1. Pure PoW Confirmation Depth
Idea: The consumer only accepts Zcash block headers (and related commitments) after enough proof-of-work accumulates.
| Aspect | Notes |
|---|---|
| Primitives | PoW headers, chain work, confirmation depth |
| Strength | Simple security story; no Crosslink validator set |
| Cost | Latency until depth is met |
| Examples / fixtures | PoW block fixtures under zebra-crosslink crosslink-test-data/; pure-PoW packaging may share modules with Crosslink clients |
| Book path | Pure PoW Path |
2. Crosslink Hybrid Finality
Idea: Track a finality layer that checkpoints or certifies progress while remaining anchored to Zcash work (parent PoW / hybrid model).
| Aspect | Notes |
|---|---|
| Primitives | Finality certificates + PoW parent linkage; often Ed25519 batch verify on roster signatures |
| Strength | Faster usable finality for apps |
| Cost | Additional assumptions on the finality set |
| Code | ShieldedLabs/zebra-crosslink · cw-ics08-wasm-crosslink |
| Book path | Crosslink Path |
3. FlyClient-Style Succinct PoW (ZIP-221 Lineage)
Idea: Prove that a header is on a heavy chain with sparse sampling / succinct arguments rather than shipping the entire header history.
| Aspect | Notes |
|---|---|
| Primitives | PoW, Merkle/mountain-range style commitments, probabilistic proofs |
| Role here | Design space for lighter ingress and public verify demos |
| Honesty | Treat as research / adjacent design, not “only client you need” unless your deployment pins a specific implementation |
4. IBC 08-Wasm Light Client Programs
Idea: Encode client logic as CosmWasm bytecode stored via ICS-08 wasm so the consumer chain runs the LC in Wasm.
| Aspect | Notes |
|---|---|
| Spec / module | ibc-go 08-wasm; CosmWasm host semantics from CosmWasm |
| Primitives | Whatever the Wasm client verifies (headers, sigs, membership proofs) |
| Strength | Upgradable client logic, same deployment story as contracts |
| Examples | Crosslink 08-wasm client; Eth 08-wasm peer in Eureka programs for packaging patterns |
5. IBC Classic Channels And IBC v2 / Eureka
Idea: Light clients are only half of interoperability—the transport and packet model (classic IBC channels vs IBC v2 / Eureka-style routing) shapes how apps consume verified state.
| Aspect | Notes |
|---|---|
| Primitives | Client state, consensus state, connection/channel (v1); v2 packet/client designs per Eureka docs |
| Code / docs | cosmos/ibc specs · solidity-ibc-eureka · monorepo notes (docs/ibc-v2.md where present) |
| Role here | Choose client and IBC version together; do not assume v1 packaging on a v2-only chain |
6. ZK Validity Over Batches (App + Host)
Idea: After a tip is trusted (or in parallel), applications submit Halo2/PLONK proofs verified by the ZK-CosmWasm host (proof_instance_verify), binding app state to public inputs.
| Aspect | Notes |
|---|---|
| Primitives | Halo2-class circuits, VK registry / zkid, public inputs |
| Strength | Selective disclosure and batch validity without putting full witnesses on-chain |
| Not a substitute for | Header / finality light clients—complements them |
| Book path | Proof VM, Applications |
7. Privacy-Adjacent Membership Patterns
Idea: Orchard/note/nullifier concepts appear in composition (votes, auth, bounties identity), often as circuits + app policy rather than inside the header LC.
| Aspect | Notes |
|---|---|
| Primitives | Nullifiers, commitments, spend-auth style statements (as circuits allow) |
| Book path | Vote-Sdk, Smart-Account Auth |
Choosing A Design
Need faster finality + accept hybrid set? → Crosslink path
Need minimal assumptions, can wait? → Pure PoW path (see PoW chapter next to LC)
Need succinct historical PoW? → FlyClient-style designs (evaluate maturity)
Need private/app validity proofs? → VM proof host + applications
Need on-chain upgradable LC logic? → 08-wasm packaging (ICS-08)
Need modern packet routing? → Align IBC v1 vs v2 / Eureka with the client
Expansion Beyond Zcash
Future non-Zcash light clients and app packs can sit beside these designs without rewriting the VM guide. Today’s survey is Zcash-first, with CosmWasm / IBC packaging as the shared deployment primitive.
Crosslink Path
Crosslink is Zcash’s hybrid finality direction: a BFT-style finality layer coordinated with the underlying PoW chain. For CosmWasm / IBC integrators, the practical artifact is an ICS-08 Wasm light client that tracks Crosslink-aware state.
Credits And Code
These projects are maintained by their upstream teams; this guide only maps integrator-facing surfaces.
| Component | Upstream | Repository |
|---|---|---|
| Node / consensus / tooling | Zebra / Crosslink lineage (Shielded Labs et al.) | ShieldedLabs/zebra-crosslink · permissionlessweb/zebra-crosslink |
| CosmWasm 08-wasm client | Cosmos Solidity IBC Eureka programs | cw-ics08-wasm-crosslink |
| ICS-08 module (host chain) | IBC-Go | cosmos/ibc-go — 08-wasm |
| PoW-adjacent fixtures | Same Crosslink test data trees | crosslink-test-data/ in zebra-crosslink — also used for pure PoW engineering tests |
Integrator shape (08-wasm)
Following the same pattern as other 08-wasm clients:
- Build the Wasm light-client contract (optimizer / Just targets in the Eureka programs tree).
- Store bytecode on the host chain via 08-wasm governance / store messages (IBC docs).
- CreateClient with:
- Wasm checksum of the stored bytecode
- Initial client + consensus state for the Crosslink / Zcash view you track
- UpdateClient as finality advances (relayer-submitted updates).
- Verify membership (when supported by the client) against committed IBC or application state roots.
Misbehavior and freeze policies are client-specific; expect freeze-on-conflicting-updates patterns similar to other production light clients, with governance recovery.
Relationship to ZK-CosmWasm VM
- Light clients do not replace
proof_instance_verify. They establish which chain tip / root you trust. - Contracts may combine both: e.g. verify a Halo2 proof whose public inputs bind to a header or state root already accepted by a light client.
- Some designs may even call
proof_instance_verifyduring validation of zero-knowledge light-client proofs.
Pure PoW fallback
If you do not want Crosslink committee assumptions, use confirmation depth only — Pure PoW Path — ideally with the same header/fixture sources.
Developer checklist
- Confirm target chain supports 08-wasm light clients
- Pin a specific Wasm checksum; upgrade via governance when the LC contract changes
- Align relayer software with the client’s update message schema
- Test against fixtures under zebra-crosslink /
crosslink-test-datawhen available - Document whether your product requires Crosslink finality or falls back to pure PoW
- Confirm IBC v1 vs v2 expectations on the consumer chain
Further reading
- Zebra / Crosslink README in the zebra-crosslink repository
- Program README: Eureka
programs/cw-ics08-wasm-crosslink/ - Draft settlement context:
ZCASH_INTEGRATION.mdin this CosmWasm fork
Pure PoW Path
The pure proof-of-work path tracks Zcash headers and treats finality as confirmation depth (enough accumulated work / blocks), without requiring Crosslink BFT finality.
This design sits next to the light-client packaging and Crosslink paths: same header sources and often the same 08-wasm deployment shape, different acceptance rule.
Credits And Code
| Surface | Upstream | Link |
|---|---|---|
| Header / node stack | Zebra / Crosslink forks | ShieldedLabs/zebra-crosslink, permissionlessweb/zebra-crosslink |
| PoW test fixtures | Crosslink test data | crosslink-test-data/test_pow_block_*.bin (engineering fixtures, not a public API) |
| On-chain LC packaging | ICS-08 Wasm | ibc-go 08-wasm, Eureka Wasm programs |
When to prefer pure PoW
| Prefer pure PoW when… | Prefer Crosslink when… |
|---|---|
| You want a simpler trust story (work only) | You need faster economic finality |
| Crosslink is unavailable or out of scope | Your product assumes Crosslink-active networks |
| Bridging is low-frequency and depth is acceptable | UX needs short finality latency |
Integrator notes
- Client state stores the trusted header tip (and parameters such as minimum depth).
- Updates submit new headers (or header batches) that connect to the trusted chain and increase work.
- Acceptance rule: application logic should only act on heights with depth ≥ your configured threshold.
- Test data: PoW block fixtures under zebra-crosslink
crosslink-test-data/are useful when writing verifiers.
Full pure-PoW 08-wasm packaging may lag or share modules with the Crosslink client tree. Always check current Eureka / zebra-crosslink programs for which Wasm artifacts are production-ready.
Differences from Crosslink (developer view)
| Topic | Pure PoW | Crosslink |
|---|---|---|
| Finality signal | Confirmation depth | Hybrid finality certificates / Crosslink layer |
| Update payload | Headers / work proofs | Finality + parent PoW linkage as designed by client |
| Failure mode | Reorg within depth | Conflicting finality / freeze policies |
| Ops dependency | Zcash header source | Zcash + Crosslink participants |
Combining with proofs
Public inputs to a ZK circuit can bind to a block hash, nullifier set root, or note commitment tree root that your contract only trusts after the pure PoW (or Crosslink) client has accepted that height. Keep the light-client update and the proof_instance_verify call in a deliberate order inside your application protocol.
See also
Headers And Ingress
How headers, finality signals, and related evidence enter a consumer chain so light clients can advance.
This chapter is technical.
Ingress roles
| Role | Responsibility |
|---|---|
| Source node | Zcash / Crosslink full node (e.g. zebrad family) exporting headers, finality, or RPC |
| Relayer / operator | Formats and submits UpdateClient (and packet/proof messages) to the consumer chain |
| Wasm light client | Validates updates against current client state; advances consensus state |
| Application | Reads verified heights/roots; may gate contract logic or IBC handlers |
Typical flow
Zcash / Crosslink tip
│
▼
Header / finality export (RPC, indexer, custom feeder)
│
▼
Relayer builds client update message
│
▼
Consumer chain: 08-wasm UpdateClient
│
▼
Client state height / root advanced
│
▼
App / contracts act on verified state
Design tips for public verify
- Idempotent updates — submitting an already-known tip should be a no-op or cheap reject, not a halt.
- Multiple relayers — prefer update formats that allow independent operators (historical update support where required).
- Checksum pinning — document the Wasm LC checksum your deployment expects.
- Observability — log client height, last update time, freeze status for public dashboards.
- Separation of concerns — header ingress is not proof verification; keep ZK proof submission as a separate message path.
Related demos
See Demos for developer-facing verify paths that exercise public clients and contracts.
Applications
Applications are ecosystem libraries and product surfaces that sit above the proof VM and light clients: voting, smart-account authentication, DAO bounties embeds, and demos.
This is not core VM architecture. It is the application layer—expected to grow as support expands beyond a single privacy stack.
┌────────────────────────────────────────────┐
│ Product UIs / DAO tools / demos │ ← Applications
├────────────────────────────────────────────┤
│ Vote-Sdk · Smart-Account Auth · Bounties │
├────────────────────────────────────────────┤
│ Light clients (tip / finality) │ ← Light Clients
├────────────────────────────────────────────┤
│ Proof VM (circuit verify host) │ ← Proof VM
└────────────────────────────────────────────┘
| Surface | Role |
|---|---|
| Vote-Sdk | Commitments, eligibility, vote circuits (valargroup/vote-sdk) |
| Smart-Account Authenticators | x/smart-account + TerpAccountTrait suite (terp-rs) |
| Dao Bounties Embed | DAO-scoped board embed for integrators |
| Demo Map / Public Verify | Reproducible developer demos |
Community program (audit, hackathon registration): Community.
Vote-Sdk
vote-sdk (Shielded Vote Chain) is a Cosmos SDK application for private on-chain voting using Zcash-derived cryptography: Halo2 ZKP circuits, RedPallas signatures, ElGamal encryption, and Poseidon Merkle trees.
| Upstream project | valargroup/vote-sdk — curated by the Valar / vote-sdk team |
| Protocol draft | Shielded Voting Protocol ZIP |
| Bridge into this VM | packages/zk-vote-bridge in the CosmWasm fork (footer / VK packaging toward proof_instance_verify) |
For install, local chain, circuits, and FFI, use the vote-sdk repository README and task runners—this book does not duplicate their setup cookbook.
What it provides (high level)
| Area | Contents |
|---|---|
| Chain binary | Vote module, ceremony / rounds / tally keepers |
| Circuits | Halo2 + RedPallas (often via FFI into the app) |
| Crypto helpers | ECIES, ElGamal, Shamir, ZKP utilities |
| API / proto | REST and protobuf for clients |
Typical circuits named in the bridge crate include delegation, vote commitment, and share reveal.
Connecting to ZK-CosmWasm
Halo2 crate versions may differ between vote-sdk and this fork. Byte-level serialization is the interoperability layer:
- Export params + CS + VK bytes from vote-sdk keygen (per their docs).
- Wrap with a CosmWasm
CircuitFooter(zk-vote-bridge/VoteVerifyingKey). - Store the circuit on the CosmWasm host; assign a
zkid. - Contracts call
proof_instance_verify(zkid, proof, instances)with matching public inputs.
Do not try to share Rust VerifyingKey types across incompatible halo2 versions.
Integration checklist
- Decide whether verification runs on the vote-sdk chain (native FFI) or on a CosmWasm host via
proof_instance_verify - Freeze circuit versions and footer metadata (
k,instances, curve id) - Document public input order for each circuit
- Register
zkidmappings before mainnet contracts go live
Participant / program framing lives under Community; this page is for implementers only.
Smart-Account Authenticators
This stack’s product focus is complementing the chain smart-account module with CosmWasm authenticator contracts that plug into the module’s authentication workflow.
Two layers that work together
| Layer | What it is | Role |
|---|---|---|
x/smart-account (chain module) | Cosmos SDK ante / post handlers, circuit breaker, selected authenticators, fee collection, track + confirm | Owns when authenticators run in the tx pipeline |
TerpAccountTrait + contract suite (terp-rs) | CosmWasm contracts implementing module-driven sudo hooks | Curates how messages are authenticated (passkey, curves, ZK claims, etc.) |
Optional helper crates (credential formatting, envelopes, client-side request helpers) such as smart-account-auth can be used by those contracts and by wallets. They are libraries curated by their maintainers; this book’s emphasis is the module + trait workflow and the authenticator suite that implements it.
Module workflow (what the chain expects)
Terp’s x/smart-account follows the Osmosis-style authenticator pipeline (see module README in the Terp monorepo):
- Circuit breaker — module can fall back to classic SDK auth when disabled or when no authenticators are selected.
- Per-message
Authenticate— selected authenticator validates the message (stateless preferrence for the auth step). Track— after all messages authenticate, authenticators may record stateful side effects that persist even if later execution fails.- Execute messages
ConfirmExecution— post-exec rules (spend limits, etc.); failure can revert execution changes.
CosmWasm authenticators are invoked as sudo messages from the module (AuthSudoMsg / AuthenticationRequest, add/remove hooks, track, confirm).
Contract design: TerpAccountTrait
Implementors live in terp-rs and implement terp_auth::TerpAccountTrait (legacy alias: BtsgAccountTrait):
| Hook | Purpose in the module workflow |
|---|---|
process_sudo_auth | Route all module sudo entrypoints |
on_auth_added / on_auth_removed | Validate config and lifecycle on MsgAddAuthenticator / remove |
on_auth_request | Stateless authenticate / reject (no durable state updates) |
on_auth_track | Stateful notify after successful auth (committed even if exec fails) |
on_auth_confirm | Post-execution policy |
extended_authenticate / on_hooks | Optional helpers outside the default path |
Canonical sources:
| Surface | Link |
|---|---|
| Trait + types | https://github.com/permissionlessweb/terp-rs (crates/terp-auth) |
| Authenticator contracts | https://github.com/permissionlessweb/terp-rs/tree/v0.0.2-dev/contracts/smart-accounts |
| Suite (cw-orch deploy + mock matrix) | terp-authenticator-suite in the same tree |
| Chain module | Terp monorepo x/smart-account (module SoT for ante/post semantics) |
| Credential library (optional) | https://github.com/permissionlessweb/terp-rs — curated by that project’s maintainers |
Suite members (representative)
| Crate / surface | Notes |
|---|---|
terp-passkey | Passkey / WebAuthn turnstile |
terp-ed25519, terp-eth | Classic curve signers |
terp-zkjwt | JWT-style claims (often with host ZK when zk-host tests apply) |
terp-zkpallas | Multi-curve / vote-oriented digests and host routing |
terp-vsck | Vote-sdk-oriented private voting auth |
terp-authenticator-suite | Shared deploy/test helpers |
Composition with ZK-CosmWasm
- Authenticator contracts gate execute with classical credentials or host-verified proofs.
proof_instance_verifycovers ZK statements (membership, eligibility, vote validity) when the chain’s wasmvm exports the host import.- Products often compose both: session turnstile + periodic ZK eligibility.
These crates do not replace the proof VM; they are the smart-account turnstile layer wired to x/smart-account.
Deploy and tests
See the suite README and TESTS_README.md under terp-authenticator-suite in terp-rs for green paths vs residual public testnet work. Deploy helpers live under terp-scripts in that repo.
Demo Map
Named surfaces for reproducing ZK-CosmWasm behavior as an external developer.
| Demo / artifact | Location | What it shows |
|---|---|---|
| VM proof path (unit / integration) | packages/vm tests (e.g. proof_instance_verify_*) | Cold path CircuitInfo → Circuit → verify; curve_id routing |
| Circuit cache benchmarks | packages/vm/benches/, criterion under target/criterion/ZK* | Pin/hot/warm load costs |
| Example Wasm contracts | contracts/* (esp. crypto-oriented samples) | Host crypto patterns; extend with zk where enabled |
| vote-sdk | valargroup/vote-sdk | Private voting stack (see upstream README) |
| zk-vote-bridge | packages/zk-vote-bridge | Footer-wrapped vote circuits for CosmWasm verify |
| Crosslink / PoW LC | zebra-crosslink, cw-ics08-wasm-crosslink | Hybrid finality + PoW header fixtures |
| Bounties e2e scripts | monorepo crates/zec-bounties/scripts | Auth handshake and public-mode ship path |
Suggested learning order
- Read Proof VM overview and Architecture.
- Run or read a
proof_instance_verifytest inpackages/vm. - Serialize a toy circuit footer and store via VM cache APIs.
- Optionally run vote-sdk or light-client scripts if your product needs them.
Hackathon submission themes: Community hackathon.
Public Verify
How an external developer follows a public verification path: open clients, contracts, and reproducible checks—without private lab runbooks.
Goals of a public verify path
- Anyone can fetch client / contract artifacts (checksums, Wasm, circuit blobs).
- Anyone can re-run verification against published public inputs and proofs (or against chain state).
- Operators document RPC / LCD endpoints and light-client checksums in public channels.
Layers you can verify
| Layer | What to check | How |
|---|---|---|
| Circuit blob integrity | Dual SHA-256 in footer | check_circuit / load APIs; recompute checksums |
| On-chain proof | proof_instance_verify result | Submit or simulate tx calling the contract |
| Light client | Client not frozen; height advances | Query 08-wasm client state; compare to source tip |
| Vote ceremony (if used) | Published tallies / nullifiers | vote-sdk / app APIs and chain queries |
| Bounties public mode | DTO redaction | Call public list/detail; assert no private fields |
Minimal contract-side pattern
#![allow(unused)]
fn main() {
// Pseudocode — wire to your ExecuteMsg
let code = deps.api.proof_instance_verify(zkid, proof, instances)?;
ensure!(code == 0, ContractError::InvalidProof {});
// then mutate state that is safe only after a valid proof
}
Ensure zkid is already registered on the target network; publish the circuit key / checksum next to your contract address in release notes.
What not to rely on for “public”
- Private agent boards, lab SSH, or unpublished
.envsecrets - Unpinned “latest” Wasm without checksum
- Proofs without public inputs and circuit id
For program desk and forum links, see Public surfaces.
What This Section Covers
Community Led Audit & Design Space Hackathon Surface Areas.
It is separate from day-to-day VM usage and from light-client / application libraries:
| Focus | Where |
|---|---|
| Proof VM, tooling, reference | Using ZK-CosmWasm |
| Light clients and applications | Light Clients, Applications |
Public Surfaces And Residual Ask
| Surface | URL |
|---|---|
| Public desk | https://permissionless.money/zk |
| Forum thread | https://forum.zcashcommunity.com/t/54211 |
| Live ZCG application | https://github.com/ZcashCommunityGrants/zcashcommunitygrants/issues/369 |
This book links public program material. Dollar amounts, legal application text, and residual asks must match the live application and desk, not diverge here.
Community-Led Audit
High-level goals and participation shape for the community-led audit track:
- Explore the published stack (VM proof path, light clients, ecosystem applications)
- Report security-sensitive findings through published private channels — not public chat dumps
- Prefer reproducible, technical write-ups against pinned commits / checksums
Detailed operational playbooks, internal triage boards, and grant budget tables are out of scope for this developer book. Watch the public surfaces for official audit windows and contact paths.
Dao Bounties Embed
Design-Space Hackathon
Intent of the design-space hackathon: demos that exercise the VM, light clients, and/or application surfaces documented in Parts I–II.
Prize tables, registration, and deadlines live in published program materials (desk / forum / application). This chapter only orients developers who may submit technical work—use the demo map to pick a concrete target.