Understanding PLONK
PLONK is the state of the art when it comes to general-purpose proof system. While it was released in 2019, the paper has recently received some updates, and the scheme is still evolving (with Aztec announcing an UltraPLONK version coming soon). This is the scheme that we use at Mina to compress the size of the blockchain from gigabytes to a fixed size of a dozen kilobytes.
While I don’t think the core ideas are the hardest to understand, the scheme compresses a myriad of optimization which makes it hard to parse. In this post I hope to add some clarity to some aspects of the scheme. Note that I assume that you have some knowledge of how PLONK works.
How PLONK works, the short version
Eventually, the idea of PLONK is to prove that some polynomial vanishes on some domain (and I will ignore the permutation argument, which is just another proof). To prove that, we reduce the problem to some other problem. Incrementaly, it looks like this:
- Proving the previous statement is equivalent to proving that the polynomial is divisible by , the polynomial that has all the elements of as roots (also called vanishing polynomial).
- Which is equivalent to proving the following identity (for some quotient polynomial ):
- Which is equivalent to proving the identity on some random point (thanks to the Schwartz-Zippel lemma):
To prove the last statement, the prover uses of polynomial commitment scheme (specifically, the KZG scheme) to commit to the polynomial and . The prover then sends the commitments to the verifier. At that point, the verifier has to check that for some random point
This is done by sending a random point to the prover and doing an “opening” of the commitments at this point: the prover sends the values and as well as a proof that these are the correct evaluations.
This is in essence the PLONK protocol, except that this is not really what happens in the paper…
More reductions
The newer PLONK actually does one more reduction of the last statement:
- As per the previous section: we want to prove that
- Which is equivalent to proving that is a root of the polynomial
- Since the verifier already knows one of the polynomial (), they can evaluate it in advance. So the previous statement is equivalent to proving that is a root of
The last two steps is an optimization (called Maller’s optimization) that removes the need for the prover to send , as the verifier can use the commitment to to produce a commitment to (to verify the opening proof).
These additional reductions moved us from a protocol in which the prover sends openings to let the verifier check an identity by themselves, to a protocol where the prover simply sends openings.
To verify the opening of for , the verifier will have to reconstruct a commitment to first. That’s easy, it is:
which will use:
- the commitment to received during the protocol
- the commitment to received during the protocol
- the evaluation of at which they can do by themselves
Not so fast… t is too large
If you’ve read PLONK, you’ve noticed that the prover actually doesn’t send a commitment to directly, because is too large and polynomial commitment schemes have an upperbound fixed during the trusted setup. (By the way, is too large because the permutation argument makes it three times as large due to the three witness polynomials.) To circumvent that limitation, the polynomial is split into three smaller polynomials such that:
This means that in our previous protocol, we can’t prove directly that is a root of
instead we have to prove the equivalent that is a root of
This is not great, as the prover cannot produce a commitment to anymore. The reason is that and cannot be committed as they’re larger than the upperbound of our polynomial commitment. Instead, notice that since the verifier already knows these values, so they can pre-evaluate them at and ask instead for a proof that:
which is a fine request, as the verifier can produce the commitment of needed to verify the opening proof:
At this point, the protocol looks more like this:
Uh-oh, what about f?
The big proof in PLONK really boils down to two things:
- The permutation argument, which links the wires in our circuit. I ignore this proof in the post.
- the main polynomial , which is our circuit.
Since the polynomial needs to be constructed such that:
- it does not leak any non-public information to the verifier
- it does not allow the prover to change fixed parts of the circuit
the prover and the verifier perform a “polynomial dance” to construct the polynomial together. The end product sorts of looks like this:
where are private polynomials that the prover constructs, commits, and sends to the verifier; and are public polynomials (the selector polynomials) that both the verifier and the prover can construct (and commit to if necessary).
So the end protocol looks more like this:
And as in the previous section, the verifier needs to reconstruct a commitment to before being able to ask for an opening, which is now impossible as we’re dealing with multiplication of commitments
but since the prover sends the evaluations of at (with proofs), the verifier can use that to simplify the polynomial to:
Finally, the verifier can produce the commitment of as:
There’s much more to PLONK. I’ve skipped the circuit part, the permutation argument, I’ve also ignored the big pairing equation at the end. These will be subjects for another post :)