- Recall: Polynomial Commitments
- KZG Poly-commit Scheme
- Dory Poly-commit Scheme
- PCS to Commit to a Vector
- Proving Properties of Committed Polynomials
- PLONK

# Recall: Polynomial Commitments

We will use polynomial commitments in this lecture, so let's quickly recall what they are!

- The prover would like to commit to some polynomial $f∈F_{p}[X]$.
- An $eval$ function uses evaluate some values for this polynomial, without revealing it. For example, pick some public $u,v∈F_{p}$.
- Prover will convince that $f(u)=v$ and $deg(f)≤d$.
- Verifier will only know $d,u,v$ and a polynomial commitment $com_{f}$, also shown as $f $ sometimes.

- The proof size for $eval$ and the verifier time should both be in $O_{λ}(gd)$.
**Spoilers**: it will turn out be constant $O(1)$ which is really a magical thing to me.

# KZG Poly-commit Scheme

In this lecture, we will use KZG [Kate-Zaverucha-Goldberg'10] polynomial commitment scheme.

Fix some finite cyclic group $G$ of order $p$. This group basically has some generator value $G$ and the group consists of it's multiplications:

$G={0,G,2G,3G,…,(p−1)G}$

The group has addition operation defined on it, where you can add $aG+bG$ to obtain $cG$ where $a+b≡c(modp)$.

## Trusted Setup: $setup(λ)→gp$

KZG starts with a trusted setup $setup(λ)→gp$ to produce public parameters. This is done as follows:

- Sample some random $τ∈F_{p}$.
- Compute $∀i∈[d]:H_{i}=τ_{i}G$. Basically, you have $d+1$ group elements, each multiplied to some power of tau ($τ$) and multiplied by $G$. These computed values will be the public parameters $gp$.

$gp=(H_{0}=G,H_{1}=τG,H_{2}=τ_{2}G,…,H_{d}=τ_{d}G)∈G_{d+1}$

- Finally and most importantly,
**delete**$τ$. If this number is leaked and in wrong hands, they can create fake proofs! This is why the setup must take place in a trusted environment. We will actually see a better way for this setup, where multiple parties will take place in the ceremony and it suffices for only one of them to be trusted!

## Commitment: $commit(gp,f)→com_{f}$

A commitment will take the public parameters $gp$ along with the polynomial $f$ to be committed, and produces the commitment.

- The commitment is shown as $commit(gp,f)→com_{f}$
- Our commitment will be $com_{f}=f(τ)G∈G$.

But wait, $τ$ was deleted after setup so how do we obtain this? Well, think of the polynomial $f$ as follows:

$f(X)=f_{0}+f_{1}X+f_{2}X_{2}+…+f_{d}X_{d}$

Notice that for every $X_{i}$ (including $X_{0}$) you write $H_{i}$ you get the following:

$f_{0}H_{0}+f_{1}H_{1}+f_{2}H_{2}+…+f_{d}H_{d}$

We can very well do this because we know what each $H_{i}$ is, they are given us within the public parameters $gp$. If you expand $H_{i}$ you notice that:

$f_{0}G+f_{1}τG+f_{2}τ_{2}G+…f_{d}τ_{d}G=f(τ)G$

We got the commitment we've wanted! Note that this commitment is **binding**, but not **hiding** as is.

## Evaluation: $eval$

Let us now see how a verifier evaluates the commitment.

- Prover knows $(gp,f,u,v)$ and wants to prove that $f(u)=v$.
- Verifier knows $(gp,com_{f},u,v)$.

We will have some series of if-and-only-if's now, which will connect everything really nicely.

- $f(u)=v$ if and only if $u$ is a root of $f^ :=f−v$. This makes sense because if indeed $f(u)=v$ then $f(u)−v=0$ which would make $u$ a root for $f^ $.
- $u$ is a root of $f^ $ if and only if the polynomial $(X−u)$ divides $f^ $. You might be familiar with this property already throughout this lecture.
- $(X−u)$ divides $f^ $ if and only if $∃q∈F_{p}[X]$ such that $q(X)(X−u)=f^ (X)=f(X)−v$. This is another way of saying that since $(X−u)$ divides $f^ $ there will be no remainder left from this division, and there will be some resulting quotient polynomial $q$.

With this knowledge in mind, here is the plan:

- Prover computes $q(X)$ and commits to $q$ as $com_{q}$. Remember that commitment results in a single group element only.
- Prover send the proof $π=com_{q}$. That's right, the entire proof is just the commitment to $q$ which means the proof size is a single group element, independent of the degree $d$.
- Verifier accepts if $(τ−u)com_{q}=com_{f}−vG$

You may notice that there is $τ$ here, which is supposed to be secret; and you are right. What actually happens is that something called **pairing** is used here to hide $τ$ while still allowing the above computation. In doing so, only $H_{0}$ and $H_{1}$ will be used, which again makes this thing independent of degree $d$.

So are we really independent of $d$? Well, the prover must compute the quotient polynomial $q$ and the complexity of that is related to $d$, so you will lose from prover time when you have large degrees.

You might ask, how to prove that this is a secure poly-commit scheme? We are not going into that today…

## Properties of KZG

KZG has some cool properties!

**Generalizations**: It has been shown that you can use KZG to commit to $k$-variate polynomials [Papamanthou-Shi-Tamassia'13]**Batch Proofs**: Suppose you have commitments to $n$ polynomials $f_{1},f_{2},…,f_{n}$ and you have $m$ values to reveal in each of them, meaning that you basically want to prove all evaluations defined by $f_{i}(u_{i,j})=v_{i,j}$ for $i∈[n]$ and $j∈[m]$.- Normally, this would require $n×m$ evaluations, but thanks to KZG we can actually do this in a single proof that is a single group element!

**Linear-time Commitments**: How long does it take to commit to a polynomial of degree $d$? Well, we would really like this to be in linear time with $d$, and turns out it is possible to do so. This deserves a sub-section on its own though, so let us do that.

## Linear-time Commitments

The way we calculate the commitment $com_{f}=f(τ)G$ will change based on how we represent a polynomial $f∈F_{p}[X]$. There are several ways.

**Coefficient Representation**: Simply, keep a record of $d+1$ coefficients to construct the polynomial.- $f(X)=f_{0}+f_{1}X+…f_{d}X_{d}$ would mean that we are storing an array of values $[f_{0},f_{1},…,f_{d}]$.
- We can compute the commitment in linear time $O(d)$ since we just have to multiply $f_{i}$ with $H_{i}$ for $i∈[d]$, giving us: $com_{f}=f_{0}H_{0}+f_{1}H_{1}+…+f_{d}H_{d}$

**Point-Value Representation with NTT**: A polynomial of degree $d$ can be defined by $d+1$ points. So, we have $d+1$ points and their evaluations $(a_{0},f(a_{0})),(a_{1},f(a_{1})),…,(a_{d},f(a_{d}))$.- Computing $com_{f}$ naively would be to construct the coefficients $f_{0},f_{1},…,f_{d}$ to basically convert point-value representation to coefficient representation, and then compute the commitment as shown in that case.
- Converting from point-value to coefficient representation takes time $O(dgd)$ using Number Theoretic Transform (NTT) which is closely related to Fourier Transform. However, this is more than linear time, we want to do better!

**Point-Value Representation with Lagrange Interpolation**: Thankfully, there is a linear-time algorithm to commit to a polynomial in point-value representation. The idea is to use Lagrange Interpolation to compute the commitment.

$f(τ)=i=0∑d λ_{i}(τ)f(a_{i})$

$λ_{i}(τ)=∏_{j=0,j=i}(a_{i}−a_{j})∏_{j=0,j=i}(τ−a_{j}) ∈F_{p}$

The idea here is that our public parameters will actually be in Lagrange form, and the process of getting this just a linear transformation that everyone can do. So, we obtain public parameters $gp^ $ that looks like:

$gp^ =(H^_{0}=λ_{0}(τ)G,H^_{1}=λ_{1}(τ)G,…,H^_{d}=λ_{d}(τ)G)∈G_{d+1}$

This way, the commitment can be compute in linear time $O(d)$:

$com_{f}=f(τ)G=f(a_{0})H^_{0}+f(a_{1})H^_{1}+…+f(a_{d})H^_{d}$

## Fast Multi-point Proof Generation

Let $Ω⊆F_{p}$ and $∣Ω∣=d$. Suppose that the prover needs an evaluation proof $π_{a}$ for all $a∈Ω$. Normally, this would require $O(d_{2})$ time because proving one takes time linear in $d$ and there are $d$ values.

Thanks to [Feist-Khovratovic'20] there is a much faster algorithm to do this.

- If $Ω$ is a multiplicative group then it takes time in $O(dgd)$
- otherwise, it takes time in $O(dg_{2}d)$

# Dory Poly-commit Scheme

KZG has some difficulties:

- it requires a trusted setup to compute the public parameters $gp$
- $gp$ size is linear in the degree $d$

Can we do any better? Kind of yeah! Dory [Lee'20] is a polynomial commitment scheme with the following properties:

- 🟢 It has transparent setup, so there is no need for a trusted setup
- 🟢 $com_{f}$ is still just a single group element, independent of degree
- 🔴 $eval$ proof size is $O(gd)$ group elements; KZG took constant time.
- 🔴 $eval$ verification time is $O(gd)$; KZG took constant time.
- 🟢 prover time is $O(d)$

# PCS to Commit to a Vector

Poly-commit schemes are a drop-in replacement for Merkle Trees, which we have used before to make vector commitments.

Suppose you have some vector $(u_{1},u_{2},…,u_{k})∈F_{p}$. To commit to this vector, the prover will interpolate a polynomial $f$ such that $f(i)=u_{i}$ for $i∈[k]$. Then, the prover can simply commit to this polynomial $f$ as we have described above.

If a verifier wants to query some vector elements, like "show me that $u_{2}=a$ and $u_{4}=b$" this translate to "show me $f(2)=a$ and $f(4)=b$" and we know we can prove this in a single group element using a batch proof thanks to KZG.

If we were to use a Merkle Tree, each evaluation proof would have size $O(gk)$ and for $ℓ$ proofs this would mean $O(ℓgk)$ proof size, a lot bigger than the constant proof size of KZG.

For more applications of using PCS in Merkle Trees, see Verkle Trees!

# Proving Properties of Committed Polynomials

Before we start, we would like to make note of a shorthand notation: when we say the verifier queries a polynomial $f$ at some random point $r$ to get $f(r)$ we actually mean that the prover computes $y=f(r)$ and a proof of this evaluation $π_{f}$, then it sends back $y,π_{f}$ to the verifier.

Also note that everything we will do in our interactive proofs will be public-coin protocols, so although what we will do looks interactive just keep in mind that we can use Fiat-Shamir transform to make them non-interactive.

## Equality Testing

Recall that in KZG, the verifier could test if $f=g$ just by knowing $com_{f},com_{g}$, also shown as $f ,g $. For bit more complex equality tests, that won't be enough.

For example, suppose that the verifier has $f ,g_{1} ,g_{2} ,g_{3} $ and would like to see if $f=g_{1}g_{2}g_{3}$. To do this, the verifier has to query the prover on all four polynomials at some random field element and test equality.

## Important Proof Gadgets for Uni-variates

Let $Ω⊆F_{p}$ where $∣Ω∣=k$. Let $f∈F_{p}[X]$ be a polynomial of degree $d$ and $d≥k$. The verifier has a commitment to this polynomial, $f $.

We will now construct efficient poly-IOPs for the following proof gadgets:

**Equality Test**: prove that $f,g$ are equal. We know that evaluating them at a random point and seeing if they are equal does the trick, assuming degree is much smaller than the size of the finite field.**Zero Test**: prove that $f$ is identically zero on $Ω$, meaning that it acts like a zero-polynomial for every value in $Ω$, but of course it can do whatever it wants for values outside of $Ω$ but in $F_{p}$.**Sum Check**: prove that $∑_{a∈Ω}f(a)=0$**Product Check**: prove that $∏_{a∈Ω}f(a)=1$**Permutation Check**: prove that evaluations of $f$ over $Ω$ is a permutation of evaluations of $g$ over $Ω$**Prescribed Permutation Check**: prove that evaluations of $f$ over $Ω$ is a permutation of evaluations of $g$ over $Ω$, with a "prescribed" permutation $W:Ω→Ω$. This permutation is a bijection $∀i∈[k]:W(ω_{i})=ω_{j}$

To start, we need to introduce the concept of a **vanishing polynomial**.

**Definition**: The vanishing polynomial of $Ω$ (as defined above) is:

$Z_{Ω}(X):=a∈Ω∏ (X−a)$

with degree $k$. Then, let $ω∈F_{p}$ be a primitive $k$-th root of unity, meaning that $ω_{k}=1$. If the set $Ω$ is defined as follows:

$Ω={1,ω,ω_{2},…,ω_{k−1}}⊆F_{p}$

then $Z_{Ω}(X)=X_{k}−1$. This is really nice, because for such cases, evaluating $Z_{Ω}(r)$ for some random field element $r$ means just taking $r_{k}$ and subtracting one, which costs around $gk$ field operations, thanks to repeated-squaring method of multiplication.

### Zero Test

In the following graph, we denote `Z(r)`

for $Z_{Ω}(r)$. Also remember that when we say "the verifier queries some polynomial and the prover shows its evaluation", what we mean is that in the background the prover computes them and sends the result along with an evaluation proof.

With that said, let us see the zero-test poly-IOP.

sequenceDiagram actor P as Prover(f) actor V as Verifier(com_f) note over P: q(X) = f(X) / Z(X) P ->> V: com_q note over V: r ← F_p V ->> P: query f(X) and q(X) at r P ->> V: show f(R) and q(R) note over V: accept if f(R) = q(R) * Z(R)

Let's analyze the costs in this IOP:

- The verifier made two polynomial queries (although a batch proof could have been done), and also it computed $Z_{Ω}(r)$ on it's own which takes time $O(gk)$.
- The prover time is dominated by the time to compute $q(X)$ and then commit to it, which runs in time $O(kgk)$.

### Product Check and Sum Check

Prod-check and sum-check are almost identical, so we will only look at prod-check. Again, our claim is that $∏_{a∈Ω}f(a)=1$ and we would like to prove that.

Set $t∈F_{p}[X]$ to be a polynomial of degree $k$. Define the evaluations of this polynomial as follows:

- $t(1)=f(1)$
- $t(ω)=f(1)×f(ω)$
- $t(ω_{2})=f(1)×f(ω)×f(ω_{2})$
- and so on, with the final evaluation of $t(ω_{k−1})$ being equal to the product itself!
- $t(ω_{k−1})=∏_{a∈Ω}f(a)=1$

You can see that we can define $t(ω_{s})=∏_{i=0}f(ω_{i})$ for $s∈[k−1]$. It is also important to notice the recurrence relation between $t$ and $f$:

$∀x∈Ω:t(ωx)=t(x)f(ωx)$

which is made possible because $Ω$ consists of powers of $ω$. The lemma we will use with these is the following:

- if $t(ω_{k−1})=1$
- and $t(ωx)−t(x)f(ωx)=0$ for all $x∈Ω$
- then, $∏_{a∈Ω}f(a)=1$

Let's write the interactive proof! The idea will to construct another polynomial $t_{1}(X)$ which is:

$t_{1}(X)=t(ωX)−t(x)f(ωX)$

which implies that if a zero-test on $t_{1}(X)$ for $Ω$ passes, then prod-check passes.

sequenceDiagram actor P as Prover(f) actor V as Verifier(com_f) note over P: construct t(X) note over P: construct t1(X) = t(ωX) - t(X) * f(ωX) note over P: set q(X) = t1(X)/(X^k - 1) P ->> V: com_q, com_t note over V: r ← F_p V ->> P: query t(X) at ω^(k-1), r, ωr P ->> V: show t(ω^(k-1)), t(r), t(ωr) V ->> P: query q(X) at r P ->> V: show q(r) V ->> P: query f(X) at ωr P ->> V: show f(r) note over V: accept if t(ω^(k-1)) = 1 note over V: and if t(ωr) - t(r)f(ωr) = q(r)(r^k - 1)

The cost of this protocol is as follows:

- Proof size is two commitments ($q ,t $) and five evaluations, and keeping in mind that evaluations can be batched, the entire proof size is just 3 group elements.
- Prover time is dominated by computing $q(X)$ that runs in time $O(kgk)$
- Verifier time is dominated by computing $(r_{k}−1)$ and $ω_{k−1}$, both in time $O(gk)$

Note that almost the same protocol works for **rational functions**. There, our claim is $∏_{a∈Ω}(f/g)(a)=1$ and we construct a similar $t$ polynomial, only this time $f(x)$ is divided by $g(x)$ in the definition. Then, the lemma is also similar:

- if $t(ω_{k−1})=1$
- and $t(ωx)g(wx)−t(x)f(ωx)=0$ for all $x∈Ω$
- then, $∏_{a∈Ω}f(a)/g(a)=1$

Almost the same!

### Permutation Check

We have two polynomials $f,g∈F_{p}[X]$ and we want to show that

- $(f(1),f(ω),f(ω_{2}),…,f(ω_{k−1}))∈F_{p}$ is just a permutation of
- $(g(1),g(ω),g(ω_{2}),…,g(ω_{k−1}))∈F_{p}$
- essentially proving that $g(Ω)$ is same as $f(Ω)$, but just permuted.

To prove this, we will do what is known as the Lipton's trick [Lipton'89]. We will construct two auxiliary polynomials:

- $f^ (X)=∏_{a∈Ω}(X−f(a))$
- $g^ (X)=∏_{a∈Ω}(X−g(a))$

Now notice that $f^ =g^ $ if and only if $f$ is a permutation of $g$. This is because the product is a series of multiplications, which is a commutative operation.

Normally, to prove that $f^ =g^ $ the prover would only have to show the evaluation of them at a random point, $r∈F_{p}$ given by the verifier. However, computing these polynomials are a bit expensive, so instead the prover will do a clever trick: do a prod-check on the following rational function:

$g^ (r)f^ (r) =a∈Ω∏ (r−g(a)r−f(a) )=1$

We have just mentioned that prod-check can be done on rational functions, so we can very well do this! The cost of this proof is just two commitments, and six evaluations.

### Prescribed Permutation Check

Again we have two polynomials $f,g∈F_{p}[X]$ and a permutation $W:Ω→Ω$. The verifier has commitments to these $f ,g ,W $. Our claim is that $f(y)=g(W(y))$ for all $y∈Ω$, in other words, $g$ is a permutation of $f$ over $Ω$ as described by $W$.

At a first glance, it is tempting to do a simple **zero-test** on $f(y)−g(W(y))=0$, right? Nope, notice that $g(W(y))$ results in a polynomial of degree $∣Ω∣_{2}$, but we wanted to have a linear time prover; this results in a quadratic time prover!

Instead, we have a clever method that will run in linear time. We start with the following observation: if the set of pairs $(W(a),f(a))_{a∈Ω}$ is a permutation of $(a,g(a))_{a∈Ω}$ then $f(y)=g(W(y))$ for all $y∈Ω$.

Here is a quick example of this:

- Permutation: $W(ω_{0})=ω_{2},W(ω_{1})=ω_{0},W(ω_{2})=ω_{1}$
- First set of pairs: $(ω_{0},g(ω_{0})),(ω_{1},g(ω_{1})),(ω_{2},g(ω_{2}))$
- Second set of pairs: $(ω_{0},f(ω_{0})),(ω_{2},f(ω_{1})),(ω_{1},f(ω_{2}))$

For the proof itself, we actually need bivariate polynomials; univariate polynomials will not be enough. Nevertheless, the proof is much similar to the previously described permutation check.

Define two auxiliary polynomials, which will be bivariate polynomials of total degree $∣Ω∣$:

- $f^ (X,Y)=∏_{a∈Ω}(X−Y⋅W(a)−f(a))$
- $g^ (X,Y)=∏_{a∈Ω}(X−Y⋅a−g(a))$

The lemma here is that if $f^ (X,y)=g^ (X,Y)$ then $(W(a),f(a))_{a∈Ω}$ is a permutation of $(a,g(a))_{a∈Ω}$. The proof of this is left as exercise, though if you want to try, you might make use of the fact that $F_{p}[X,Y]$ is a unique factorization domain.

The protocol continues with the verifier generating two random points $r,s∈F_{p}$ and sending these to the prover. Again, instead of actually evaluating the auxiliary polynomials, the prover will do a prod-check over what they describe:

$g^ (r,s)f^ (r,s) =a∈Ω∏ (r−s⋅a−g(a)r−s⋅W(a)−f(a) )=1$

This protocol is sound and complete, assuming $2d/p$ is negligible. The cost of this protocol is just like the cost described for prod-check.

# PLONK

The time has come! **PLONK** [Gabizon-Williamson-Ciobotaru'19] is a poly-IOP for a general circuit $C(x,w)$.

But, before we delve into PLONK, we must realize that PLONK itself in practice is more like an abstract IOP, that when used with some poly-commit scheme will result in a SNARK system. Here are some examples in practice:

Poly-commit Scheme | Poly-IOP | SNARK System |
---|---|---|

KGZ'10, uses pairings | PLONK | Aztec, JellyFish |

Bulletproofs, no pairings required | PLONK | Halo2 |

FRI, uses hashes | PLONK | Plonky2 |

With that said, let us begin.

## Step 1: Compile circuit to computation trace

We will use an example circuit with an example evaluation. Our circuits have gates with two inputs and a single input, also shown as "gate fan-in = 2".

flowchart LR x1((x_1)) --> a1[+] x2((x_2)) --> a1 x2((x_2)) --> a2[+] w1((w_1)) --> a2 a1 --> m1[x] a2 --> m1[x] m1 --> o(( ))

The circuit above computes $(x_{1}+x_{2})(x_{2}+w_{1})$. Suppose that the public inputs are $x_{1}=5,x_{2}=6$ and the secret input (witness) is $w_{1}=1$. As a result, the output of this circuit is 77, which is also public. The prover will try to prove that he knows a value of $w_{1}$ that makes the output 77 with the given public inputs.

flowchart LR x1((x_1)) --5--> a1[+] x2((x_2)) --6--> a1 x2((x_2)) --6--> a2[+] w1((w_1)) --1--> a2 a1 --11--> m1[x] a2 --7--> m1[x] m1 --77--> o(( ))

We compile this evaluation into a computation trace, which is simply a table that shows inputs and outputs for each gate, along with circuit inputs.

- Circuit inputs are $5,6,1$.
- Gate traces are given in the following table.

Gate No. | Left Input | Right Input | Output |
---|---|---|---|

Gate 0 | 5 | 6 | 11 |

Gate 1 | 6 | 1 | 7 |

Gate 2 | 11 | 7 | 77 |

## Step 1.5: Encode trace as a polynomial

We have spent a lot of time learning how to commit to polynomials, so let's get them to work! First, some definitions:

- $∣C∣$ is the circuit size, equal to number gates in the circuit.
- $∣I∣=∣I_{x}∣+∣I_{w}∣$ is the number of inputs to the circuit, which is the number of public inputs and the secret inputs combined.
- We then let $d=3×∣C∣+∣I∣$
- Let $Ω={1,ω,ω_{2},…,ω_{d−1}}$ where $ω_{d}=1$.

The plan is to encode the entire computation trace into a polynomial $T∈F_{p}[X]$ such that:

- $T$ encodes all inputs with $T(ω_{−j})$ correspond to input $j∈[∣I∣]$
- $T$ encodes all wires, which it does $∀ℓ∈{0,1,…,∣C∣−1}$:
- $T(ω_{3l})$ corresponds to the left input of gate $ℓ$
- $T(ω_{3l+1})$ corresponds to the right input of gate $ℓ$
- $T(ω_{3l+2})$ corresponds to output of gate $ℓ$

In the circuit example above, there are 12 points, which defines a degree-11 polynomial. To interpolate a polynomial to the values in the computation trace, the prover can actually use Fast Fourier-Transform (FFT) to compute the coefficients of polynomial $T$ in time $O(dgd)$.

However, in general we won't compute the coefficients, but instead use the point-value representation of the polynomial as described above.

## Step 2: Prove validity of $T$

So the prover has computed $T$, and committed to it as $T $. It sends it to the verifier, but the verifier must make sure that $T$ indeed belongs to the correct computation trace. To do that, it must do the following:

- $T$ encodes the correct inputs
- Every gate is evaluated correctly
- The "wiring" is implemented correctly
- The output of last gate is 0. Well, in this example the output is 77, but generally the verifier expects a 0 output, remember how we say $C(x,w)=0$.

### (1) $T$ encodes the correct inputs

Remember both prover and verifier has the statement $x$. They will now interpolate a polynomial $v(X)∈F_{p}[X]$ that encodes the $x$-inputs to the circuit:

- for $j∈{1,2,…,∣I_{x}∣}:v(ω_{−j})=input #j$
- In our example: $v(ω_{−1})=5,v(ω_{−2})=6,v(ω_{−3})=1$ so $v$ is quadratic (i.e. it is defined by 3 points).
- Constructing $v(X)$ takes linear time proportional to the size of input $x$.

Next, they will agree on the points encoding the input $Ω_{inp}:={ω_{−1},ω_{−2},…,ω_{−∣I_{x}∣}}$. Then, the prover will use a zero-test on $Ω_{inp}$ to prove that $T(y)−v(y)=0$ for all $y∈Ω_{inp}$.

It is quite easy to do this, because vanishing polynomial for $Ω_{inp}$ is often calculated quickly.

### (2): Every gate is evaluated correctly

The idea here is to encode gate types using a selector polynomial $S(X)$. Remember that in our example we encoded the two gate inputs and an output as $ω$ to the power $3ℓ,3ℓ+1,3ℓ+2$ for some gate $ℓ$. Now, we will encode the "types" of these gates.

Define $S(X)∈F_{p}[X]$ such that $∀ℓ∈{0,1,…,∣C∣−1}$:

- $S(ω_{3l})=1$ if gate $ℓ$ is an addition gate
`+`

- $S(ω_{3l})=0$ if gate $ℓ$ is a multiplication gate
`x`

In our example, $S(ω_{0})=1,S(ω_{3})=1,S(ω_{6})=0$. Notice that the selector polynomial depends on the circuit, but not on the inputs! So in fact, the selector polynomial is a product of the preprocessing setup: prover will have $S$ itself, and the verifier will have a commitment to it $S $.

Now, we make a really nice observation: $∀y∈Ω_{gates}:={1,ω_{3},ω_{6},…,ω_{3(∣C∣−1)}}$ it should hold that:

$S(y)(T(y)+T(ωy))+(1−S(y))(T(y)×T(ωy))=T(ω_{2}y)$

Here, $T(y),T(ωy),T(ω_{2}y)$ are the left input, right input and output respectively. Prover will use a zero-test on the set $Ω_{gates}$ to prove that $∀y∈Ω_{gates}$:

$S(y)×(T(y)+T(ωy))+(1−S(y))(T(y)×T(ωy))−T(ω_{2}y)=0$

### (3) The wiring is correct

What do we mean by wiring? Well, if you look at the circuit (or the table) you will notice that some outputs become inputs on other gates. For example, the input 6 is a right input for gate 0, and a left input for gate 1 and such. Prover will have to prove that this wiring has been done correctly.

For that, the wires of $C$ are encoded with respect to their constraints. In our example:

- $T(ω_{−2})=T(ω_{1})=T(ω_{3})$
- $T(ω_{−1})=T(ω_{0})$
- $T(ω_{2})=T(ω_{6})$
- $T(ω_{−3})=T(ω_{4})$

Define a polynomial $W:Ω→Ω$ that implements a single left-rotation:

- $W(ω_{−2},ω_{1},ω_{3})=(ω_{1},ω_{3},ω_{−2})$
- $W(ω_{−1},ω_{0})=(ω_{−1},ω_{0})$
- $W(ω_{2},ω_{6})=(ω_{6},ω_{2})$
- $W(ω_{−3},ω_{4})=(ω_{4},ω_{−3})$

Why we do this fantastic thing is due to a lemma; if $∀y∈Ω:T(y)=T(W(y))$ then the wire constraints are satisfied. The idea behind this bizarre method is that, if $T$ is indeed **invariant** (does not change its behavior) under such a rotation, then the wiring must be correct. This is because had the wirings be false, the rotation would cause a value to be different and this would not hold.

Remember that $P(W(y))$ has degree $d×d=d_{2}$ but we want prover to work in linear time $d$ only. This is where the **prescribed permutation check** we have described in this lecture comes into play.

### (4) Output of last gate is 0

Proving the last one is easy, just show that $T(ω_{3∣C∣−1})=0$.

## Final Step: The PLONK Poly-IOP

The setup procedure results in $pp→(S,W)$ and $vp→(S ,W )$and is transparent, no need for trust! The prover knows $(pp,x,w)$ and verifier knows $(vp,x)$.

sequenceDiagram actor P as Prover actor V as Verifier note over P: construct T(X) P ->> V: com_T note over V: construct V(x) note over P, V: ✅ T encodes the inputs note over P, V: ✅ gates are evaluated correctly note over P, V: ✅ wiring is correct note over P, V: ✅ output of last gate is 0

The resulting PLONK proof is a short one, it has $O(1)$ commitments! Furthermore, the verifier is fast. Although the SNARK we have described is not zero-knowledge, it is quite easy to make it into a zkSNARK. There are actually generic transformations that can convert any poly-IOP into a zero-knowledge poly-IOP.

The paper proves that if $7∣C∣/p$ is negligible, then this PLONK poly-IOP is complete and knowledge sound. Try and see for yourself where that 7 comes from.

## PLONK Extensions

The main challenge is to reduce the prover time. Furthermore, just using `+`

and `x`

gates might feel a bit too constraining. We do have alternative solutions though! Each of the following try to improve the prover time in various ways.

### HyperPlonk

What HyperPlonk [Chen-Bünz-Boneh-Zhang'22] does is that they replace $Ω$ with ${0,1}_{t}$ where $t=g∣Ω∣$. As such, the polynomial $T$ becomes a multilinear polynomial with $t$ variables. Zero-test is then replaced by a multilinear sum-check that runs in linear time.

### Plonkish Arithmetization: Custom Gates

In our example, we had gates with two inputs and an output, along with selector polynomials that cover addition and multiplication. Furthermore, each constraint was specific to the row itself. It is possible to generalize this usage to obtain **custom gates**, that can even make use of multiple rows! Custom gates are included in the gate check step. This is used in AIR (Algebraic Intermediate Representation).

### Plookup: Lookup Tables

There is an extension of Plonkish Arithmetization, that actually enables one to ensure that some values in the computation trace are present in a pre-defined list, basically acting like a look-up argument!