Special thanks to Justin Drake and Sean Bowe for wonderfully pedantic and thoughtful feedback and review, and to Pratyush Mishra for discussion that contributed to the original IPA exposition.
Readers who have been following the ZK-SNARK space closely should by now be familiar with the high level of how ZK-SNARKs work. ZK-SNARKs are based on checking equations where the elements going into the equations are mathematical abstractions like polynomials (or in rank-1 constraint systems matrices and vectors) that can hold a lot of data. There are three major families of cryptographic technologies that allow us to represent these abstractions succinctly: Merkle trees (for FRI), regular elliptic curves (for inner product arguments (IPAs)), and elliptic curves with pairings and trusted setups (for KZG commitments). These three technologies lead to the three types of proofs: FRI leads to STARKs, KZG commitments lead to "regular" SNARKs, and IPA-based schemes lead to bulletproofs. These three technologies have very distinct tradeoffs:
Technology | Cryptographic assumptions | Proof size | Verification time |
---|---|---|---|
FRI | Hashes only (quantum safe!) | Large (10-200 kB) | Medium (poly-logarithmic) |
Inner product arguments (IPAs) | Basic elliptic curves | Medium (1-3 kB) | Very high (linear) |
KZG commitments | Elliptic curves + pairings + trusted setup | Short (~500 bytes) | Low (constant) |
So far, the first and the third have seen the most attention. The reason for this has to do with that pesky right column in the second row of the table: elliptic curve-based inner product arguments have linear verification time. What this means that even though the size of a proof is small, the amount of time needed to verify the proof always takes longer than just running the computation yourself. This makes IPAs non-viable for scalability-related ZK-SNARK use cases: there's no point in using an IPA-based argument to prove the validity of an Ethereum block, because verifying the proof will take longer than just checking the block yourself. KZG and FRI-based proofs, on the other hand, really are much faster to verify than doing the computation yourself, so one of those two seems like the obvious choice.
More recently, however, there has been a slew of research into techniques for merging multiple IPA proofs into one. Much of the initial work on this was done as part of designing the Halo protocol which is going into Zcash. These merging techniques are cheap, and a merged proof takes no longer to verify than a single one of the proofs that it's merging. This opens a way forward for IPAs to be useful: instead of verifying a size-$n$ computation with a proof that takes still takes
So how do these techniques work, and what can they do? That's exactly what this post is about.
Inner product arguments are a proof scheme that can work over many mathematical structures, but usually we focus on IPAs over elliptic curve points. IPAs can be made over simple elliptic curves, theoretically even Bitcoin and Ethereum's secp256k1 (though some special properties are preferred to make FFTs more efficient); no need for insanely complicated pairing schemes that despite having written an explainer article and an implementation I can still barely understand myself.
We'll start off with the commitment scheme, typically called Pedersen vector commitments. To be able to commit to degree
To commit to a polynomial
Though it's not really mathematically accurate to think of elliptic curve points as being like real numbers that have sizes, area is nevertheless a good intuition for thinking about linear combinations of elliptic curve points like we use in these commitments. The blue area here is the value of the Pedersen commitment $C = \sum_i c_i G_i$ to the polynomial $P = \sum_i c_i x^i$.
Now, let's get into how the proof works. Our final goal will be a polynomial evaluation proof: given some
Of course, technically any point is some multiple of
The prover could, of course, just provide
You may be able to see where this is going: if you add
But there's a problem: if
Choose a random factor
- The yellow area (
$L$ ) gets multiplied by$\alpha^2$ (because every yellow square is scaled up by$\alpha$ on both dimensions) - The green area (
$R$ ) gets divided by$\alpha^2$ (because every green square is scaled down by$\alpha$ on both dimensions) - The blue area (
$C$ ) remains unchanged (because its width is scaled up but its height is scaled down)
Hence, we can generate our new half-size instance of the problem with some simple transformations:
- $G'{i} = \alpha G{2i} + \frac{G_{2i+1}}{\alpha}$
- $c'{i} = \frac{c{2i}}{\alpha} + \alpha c_{2i+1}$
$C' = C + \alpha^2 L + \frac{R}{\alpha^2}$
(Note: in some implementations you instead do $G'i = \alpha G{2i} + G_{2i+1}$ and $c'i = c{2i} + \alpha c_{2i+1}$ without dividing the odd points by
And then we repeat the process until we get down to one point:
Finally, we have a size-1 problem: prove that the final modified $C^$ (in this diagram it's $C'''$ because we had to do three iterations, but it's $log(n)$ iterations generally) equals the final modified $G^_0$ and $c^_0$. Here, the prover just provides $c^_0$ in the clear, and the verifier checks $c^_0 G^_0 = C^$. Computing $c^0$ required being able to compute a linear combination of ${c_0 ... c{n-1}}$ that was not known ahead of time, so providing it and verifying it convinces the verifier that the prover actually does know all the coefficients that go into the commitment. This concludes the proof.
- The statement we are proving is that
$C$ is a commitment to some polynomial$P(x) = \sum_i c_i x^i$ committed to using the agreed-upon base points${G_0 ... G_{n-1}}$ - The proof consists of
$log(n)$ pairs of$(L, R)$ values, representing the yellow and green areas at each step. The prover also provides the final$c^*_0$ - The verifier walks through the proof, generating the
$\alpha$ value at each step using the same algorithm as the prover and computing the new$C'$ and$G'_i$ values (the verifier doesn't know the$c_i$ values so they can't compute any$c'_i$ values) - At the end, they check whether or not $c^_0 G^_0 = C^*$
On the whole, the proof contains
See also: Dankrad Feist's more detailed explanation of inner product arguments.
We can extend to polynomial evaluations with a simple clever trick. Suppose we are trying to prove
We can make a Pedersen commitment using this extended base!
Now, here's a puzzle. Suppose
The answer is: it must be equal to
Hence, if
Note that in practice, this is usually done slightly differently as an optimization: instead of attaching the numbers to the points and explicitly dealing with structures of the form
See here for an example implementation of this whole protocol.
Suppose that you are given two polynomial evaluation proofs, with different polynomials and different evaluation points, and want to make a proof that they are both correct. You have:
- Proof
$\Pi_1$ proving that$P_1(z_1) = y_1$ , where$P_1$ is represented by$com(P_1) = C_1$ - Proof
$\Pi_2$ proving that$P_2(z_2) = y_2$ , where$P_2$ is represented by$com(P_2) = C_2$
Verifying each proof takes linear time. We want to make a proof that proves that both proofs are correct. This will still take linear time, but the verifier will only have to make one round of linear time verification instead of two.
We start off with an observation. The only linear-time step in performing the verification of the proofs is computing the
This is using the
The above polynomial has degree
- The prover computes the above polynomial for each proof; we'll call these polynomials
$K_1$ with$com(K_1) = D_1$ and$K_2$ with$com(K_2) = D_2$ . In a "normal" verification, the verifier would be computing$D_1$ and$D_2$ themselves as these are just the$G^*_0$ values for their respective proofs. Here, the prover provides$D_1$ and$D_2$ and the rest of the work is proving that they're correct. - To prove the correctness of
$D_1$ and$D_2$ we'll prove that they're correct at a random point. We choose a random point$t$ , and evaluate both$e_1 = K_1(t)$ and$e_2 = K_2(t)$ - The prover generates a random linear combination
$L(x) = K_1(x) + rK_2(x)$ (and the verifier can generate$com(L) = D_1 + rD_2$ ). The prover now just needs to make a single proof that$L(t) = e_1 + re_2$ .
The verifier still needs to do a bunch of extra steps, but all of those steps take either
This technique can easily be generalized to merge
Now, we get into the core mechanic of the Halo protocol being integrated in Zcash, which uses this proof combining technique to create a recursive proof system. The setup is simple: suppose you have a chain, where each block has an associated IPA-based SNARK (see here for how generic SNARKs from polynomial commitments work) proving its correctness. You want to create a new block, building on top of the previous tip of the chain. The new block should have its own IPA-based SNARK proving the correctness of the block. In fact, this proof should cover both the correctness of the new block and the correctness of the previous block's proof of the correctness of the entire chain before it.
IPA-based proofs by themselves cannot do this, because a proof of a statement takes longer to verify than checking the statement itself, so a proof of a proof will take even longer to verify than both proofs separately. But proof merging can do it!
Essentially, we use the usual "recursive SNARK" technique to verify the proofs, except the "proof of a proof" part is only proving the logarithmic part of the work. We add an extra chain of aggregate proofs, using a trick similar to the proof merging scheme above, to handle the linear part of the work. To verify the whole chain, the verifier need only verify one linear-time proof at the very tip of the chain.
The precise details are somewhat different from the exact proof-combining trick in the previous section for efficiency reasons. Instead of using the proof-combining trick to combine multiple proofs, we use it on a single proof, just to re-randomize the point that the polynomial committed to by
Expressed in math:
- Let
$P(z) = a$ be the previous statement that needs to be proven - The prover generates
$G^*_0$ - The prover proves the correctness of the new block plus the logarithmic work in the previous statements by generating a PLONK proof:
$Q_L * A + Q_R * B + Q_O * C + Q_M * A * B + Q_C = Z * H$ - The prover chooses a random point
$t$ , and proves the evaluation of a linear combination of${G^*_0,\ Q_L,\ A,\ Q_R,\ B,\ Q_O,\ C,\ Q_M,\ Q_C,\ Z,\ H}$ at$t$ . We can then check the above equation, replacing each polynomial with its now-verified evaluation at$t$ , to verify the PLONK proof.
The size of each "step" does not need to be a full block verification; it could be something as small as a single step of a virtual machine. The smaller the steps the better: it ensures that the linear work that the verifier ultimately has to do at the end is less. The only lower bound is that each step has to be big enough to contain a SNARK verifying the
But regardless of the fine details, this mechanism allows us to make succinct and easy-to-verify SNARKs, including easy support for recursive proofs that allow you to extend proofs in real time as the computation extends and even have different provers to do different parts of the proving work, all without pairings or a trusted setup! The main downside is some extra technical complexity, compared with a "simple" polynomial-based proof using eg. KZG-based commitments.
Technology | Cryptographic assumptions | Proof size | Verification time |
---|---|---|---|
FRI | Hashes only (quantum safe!) | Large (10-200 kB) | Medium (poly-logarithmic) |
Inner product arguments (IPAs) | Basic elliptic curves | Medium (1-3 kB) | Very high (linear) |
KZG commitments | Elliptic curves + pairings + trusted setup | Short (~500 bytes) | Low (constant) |
IPA + Halo-style aggregation | Basic elliptic curves | Medium (1-3 kB) | Medium (constant but higher than KZG) |
A common alternative to building SNARKs out of polynomial games is building SNARKs out of matrix-vector multiplication games. Polynomials and vectors+matrices are both natural bases for SNARK protocols because they are mathematical abstractions that can store and compute over large amounts of data at the same time, and that admit commitment schemes that allow verifiers to check equations quickly.
In R1CS (see a more detailed description here), an instance of the game consists of three matrices
An R1CS instance with a single constraint (so $A$, $B$ and $C$ have width 1), with a satisfying $Z$ vector, though notice that here the $Z$ appears on the left and has 1 in the top position instead of the bottom.
Just like with polynomial-based SNARKs, this R1CS game can be turned into a proof scheme by creating commitments to
Ioanna Tzialla et al describe such a scheme in a recent paper (see page 8-9 for their description). They first modify the game by introducing an expanded equation:
For a "base" instance,
The trick involves taking a random linear combination
This expands into the following (grouping the
The first term is just
Hence, it's possible to make merging schemes for R1CS-based protocols too. Interestingly enough, we don't even technically need to have a "succinct" protocol for proving the $$ (A \cdot Z) \circ (B \cdot Z) = u * (C \cdot Z) + E$$ relation at the end; instead, the prover could just prove by opening all the commitments directly! This would still be "succinct" because the verifier would only need to verify one proof that actually represents an arbitrarily large number of statements. However, in practice having a succinct protocol for this last step is better because it keeps the proofs smaller, and Tzialla et al's paper provides such a protocol too (see page 10).
- We don't know of a way to make a commitment to a size-$n$ polynomial where evaluations of the polynomial can be verified in
$< O(n)$ time directly. The best that we can do is make a$log(n)$ sized proof, where all of the work to verify it is logarithmic except for one final $O(n)$-time piece. - But what we can do is merge multiple proofs together. Given
$m$ proofs of evaluations of size-$n$ polynomials, you can make a proof that covers all of these evaluations, that takes logarithmic work plus a single size-$n$ polynomial proof to verify. - With some clever trickery, separating out the logarithmic parts from the linear parts of proof verification, we can leverage this to make recursive SNARKs.
- These recursive SNARKs are actually more efficient than doing recursive SNARKs "directly"! In fact, even in contexts where direct recursive SNARKs are possible (eg. proofs with KZG commitments), Halo-style techniques are typically used instead because they are more efficient.
- It's not just about polynomials; other games used in SNARKs like R1CS can also be aggregated in similar clever ways.
- No pairings or trusted setups required!
The march toward faster and more efficient and safer ZK-SNARKs just keeps going...