$$ \def\Zp{{\mathbb{Z}_p}} \def\F{{\mathbb{F}}} \def\Bit{{\{0, 1\}}} \def\PI{{\textsf{PI}}} \def\bold#1{\boldsymbol{#1}} \def\stop{{\rlap{\quad.}\hphantom{}}} \def\qed{{\rlap{\quad \tiny\blacksquare}\hphantom{}}} \def\par{{\thinspace {\parallel} \thinspace}} \def\hso{{\hspace{1pt}}} $$ # PLONK Arithmetization ## PLONK v.s. Halo **Similarities:** proofs systems, use polynomial commitment schemes, same constraint system (constraint polynomial, BG12 permutations, lookup tables, custom gates) **Differences:** PLONK requires a trusted-setup, PLONK uses pairings, Halo has proof recursion (2-cycle of elliptic curve groups), PLONK uses a Kate-like PCS, Halo uses a Hyrax-like PCS **Timeline:** **[Standard] PLONK** (Aug-2019) - proof system via polynomial commitments using a single updateable trusted-setup. Uses pairings, a non-R1CS constraint-system, BG12 permutation proofs, and Kate-like polynomial commitments. **Halo** (Sep-2019) - proof recursion via elliptic curve cycles, no pairings, no trusted setup, Hyrax-like PCS. **TurboPLONK** (late-2019/early-2020) - PLONK with custom gates/constraints. **plookup** (Nov-2020) - extends PLONK with lookup tables (replace expensive computations with key-value maps to lookup a computation's output on an input, currently lookup tables focus on replacing bitwise operations such as bitwise AND and XOR). **UltraPLONK** (late-2020) - PLONK with custom gates and lookup tables, i.e. combines TurboPLONK and plookup (makes many algorithms that are SNARK unfriendly, more friendly). Side note: using lookup tables and custom gates allows for efficient modular arithmetic in a field smaller than the PLONK field, which could allow for recursive proofs without cycles of elliptic curves (i.e. multiple base and scalar fields). Side note #2: Pedersen hashing within UltraPLONK is roughly as efficient as Poseidon. **Halo2** (late-2020) - combines UltraPLONK, a PCS that does not require a trusted-setup, and cycles of elliptic curves for recursion. **Question:** Verification time is constant in PLONK, but is not in Halo/Halo2 because Halo's proof size varies with computation size? Zcash will rely on batch transaction verification to achieve something close to succinctness. ## Standard PLONK Arithmetization **Arithmetization** - breaks a general computation into a sequence of steps. ![Mul-Add-Const Gates](https://i.imgur.com/nHhg1PK.png) **Example:** $a * b + 23 == 100$: ![Example Circuit](https://i.imgur.com/Fxo6bGL.png) Arithmetization converts a general computation into a system of polynomials (a set of interdependent polynomials) where each is constrained to a value. A general computation's set of polynomials is its **constraint system**. Every polynomial is of the same form. Standard PLONK uses the **constraint** polynomial: $$ s_lx_l + s_rx_r + s_mx_lx_r = s_ox_o + c $$ * $s_l, s_r, s_o, s_m \in \Bit$ are boolean **selectors** * $x_l, x_r, x_o \in \F$ are values used in arithmetic * $c \in \F$ is an optional constant used to assign constraint system values to a constant (public input) which can encode addition, multiplication, and constant assignment. | | | Constraint | |:-:|:-:|:-:| | Addition | $l + r = o$ | $1x_l + 1x_r + 0x_lx_r = 1x_o + 0$ | | Multiplication | $l * r = o$ | $0x_l + 0x_r + 1x_lx_r = 1x_o + 0$ | | Assign Constant <br> (Public Input) | $l = 5$ <br> $r = 5$ <br> $l + r = 5$ <br> $l * r = 5$ | $1x_l + 0x_0 + 0x_lx_r = 0x_o + 5$ <br> $0x_l + 1x_r + 0x_lx_r = 0x_o + 5$ <br> $1x_l + 1x_r + 0x_lx_r = 0x_0 + 5$ <br> $0x_l + 0x_r + 1x_lx_r = 0x_o + 5$ | | Exponentiation | $(l * r) * r = o$ | $$\eqalign{{\small\text{(0)}} & \ \ 0x_l + 0x_r + 1x_lx_r = 1x_o \\ {\small \text{(1)}} & \ \ 0x_l + 0x_r + 1x_o^{(0)}x_r = 1x_o}$$ | ![Add-Mul Gate](https://i.imgur.com/p348KF8.png) **Note:** a constraint may reference a value from another constraint, e.g. exponentiation. This is enforced via a permutation argument, not using constraint. **TODO:** The $s_l, s_r, s_o, s_m, c$ values define a computation. The $x_l, x_r, x_o$ values are filled in by someone who knows how the computation proceeds (the inputs and outputs at each gate). We can think of a computation's constraint system as a **matrix**: | $\boldsymbol{x_l}$ | $\boldsymbol{x_r}$ | $\boldsymbol{x_o}$ | $\boldsymbol{s_l}$ | $\boldsymbol{s_r}$ | $\boldsymbol{s_m}$ | $\boldsymbol{s_o}$ | $\boldsymbol{c}$ | | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ---------------- | | $x_l^{(1)}$ | $x_r^{(1)}$ | $x_o^{(1)}$ | $s_l^{(1)}$ | $x_r^{(1)}$ | $s_m^{(1)}$ | $s_o^{(1)}$ | $c^{(1)}$ | | $\vdots$ | $\vdots$ | $\vdots$ | $\vdots$ | $\vdots$ | $\vdots$ | $\vdots$ | $\vdots$ | | $x_l^{(n)}$ | $x_r^{(n)}$ | $x_o^{(n)}$ | $s_l^{(n)}$ | $x_r^{(n)}$ | $s_m^{(n)}$ | $s_o^{(n)}$ | $c^{(n)}$ | where the prover fills in the columns $\boldsymbol{x_l}$, $\boldsymbol{x_r}$, and $\boldsymbol{x_o}$ with values (the **witnesses**) such that every constraint is satisfied. <br> **Example:** $a * b + 23 == 100$ (cont.) The $s$'s and equality constraints define a computation, the $c$'s give an instance of the computation; the prover fills in $x$ values to show that they know how a computation proceeds. | | $\boldsymbol{x_l}$ | $\boldsymbol{x_r}$ | $\boldsymbol{x_o}$ | $\boldsymbol{s_l}$ | $\boldsymbol{s_r}$ | $\boldsymbol{s_m}$ | $\boldsymbol{s_o}$ | $\boldsymbol{c}$ | |-| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ---------------- | | $a * b = c$ | $x_l^{(1)}$ | $x_r^{(1)}$ | $x_o^{(1)}$ | $0$ | $0$ | $1$ | $1$ | $0$ | | $d = 23$ | $x_l^{(2)}$ | $x_r^{(2)}$ | $x_o^{(2)}$ | $1$ | $0$ | $0$ | $0$ | $23$ | | $c + d = e$ | $x_l^{(3)}$ | $x_r^{(3)}$ | $x_o^{(3)}$ | $1$ | $1$ | $0$ | $1$ | $0$ | | $f = 100$ | $x_l^{(4)}$ | $x_r^{(4)}$ | $x_o^{(4)}$ | $1$ | $0$ | $0$ | $0$ | $100$ | $$ \textbf{Equality Constraints:} \\ x_o^{(1)} = x_l^{(3)} \\ x_l^{(1)} = x_r^{(3)} \\ x_o^{(3)} = x_o^{(4)} $$ ## Compressing Constraint Checks We would like to replace $n$ constraint checks (i.e. $\forall i \in [n]$ is the $i^{th}$ constraint satisfied?) with a single check of some form. We do this by transforming the constraint system into a polynomial expression that is true if and only if the constraint system is satisfied. ### Lagrange Interpolation Lagrange interpolation converts a function's evaluation form $\{(x_1, y_1), \dots, (x_n, y_n)\}$ into a passing through each point. Lagrange interpolation is used to represent each column as a polynomial: $x_l(X), x_r(X), x_o(X), s_l(X), s_r(X), s_m(X), s_o(X), c(X)$, where each column's polynomial on the $i^{th}$ input outputs the column's value in row $i$. We associate each matrix row $i \in [n]$ with a unique value $\omega^i$ where the set of values associated with all rows is $\mathbb{H} = \{\omega^1, \dots, \omega^n\}$. Zipping this set of inputs with a column $\textsf{zip}(\mathbb{H}, \textbf{column}) = \{(\omega^1, a_1), \dots, (\omega^n, a_n)\}$ gives the **evaluation form** for a polynomial that outputs the $i^{th}$ column value on row $i$'s input $\omega^i$. Performing Lagrange interpolation on each column's evaluation form produces the polynomial that maps each row's input $\omega^i$ to the value in the column at that row $a_i$. For example, to interpolate column $\boldsymbol{x_l}$ as $x_l(X)$ we use the evaluation form $\{(\omega^1, x_l^{(1)}), \dots, (\omega^n, x_l^{(1)})\}$. | $\mathbb{H}$ | $\boldsymbol{x_l}$ | $\boldsymbol{x_r}$ | $\boldsymbol{x_o}$ | $\boldsymbol{s_l}$ | $\boldsymbol{s_r}$ | $\boldsymbol{s_m}$ | $\boldsymbol{s_o}$ | $\boldsymbol{c}$ | |-| ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | ---------------- | | $\omega^1$ | $x_l^{(1)}$ | $x_r^{(1)}$ | $x_o^{(1)}$ | $s_l^{(1)}$ | $x_r^{(1)}$ | $s_m^{(1)}$ | $s_o^{(1)}$ | $c^{(1)}$ | |$\vdots$| | $\omega^n$ | $x_l^{(n)}$ | $x_r^{(n)}$ | $x_o^{(n)}$ | $s_l^{(n)}$ | $x_r^{(n)}$ | $s_m^{(n)}$ | $s_o^{(n)}$ | $c^{(n)}$ | ### Rewriting Constraint Checks as a Polynomial Expression Given the set of interpolating polynomials, we use the constraint equation to write an expression that holds for every input $\omega^i \in \mathbb{H}$: $$ s_l(\omega^i)x_l(\omega^i) + s_l(\omega^i)x_l(\omega^i) + s_m(\omega^i)x_l(\omega^i)x_r(\omega^i) = s_o(\omega^i)x_o(\omega^i) + c(\omega^i) $$ moving the right hand side to the left, we rewrite the above as: $$ s_l(\omega^i)x_l(\omega^i) + s_l(\omega^i)x_l(\omega^i) + s_m(\omega^i)x_l(\omega^i)x_r(\omega^i) - s_o(\omega^i)x_o(\omega^i) - c(\omega^i) = 0 \quad. $$ We can write the left hand side of the above equation as a polynomial: $$ s_l(X)x_l(X) + s_l(X)x_l(X) + s_m(X)x_l(X)x_r(X) - s_o(X)x_o(X) - c(X) $$ which that outputs $0$ on every input $\omega^i$, i.e. has roots $\omega^1, \dots, \omega^n$. We know some of the polynomial's roots, therefore we know part of its linear factorization contains the degree-1 terms $(X - \omega^1)\dots(X - \omega^n)$: $$ s_l(X)x_l(X) + s_l(X)x_l(X) + s_m(X)x_l(X)x_r(X) - s_o(X)x_o(X) - c(X) = (X - \omega^1)\dots(X - \omega^n)h(X) \stop $$ We call $(X - \omega^1)\dots(X - \omega^n)$ the **vanishing polynomial** $V(X)$ which outputs $0$ on every input $\omega^i$: $$ V(X) = \prod_{i \in [n]}(X - \omega^i) $$ which in a cyclic multiplicative group of order $n$ simplifies to: $$ \eqalign{ V(X) &= X^n - 1 \\ ~\\ V(\omega^i) &= (\omega^i)^n - 1 \\ &= \omega^{in \text{ mod } n} - 1 \\& = \omega^0 - 1 \\ &= 1 - 1 \\ &= 0 } $$ and $h(X)$ its cofactor polynomial. Thus, we can write the constraint system polynomial as as equality: $$ s_l(X)x_l(X) + s_l(X)x_l(X) + s_m(X)x_l(X)x_r(X) - s_o(X)x_o(X) - c(X) = V(X)h(X) \stop $$ The constraint system is **satisfied** if its polynomial representation $s_l(X)x_l(X) + \dots - c(X)$ is divisible by $V(X)$ without remainder. $$ V(X) \mathbin{\large|} s_l(X)x_l(X) + s_l(X)x_l(X) + s_m(X)x_l(X)x_r(X) - s_o(X)x_o(X) - c(X) $$ Thus we can perform $n$ constraint checks using a single polynomial division check. ## Permutation Notation A permutation $\sigma$ that shuffles an array of $n$ elements $\sigma((a_1, \dots, a_n)) = (b_1, \dots,b_n)$ can be written: $$ \sigma = (\sigma_1, \dots, \sigma_n) $$ where $\sigma_1 = 2$ means that $a_2 \mapsto b_1$. ![](https://i.imgur.com/HdLPvty.png) ## Equality Constraints The polynomial division check ensures that the prover knows satisfying inputs and outputs for each gate, but does not ensure a correct **wiring**, e.g. the output of one gate is the input to another. <br> **Example:** I know $(a, b)$ such that $a + b = a * b$. Applying the division check on the two gates proves that I know satisfying inputs and outputs for each gate in isolation, i.e. I know $(a, b, c, d, e, f)$ such that $a + b = e$ and $c * d = f$: ![](https://i.imgur.com/wzJEZpG.png) adding copy constraints proves that the left inputs are equal, the right inputs are equal and the outputs are equal, i.e. I know $(a, b)$ such that $a + b = a * b$: ![](https://i.imgur.com/LtuQj5g.png) <br> To prove equality of wires we apply a **permutation check** across the constraint system values $\boldsymbol{x_l}, \boldsymbol{x_r}, \boldsymbol{x_o}$. We join each of the three columns into a single array of length $3n$: $$ \boldsymbol{u} = \boldsymbol{x_l} \parallel \boldsymbol{x_r} \parallel \boldsymbol{x_o} = (x_l^{(1)}, \dots, x_l^{(n)}, x_r^{(1)}, \dots, x_r^{(n)}, x_o^{(1)}, \dots, x_o^{(n)}) \quad. $$ and create a permutation $\sigma \in S_{3n}$ that acts on $\boldsymbol{u}$ to produce an array $\boldsymbol{v} = \sigma(\boldsymbol{u}) = (u_{\sigma_1}, \dots, u_{\sigma_{3n}})$. We choose $\sigma$ such that each subset of copied values forms a **cycle**, i.e. copied values are permuted with only their copies. :::spoiler **Side Note:** permutation cycles Given a permutation $\sigma \in S_6$ where: $$ \sigma = \begin{bmatrix} 1 & 2 & 3 & 4 & 5 & 6 \\ 2 & 1 & 4 & 6 & 5 & 3 \end{bmatrix} $$ we can write $\sigma$ in **cycle notation**: $\sigma = (1 \ 2)(3 \ 4 \ 6)(5)$ or simply $(1 \ 2)(3 \ 4 \ 6)$. An $m$-cycle is a subset of $m$ elements that repeat after $m$ applications of $\sigma$, e.g. the $2$-cycle $(1 \ 2)$ maps $1 \rightarrow 2$ then $2 \rightarrow 1$. ::: <br> :::spoiler **Example:** permutation of constraint system values Given a constraint system of $n = 3$ constraints: $$ \boldsymbol{x_l} = (x_l^{(1)}, x_l^{(2)}, x_l^{(3)}) \\ \boldsymbol{x_r} = (x_r^{(1)}, x_r^{(2)}, x_r^{(3)}) \\ \boldsymbol{x_l} = (x_o^{(1)}, x_o^{(2)}, x_o^{(3)}) \\~\\ \eqalign{ \boldsymbol{u} = \boldsymbol{x_l} \parallel \boldsymbol{x_r} \parallel \boldsymbol{x_l} = \thinspace (&x_l^{(1)}, &x_l^{(2)}, &x_l^{(3)}, &x_r^{(1)}, &x_r^{(2)}, &x_r^{(3)}, &x_o^{(1)}, &x_o^{(2)}, &x_o^{(3)}) \\ & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 } $$ and wiring: $$ \eqalign{ & x_l^{(1)} = x_l^{(2)} \\ & x_o^{(1)} = x_r^{(2)} = x_l^{(3)} } $$ we create a permutation $\sigma$, which operates on a set containing $|\bold{u}| = 3n$ elements, such that each set of copied constraint system values forms a cycle: $$ \sigma = (x_l^{(1)} \ x_l^{(2)})(x_l^{(3)} \ x_r^{(2)} \ x_o^{(1)}) $$ written in a less cumbersome way using indices in $\boldsymbol{u}$ as: $$ \sigma = (1 \ 2)(3 \ 5 \ 7) \quad. $$ The permuted vector $\boldsymbol{v} = \sigma(\boldsymbol{u}) = (u_{\sigma_1}, \dots, u_{\sigma_{3n}})$ is: $$ \eqalign{ \boldsymbol{v} = \thinspace (&x_l^{(2)}, &x_l^{(1)}, &x_o^{(1)}, &x_r^{(1)}, &x_l^{(3)}, &x_r^{(3)}, &x_r^{(2)}, &x_o^{(2)}, &x_o^{(3)}) \\ & 2 & 1 & 7 & 4 & 3 & 6 & 5 & 8 & 9 \quad\quad. } $$ ![Permutation Example](https://i.imgur.com/kSSOm2X.png) ::: <br> The unpermuted array $\boldsymbol{u}$ is encoded into the polynomial: $$ u(X) = \prod_{i \in [3n]} (iX + u_i) $$ and the permuted array $\boldsymbol{v}$ is encoded into the polynomial: $$ v(X) = \prod_{i \in [3n]} (\sigma_iX + v_i). $$ where $\sigma_i$ is the index in $\boldsymbol{u}$ that permutes into $v_i$, i.e. $v_i = u_{\sigma_i}$ and $\bold{v} = \sigma(\bold{u}) = (u_{\sigma_1}, \dots, u_{\sigma_{3n}})$. Also let $u_i(X)$ and $v_i(X)$ denote the $i^{th}$ terms of $u(X)$ and $v(X)$ respectively: $$ \eqalign{ u_i(X) &= (iX + u_i) \\ v_i(X) &= (\sigma_iX + v_i) \quad. } $$ Notice that for each term $v_i(X)$ in $v(X)$ there is an identical term $u_{\sigma_i}(X)$ in $u(X)$, thus the polynomials $u(X)$ and $v(X)$ are the same, despite their $i^{th}$ terms possibly being different: $$ \eqalign{ u_i(X) &\neq v_i(X) \quad\quad \text{if } i \neq \sigma_i \\ u_{\sigma_i}(X) &= v_i(X) \\ \Rightarrow \prod_{i \in [3n]} u_i(X) &= \prod_{i \in [3n]} v_i(X) } $$ thus the following relation holds: $$ {u(X) \over v(X)} = \prod_{i \in [3n]} {(iX + u_i) \over (\sigma_iX + v_i)} = \prod_{i \in [3n]} {u_i(X) \over v_i(X)} = 1 \quad. $$ This relation between a polynomial representing an array and a polynomial representing a permutation of the array can be tested using Schwartz-Zippel: given a random input $\beta$ the probability the $u(\beta) = v(\beta)$, or ${u(\beta) \over v(\beta)} = 1$, is negligible. <br/> :::spoiler **Side Note:** PLONK uses a slightly different relation. PLONK actually defines $u(X) = \prod_{i \in [3n]} (iX + u_i + \gamma)$ and $v(X) = \prod_{i \in [3n]} (\sigma_iX + v_i + \gamma)$ where the verifier chooses a random $\gamma$ and sends it to the prover (which are equivalent via the **right-shift Schwartz-Zippel** lemma), thus in reality the above expression is: $$ {u(X) \over v(X)} = \prod_{i \in [3n]} {(iX + u_i + \gamma) \over (\sigma_iX + v_i + \gamma)} = 1 \quad. $$ ::: <br/> :::spoiler **Side Note:** the trace of a running product. The trace of a running product is an array $\bold{s}$ whose first element is $1$ an contains the value of the product after each multiplicand, e.g. $$ \prod_{i \in [3]} x^i \\ \bold{s} = (1, 1 {*} x^1, 1 {*} x {*} x^2, 1 {*} x {*} x^2 {*} x^3) $$ ::: <br/> The verifier chooses a random $\beta$ for the prover to evaluate ${u(\beta) \over v(\beta)}$ and the prover constructs a **grand product** array $\boldsymbol{s} = (s_1, \dots, s_{3n})$ that represents $u(\beta) \over v(\beta)$, i.e. $\bold{s}$ is the trace of the product $u(\beta) \over v(\beta)$: $$ \eqalign{ s_1 &= 1 \\ s_2 &= s_1 {u_1(\beta) \over v_1(\beta)} &= (1) {u_1(\beta) \over v_1(\beta)} \\ s_3 &= s_2{u_2(\beta) \over v_2(\beta)} &= \left(1 {u_1(\beta) \over v_1(\beta)} \right) {u_2(\beta) \over v_2(\beta)} \\ & \vdots \\ s_{3n} &= s_{3n - 1} {u_{3n - 1}(\beta) \over v_{3n - 1}(\beta)} &= \left( 1 {u_1(\beta) \over v_1(\beta)} \dots {u_{3n - 2}(\beta) \over v_{3n - 2}(\beta)} \right) {u_{3n - 1}(\beta) \over v_{3n - 1}(\beta)} } $$ $\boldsymbol{s}$ is recursive in that its $i^{th}$ element is equal to the previous element times $u_{i - 1}(\beta) \over v_{i - 1}(\beta)$: $$ s_i = s_{i - 1} {u_{i - 1}(\beta) \over v_{i - 1}(\beta)} \quad\quad \text{where: } i \in [2, 3n] \quad. $$ Notice that the $u(\beta) \over v(\beta)$ can be computed from $\bold{s}$ by multiplying its last element by the last product term in $u(\beta) \over v(\beta)$: $$ {u(\beta) \over v(\beta)} = \prod_{i \in [3n]} {u_i(\beta) \over v_i(\beta)} = s_{3n} {u_{3n}(\beta) \over v_{3n}(\beta)} = s_{3n + 1} $$ The prover creates a polynomial $s(X)$ using Lagrange interpolation on a publicly known set of $3n$ inputs $\mathbb{H} = \langle \omega \rangle = \{\omega^1, \dots, \omega^{3n}\} \subset \F$ and image $\bold{s}$ such that: $$ \forall i \in [3n]: s(\omega^i) = s_i \quad. $$ Notice that the following relation holds for a pair of **neighboring inputs** $\omega^i$ and $\omega^{i + 1}$: $$ \eqalign{ s_{i + 1} & = s_i {u_i(\beta) \over v_i(\beta)} \\ \Rightarrow s(\omega^{i + 1}) & = s(\omega^i) {u_i(\beta) \over v_i(\beta)} & \quad. } $$ Given $s(X)$, the verifier wants to check that $\boldsymbol{v}$ is a permutation of $\boldsymbol{u}$ according to $\sigma$. The verifier checks that the permutation identity holds at the last element in $\boldsymbol{s}$: $$ \eqalign{ {u(\beta) \over v(\beta)} & \overset{?}= 1 \\ \Rightarrow s(\omega^{3n}) {u_{3n}(\beta) \over v_{3n}(\beta)} & \overset{?}= 1 } $$ and that $\boldsymbol{s}$ is a correctly constructed running product $s_i = s_{i - 1} {u_{i - 1}(\beta) \over v_{i - 1}(\beta)}$: $$ \eqalign{ s(\omega^{3n}) &\overset{?}= s(\omega^{3n - 1}){u_{3n - 1}(\beta) \over v_{3n - 1}(\beta)} & \\ & \ \vdots \\ s(\omega^2) &\overset{?}= s(\omega^1) {u_1(\beta) \over v_1(\beta)} & \\ s(\omega^1) &\overset{?}= 1 & \quad. } $$ If ${u(\beta) \over v(\beta)} = 1$ at the random challenge $\beta$ then $u(X) = v(X)$, which implies $\bold{v} = \sigma(\bold{u})$. ## Proving Subarrays via Randomized Set Differences (Not Done) **Note:** "ordered multiset" == "array" **Note:** "subarray" == "order preserving subset of an array" PLONK defines an ordered multiset's $\bold{a} = (a_1, \dots, a_n)$ *set difference* $\bold{a}'$ as the difference between adjacent elements of $\bold{a}$: $$ \eqalign{ & \bold{a}' &= (a_{i + 1} - a_i)_{i \in [n - 1]} & \\~ \\ \text{e.g. } & \bold{a} &= (2, 6, 4) & \\ & \bold{a}' &= (6 - 2, 4 - 6) = (4, -2) & \quad. } $$ Given arrays $\bold{a}$ and $\bold{b}$, if $\bold{b}$ is a subarray of $\bold{a}$, then the set difference of $\textsf{sorted}(\bold{a} \parallel \bold{b})$ contains $|\bold{b}|$ number of zeros because each $b_i$ is inserted next to an $a_j$ having the same value: $$ \eqalign{ \text{e.g. } & \bold{a} &= (1, 3, 4, 7) & \\ & \bold{b} &= (1, 7) & \\ & \bold{c} &= \textsf{sorted}(\bold{a} \parallel \bold{b}) = (1, 1, 3, 4, 7, 7) & \\ & \bold{c}' &= (0, 2, 1, 3, 0) & \\ & \bold{c}' & \text{contains } |\bold{b}| = 2 \text{ zeros} & . } $$ However, this alone does not prove that an array is a subarray of $bold{a}$ because we can find an array$\bold{f} \not\subset \bold{a}$ where the set difference of $\textsf{sorted}(\bold{a} \parallel \bold{f})$ contains $|\bold{f}|$ number of zeros: $$ \eqalign{ \text{e.g. } & \bold{a} &= (1, 1) & \\ & \bold{f} &= (3, 3) & \\ & \bold{g} &= \textsf{sorted}(\bold{a} \parallel \bold{f}) = (1, 1, 3, 3) \\ & \bold{g}' &= (0, 0) \\ & \bold{g}' & \text{contains } |\bold{f}| = 2 \text{ zeros} & . } $$ However, given a random value $\gamma$, we can test (w.h.p.) that an array $\bold{b}$ is subarray of an array $\bold{a}$ by shifting all elements by $\gamma$: $$ \eqalign{ \text{e.g. } & \bold{a} + \gamma &= (a_1 + \gamma, \dots, a_n + \gamma) & \\ & \bold{b} + \gamma &= (b_1 + \gamma, \dots, b_{m} + \gamma) & \\ & \bold{c} &= \textsf{sorted}(\bold{a} \parallel \bold{b}) = (1, 1, 3, 4, 7, 7) & \\ & \bold{c}' &= (0, 2, 1, 3, 0) & \\ & \bold{c}' & \text{contains } |\bold{b}| = 2 \text{ zeros} & . } $$ <br/> <br/> <br/> <br/> <br/> <br/> ## Multiset Checks (Right-Shift Schwartz-Zippel) Given two arrays $\bold{a}$ and $\bold{b}$ of equal length $n$, if both $\bold{a}$ and $\bold{b}$ contain the same elements, regardless of their ordering, then the products of the arrays' elements will be equal: $$ \eqalign{ \bold{a} & = (x, y, z) \ \ & \\ \bold{b} & = (x, z, y) = \sigma(\bold{a}) \ \ & \\ a_1a_2a_3 & = b_1b_2b_3 & . } $$ However, the products of two [equally lengthed] arrays' elements being equal does not guarantee that $\bold{a}$ and $\bold{b}$ contain the same elements, e.g. $$ \eqalign{ \bold{a} &= (x, y, z) \\ \bold{b} &= \left( {x \over 2}, {z \over 2}, 4y \right) \neq \sigma(\bold{a}) \\ \prod_{i \in [n]} a_i &= \prod_{i \in [n]} b_i \quad\quad. } $$ We can use a product equality check on the elements of two arrays to guarantee that the arrays contain the same elements by right-shifting every element of each array by a random value $\gamma$: $$ \bold{a} = (x, y, z) \\ \bold{b} = (x, z, y) \\ (a_1 + \gamma)(a_2 + \gamma)(a_3 + \gamma) = (b_1 + \gamma)(b_2 + \gamma)(b_3 + \gamma) \\ \Longrightarrow \bold{b} = \sigma(\bold{a}) \quad. $$ # Background ## Linear Factors Contain Roots A univariate polynomial $f(X)$ having $n$ roots $\{a_1, \dots, a_n\}$ can be written uniquely as $n$ degree-$1$ polynomials: $$ f(X) = c(X - a_1)\dots(X - a_n) \\ \text{roots}(f) = \{a_1, \dots, a_n\} $$ where $c$ is a constant. If we don't care about the sign of the roots we can write: $$ f(X) = c(X + a_1)\dots(X + a_n) \\ \text{roots}(f) = \{-a_1, \dots, -a_n\} \quad. $$ A polynomial that has a linear factor $(iX - a)$ has a root at $a \over i$: $$ \eqalign{ f(X) &= \prod_{i \in [n]}(iX - a_i) \\ &= c(X - {a_1 \over 1})\dots(X - {a_n \over n}) \quad\quad \text{where: } c = 1 * \dots * n \\ \text{roots}(f) &= \left\{ {a_1 \over 1}, \dots, {a_n \over n} \right\} \quad. } $$ ## Encoding Sets and Arrays into Polynomials We can encode a set of values $\{a_1, \dots, a_n\}$ into a unique polynomial: $$ f(X) = \prod_{i \in [n]}(X - a_i) \\ \text{roots}(f) = \{a_1, \dots, a_n\} \quad. $$ <br> We can encode an array $(a_1, \dots, a_n)$ into a unique polynomial where each root encodes an array element and its position: $$ f(X) = \prod_{i \in [n]}(iX - a_i) \\ \text{roots}(f) = \left\{ {a_1 \over 1}, \dots, {a_n \over n} \right\} \quad. $$ <br> **Side Note:** if an array is a permutation of another, e.g. $\boldsymbol{a} = (a_1, \dots, a_n)$ and $\boldsymbol{b} = (b_1, \dots, b_n) = \sigma(\boldsymbol{a})$ where $\sigma = (\sigma_1, \dots \sigma_n)$ is a permutation, then the following equality holds: $$ \prod_{i \in [n]} (iX - a_i) = \prod_{i \in [n]} (\sigma_iX - b_i) $$ e.g. $\boldsymbol{a} = (5, 6, 7)$ and $\boldsymbol{b} = (6, 7, 5) = \sigma(\boldsymbol{a})$: $$ \eqalign{ a_1 & \rightarrow b_3 \quad & (\sigma_3 = 1) \\ a_2 & \rightarrow b_1 & (\sigma_1 = 2) \\ a_3 & \rightarrow b_2 & (\sigma_2 = 3) } \\ ~\\ \eqalign{ \prod_{i \in [n]} (iX - a_i) &= \prod_{i \in [n]} (\sigma_iX - b_i) \\ (1X - a_1)(2X - a_2)(3X - a_3) &= (\sigma_1X - b_1)(\sigma_2X - b_2)(\sigma_3X - b_3) \\ (1X - 5)(2X - 6)(3X - 7) &= (2X - 6)(3X - 7)(1X - 5) } $$ ## Schwartz-Zippel Given two univariate polynomials: $$ f(X) = (X + a_1)\dots(X + a_n) \\ g(X) = (X + b_1)\dots(X + b_n) $$ Schwartz-Zippel says that for a random input $\gamma \leftarrow \F$ the probability that different polynomials $f(X) \neq g(X)$ evaluate to the same value $f(\gamma) = g(\gamma)$ is very low. $$ \Pr[f(\gamma) = g(\gamma) \mid f(X) \neq g(X)] \leq {\max(d_f, d_g) \over |\F|} $$ This allows us to test **polynomial equivalency**, i.e. is $f(X)$ the same polynomial as $g(X)$. Schwartz-Zippel holds if every root of $f(X)$ and $g(X)$ is shifted by the a randomly chosen constant $\delta \leftarrow \F$: $$ f(X) = (X + a_1 + \delta)\dots(X + a_n + \delta) \\ g(X) = (X + b_1 + \delta)\dots(X + b_n + \delta) \\ \Pr[f(\gamma) = g(\gamma) \mid f(X) \neq g(X)] \leq {\max(d_f, d_g) \over |\F|} $$ because shifting two polynomials by the same value along the x-axis does not affect their equality. ![](https://i.imgur.com/5gJrVUS.png) We can encode the elements of a set $\{a_1, \dots, a_n\}$ into a polynomial $f(X) = (X - a_1)\dots(X - a_n)$ and the set $\{a_1, \dots, a_n\}$ into a polynomial $g(X) = (X - b_1)\dots(X - b_n)$ and use Schwartz-Zippel to test **set equality** (i.e. do sets $\{a_1, \dots, a_n\}$ and $\{b_1, \dots, b_n\}$ contain the same elements). We can encode an array $(a_1, \dots, a_n)$ as a polynomial whose roots contains the array elements and their positions: $$ f(X) = (1X - a_1)\dots(nX - a_n) \\ \text{roots}(f) = \left\{ {a_1 \over 1}, \dots, {a_n \over n} \right\} $$ thus, we can use Schwartz-Zippel to test **array equality** (i.e. $\forall i \in [n]: a_i = b_i$). PLONK uses Schwartz-Zippel (on random input $\lambda \leftarrow \F$) with a random right-shift $\delta \leftarrow \F$ to check array equality: $$ f(X) = (1X - a_1 + \delta)\dots(nX - a_n + \delta) \\ g(X) = (1X - b_1 + \delta)\dots(nX - b_n + \delta) \\ \Pr[f(\lambda) = g(\lambda) \mid f(X) \neq g(X)] \leq {\max(d_f, d_g) \over |\F|} \quad. $$ ### Multivariate Variant The Schwartz-Zippel probability is the same for an $n$-variate polynomial $f(X_1, \dots, X_n)$ and a randomly selected evaluation point $(x_1, \dots, x_n) \leftarrow \F^n$ $$ \Pr[f(x_1, \dots, x_n) = 0] \leq {d \over |\F|} \quad. $$ ### Zero-Polynomial Variant Given a random evaluation point such that $f(x_1, \dots, x_n) = 0$, the probability that $f(X_1, \dots, X_n)$ is the zero-polynomial (always a zero-function) is the converse of the Schwartz-Zippel probability $$ \Pr[f(X_1, \dots, X_n) \text{ is the zero-polynomial}] = 1 - \Pr[f(x_1, \dots, x_n) = 0] \quad. $$ ## Low-Degree Extension Given an array $\bold{a} = (a_1, \dots, a_n) \in \F^n$ and a subset $S = \{s_1, \dots, s_n\} \subset \F$, then the low-degree extension of $\bold{a}$ is the interpolation polynomial $a(X)$ of degree $d = n - 1$ that passes through the points $\{(s_1, a_1), \dots, (s_n, a_n)\}$: $$ \forall i \in [n]: a(s_i) = a_i \quad. $$ ## Cosets (todo) We associate each value in the constraint system with a unique value in $\mathbb{F}$: $$ \eqalign{ \boldsymbol{x_l} &\rightarrow \mathbb{H}_1 \quad\quad\quad & \forall i \in [n]: x_l^{(i)} \rightarrow \omega^i \\ \boldsymbol{x_r} &\rightarrow \mathbb{H}_2 & \forall i \in [n]: x_r^{(i)} \rightarrow 2\omega^i \\ \boldsymbol{x_o} &\rightarrow \mathbb{H}_3 & \forall i \in [n]: x_o^{(i)} \rightarrow 3\omega^i } $$ where $\mathbb{H}_1, \mathbb{H}_2, \mathbb{H}_3 < \mathbb{F}$ are disjoint subgroups and $\omega^i \in \mathbb{H}$, . We then join the labels into an array of length $3n$: $$ \boldsymbol{u} = (\omega^1, \dots, \omega^n, 2\omega^1, \dots, 2\omega^n, 3\omega^1, \dots, 3\omega^n) $$