Zero-knowledge proofs for developers: what they actually are and when you need them
ZK is the most over-mystified concept in Web3. Here's what zero-knowledge proofs actually do, the SNARKs vs STARKs distinction that matters in practice, and the tools we reach for when building with them.
Most explanations of zero-knowledge proofs start with the same thought experiment. Alice wants to prove to Bob she knows a secret without revealing the secret. Bob accepts. Everyone nods. Nobody comes away understanding how this maps to production software.
We've implemented ZK components in three protocols. Here's the version of this explanation we wish had existed when we started.
What ZK proofs actually do
A zero-knowledge proof lets you prove that a computation was done correctly without revealing the inputs to that computation. That's the entire idea. Everything else is implementation detail.
The practical applications fall into two categories. Privacy: prove you know something - a credential, a balance above a threshold, an identity attribute - without revealing what it is. And scalability: prove that a large batch of transactions was valid without making a verifier re-execute every one of them. Both are being built on in production right now. Both are genuinely useful.
SNARKs vs STARKs - the distinction that actually helps you decide
Every ZK explainer tells you SNARKs are smaller and faster to verify, and STARKs are larger but don't require a trusted setup. Both are true. Neither is the thing that should drive your decision.
SNARKs (Groth16, PLONK) are what you reach for when you're building on Ethereum mainnet and gas cost per verification matters. Proof size is small - a few hundred bytes - and verification is cheap on-chain. The trusted setup is a real consideration, but multi-party ceremonies like Ethereum's KZG ceremony have made it manageable for most use cases.
STARKs are what you reach for when you need post-quantum security guarantees, or when you're in an environment where a trusted setup isn't feasible. They're also significantly easier to audit - the math is based on hash functions rather than elliptic curve pairings, which means more people can actually verify the security arguments. The tradeoff is proof size and on-chain verification cost. StarkWare's entire stack is built on STARKs.
Building on Ethereum L1 and care about gas? Probably SNARKs. Building your own rollup or appchain? Evaluate STARKs seriously. Not sure yet? You probably don't need ZK at this stage.
The tools developers actually use
Circom is where most developers start. It's a domain-specific language for writing arithmetic circuits - the representation ZK proving systems operate on. The learning curve is steep because you're not writing a program, you're describing constraints. A program runs sequentially. A circuit defines relationships between values that must all hold simultaneously. That mental shift is the hardest part of getting started.
Noir is the more recent alternative. It looks more like Rust, it compiles to an intermediate representation that multiple proving backends can target, and it feels closer to writing normal code. If you're new to ZK and don't have a specific reason to use Circom, start with Noir. The onboarding friction is meaningfully lower.
For zkEVM work - circuits that prove Ethereum Virtual Machine execution - Halo2 from the Zcash team is widely used. It's powerful and the documentation is solid, but it requires a working understanding of the polynomial commitment scheme underneath it. Not a beginner tool.
SP1 from Succinct Labs is worth watching. It lets you write ZK programs in standard Rust, which brings the barrier down dramatically. Proofs are larger than hand-optimised circuits, but for many use cases the developer experience tradeoff is justified. We've used it on a project where time-to-working-proof mattered more than proof size.
When you actually need ZK in a project
This is the question nobody answers directly in ZK content. Here are the real cases where it belongs:
- You need to prove something about private data without exposing it - identity credentials, credit scores, balances above a threshold, medical attributes
- You're building a rollup and need to prove off-chain transaction batches are valid without relying on an honest majority assumption (ZK-rollup vs optimistic rollup is fundamentally this tradeoff)
- You need on-chain verification of off-chain computation that's too expensive to run on-chain directly
- You're building a privacy-preserving DeFi protocol where counterparties shouldn't know each other's positions or order sizes
What you don't need ZK for: most standard DeFi. If your protocol is moving tokens, running AMM swaps, or operating a straightforward lending market, ZK adds significant development complexity without solving a problem you actually have. The impulse to add ZK because it signals technical depth is real in this space. Resist it.
The part nobody warns you about
ZK circuit development is debugging in the dark.
When a normal program has a bug, you get an error, a stack trace, sometimes a line number. When a ZK circuit has a bug - a constraint that's wrong or missing - you get a proof that fails to verify, with very little signal about where the failure is. The tooling is improving, but it's still nowhere near the developer experience of conventional software. Plan for this.
The other cost that surprises teams is proving time. Generating a ZK proof is computationally expensive. For a complex circuit, proof generation can take seconds to minutes even on high-end hardware. Production systems that need fast proof generation require pre-computation strategies, dedicated proving infrastructure, or both. This is a real engineering problem, not a footnote.
Budget 30-40% more time than you think you need for ZK circuit development. Constraint bugs are subtle, the debugging experience is unlike anything in conventional software, and the first time you get a proof to verify correctly on-chain, you'll understand why teams underestimate this.
Where to start if you're coming in fresh
Don't start with the math. Start with what you're trying to prove and why.
- Build something small in Noir first: prove you know a secret that hashes to a given value. Get it working before touching anything more complex.
- Deploy it and verify on-chain once, even on a testnet. The path from circuit to on-chain verifier is the most useful thing to understand end-to-end.
- Read the Groth16 paper if you want the theory - but don't block on it. The intuition comes from building, not from the math alone.
- Then go deeper on the specific proving system that fits your actual use case.
ZK is real technology running in production systems today. zkSync, StarkNet, Aztec, Polygon zkEVM - these aren't research projects. But the gap between understanding the concept and shipping production ZK code is larger than almost any other area of Web3 development. Go in with realistic expectations, patience for the fundamentals, and a clear answer to the question: what problem does ZK actually solve for this specific project?
