The privacy tech behind rollups, private voting, and hidden-amount payments — plus how to pick a proof system and build with it.
Every blockchain is a public ledger, which means every amount, every counterparty, and every vote stays visible forever. What you actually want is to prove a claim is true — this transfer balances, I am on the allowlist, this program ran correctly — without publishing the data behind it. That is the job of a zero-knowledge proof (ZKP), and this course walks the whole landscape of them. You start with Schnorr, a three-move protocol small enough to write in fifty lines of Python, then build up through Pedersen and KZG commitments, turning a program into a rank-1 constraint system (R1CS), and the two big families: SNARKs (succinct non-interactive arguments of knowledge — tiny proofs, but a trusted setup) and STARKs (scalable transparent arguments — no setup, post-quantum, bigger proofs). After that come folding schemes and zkVMs (zero-knowledge virtual machines) that prove an ordinary Rust program instead of a hand-written circuit. Python and Rust throughout. Five capstones — a hash-preimage proof, a confidential transfer, a proof of reserves, an anonymous membership proof, a zkVM run — and you submit any three.
Built by Lakshya
We grant free access case-by-case — students, career-switchers, builders on a tight budget. Sign in to send us a note.
Sign in to applyFinished the tasks? Take the prompt to your AI and get tested on it. We copy the prompt and open the app — just paste it in.
Lock a number away so nobody can read it or change it, then prove it is in range — the trick behind private payments.
A prover cannot run your code; it can only check equations. This module is how the translation happens, and why it costs so much.
Groth16 proofs are three points and verify in milliseconds — the catch is a ceremony you have to trust. See exactly how both work.
Groth16 makes you redo the ceremony for every circuit. Universal setup does it once — here is the machinery that buys that.
Trade proof size for trusting nobody at all. Hash-based proofs that survive quantum computers, built up from FRI to a working STARK.
Recursion re-proves everything each round. Nova folds two claims into one instead, so long computations stop blowing up your prover.
Skip circuit writing entirely: compile normal Rust, get a proof it ran correctly. Learn when that is a bargain and when it is not.
Pull apart rollups, Semaphore, ZK Email, and MACI to see the design choices real teams made under real constraints.
An under-constrained circuit still produces proofs — they just prove nothing. Learn to find those bugs before an attacker does.
Complete all modules, then submit the required number of capstone projects. Each must earn a passing rating from an admin reviewer.
Prove knowledge of x such that SHA-256(x) = y without revealing x. Use Circom + Groth16 (easiest) or axiom-circuit + Halo2 (modern). Submit: the circuit source, a trusted-setup ceremony artefact (or reference to one), one generated proof + verification key, and a verification run showing 'proof valid.' Include a benchmark: constraint count, prover time, verifier time, proof size.
Build a Bitcoin-style UTXO transfer where amounts are hidden (Pedersen-committed) and conservation (sum of inputs = sum of outputs) is enforced via a Bulletproof range proof proving each output amount is in [0, 2^64]. Deliver: Rust or Python code, a test transaction, and the proof bytes. Publish the proof size (expected ~700 bytes per output with Bulletproofs) and the verification time.
Prove 'I am one of the N members of this set' without revealing which. Implement a zk-circuit that proves knowledge of a leaf + Merkle path in a 20-level tree (1M member capacity). Submit: circuit, proof generation script, and a demo where the proof binds a signal (e.g., a message) via a nullifier. This is the Semaphore primitive used in Worldcoin-style anonymous credentials.
Build a proof-of-reserves system where an exchange commits to the sum of all customer balances and proves to each customer 'your balance is included in this total' without revealing other customers' balances. Use a Merkle tree of balances + sum checks. Submit: prover + verifier code, a test run with 1000 synthetic accounts totalling a known sum, and a short design note explaining liabilities and why this does NOT prove solvency on its own.
Use RISC Zero (or SP1) to compile a non-trivial Rust program — a Fibonacci sequence verifier, or a simple SHA-256 preimage checker — into a ZK proof of its execution. Submit: the Rust program, the generated proof, and the verifier output. Bonus: measure cycle count and prover time, and compare against a hand-written circuit's size.
The clearest intro to how R1CS becomes a polynomial identity. Read before Module 4.