A service needs to check that you are old enough to use it. You send it a copy of your ID. It now has your name, date of birth, photo, and whatever else was on the document, all to answer one question.
That is the problem that makes zero-knowledge proofs interesting to me. We often hand over the data behind a claim just so someone else can check it. A zero-knowledge proof lets us build systems that check the claim while keeping that data private.
This post covers what that means, how the proof gets made, and a few of the systems you will run into.
What are zero-knowledge proofs?
There are two parties: a prover, who wants to prove a statement, and a verifier, who checks it. Zero-knowledge means the proof reveals nothing beyond what follows from the public statement being true.
Say I claim to know the solution to a puzzle. Sending you the solution would let you check my answer, but you would then know it too. With a zero-knowledge proof of knowledge, I can convince you that I know a valid solution while keeping it to myself.
The solution is called a witness. The verifier gets a proof that I know one. The witness stays with me.
For the age check, the statement might be that I hold a valid credential from an accepted issuer and that its date of birth puts me above the required age. The proof would need to check both the issuer's signature and the age condition. Checking a date I typed in myself would prove very little!
The service learns that I meet the requirement. It does not need to receive my full ID to make that decision.
But I hate crypto!
That is fine. Here, crypto means cryptography. You can use zero-knowledge proofs without a blockchain, a token, or anything to trade.
The part I care about is how much information an application needs to collect. If it only needs to check one property of my data, a proof can let it do that without taking a copy of everything else.
Depending on what the application needs, we could prove that:
- we know a secret associated with a public value,
- a private number falls within an allowed range,
- we hold a credential signed by an accepted issuer, while keeping some of its fields private,
- a computation produced the claimed result using private inputs.
The data still exists on the prover's side, and anything we choose to make public remains public. The useful change is that the verifier can check a specific claim without collecting the private inputs behind it.
How do they work?
We first need to express what a valid answer looks like. Many proving systems do this with a circuit: arithmetic operations and constraints that describe the computation we want to check.
The prover computes the witness, including private inputs and intermediate values. The proof then establishes that those values satisfy the constraints. This is where the exact statement matters. The verifier accepts whatever the circuit actually checks.
I'll use an arithmetic example to walk through circuits, constraints, and polynomials. This is one route used by some SNARK constructions; other proving systems organise the work differently.
Arithmetic circuits
An arithmetic circuit uses addition and multiplication gates, usually over a finite field. You can think of the field here as arithmetic modulo a fixed prime.
Suppose we want to check:
We can split that into two constraints by introducing an intermediate value :
Now we have one constraint that checks the square and another that checks the result. The witness includes the values of , , and . A valid assignment has to satisfy both equations in the chosen field.
Rank-1 Constraint System (R1CS)
R1CS writes each constraint as a product of two linear combinations, equal to a third:
Here is the vector of values used by the circuit, including a constant , public inputs, and private witness values. The vectors , , and contain the coefficients for constraint . Each dot product selects and combines values from .
In the first constraint above, the left side selects twice and the right side selects . In the second, the left side selects and multiplies it by . The right side is zero.
Same checks, written in a form the proving system can work with.
Quadratic Arithmetic Programs (QAP)
A QAP encodes those constraints using polynomials. We assign each constraint a distinct field point and use interpolation to build polynomials that match the constraint coefficients at those points.
After combining those polynomials with the witness values, we get , , and . If every constraint holds, then is zero at every constraint point. It must therefore be divisible by the target polynomial , whose roots are those points:
The polynomial is the quotient. We have turned checking the individual constraints into checking a polynomial relationship. That relationship is the basis for the next part, but it does not hide the witness by itself.
Generating the proof
The prover uses the witness and the proving system's parameters to construct a proof. In a QAP-based SNARK, this proves the polynomial relationship above without sending the witness or its polynomials in the clear.
The cryptographic construction does the work of preventing false proofs and hiding the witness. How it does that depends on the system. Pairings, polynomial commitments, and hash functions appear in different constructions; they are not interchangeable steps in one recipe.
Sending and checking it
For a non-interactive proof, the prover sends a single proof, along with any public inputs the verifier needs. The verifier checks it using the verification parameters for the circuit.
With a succinct system, this can take much less work than repeating the computation. The prover does the expensive part, and the verifier gets a smaller check.
If verification succeeds, the verifier accepts the statement under the system's security assumptions. In our example, that means accepting that the prover knows values satisfying the equations. It says exactly what we encoded in the circuit.
The names you will run into
Proof size, proving time, verification cost, and setup requirements all matter. Here are a few names that come up often, and what they mean.
zk-SNARKs
SNARK stands for "succinct non-interactive argument of knowledge." The zk adds zero-knowledge. The appeal is a small proof with efficient verification, even when the computation being proved is large.
Some constructions need a trusted setup, where public parameters are generated using secret randomness that must be discarded. Others avoid that requirement. It depends on the construction. Zcash's explanation covers both the terminology and why the setup matters.
zk-STARKs
STARK stands for "scalable transparent argument of knowledge." Transparent means there is no trusted setup relying on secret randomness that someone must destroy. STARKs use hash-based techniques and are designed to scale to large computations. The original paper describes the construction and its security assumptions.
That does not give us a blanket rule that STARKs verify faster than SNARKs. We still need to compare concrete systems and workloads.
PLONK
PLONK is a SNARK construction with a universal, updatable trusted setup. The same setup can support different circuits up to its supported size, and additional participants can contribute randomness to it.
That is useful when the circuit changes: we can reuse the setup within those limits instead of running a new ceremony for each circuit.
Bulletproofs
Bulletproofs provide short zero-knowledge proofs without a trusted setup. A common use is a range proof: showing that a hidden value falls within an allowed range.
That lets a confidential transaction prove that an amount is valid while keeping the amount private. Short proofs do not automatically mean cheap verification, though. Bulletproof verification requires more work than the succinct verification offered by SNARKs.
Why I care
The age check is a small example, but it captures what I find useful about ZK. A service has a question it needs answered. We can build a proof around that question and leave the rest of the user's data out of it.
There is real work in choosing the statement, writing the constraints, and making the system practical. But reducing how much private data an application needs to hold is a good reason to learn how this works.
For more on the math and the tools:
- Vitalik's cryptography posts cover SNARKs, STARKs, and the ideas behind them.
- ZK HACK's whiteboard sessions walk through proof systems and their underlying constructions.
- 0xPARC's Halo2 learning material covers building circuits with Halo2.
- Matter Labs' resource list collects papers, explainers, and tools.