---
# System prepended metadata

title: Plonk-co-learn-notes_By_MartinYeung5
tags: [Plonk]

---

# Plonk 學習

* "證明"的目的很重要，必須要了解到底證明什麼。

ZKP有兩個角色, 一個是prover, 一個verifier, 
如果要編寫prover, 有兩點要留意，第一是要產生一個有效的proof, 第二是要注意在產生proof時，有沒有暴露了一些不想公開的訊息。
如果要編寫verifier，要關注檢查的proof是不是有效的，能否滿足成為有效證明的條件。
prover要用最少的資源去證明一件事，verifier要用最少的資源去驗證一件事。

當完成一組代碼後，就算順利完成編譯，也不算是完全沒有bug的。因為代碼的完整性是不能忽視，需要經過測試，不過惡意的prover有很多種，在測試上是存在很大難度，難以完全進行所有測試。畢竟技術也在進步，有時候新的技術可能會欺騙到verifier。
所以在設計上，最重要的要考慮到自己寫的verifier如何不被惡意prover欺騙。

一個協議需要關注以下三部分: 
1. 完整性(completeness)
能否驗證所有為真的證明

2. 可靠性(soundness)
當證明是真的，就會通過驗證

3. 零知識(Zero-knowledge)
保護個人隱私

在prover與verifier之間要有大量交互，在有足夠多的交互下，才可以進一步減低作弊的風險。
真的證明能通過驗證，是其中一項條件，不代表這就是完整的。
如果要是假的證明又能通過驗證，這就雖然通過完整性，但就欠缺可靠性。所以兩者需要同時
如果不能區分假的證明，這就雖然通過可靠性，但就欠缺完整性。
所以兩者需要同時為真，才可以做到有效的驗證。

基於Non-interactive zero-knowledge proof ，用戶可以直接生成proof，然後發送到區塊鏈上進行驗證。
從而加快驗證效率

透過Fiat-Shamir transformation，可以實現Non-interactive zero-knowledge proof，
令public coin protocol變成Non-interactive proof。
public coin protocol 可以讓誠實的驗證點發出隨機的coin(可以理解為隨機數)作為訊息，然後由prover產生一個proof。
不過發出隨機的coin的動作不一定由verifier負責，可以由其他人負責。
所以可以引入random oracle(例如是 cryptographic hash function)來生成隨機數，然後由prover產生一個proof，再直接發送給verifier(on-chain)。因此，也減少了verifier的工作量。

![public coin protocol 變成 Non-interactive proof](https://miro.medium.com/v2/resize:fit:1100/format:webp/0*KFAp0RYRk0cOVMqc.png?raw=true "public coin protocol 變成 Non-interactive proof")

commitment 有以下特性: 
- O(1) size
- Binding, 當commitment出現，其數值就不能被修改。保證其他人拿到你的commitment也不可以再改它。
- Hiding, 當數值不公開，就不能被發現。不被人知道你的輸入資料, 每次生成的commitment都不同。

Plonk具有 commit-and-prove的特性，

commitment 有什麼種類?
1. hash
2. merkle-tree
3. pedersen commitment
* 當然是還有其他的，我會繼續去深入了解。

why zkSNARK?
1. 可以實現verifier on-chain
2. recursive proof: 可以進一步優化計算的compression及可以做到不同組合的計算效果.

why Plonk?
1. 是一個universal trust setup (KZG10)
2. Proving O(nlogn), Verifier O(logn), Proof-size O(1)

Plonk 的組成部分是 arithematic +  polynomial IOP。

circut:
門是屬於 Polynomial Gates。
當Circut經過計算之後會產出一堆polynomial。

polynomial會交給polynomial IOP

polynomial commitment
例子 : KZG10, IPM, FRI

這裡不是單單驗證一件事，而是驗證整個多項式。

#### 參考文章:
1. Fiat-Shamir transformation 
* https://www.zkdocs.com/docs/zkdocs/protocol-primitives/fiat-shamir/

2. zkSNARK是如何組成的 — 1
* https://medium.com/swf-lab/zksnark%E6%98%AF%E5%A6%82%E4%BD%95%E7%B5%84%E6%88%90%E7%9A%84-1-2c6a474bcb06

3. Zero Knowledge Proofs: Example with Pedersen Commitments in Monero
* https://medium.com/coinmonks/zero-knowledge-proofs-um-what-a092f0ee9f28

4. Understanding KZG10 Polynomial Commitments
* https://taoa.io/posts/Understanding-KZG10-Polynomial-Commitments

5. Recursive zkSNARKs: Exploring New Territory
* https://0xparc.org/blog/groth16-recursion


## PLONK算術化
https://www.youtube.com/watch?v=L3qMBzPgfWY

Plonkish算术化是PLONK證明系統特有的算术化
在Plonkish出現之前，其實主流的電路表達形式都是為RICS，而這表達形式已被多個零知識證明算法所使用，包括Groth16。
學習了加法門和乘法門在運算符中的區分。
* 以下是一個電路例子:

![alt text](https://github.com/MartinYeung5/20240770_ZKP_Plonk/blob/main/lesson2_2.png?raw=true)
1. 有3個門、6個輸入及1個輸出。
2. 滿足了3個約束。
    * X1 + X2 = X6
    * X3 * X4 = X5
    * X6 * X5 = OUT


* 以下是一個矩陣W表格:

![alt text](https://github.com/MartinYeung5/20240770_ZKP_Plonk/blob/main/lesson2_3.png?raw=true)

* 在表格中的第1行是各欄的標題，i是指門、 WL是指左輸入、WR是指右輸入及WO是指輸出。
第1列是指第1個門，會看到X6是指左輸入、X5是指右輸入及OUT是指輸出。
第2列是指第2個門，會看到X1是指左輸入、X2是指右輸入及X6是指輸出。
第3列是指第3個門，會看到X3是指左輸入、X4是指右輸入及X5是指輸出。

* 為了能對加法門和乘法門進行區分，會以這個矩陣Q表格作展示:

![alt text](https://github.com/MartinYeung5/20240770_ZKP_Plonk/blob/main/lesson2_4.png?raw=true)

* QL 和 QR 來表示加法門的輸入
* QL 是指左輸入
* QR 是指右輸入

* QM 表示乘法門
* QC 表示常量的數值
* QO 表示輸出


### 認識複製約束
* 由於在矩陣W表格中，可以看到第1個門的左轉入W6不一定等於第2個門的輸出X6。所以需要加入複製約束來確保第1個門的左轉入W6一定等於第2個門的輸出X6。也可以看到加入複製約束可以讓輸出的值會等於另一輸入的值，從入讓事出和輸入形成一種關連，而不是各自各的約束。

### 插值 (拉格朗日插值)
拉格朗日插值法可以找到一個多項式，其恰好在各個觀測的點取到觀測到的值。
有了一個多項式，可以便利驗證。

### 例子解說
矩陣W表格可以說是Prover需要準備的資料，當準備好之後，可以進行編譯。
完成後編譯，可以將結果發送給Verifier。
現在在矩陣W加多一項約束，約束是最終輸出是99。
因此，新增一條約束後的矩陣W表格會是這個:
![alt text](https://github.com/MartinYeung5/20240770_ZKP_Plonk/blob/main/lesson2_6.png?raw=true)


* 由於只是新增輸出一項約束，不會影響算術門的數量及輸入的值。

假設參數:
* 第1列是指第1個門，左輸入X6是3、右輸入X5是33及OUT輸出是99。
* 第2列是指第2個門，左輸入X1是1、右輸入X2是2及X6是3。
* 第3列是指第3個門，左輸入X3是3、右輸入X4是11及X5是33。
* 第4列是沒有指向任何門，只是其中一個輸出約束，左輸入是0、右輸入是0及輸出是99。

另外，新增一條約束後的矩陣Q表格會是這個:
![alt text](https://github.com/MartinYeung5/20240770_ZKP_Plonk/blob/main/lesson2_5.png?raw=true)

當拉格朗日插值需要滿足QL[0,1,0,0]時，即f(0)=0, f(1)=1, f(2)=0, f(3)=0 . 
```math
L_{0}(x) = \frac{(x-1)(x-2)(x-3)}{(0-1)(0-2)(0-3)} = 84*[x^3 - 6*x^2 + 11x -6] = 84x^3 + x^2 + 15x + 1
```

```math
L_{1}(x) = \frac{(x)(x-2)(x-3)}{(1-0)(1-2)(1-3)} = 51*[x^3 - 5*x^2 + 6x] = 51x^3 + 48x^2 + 3x
```

```math
L_{2}(x) = \frac{(x)(x-1)(x-3)}{(2-0)(2-1)(2-3)} = 50*[x^3 - 2*x^2 + 49x] = 50x^3 + 2x^2 + 49x
```

```math
L_{3}(x) = \frac{(x)(x-1)(x-2)}{(3-0)(3-1)(3-2)} = 17x^3 + 50x^2 + 34x
```

* 最終的拉格朗日插值式為:
```math
P(x) = 0*L_{0}(x) + 1*L_{1}(x) + 0*L_{2}(x) + 0*L_{3}(x) = 51x^3 + 48x^2 + 3x
```

當拉格朗日插值需要滿足WL[3,1,3,0]時，即f(0)=3, f(1)=1, f(2)=3, f(3)=0 . 
* 最終的拉格朗日插值式為: 
```math
P(x) = 3*L_{0}(x) + 1*L_{1}(x) + 3*L_{2}(x) + 0*L_{3}(x) = 49x^3 + 57x^2 + 94x + 3
```

換言之，要滿足QL[3,1,3,0]，就必須在f(0)=3, f(1)=1, f(2)=3, f(3)=0時通過以上多項式。

## PLONK中的多項式

* 透過多項式編碼，可以將多個約束轉換成一個約束。

### 多項式的概率檢查
* 要做多項式的概率檢查，需要有2個多項式，而且同為2個次數不多於d的多項式。Verifier只要進行一次多項式隨機挑戰就可以。這是Schwartz-Zippel定理。
* 因為可以進一步地去使用多項式承諾(Polynomial Commitment)，讓Prover負責計算x在某一任意地方的值，然後發送證明，這樣Verifier的工作量可以減少。
* 假設要驗證向量a + 向量b是否等於向量c:
可以先把向量編碼成多項式(系數編碼方式)
```math
a(x) = a_{0} + a_{1}(x) + a_{2}(x^2) + ... +  a_{n-1}(x^n-1)
```
```math
b(x) = b_{0} + b_{1}(x) + b_{2}(x^2) + ... +  b_{n-1}(x^n-1)
```
```math
c(x) = c_{0} + c_{1}(x) + c_{2}(x^2) + ... +  c_{n-1}(x^n-1)
```
Verifier 只需要給出一個隨機挑戰值(任意值) ζ∈F
```math
a(ζ) + b(ζ) = c(ζ)
 ```
如果成功證明到以上公式，則向量a + 向量b是等於向量c。
不過當要驗證向量a乘向量b是否等於向量c，就需要用拉格朗日插值的編碼方式，經轉換之後如下:
```math
a(X)⋅b(X)=c(X),∀X∈H
 ```
但在這公式，Verifier需要挑戰多次才可以縮小出錯概率。
因此，需要更高效的方法來進行檢測，目標是只用一次就可以檢查出Prover是否存在作弊行為。
```math
a(X)⋅b(X)−c(X)=q(X)⋅z H(X),∀X∈F
 ```
在公式上可以看到a(X)⋅b(X)−c(X)會等於0，所以q(X)⋅zH(X)也會等於0。
換言之，在X∈H的條件下，H會是a(X)⋅b(X)−c(X)的根集合。因為X必須要使到a(X)⋅b(X)−c(X)等於0。

另外，a(X)⋅b(X)−c(X)可以被多項式zH(X)整除，並得到一個商多項式q(X)。所以只要讓Prover計算出q(X)，就可以使到Verifier的工作量減少至只需進行一次隨機檢測就可知道a(X)⋅b(X)−c(X)在X∈H的條件下是否等於0。而Verifier 計算 zH(ζ) 需要 O(n) 的計算量。

### 單位根 Roots of Unity
以單位根作為 H，這可使到zH(ζ)的計算量會減少至O(logn)。

## PLONK中的置換證明
Plonk 的複製約束是通過置換證明（Permutation Argument）來實現。
在這個矩陣W表格中(加入位置標示):
![alt text](https://github.com/MartinYeung5/20240770_ZKP_Plonk/blob/main/lesson4_1.png?raw=true)
可以看到，WL1 = WO2, WR1 = WO3, WO1 = WO4 。而置換證明可以通過轉換它們的位置，然後再證明置換後的新矩陣是等於矩陣W。

### 基礎協議 - Grand Product Argument
由於進行多項式編碼，所以會把多個單乘法壓縮成單次乘法的驗證。
這裡可以理解成將多個約束壓縮在一起，轉換成1個可驗證的多項式。
* 引入一個輔助向量r
```math
r_{0} = 1
 ```
 *  r是每一個對上計算的結果(Accumulator)
 ```math
r_{k+1} = q_{k}*r_{k}
 ```
假設現在有3個約束，第1個約束的起始值是1，公式是:
 ```math
L_{0}*(r(X)-1) = 0 ,∀X∈H
 ```
第2個約束(遞歸的乘法關系)的公式是:
```math
q(X)*r(X) = r(w.X) ,∀X∈H∖{ω-^1}
 ```
第3個約束 - 為最後結果是:  
```math
r_{n-1} = p ,∀X∈H
 ```
第3個約束的公式是:
```math
L_{n-1}*(r(X)-r_{n-1}) = 0 ,∀X∈H
 ```
利用遞歸的乘法關系:
```math
q(X)*r(X) = r(w.X) ,∀X∈H
 ```
最後得出可以驗證的多項式:(以下是相關步驟)
```math
q(X)*r(X) - r(w.X) = 0 ,∀X∈H
 ```
 ```math
L_{0}(X)*(r(X) - 1) + q(X)*r(X) - r(w.X) = 0 ,∀X∈H
 ```
```math
L_{0}(X)*(r(X) - 1) + (α*q(X)*r(X) - r(w.X)) = 0 ,∀X∈H
 ```
```math
L_{0}(X)*(r(X) - 1) + α*(q(X)*r(X) - r(w.X)) = h(X)*Z_{H}(X) ,∀X∈H
```
當中α是一個隨機數，h(X)是商多項式，
```math
Z_{H}(X)是(X-1)(X-W)...(X-W^{n-1})
```
### 如何利用連乘證明來實現Multiset等價證明（Multiset Equality Argument）

假設向量 {qi} 為一個多項式 q(X) 的根集合，即對向量中的任何一個元素qi，都滿足q(ri)=0。這個多項式可以定義為：
```math
q(X) = (X - q_{0})(X - q_{1})...(X - q_{n-1})
```
如果有另一多項式p(X)與q(x)相同，則會具有相同的根集合。
可以利用 Schwartz-Zippel 定理做檢驗，只要Verifier輸入一個隨機數 γ，Prover就可以通過下面的公式以證明向量 {pi} 和 {qi} 是在多重集合上是等價。
```math
\prod_{i\in[n]}(γ-p_{i}) = \prod_{i\in[n]}(γ-q_{i})
```
然後，再使用連乘證明完成驗證，通過加入輔助向量，轉換成可以驗證的多項式。在目前例子，兩個連乘公式可以轉換成為一個連乘公式:
```math
\prod_{i\in[n]}\frac{(γ-p_{i})}{(γ-q_{i})} = 1
```

### 如何證明Multiset與置換證明（Permutation Argument）的關係
首先，要Prover證明兩個向量是滿足奇偶位置互換的置換情況。
```math
\vec{a} = (a_{0}, a_{1}, a_{2}, ..., a_{n-1}, a_{n})
```
```math
\vec{b} = (b_{0}, b_{1}, b_{2}, ..., b_{n-1}, b_{n})
```
可以運用多項式編碼把向量轉換成多項式，同時加入位置向置來表示奇偶位置互換。
```math
\vec{i} = (0, 1, 2, 3, ..., n-1, n)
```
```math
σ = (0, 1, 3, 2, ..., n, n-1)
```

兩個向量以表格形式列出一部分:
![alt text](https://github.com/MartinYeung5/20240770_ZKP_Plonk/blob/main/lesson4_2.png?raw=true)
之後，再整理一下，將表格中的左面和右面分成2組如下:
```math
a^{\prime} = (a_{i}, i) , b^{\prime} = (b_{i}, σ(i))
```
```math
(a_{0}, 0) , (b_{0} = a_{1}, 1)
```
```math
(a_{1}, 1) , (b_{1} = a_{0}, 0)
```
```math
\vdots , \vdots
```
```math
(a_{n-1}, n-1) , (b_{n-1} = a_{n}, n)
```
```math
(a_{n}, n) , (b_{n} = a_{n-1}, n-1)
```
根據以上情況，如果2個向量(a, b)滿足奇偶位置互換的置換情況，則以上2個向量(a', b')也會滿足Multiset等價的關系。

若要轉換為一個多項式(或一個新的向量)，可以加入一個隨機數β，結果如下:
```math
a_{i}^{\prime} = (a_{i} + β*i) , b_{i}^{\prime} = (b_{i} + β*σ(i))
```
```math
(a_{0} + β*0) , (b_{0} + β*1)
```
```math
(a_{1} + β*1) , (b_{1} + β*0)
```
```math
\vdots , \vdots
```
```math
(a_{n-1} + β*(n-1)) , (b_{n-1} + β*(n))
```
```math
(a_{n} + β*(n)) , (b_{n} + β*(n-1))
```

## 算術約束與複製約束

### 向量的複製約束
一個向量中，可以證明多個不同位置上的向量元素相等，例子如下:
```math
\vec{a}= (a_{0} + a_{1} + a_{2} + a_{3})
```
如果要證明
```math
a_{0} = a_{2}
```
可以將它們的位置對調，以σ 表示位置向量:
```math
\vec{a}_{σ} 為置換後的向量
```
```math
σ = (2, 1, 0, 3), \vec{a}_{σ} = (a_{2} + a_{1} + a_{0} + a_{3})
```
只要Prover證明到置換前的向量和置換後的向量相等，就表示:
```math
a_{0} = a_{2} 是正確的
```
### 向量(多個)的複製約束
* 以下會以例子說明整個流程:
選用矩陣W表格，同時加入一個輸出的約束。
![alt text](https://github.com/MartinYeung5/20240770_ZKP_Plonk/blob/main/lesson5_1.png?raw=true)
會留意到有些地方的值是相等的，包括:
```math
w_{a,1} = w_{c,2}, w_{b,1} = w_{c,3}, w_{c,0} = w_{c,1}
```
* 對表格中的三列向量用三個置換向量統一地進行位置編碼，結果如下:
![alt text](https://github.com/MartinYeung5/20240770_ZKP_Plonk/blob/main/lesson5_2.png?raw=true)
置換後的向量為:
```math
σ_{a} , σ_{b} , σ_{c}
```
![alt text](https://github.com/MartinYeung5/20240770_ZKP_Plonk/blob/main/lesson5_3.png?raw=true)

因此，現在會有2個向量，分別是置換前的向量及置換後的向量。為了進行下一步驗證，需要利用一個隨機數β來進行向量合併。
之後再利用另一個隨機數γ配合連乘以獲得2個向量的Multisets。
置換前的向量:
```math
f_{i} = (w_{a,i} + β*id_{a,i} + γ)(w_{b,i} + β*id_{b,i} + γ)(w_{c,i} + β*id_{c,i} + γ)
```
置換後的向量:
```math
g_{i} = (w^{\prime}_{a,i} + β*σ_{a,i} + γ)(w^{\prime}_{b,i} + β*σ_{b,i} + γ)(w^{\prime}_{c,i} + β*σ_{c,i} + γ)
```
進一步演示 - 置換前的向量:
```math
f_{0} = (w_{a,0} + β*0 + γ)(w_{b,0} + β*4 + γ)(w_{c,0} + β*8 + γ)
```
```math
f_{1} = (w_{a,1} + β*1 + γ)(w_{b,1} + β*5 + γ)(w_{c,1} + β*9 + γ)
```
```math
f_{2} = (w_{a,2} + β*2 + γ)(w_{b,2} + β*6 + γ)(w_{c,2} + β*10 + γ)
```
```math
f_{3} = (w_{a,3} + β*3 + γ)(w_{b,3} + β*7 + γ)(w_{c,3} + β*11 + γ)
```
進一步演示 - 置換後的向量:
```math
g_{0} = (w^{\prime}_{a,0} + β*0 + γ)(w^{\prime}_{b,0} + β*4 + γ)(w^{\prime}_{c,0} + β*9 + γ)
```
```math
g_{1} = (w^{\prime}_{a,1} + β*10 + γ)(w^{\prime}_{b,1} + β*11 + γ)(w^{\prime}_{c,1} + β*8 + γ)
```
```math
g_{2} = (w^{\prime}_{a,2} + β*2 + γ)(w^{\prime}_{b,2} + β*6 + γ)(w^{\prime}_{c,2} + β*1 + γ)
```
```math
g_{3} = (w^{\prime}_{a,3} + β*3 + γ)(w^{\prime}_{b,3} + β*7 + γ)(w^{\prime}_{c,3} + β*5 + γ)
```
由於
```math
w_{a,1} = w^{\prime}_{c,2}
```
```math
w_{c,2} = w^{\prime}_{a,1}
```
所以:
```math
(w_{a,1} + β*1 + γ) = (w^{\prime}_{c,2} + β*1 + γ)
```
```math
(w_{c,2} + β*10 + γ) = (w^{\prime}_{a,1} + β*10 + γ)
```
換言之:
```math
\prod_{x\in H}f(X) = \prod_{i\in H}g(X)
```
```math
\prod_{x\in H}\frac{f(X)}{g(X)}
```
現在再利用新的向量z，以表示連乘計算的一系列中的過程。
需假設:
```math
Z_{0} = 1, Z_{i+1} = Z_{i}*\frac{f(i)}{g(i)}
```
Prover可以計算出以下的值:
![alt text](https://github.com/MartinYeung5/20240770_ZKP_Plonk/blob/main/lesson5_4.png?raw=true)
```math
如果\vec{f} = \vec{g}，則Z_{N}會等於1
```
所以:
```math
 Z_{N} = Z_{0} = 1
```