Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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

PartFocus
I — Using ZK-CosmWasmProof VM · Cw-Orch / ict-rs tooling · reference
II — EcosystemLight clients · applications (vote-sdk, auth, bounties, demos)
III — Community ProgramThin public residual links (audit / hackathon)

Build Path

Start here when writing contracts or tests:

  1. Proof VM
  2. Architecture
  3. Circuits And Verifying Keys
  4. 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 contractsProof VM
Tracking Zcash tips / finalityLight Clients
Building product protocolsApplications
Writing tests and deploy scriptsCw-Orch Testing And Scripting
Following the residual community programCommunity Program

Relationship To CosmWasm Book

CosmWasm BookThis book
Sitehttps://book.cosmwasm.com/https://zk.permissionless.money/ (when published)
FocusWriting CosmWasm contractsZK-CosmWasm extensions, light clients, ecosystem applications
Upstream API docshttps://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

ConcernStock CosmWasmZK-CosmWasm
Crypto hostssecp256k1, ed25519, BLS12-381, …Same, plus Halo2/PLONK-style proof verification
Circuit selectionSmart-Contract SpecificApplication-assigned zkid → circuit metadata / key
Storage of VKsSmart-Contract SpecificContent-addressed blob (params + constraint system + VK + footer)
Contract APIapi.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

  1. Upload / register a circuit verifying key (often with contract code via store_code_with_circuit, or as a standalone circuit via store_circuit).
  2. Map an application zkid to the circuit’s content-addressed key (consensus/app state).
  3. 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)
Stock CosmWasm rows are always present on modern hosts. Rows marked NEW require the listed feature on the linked wasmvm / cosmwasm-vm build. Contract crates call api.proof_instance_verify via cosmwasm-std feature zk; hash and BN254 may be used as Wasm imports depending on std bindings.

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)
Poseidon / RedJubjub helpers may exist as library stubs; they are not listed until a stable host import is wired.

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)
Defined as CurveType in packages/zk. Host BN254 precompiles (bn254_*) share the same curve family as id 4 but are separate entrypoints from proof verification.

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:

CrateRole
packages/stdContract-facing API and Wasm imports
packages/vmHost import, gas, cache integration
packages/zkFooter, serialization, AnyVerifyingKey
packages/zk-vote-bridgeExample: vote-sdk circuits → CosmWasm footer format
packages/cryptoShared 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 zk on cosmwasm-std / contract crates that call proof_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

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

LayerIdentifierWhat it stores
App / consensuszkid (u64 / u32 at the Wasm boundary)Logical circuit id → content key / checksum mapping
VM cacheCircuit 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:

  1. Charge host-call gas and read proof / instance regions from Wasm memory
    • Proof max size: 2 MiB
    • Instances max size: 64 KiB
  2. Charge halo2_proof_instance_verify gas (linear cost model).
  3. Query CircuitInfo for zkidcircuit_key (72 bytes).
  4. Load verifying key:
    • Prefer host cache loader (no full circuit over the querier)
    • Else cold path: Circuit query → deserialize footer + body → AnyVerifyingKey
  5. Decode instances with footer.curve_id (never with zkid as a curve hint).
  6. Verify; return codes:
    • 0 — cryptographic verification succeeded
    • 1 — 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 conceptZK-CosmWasm
Virtual addresszkid
Page tableApp mapping / CircuitInfo
Physical frameDeserialized VK in pinned memory
Page faultCache miss → disk or Circuit query
Wired pagesPinned circuits
Page cacheFile-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

SymptomLikely cause
“circuit not found” / CircuitInfo errorzkid never registered or wrong chain state
Deserialization / footer errorsCorrupt blob, wrong format version, truncated file
Ok(1)Valid host path, invalid proof or wrong public inputs
Instance length errorsInstances not multiple of 32-byte field elements

Implementation map

AreaPath
Host importpackages/vm/src/imports.rs
Gas / envpackages/vm/src/environment.rs
Cachepackages/vm/src/cache.rs, packages/vm/src/zk.rs
Serializationpackages/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 same k and 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  ]
OffsetSizeField
01prover_id (0 = Plonkish)
11curve_id (e.g. Pasta; BN254 uses a distinct id)
21k
31i (public input scalar count)
4–74param_len (u32 LE)
8–114cs_len (u32 LE)
12–154vk_len (u32 LE)
16–4732param_checksum = SHA256(params)
48–7932vk_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 AnyInstance from curve_id in the footer, so a single zkid space 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:

AttributeMeaning
kCircuit size (2^k rows); common range 11–20
instancesNumber of public input scalars
footer_version≥ 2 for CS-inclusive format
analyze_csDefault 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

  1. Implement Halo2 (or supported) circuit; keygen VK with matching params.
  2. Serialize params, CS, VK; build footer with dual checksums (or use macro helpers).
  3. Store via store_circuit / store_code_with_circuit on the host.
  4. Register zkidcircuit_key in app state.
  5. From contracts, call proof_instance_verify with matching public inputs.
  6. 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)

AudienceDocument
Circuit implementersZK_COSMWASM_CIRCUIT_MACRO.md
Byte formatZK_CIRCUIT_SERIALIZATION_FORMAT.md
IndexZK_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

TierKeyEvictionPersistence
Pinned memory72-byte circuit / 36-byte paramManual pin/unpin onlyLost on process restart
In-memory LRUUnified CacheKey (module / partial / circuit)Weight-based LRULost on restart
File systemHex filenames under zk_*Manual removeSurvives 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

CallEffect
pin_circuitEnsure deserialized VK is in pinned map (idempotent)
unpin_circuitDrop pinned entry (disk may remain)
remove_circuitUnpin 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

LevelUse
Per-VK size_estimateWeighting, metrics
Pinned / LRU totalsObservability, optional limits
Global pinned circuit memoryOptional host limits

Pinned circuits are not automatically evicted. Treat pin as a performance wire for production hot paths.

Operator tips

  1. After restart, re-pin circuits that appear on every block.
  2. Watch pinned hit rate vs FS loads (deserialization is expensive).
  3. Prefer split layout so many circuits share param files for the same k.
  4. Keep consensus zkid mappings 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

CapabilityRough meaning
iteratorRange queries on storage
stakingStaking module messages/queries
stargateProtobuf / IBC-era messages
ibc2IBC v2 surfaces
cosmwasm_1_1cosmwasm_3_0Versioned 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 GasConfig and docs/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

  1. 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).
  2. Prefer pinned circuits on validators that serve many ZK txs.
  3. Keep public inputs small and well-typed; oversized instance regions fail or waste gas.
  4. When targeting multiple chains, document required CosmWasm version capabilities and that the chain’s wasmvm must be ZK-enabled.
  5. After changing circuits or host crypto, re-run:
cargo run -p zk-cosmwasm --features bn254 --bin verify_gas_calibrate --release

References in this repo

PathContent
docs/CAPABILITIES.mdNegotiation model
docs/CAPABILITIES-BUILT-IN.mdBuilt-in list
docs/GAS.mdPoints to upstream gas docs
packages/vm/src/environment.rsGasConfig defaults
packages/vm/src/imports.rsdo_proof_instance_verify unit formula
packages/zk/src/bin/verify_gas_calibrate.rsCalibration 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

LayerCapability
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 envsMock → local daemon → Docker-spawned chain via ict-rs
E2E suitesCompose 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.

PieceRole
cw_orch_circuit_derive::circuit_interfaceMacro parallel to contract interface
CircuitUploadableTrait 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 keysPK = params + proving material; VK carries terpvm circuit footer metadata expected by zk-wasmvm
Daemonupload_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:

  1. Compile / export circuit VK (and optional zk package) into artifacts/.
  2. Implement CircuitUploadable (or generated circuit_interface) for that artifact name.
  3. On a chain env: upload circuit then upload + instantiate the verifier / app contract.
  4. 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:

APIPurpose
QuickSpawn / SnapshotStoreSnapshot 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
QuickSpawnEnvWraps manager + daemon as Environment<Daemon> — drop-in for existing cw-orch tests; Drop stops the container
ict-rs-cw-orchCrate 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
Sidecarse.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)

PathRole
crates/cw-orchestrator/cw-orchInterfaces, prelude, circuit_interface re-export
crates/cw-orchestrator/cw-orch-daemonLive chain + upload_circuit
crates/cw-orchestrator/packages/cw-orch-corecircuits module, CircuitUploadable
crates/cw-orchestrator/packages/macros/cw-orch-circuit-deriveDerive macros for circuits
crates/ict-rs/ict-rsDocker spawn, QuickSpawnEnv, Terp ZK suite traits
crates/ict-rs/ict-rs-cw-orchAdapter package

  1. Unit — mock cw-orch interfaces for contract messages.
  2. Circuit artifacts — generate VK/zk into artifacts/; unit-test serialize/footer if needed.
  3. Integration — daemon against local terpd with zk-wasmvm.
  4. E2E — ict-rs Docker spawn + upload circuit + contract + proof path; optional sidecars.
  5. CI — pin images/snapshots; always stop / Drop containers.

See Also

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 pathBook chapter
README.mdIntroduction, Proof VM
ZCASH_INTEGRATION.mdProof VM (context only; no TZE design dump)
ZK_COSMWASM_ZKVM_SPEC.mdArchitecture
ZK_PROOF_VERIFICATION_ARCHITECTURE.mdArchitecture
ZK_CIRCUIT_QUICK_REFERENCE.mdCircuits And Verifying Keys
ZK_CIRCUIT_SERIALIZATION_FORMAT.mdCircuits And Verifying Keys
ZK_COSMWASM_CIRCUIT_MACRO.mdCircuits And Verifying Keys
ZK_STORAGE_AND_CACHING.mdStorage And Caching
docs/CAPABILITIES*.md, GAS.md, FEATURES.mdGas And Capabilities
packages/vm/src/environment.rsGas And Capabilities (GasConfig)

Tooling

PathBook 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

Glossary

TermMeaning
ZK-CosmWasmCosmWasm stack with proof-verification-oriented host support and circuit caching
zkidApplication-assigned logical circuit id resolved to a content-addressed circuit key
VKVerifying key (with embedded constraint system in this stack’s version-2 format)
CircuitFooter80-byte trailer: prover/curve/k/instances, section lengths, dual SHA-256 checksums
circuit_key72-byte content key: param_key ‖ vk_key
paramsHalo2 (or similar) commitment parameters; often shared for a given k
Path AHost-cache load of VK after CircuitInfo (avoids pulling full blob over querier)
Cold pathCircuit query + deserialize when cache misses
CrosslinkHybrid finality light-client / node path over Zcash PoW
Pure PoWConfirmation-depth light-client path on Zcash headers only
08-wasmIBC light client whose logic runs as CosmWasm Wasm bytecode
CapabilityContract/host negotiation via requires_* Wasm exports (not Cargo features)
vote-sdkShielded voting appchain and circuits (monorepo)
terp-rs smart-accountsGrant-aligned authenticator contracts + suite under contracts/smart-accounts/
FlyClientSuccinct PoW light-client approach (ZIP-221 lineage)
Cw-Orchcw-orchestrator: typed CosmWasm testing and scripting
EcosystemApplication-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.

ProjectCurated by / originRepository
ICS-08 Wasm light clients (IBC-Go)Cosmos / IBC-Go maintainerscosmos/ibc-go — 08-wasm
IBC light-client architectureIBC communityIBC docs, cosmos/ibc (specs including client semantics)
IBC v2 / Eureka-oriented programsCosmos Solidity IBC Eureka contributorscosmos/solidity-ibc-eureka
cw-ics08-wasm-crosslinkEureka programs tree (+ monorepo packaging)programs/cw-ics08-wasm-crosslink
cw-ics08-wasm-eth (structural peer)Same Eureka treeprograms/cw-ics08-wasm-eth
Zebra / Crosslink node stackShielded Labs / Zebra lineage; permissionlessweb fork for integrationShieldedLabs/zebra-crosslink, permissionlessweb/zebra-crosslink
ics08-wasm client crates (Rust)IBC-rs maintainers / forkspermissionlessweb/ibc-rs — ics08-wasm (upstream CosmWasm / IBC-rs ecosystem)
Tendermint light client cratesInformal / tendermint-rs maintainersTendermint-rs light-client packages in the monorepo vendor path
CosmWasm contract & host modelCosmWasm core teamsCosmWasm/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 Mercury docs/ibc-v2.md when 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 familyRole for light clients
Proof-of-work headersCanonical chain work, confirmation depth, pure PoW clients — see Pure PoW Path
Crosslink / hybrid finalityFaster finality certificates layered on Zcash work — Crosslink Path
ZIP-221 FlyClient-style ideasSuccinct PoW header verification patterns for sparse sampling
Halo2 / Orchard-class provingValidity 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)

DesignTrust modelZK / crypto angleStatus (honest)
Crosslink pathHybrid finality over PoWFinality + parent PoW; often paired with app-level Halo2Primary implemented LC path in monorepo
Pure PoW pathConfirmation depth onlyHeader work, no Crosslink committee — details & fixturesSecond trust dial; dual-path narrative
FlyClient / sparse PoWProbabilistic PoW proofsSuccinct work proofs (ZIP-221 lineage)Design / research adjacency for ingress
08-wasm CosmWasm LCOn-chain Wasm clientHost may verify signatures/proofs depending on clientDeployment shape for Crosslink (and peers)
IBC v1 classic + IBC v2 / EurekaChannel / client models per IBC versionSame Wasm packaging; different wire and routing assumptionsChoose stack by consumer chain IBC version
App-gated roots via proofsApplication policyproof_instance_verify on VM after LC tip advancesComposition pattern, not a separate LC binary

Details: Design Survey. Paths: Crosslink Path, Pure PoW Path, Headers And Ingress.

Integrator Checklist

  1. Choose a trust dial (pure PoW vs hybrid Crosslink vs future succinct PoW).
  2. Pin the Wasm checksum / store flow for the 08-wasm client.
  3. Define ingress (who feeds headers / certificates).
  4. Separate header advancement from application ZK verification (proof host).
  5. Align with IBC v1 vs v2 capabilities on the consumer chain.
  6. Plan for multi-source ecosystems later—the LC section is Zcash-first, not Zcash-only forever.

Next

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.

AspectNotes
PrimitivesPoW headers, chain work, confirmation depth
StrengthSimple security story; no Crosslink validator set
CostLatency until depth is met
Examples / fixturesPoW block fixtures under zebra-crosslink crosslink-test-data/; pure-PoW packaging may share modules with Crosslink clients
Book pathPure PoW Path

Idea: Track a finality layer that checkpoints or certifies progress while remaining anchored to Zcash work (parent PoW / hybrid model).

AspectNotes
PrimitivesFinality certificates + PoW parent linkage; often Ed25519 batch verify on roster signatures
StrengthFaster usable finality for apps
CostAdditional assumptions on the finality set
CodeShieldedLabs/zebra-crosslink · cw-ics08-wasm-crosslink
Book pathCrosslink 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.

AspectNotes
PrimitivesPoW, Merkle/mountain-range style commitments, probabilistic proofs
Role hereDesign space for lighter ingress and public verify demos
HonestyTreat 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.

AspectNotes
Spec / moduleibc-go 08-wasm; CosmWasm host semantics from CosmWasm
PrimitivesWhatever the Wasm client verifies (headers, sigs, membership proofs)
StrengthUpgradable client logic, same deployment story as contracts
ExamplesCrosslink 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.

AspectNotes
PrimitivesClient state, consensus state, connection/channel (v1); v2 packet/client designs per Eureka docs
Code / docscosmos/ibc specs · solidity-ibc-eureka · monorepo notes (docs/ibc-v2.md where present)
Role hereChoose 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.

AspectNotes
PrimitivesHalo2-class circuits, VK registry / zkid, public inputs
StrengthSelective disclosure and batch validity without putting full witnesses on-chain
Not a substitute forHeader / finality light clients—complements them
Book pathProof 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.

AspectNotes
PrimitivesNullifiers, commitments, spend-auth style statements (as circuits allow)
Book pathVote-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.

ComponentUpstreamRepository
Node / consensus / toolingZebra / Crosslink lineage (Shielded Labs et al.)ShieldedLabs/zebra-crosslink · permissionlessweb/zebra-crosslink
CosmWasm 08-wasm clientCosmos Solidity IBC Eureka programscw-ics08-wasm-crosslink
ICS-08 module (host chain)IBC-Gocosmos/ibc-go — 08-wasm
PoW-adjacent fixturesSame Crosslink test data treescrosslink-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:

  1. Build the Wasm light-client contract (optimizer / Just targets in the Eureka programs tree).
  2. Store bytecode on the host chain via 08-wasm governance / store messages (IBC docs).
  3. CreateClient with:
    • Wasm checksum of the stored bytecode
    • Initial client + consensus state for the Crosslink / Zcash view you track
  4. UpdateClient as finality advances (relayer-submitted updates).
  5. 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_verify during 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-data when 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.md in 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

SurfaceUpstreamLink
Header / node stackZebra / Crosslink forksShieldedLabs/zebra-crosslink, permissionlessweb/zebra-crosslink
PoW test fixturesCrosslink test datacrosslink-test-data/test_pow_block_*.bin (engineering fixtures, not a public API)
On-chain LC packagingICS-08 Wasmibc-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 scopeYour product assumes Crosslink-active networks
Bridging is low-frequency and depth is acceptableUX 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.

TopicPure PoWCrosslink
Finality signalConfirmation depthHybrid finality certificates / Crosslink layer
Update payloadHeaders / work proofsFinality + parent PoW linkage as designed by client
Failure modeReorg within depthConflicting finality / freeze policies
Ops dependencyZcash header sourceZcash + 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

RoleResponsibility
Source nodeZcash / Crosslink full node (e.g. zebrad family) exporting headers, finality, or RPC
Relayer / operatorFormats and submits UpdateClient (and packet/proof messages) to the consumer chain
Wasm light clientValidates updates against current client state; advances consensus state
ApplicationReads 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

  1. Idempotent updates — submitting an already-known tip should be a no-op or cheap reject, not a halt.
  2. Multiple relayers — prefer update formats that allow independent operators (historical update support where required).
  3. Checksum pinning — document the Wasm LC checksum your deployment expects.
  4. Observability — log client height, last update time, freeze status for public dashboards.
  5. Separation of concerns — header ingress is not proof verification; keep ZK proof submission as a separate message path.

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
└────────────────────────────────────────────┘
SurfaceRole
Vote-SdkCommitments, eligibility, vote circuits (valargroup/vote-sdk)
Smart-Account Authenticatorsx/smart-account + TerpAccountTrait suite (terp-rs)
Dao Bounties EmbedDAO-scoped board embed for integrators
Demo Map / Public VerifyReproducible 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 projectvalargroup/vote-sdk — curated by the Valar / vote-sdk team
Protocol draftShielded Voting Protocol ZIP
Bridge into this VMpackages/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)

AreaContents
Chain binaryVote module, ceremony / rounds / tally keepers
CircuitsHalo2 + RedPallas (often via FFI into the app)
Crypto helpersECIES, ElGamal, Shamir, ZKP utilities
API / protoREST 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:

  1. Export params + CS + VK bytes from vote-sdk keygen (per their docs).
  2. Wrap with a CosmWasm CircuitFooter (zk-vote-bridge / VoteVerifyingKey).
  3. Store the circuit on the CosmWasm host; assign a zkid.
  4. 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 zkid mappings 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

LayerWhat it isRole
x/smart-account (chain module)Cosmos SDK ante / post handlers, circuit breaker, selected authenticators, fee collection, track + confirmOwns when authenticators run in the tx pipeline
TerpAccountTrait + contract suite (terp-rs)CosmWasm contracts implementing module-driven sudo hooksCurates 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):

  1. Circuit breaker — module can fall back to classic SDK auth when disabled or when no authenticators are selected.
  2. Per-message Authenticate — selected authenticator validates the message (stateless preferrence for the auth step).
  3. Track — after all messages authenticate, authenticators may record stateful side effects that persist even if later execution fails.
  4. Execute messages
  5. 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):

HookPurpose in the module workflow
process_sudo_authRoute all module sudo entrypoints
on_auth_added / on_auth_removedValidate config and lifecycle on MsgAddAuthenticator / remove
on_auth_requestStateless authenticate / reject (no durable state updates)
on_auth_trackStateful notify after successful auth (committed even if exec fails)
on_auth_confirmPost-execution policy
extended_authenticate / on_hooksOptional helpers outside the default path

Canonical sources:

SurfaceLink
Trait + typeshttps://github.com/permissionlessweb/terp-rs (crates/terp-auth)
Authenticator contractshttps://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 moduleTerp 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 / surfaceNotes
terp-passkeyPasskey / WebAuthn turnstile
terp-ed25519, terp-ethClassic curve signers
terp-zkjwtJWT-style claims (often with host ZK when zk-host tests apply)
terp-zkpallasMulti-curve / vote-oriented digests and host routing
terp-vsckVote-sdk-oriented private voting auth
terp-authenticator-suiteShared deploy/test helpers

Composition with ZK-CosmWasm

  • Authenticator contracts gate execute with classical credentials or host-verified proofs.
  • proof_instance_verify covers 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 / artifactLocationWhat 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 benchmarkspackages/vm/benches/, criterion under target/criterion/ZK*Pin/hot/warm load costs
Example Wasm contractscontracts/* (esp. crypto-oriented samples)Host crypto patterns; extend with zk where enabled
vote-sdkvalargroup/vote-sdkPrivate voting stack (see upstream README)
zk-vote-bridgepackages/zk-vote-bridgeFooter-wrapped vote circuits for CosmWasm verify
Crosslink / PoW LCzebra-crosslink, cw-ics08-wasm-crosslinkHybrid finality + PoW header fixtures
Bounties e2e scriptsmonorepo crates/zec-bounties/scriptsAuth handshake and public-mode ship path

Suggested learning order

  1. Read Proof VM overview and Architecture.
  2. Run or read a proof_instance_verify test in packages/vm.
  3. Serialize a toy circuit footer and store via VM cache APIs.
  4. 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

  1. Anyone can fetch client / contract artifacts (checksums, Wasm, circuit blobs).
  2. Anyone can re-run verification against published public inputs and proofs (or against chain state).
  3. Operators document RPC / LCD endpoints and light-client checksums in public channels.

Layers you can verify

LayerWhat to checkHow
Circuit blob integrityDual SHA-256 in footercheck_circuit / load APIs; recompute checksums
On-chain proofproof_instance_verify resultSubmit or simulate tx calling the contract
Light clientClient not frozen; height advancesQuery 08-wasm client state; compare to source tip
Vote ceremony (if used)Published tallies / nullifiersvote-sdk / app APIs and chain queries
Bounties public modeDTO redactionCall 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 .env secrets
  • 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:

FocusWhere
Proof VM, tooling, referenceUsing ZK-CosmWasm
Light clients and applicationsLight Clients, Applications

Public Surfaces And Residual Ask

SurfaceURL
Public deskhttps://permissionless.money/zk
Forum threadhttps://forum.zcashcommunity.com/t/54211
Live ZCG applicationhttps://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.