Why Cairo/STARKs for Ztarknet (and the STARK_VERIFY TZE)
Reminder: STARK_VERIFY TZE proposal - Ztarknet proposal
Goal. Explain why we chose a Cairo/STARK stack for Ztarknet and for the proposed
STARK_VERIFYTZE, and why we believe it is the most robust, future‑proof path for Zcash even amid strong progress on RISC‑V‑based zkVMs.
Thesis. For Zcash’s priorities—minimal L1 change, tight consensus risk budget, and predictable verification economics—a zk‑native ISA (Cairo) coupled with hash‑based STARK verification yields a better cost/risk profile than general‑purpose RISC‑V zkVMs, especially once you include the often‑underestimated glue cost of modeling a stack interpreter and consensus semantics inside a zkVM.
Why Cairo vs RISC-V zkVMs
Smart contract first
Cairo is a smart-contract focused language and VM, it has an established ecosystem of tooling, devs, and apps running in prod for multiple years (including top perp DEXes and large scale onchain games). So far RISC-V zkVMs provide EVM emulation which comes with a huge overhead, and the longer term plans to introduce a native smart contract framework has many pitfalls: Long-term L1 execution layer proposal: replace the EVM with RISC-V - Primordial Soup - Fellowship of Ethereum Magicians
Simplicity → Formal Security
A small, minimalist VM can have its entire transition logic fully specified and mechanically verified using Lean and other theorem provers. Large ISAs create combinatorial explosions in proof state space, making full end-to-end formal security (and bug eradication) much harder for general-purpose RISC-V zkVMs.
Maximal Efficiency for L1/L2 Use
Cairo avoids emulating hardware conventions and is not shackled by legacy opcode baggage. It only implements what is required for succinct verification, whereas RISC-V zkVMs inherently bear the cost of CPU semantics and conversion layers.
Sustainability and Evolution
Cairo (as an ISA) has already ossified, i.e. very few new features, reliability is maximized, and the core needs no constant reinvention. Cairo is built for the vision of the eventual “maintenance mode” and is thus less likely to accrue technical debt compared to feature-crowded RISC-V-based stacks.
Recursion and Aggregation as First-Class
Cairo ISA has been optimized for efficient recursion (e.g. by introducing specific opcodes) which allows the proving system to operate at far lower cost. RISC-V zkVMs typically optimize for compatibility first, and optimization for efficient recursion is more “bolted on” and less deeply integrated
Summary
| Feature/Dimension | Cairo | RISC-V zkVMs |
|---|---|---|
| Instruction Set | Minimal & purpose-built | Full RISC-V (RV32/RV64): general-purpose, complex |
| Complexity / Verifiability | Relatively small codebase | Complex, larger attack surface, harder full formal proofs |
| Efficiency (Proof Costs) | Circle STARK and logup lookups cut commitment costs, optimized for recursion | RISC-V zkVMs (e.g., RISC Zero) require elaborate CIRCUIT translation layers (e.g., MLIR), and proof optimization post hoc |
| Blockchain alignment | Designed for smart contracts, has an intermediate representation for gas accounting | Used for general-purpose zk projects, smart contracts possible but with higher wrapping layers |
| Long-term Maintenance | Deliberate, slow evolution — stability prioritized | Churn with evolving RISC-V ISAs and circuit dev stack |
“General‑purpose” means semantics, not “is RISC‑V”
A persistent conflation: “Only RISC‑V zkVMs are general‑purpose.” Not so.
- Cairo is Turing‑complete and can express arbitrary computations.
- The non‑compatibility is about host toolchains (you won’t
cargo buildyour Rust onto Cairo), not expressiveness. - For Zcash’s L2, we do not need L1‑visible reuse of existing Rust/C++; we need a provable state transition and a simple L1 verifier.
We explicitly accept the DevX trade‑off (write Cairo) to gain proof efficiency and L1 simplicity. That’s the right trade for a minimal‑change settlement layer like Zcash.
Script/transparent logic: why interpreter‑in‑zkVM is costly
Even if you never intend to scale the transparent part, any design that anchors L2 to L1 Script semantics or re‑uses Script in a zkVM inherits major costs:
- Stack machine with variable‑length opcodes → many branches, memory shuffles, and bit fiddling.
- Introspection ops (signature checks, serialization, sighash variants) blow up constraints unless you add specialized gadgets—at which point you are halfway to a zk‑native ISA anyway.
- Teams building Script interpreters in zkVMs consistently find the glue dominates. In contrast.
Pragmatic conclusion: do not try to lift Script or TZEs into a zkVM to make them L2‑executable; keep Script/TZEs on L1 and let L2 be Cairo‑native. The interface is the proof, not the program.
Addressing concerns
“We’re building Tachyon; scaling Script/TZEs in‑circuit is infeasible anyway.”
Agreed. Tachyon (the zk stack for shielded verification) will not initially accelerate the transparent part (Script or TZE). That’s fine:
- The
STARK_VERIFYTZE does not require Tachyon. It’s a consensus verifier, separate from shielded proving. - Later, if Tachyon wants to also verify STARK receipts in‑circuit (e.g., for compound proofs), it can: the TZE pins parameters and formats ahead of time, making an in‑circuit gadget feasible and well‑specified.
- Until then, L1 remains conservative and L2 scales independently.
“RISC‑V zkVMs have amazing DevX and reuse Rust; why turn that down?”
Because DevX ≠ verifier economics, and reuse ≠ safety in consensus:
- Running “existing Rust” under a zkVM requires deterministic host modeling, syscalls shims, and ELF discipline. That is security engineering we would then be anchoring into Zcash consensus via the L2 interface.
- The cost to prove a stack interpreter + environment is large and workload‑sensitive. A Cairo spec gives predictable proof sizes and a simple L1 verifier.
“Doesn’t Cairo lock us in?”
We pin wire formats and verifier parameters in the TZE so L1 is not Cairo‑specific; it only checks STARK receipts. On L2 we choose Cairo because it’s the most mature zk‑native ISA with production tooling. If a better zk‑native ISA emerges, the TZE stays the same; only L2 changes.
Comparison and trade‑offs
| Aspect | RISC‑V zkVM (typical) | Cairo/CPU‑AIR |
|---|---|---|
| Memory | Read‑write RAM; last‑write‑wins via sorted views/permutation | Write‑once memory; reads link to unique write |
| Continuations | VM‑level continuations (resume PC/RAM); convenient, but expensive RAM argument | Application‑level; less convenient, cheaper proofs and aggregation |
| Built‑ins | Few; rely on instruction count | Many; hash/bitwise/range/EC built directly into columns |
| Proof composition | Often SNARKish or hybrid; verifier may include pairings/IPA | STARK‑on‑STARK recursion; hash‑heavy verifier; still priced by bytes |
| DevX | Excellent (reuse LLVM/Rust) | Requires Cairo; worse DevX, better proof economics |
The STARK_VERIFY TZE: shape and reasonableness
- Type:
STARK_VERIFY_V1 - Mode:
Stwo(Circle‑STARK). - Public inputs (bounded):
root_old,root_new,program_or_air_id, optionalDA_commitment, optional aux. - Witness: proof bytes (bounded).
- Consensus bounds:
MAX_PROOF_BYTES(per mode/parameter set),MAX_PUBIN_BYTES; deterministic parser; fail‑fast. - Policy: initially limit one TZE input per tx; lower byte caps.
Why this is safe:
- No minting path; value conservation stays in existing code paths.
- Pinned parameters eliminate ambiguity; byte caps bound cost.
- Transparent assumptions (hashes, FRI).
- Small surface area → easier audits.
What we learned building Script‑like provers
- The interpreter itself isn’t the only cost; the adapter layer to consensus semantics (sighashes, malleability, lock‑times, serialization) dominates in zkVM settings.
- Stack/bytecode workloads are especially unfriendly to RISC‑V zkVMs: lots of RAM traffic and branching.
- In Cairo, these patterns map to compact AIRs with built‑in primitives (bitwise/range/hash), and we can slice via application‑level continuations to keep traces small.
Parameterization: proof size, security level (λ), and blockspace policy
This section makes explicit the dials we will expose in the STARK_VERIFY_V1 TZE and the initial targets we propose for a mainnet pilot. The aim is to give Zcash core developers a bounded, auditable cost envelope and a clear path to ratchet security up without redesigns.
What controls proof size & verifier cost?
For a STARK, the L1 verifier is dominated by hashing for Merkle openings and FRI queries. Concretely, verifier time and proof bytes scale roughly linearly with:
- the number of query rounds in the IOP of proximity,
- the hashes per opening (Merkle depth / commitment scheme),
- and a small fixed overhead for field arithmetic.
That makes verification economics “priced by bytes” with excellent predictability: if we cap proof bytes in consensus, we cap validation cost. This byte‑pricing is consistent with the TZE framework (ZIP‑222) and with the v5+ digest plumbing (ZIP‑244/245).
Initial targets and how to increase security if needed
| Dial | Pilot target | Effect on proof size & L1 time | How to increase security later |
|---|---|---|---|
| Security level (λ) | ≈ 100–110 bits end‑to‑end | Adds ~linearly to queries/bytes | Increase query count; reduce code rate; add grinding bits |
| Proof bytes cap (consensus) | ≤ 100 KiB per STARK_VERIFY input |
Upper‑bounds L1 CPU and block bytes | Raise slowly after measurements |
| Mempool policy | 1 proof per block, or ≤ 5–10% of block bytes | Prevents DoS & “sticker shock” | Relax if ops show headroom |
| Grinding bits (optional) | 26 bits (pilot) | Negligible verifier cost; small prover overhead | Up to 32 bits for +6 security bits (provable linear cost) |
| Code rate (ρ) | 1/2 (pilot) | Balanced prover/verifier tradeoff | Can drop to 1/4 if a narrow recursive circuit needs it |
Why the 100–110‑bit target? Zcash reviewers have historically preferred ≥100‑bit concrete security. STARK parameterization makes that straightforward: increase FRI/IOPP query count and/or grinding; verifier cost grows roughly with proof bytes.
Expected proof size & cadence
- Proof bytes. We are comfortable targeting 50–100 KiB proofs for L2 state‑root updates under Circle‑STARK/Stwo with tuned parameters (more below on why STIR/WHIR isn’t needed at the L1 verifier). This is aligned with the “priced by bytes” cap above.
- Frequency. Post a single proof every few hours (amortizing 10^5+ L2 tx per proof in typical batches). Even if we limit to 1 proof per block or ≤10% of block bytes, this is fine for settlement latency and does not worsen shielded sync costs (TZE proofs do not contribute to note‑scanning).
- Splitting, if needed. If governance wants smaller envelopes per tx, we can split a large proof across multiple TZE transactions via an accumulator‑UTXO pattern (each tx commits to a chunk; the final tx verifies the whole proof)
Why not switch the verifier to STIR/WHIR to “shrink proofs”?
Recent IOPP work (STIR, WHIR) reduces query complexity for RS proximity in some regimes. However, in wide‑trace STARKs (dozens to thousands of columns) that use many‑to‑1 FRI steps, the first commitment/FRI layer dominates both bytes and time. In that setting:
- STIR/WHIR saves ≈ 1% on proof bytes in practice while adding protocol complexity, and it interferes with grinding‑based security amplification (grinding is a simple, robust knob for us).
- Therefore, for the L1 verifier we stay with FRI and get predictability and simpler audits; if we later add a narrow recursive circuit off‑chain, that’s where trying WHIR/STIR might make sense (it’s a different regime).
“Proximity gap” results & our safety margin
There’s been important progress on Reed–Solomon proximity gaps, clarifying limits near the list‑decoding radius. The upshot for engineering is simple:
- You do not need to rely on proximity‑gap conjectures to run a secure STARK; if a conjecture were weakened, you tweak parameters (more queries / lower ρ) and proofs get longer by a bounded factor.
- That is exactly the kind of byte‑priced knob we want at L1. We will document a “no‑conjectures mode” with larger proof sizes as a fallback profile in the ZIP.
Field choice & hashes
- Circle‑STARK (Stwo) operates over Mersenne M31 with a circle‑FFT; this unlocks speed and predictable verifier costs while keeping assumptions transparent & hash‑based. Hash choices will be pinned in the ZIP.
- The TZE does not bake in Cairo; it pins a STARK verifier with exact formats/parameters. L2 can evolve (e.g., choose a different zk‑native ISA later); the L1 port stays the same.
- Post‑quantum plausibility is preserved because the L1 proof check relies on hash and IOPP soundness, not pairings or trusted setups
Blockspace & mempool policy options
None of this requires a consensus fork beyond the TZE itself. We can achieve predictable resource use via policy:
- Per‑class feerate floor: Give
STARK_VERIFYinputs their own mempool class and feerate floor, so general txs aren’t displaced unpredictably. - Per‑block byte quota: Allow
STARK_VERIFYto consume at most 5–10% of serialized block bytes initially (soft policy). - At‑most‑one or two per block: Very conservative policy for the first testnet → mainnet phase.
- Pool coordination: Mining pools can voluntarily adopt a common template honoring the lane/quota to help network sync and encourage adoption; this is operational policy, not a consensus rule.
Forced withdrawals & exits (practical design notes)
Do we need an L1 ZKP for every forced withdrawal? Not necessarily.
- Permissionless block building on L2 lets any party include outstanding exits in a batch that moves
root_old → root_new; the one L1 proof covers many exits. - If governance still wants an L1 escape hatch, we can use a header‑cache UTXO pattern (accumulating recent L2 anchors) so batched exits are verified against a cached root without re‑introducing a large L1 state machine.
- The key is that exits aggregate behind the same
STARK_VERIFY—so even worst‑case “mass exit” scenarios map to few proofs at predictable byte cost.
