Open this lesson in your favourite AI. It'll walk you through the why, explain the demo, and quiz you on the try-it list.
Every week a new ZK scheme is announced. By the end of Module 1 you need a mental map of the major families, their trade-offs, and which problem each is solving. This task is a survey — not a deep-dive into any scheme, but enough that you can read any paper's 'Related Work' section with orientation.
Four families: SNARKs (Groth16, PLONK, Marlin, Halo2) give short proofs and fast verification but most need trusted setup; STARKs (StarkWare, RISC Zero) need no trusted setup but have larger proofs; Bulletproofs (Büntz et al.) excel at range proofs, no setup, but linear verification; folding schemes (Nova, ProtoStar) accumulate computation efficiently over many steps — great for incremental verification. Which you pick depends on: do you need a trusted setup? How large can the proof be? How fast must verification be? What's the circuit size?
// main.go
// Rough 2025 snapshot (numbers change; order of magnitude correct).
//
// Family | Setup | Proof size | Prover | Verifier | PQ?
// --------------------- | ---------- | ----------- | --------- | --------- | ---
// Groth16 | per-circuit| 192 bytes | fast | 3ms | No
// PLONK / UltraPLONK | universal | ~1 KB | fast-ish | ~10ms | No
// Marlin | universal | ~1 KB | slow | fast | No
// Halo2 (Zcash) | universal | ~1 KB | medium | medium | No
// Nova / ProtoStar | none | ~2-20 KB | fast/step | 50ms | No
// Bulletproofs | none | log(N)·32B | slow | linear | No
// STARK (Plonky/Risc0) | none | ~100 KB | fast | fast | Yes
//
// Pick STARK if: no trusted setup, proof size tolerable, post-quantum.
// Pick Groth16 if: on-chain verification, tiny proof mandatory.
// Pick PLONK if: universal setup, flexible circuits, standard choice.
// Pick Bulletproofs if: range proofs, confidential transactions, no setup.
// Pick Nova / ProtoStar if: very long computation, incremental verification.
package main
import "fmt"
func main() {
schemes := []struct {
Family string
Setup string
ProofSize string
Prover string
Verifier string
PQ string
}{
{"Groth16", "per-circuit", "192 bytes", "fast", "3ms", "No"},
{"PLONK / UltraPLONK", "universal", "~1 KB", "fast-ish", "~10ms", "No"},
{"Marlin", "universal", "~1 KB", "slow", "fast", "No"},
{"Halo2 (Zcash)", "universal", "~1 KB", "medium", "medium", "No"},
{"Nova / ProtoStar", "none", "~2-20 KB", "fast/step", "50ms", "No"},
{"Bulletproofs", "none", "log(N)·32B", "slow", "linear", "No"},
{"STARK (Plonky/Risc0)", "none", "~100 KB", "fast", "fast", "Yes"},
}
fmt.Printf("%-22s | %-10s | %-11s | %-9s | %-9s | %s\n",
"Family", "Setup", "Proof size", "Prover", "Verifier", "PQ?")
fmt.Println("---------------------- | ---------- | ----------- | --------- | --------- | ---")
for _, s := range schemes {
fmt.Printf("%-22s | %-10s | %-11s | %-9s | %-9s | %s\n",
s.Family, s.Setup, s.ProofSize, s.Prover, s.Verifier, s.PQ)
}
}go run main.goUse these three in order. Each builds on the one before.
In one paragraph, give me a map of the ZK ecosystem — the major families (SNARKs, STARKs, Bulletproofs, folding), what each optimises for, and when to pick which.
Walk me through the concrete differences between Groth16, PLONK, and STARK prover pipelines: what does each commit to (polynomial vs vector), what's the setup phase, and why do proof sizes differ by orders of magnitude?
Given I'm designing a ZK rollup that needs post-quantum security AND sub-50ms verification AND a proof that fits in an Ethereum calldata slot, which ZK scheme(s) could I use, what's the design trade-off, and which 2024 paper is most relevant?