PLONK 與 Halo2 電路約束系統深度解析:從代數電路到零知識證明的視覺化理解

本文深入解析 PLONK 和 Halo2 的電路約束系統,從代數層面理解零知識證明的核心原理。涵蓋算術電路的基本概念、PLONK 的 Gate Constraints 和 Permutation Check 的代數推導、Halo2 的查找表和非均一化約束結構、以及 Keccak 雜湊函數的電路實現。我們提供完整的數學推導和視覺化解說,幫助讀者從密碼學理論到工程實踐全面理解 ZK Rollup 的底層技術基礎。

PLONK 與 Halo2 電路約束系統深度解析:從代數電路到零知識證明的視覺化理解


文章 metadata

欄位內容
fact_checkedtrue
factcheckeddate2026-03-26
version1.0
difficultyadvanced

前言:為什麼要折騰電路約束?

零知識證明(ZKP)這幾年火得不行,但坦白說,大部人對它的理解還停留在「我知道某個秘密,但我不想讓你看到這個秘密」這種文科生式的解釋。

我想做點不一樣的。

這篇文章,我要幫你搞懂 ZK Rollup 最核心的技術基礎:PLONK 和 Halo2 的電路約束系統。不是那種「zkSNARK 是什麼」的科普,而是真正的、代數層面的、數學視角的深度解析。

你會知道:

讀完這篇,你可能還是寫不出 ZK 證明系統,但起碼你知道自己在折騰什麼了。


第一章:從電路到約束——基本概念掃盲

1.1 什麼是「算術電路」?

在理解 ZK 證明之前,我們得先搞清楚一個基本問題:電路是什麼?

你可以把「算術電路」想像成一台計算機。它由一堆「門」(gate)和「線」(wire)組成。

簡單的算術電路示例:

輸入: a, b

          a ──┬──→ [     ]
              │     [  ×  ]──→ [     ]──→ 輸出
          b ──┴──→ [     ]     [  +  ]
                                  │
              c ──────────────────┘

計算:(a × b) + c

這是一個「乘法-加法」電路。實際上,任何可計算的函數,都可以表示成這種「門和線」的組合——這就是「電路的普遍性」(Universality)。

1.2 為什麼要「約束」?

ZK 證明的核心思想是:我不想讓你重新計算一遍,但我需要讓你相信計算是正確的。

要做到這一點,你需要一種方式來「聲明」計算的正確性。這就是「約束」(Constraint)的意義。

約束是一個數學方程式,它「約束」了某個變數的取值範圍,或者多個變數之間的關係。

約束的基本形式:

乘法約束:q_l × q_r = q_o

其中:
- q_l 是「左輸入」的標記
- q_r 是「右輸入」的標記
- q_o 是「輸出」的標記

直覺解釋:
→ 如果 q_l = a, q_r = b, q_o = a × b
→ 那麼約束成立(a × b = a × b)
→ 否則約束失敗

約束系統的妙處在於:它把「正確性證明」轉化成了「數學方程式」。只要你能驗證方程式成立,就能相信計算是正確的——不需要重新計算一遍。

1.3 電路的「大小」和「深度」

電路的兩個關鍵指標:

電路大小(Circuit Size):電路中「門」的總數。門越多,計算越複雜。

電路深度(Circuit Depth):從輸入到輸出最長的「路徑」上的門數。深度越大,計算的「依賴鏈」越長。

電路大小 vs 電路深度 示例:

電路A(淺但寬):           電路B(深但窄):

    a ──→ [×] ──→ 輸出         a ──→ [×] ──→ [+] ──→ 輸出
    b ──→ [×] ──→              b ──→         ↑
    c ──→ [×] ──→              c ──→ ──→ [+] ──→
    
    大小=3, 深度=1             大小=4, 深度=3

在 ZK 證明中,「電路大小」直接影響證明的生成時間和驗證時間。一般來說,電路越大,生成證明需要的時間越長。


第二章:PLONK 的核心:算術化

2.1 什麼是「算術化」?

PLONK 的全名是「Permutations over Lagrange-bases for Oecumenical Noninteractive arguments of Knowledge」,名字本身就透露了它的核心思想。

「算術化」(Arithmetization)是 ZK 證明的關鍵步驟。它的意思是:把「計算機程序」轉化為「數學方程式」

PLONK 使用的算術化方式是「Gate Constraints + Wire Copy Constraints」:

PLONK 算術化的核心方程式:

┌──────────────────────────────────────────────────────────────────┐
│  PLONK 約束系統的三大支柱:                                       │
│                                                                  │
│  一、Gate Constraints(門約束)                                   │
│     描述「乘法門」和「加法門」的輸入輸出關係                       │
│     q_l × a + q_r × b + q_m × a × b + q_o × c + q_c = 0        │
│                                                                  │
│  二、Wire Copy Constraints(連線約束)                            │
│     確保「電線」兩端的值是連貫的                                  │
│     某條 wire 的值,不能同時等於兩個不同的值                       │
│                                                                  │
│  三、Permutation Check(置換檢查)                                │
│     確保「公共輸入」和「私有輸入」之間的「位置對應關係」           │
│     例如:a_0 = x_0, a_1 = x_1, ...                              │
└──────────────────────────────────────────────────────────────────┘

2.2 Gate Constraints 的代數推導

PLONK 的 Gate Constraint 使用的是一個「通用的乘法-加法約束」:

PLONK Gate Equation:

q_l × a + q_r × b + q_m × a × b + q_o × c + q_c = 0

其中:
- q_l, q_r, q_m, q_o, q_c 是「選擇器係數」(Selector Coefficients)
- a, b, c 是三個「輸入 wire」的值
- 約束成立的條件是:整個表達式等於 0

這個方程式厲害的地方在於:透過不同的選擇器係數組合,它可以用來表示加法門和乘法門

讓我推導一下:

Case 1:加法門(a + b = c)

令 ql = 1, qr = 1, qm = 0, qo = -1, q_c = 0

代入方程式:

1 × a + 1 × b + 0 × a × b + (-1) × c + 0 = 0
→ a + b - c = 0
→ a + b = c ✓

Case 2:乘法門(a × b = c)

令 ql = 0, qr = 0, qm = 1, qo = -1, q_c = 0

代入方程式:

0 × a + 0 × b + 1 × a × b + (-1) × c + 0 = 0
→ a × b - c = 0
→ a × b = c ✓

Case 3:恆等門(直接把 a 複製到 b)

令 ql = 1, qr = 0, qm = 0, qo = -1, q_c = 0

代入方程式:

1 × a + 0 × b + 0 × a × b + (-1) × c + 0 = 0
→ a - c = 0
→ a = c ✓

所以,PLONK 的 Gate Constraint 可以表達任何「一個輸出,多個輸入」的運算。這就是它的「通用性」。

2.3 Permutation Check 的數學原理

Permutation Check 是 PLONK 最複雜的部分,但也是最精妙的部分。

它的目標是:讓 prover 能夠「承諾」某些變數之間的「位置對應關係」,而不需要透露具體的值。

這個思想來自「多項式承諾」——把一堆值打包成一個「承諾」,之後只需要驗證這個承諾,就能相信這些值滿足某些關係。

PLONK 的 Permutation Check 分為兩步:

第一步:建構「累加器」多項式

定義累加器(Grand Product):

Z(x) = ∏(i=0 to n-1) (σ_i + β × σ'_i + γ) / (σ_i + β × s_i + γ)

其中:
- σ_i 是「原始 wire」的標記(witness 重新排列後)
- σ'_i 是「重排後 wire」的標記(expected permutation)
- β, γ 是隨機挑戰(challenge)
- Z(x) 是「累加器多項式」

直覺解釋:
→ 分子和分母分別是「所有 wire 對」的乘積
→ 如果 σ_i 和 s_i 是同一個排列(只是順序不同),那麼分子 = 分母,Z = 1
→ 否則,Z ≠ 1(概率極高)

第二步:驗證累加器

驗證者的任務是:

  1. 確認 Z(0) = 1
  2. 確認 Z(ω^n) = 1
  3. 確認 Z(x) / Z(xω) 的形式符合約束

如果這三個條件都滿足,就可以相信 Permutation Check 通過了。

Permutation Check 的視覺化:

┌──────────────────────────────────────────────────────────────────┐
│                                                                  │
│  原始 witness 排列: [a₀, b₀, c₀, ...]                          │
│                            ↓ 重新排列                            │
│  目標 permutation: [σ₀, σ₁, σ₂, ...]                           │
│                                                                  │
│  計算:                                                          │
│  - Z₀ = 1                                                       │
│  - Z₁ = Z₀ × (σ₀ + β·0 + γ) / (a₀ + β·0 + γ)                  │
│  - Z₂ = Z₁ × (σ₁ + β·1 + γ) / (b₀ + β·1 + γ)                  │
│  - ...                                                          │
│  - Z_n = Z_{n-1} × (σ_{n-1} + β·(n-1) + γ) / (...)            │
│                                                                  │
│  驗證:                                                          │
│  - Z₀ = 1? ✓                                                    │
│  - Z_n = 1? ✓  (意味著最終乘積為 1)                            │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

Permutation Check 的核心思想是:把「位置對應關係」編碼成一個「乘積」,透過驗證這個乘積來確認對應關係

這個技巧很巧妙,但代價是:你需要額外的「乘法約束」來計算累加器。PLONK 的電路複雜度,很大一部分來自這裡。


第三章:Halo2 的創新——查找表與非均一化

3.1 為什麼需要「查找表」?

PLONK 解決了「通用 ZK 證明」的問題。但實際應用中,有些計算特別「昂貴」——比如:

這些計算用「乘法門」實現,電路會變得非常大,生成和驗證證明的成本會很高。

Halo2 的創新之一,是引入了「查找表」(Lookup Table)。

查找表的直覺:

傳統方式(用乘法門實現):         查找表方式:

a ──→ [SHA-256] ──→ 輸出           a ──→ [查找表] ──→ 輸出

需要 ~20,000 個乘法門               需要 ~100 個約束
極度昂貴                              更高效

查找表的基本思想是:把「昂貴的計算結果」預先計算好,儲存在表格中。Prover 只需要「承諾」自己的輸入,然後聲明「輸出在某個表格的某一行」。

3.2 Halo2 的「非均一化」約束系統

Halo2 和 PLONK 的核心差異,在於它們對「複製約束」的處理方式。

PLONK 用 Permutation Check 來處理複製約束——把一組值重新排列,然後驗證排列的正確性。

Halo2 用的是「非均一化」(Uneven Structure)——把電路分成不同的「區塊」(Region),每個區塊有自己的佈局和約束。

Halo2 的電路結構:

┌──────────────────────────────────────────────────────────────────┐
│                                                                  │
│  Table Region                                                   │
│  ┌────────┬────────┬────────┬────────┐                         │
│  │        │        │        │        │                         │
│  │ Table  │ Table  │ Table  │ Table  │                         │
│  │ Column │ Column │ Column │ Column │                         │
│  │   0    │   1    │   2    │   3    │                         │
│  │        │        │        │        │                         │
│  └────────┴────────┴────────┴────────┘                         │
│                                                                  │
│  Advice Region                                                   │
│  ┌────────┬────────┐                                            │
│  │ Advice │ Advice │                                            │
│  │ Column │ Column │                                            │
│  │   0    │   1    │                                            │
│  └────────┴────────┘                                            │
│                                                                  │
│  Fixed Region                                                   │
│  ┌────────┐                                                     │
│  │  Fixed  │                                                     │
│  │ Column  │                                                     │
│  └────────┘                                                     │
│                                                                  │
│  關鍵創新:                                                      │
│  → Table 和 Advice 可以「查找」                                  │
│  → Prover 可以「承諾」自己的 witness 在 Table 中               │
│  → 驗證者只檢查「查找結果是否匹配」                               │
└──────────────────────────────────────────────────────────────────┘

3.3 查找約束的代數推導

Halo2 的查找約束,用的是一個稱為「承諾的多項式」技術:

查找約束的基本方程式:

令:
- f_0, f_1, ..., f_{m-1} 是「表格列」的值
- v 是「查找輸入」(prover 提供的 witness)
- v' 是「查找輸出」(表格中對應的值)

約束成立當且僅當:
∃ i ∈ [0, m-1]: v = f_i 且 v' = g_i

其中 g_i 是表格中與 f_i 對應的「輸出值」

實現方式:
→ 將表格組織成「乘積」的形式
→ Prover 需要證明 (v, v') 在「表格多項式」的「值集合」中
查找表的「承諾」結構:

┌──────────────────────────────────────────────────────────────────┐
│                                                                  │
│  表格內容:                                                       │
│  ┌─────────────┬─────────────┐                                  │
│  │    Input    │    Output  │                                  │
│  ├─────────────┼─────────────┤                                  │
│  │      0      │      0      │                                  │
│  │      1      │      1      │                                  │
│  │      2      │      4      │                                  │
│  │      3      │      9      │                                  │
│  │      4      │     16      │                                  │
│  │     ...     │     ...     │                                  │
│  └─────────────┴─────────────┘                                  │
│                                                                  │
│  查找操作:                                                       │
│  Prover 輸入:v = 3                                              │
│  Prover 聲明:v' = 9                                             │
│  驗證:3² = 9 ✓                                                  │
│                                                                  │
│  實際電路:                                                       │
│  - Prover 不需要計算 3²                                          │
│  - 只需要「承諾」3 在表格的第 4 行                                │
│  - 只需要「承諾」9 在表格的第 4 行                               │
│  - 驗證者檢查「兩行是否匹配」                                    │
└──────────────────────────────────────────────────────────────────┘

3.4 Halo2 的「遞迴證明」能力

Halo2 最大的創新,是支持「遞迴證明」(Recursive Proofs)。

簡單來說:Halo2 的電路可以用來「驗證 Halo2 自身的證明」

這有什麼用?

用處大了。你可以把很多筆交易打包成一個「批次證明」,然後把很多批次組合成一個「區塊證明」。最後,把區塊證明提交到以太坊主網。

Halo2 遞迴證明的層級結構:

Layer 2(Rollup):
┌──────────────────────────────────────────────────────────────────┐
│                                                                  │
│  Tx₁ ──→ [ZK電路] ──→ π₁                                       │
│  Tx₂ ──→ [ZK電路] ──→ π₂                                       │
│  ...                                                            │
│  Txₙ ──→ [ZK電路] ──→ πₙ                                       │
│                                                                  │
│  然後:                                                          │
│  π₁, π₂, ..., πₙ ──→ [聚合電路] ──→ Π_block                   │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘
                    ↓
         Layer 1(以太坊主網):
         
┌──────────────────────────────────────────────────────────────────┐
│                                                                  │
│  Π_block ──→ [驗證合約] ──→ 接受/拒絕                           │
│                                                                  │
│  驗證合約只需要:                                                │
│  - 檢查 Π_block 是一個「有效的聚合證明」                        │
│  - 不需要逐個驗證 π₁, π₂, ..., πₙ                              │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

遞迴證明的好處是:大幅降低 Layer 1 的驗證成本。一筆交易的驗證成本是 O(1),不管這筆交易本身有多複雜。


第四章:Keccak 雜湊函數的電路實現

4.1 為什麼要用電路實現 Keccak?

ZK Rollup 的一個常見應用場景,是「驗證以太坊區塊的執行」。

但以太坊的區塊執行大量使用了 Keccak-256 雜湊函數。如果要在 ZK 電路中「驗證」Keccak 的結果,需要先把 Keccak 的邏輯「翻譯」成電路約束。

這就是「Keccak 電路」的由來。

Keccak 的實現非常複雜(因為它是專門為硬體設計的,不是為電路設計的)。把 Keccak 翻譯成電路約束,需要大量的約束數量。

Keccak 電路的約束數量估算:

┌──────────────────────────────────────────────────────────────────┐
│  Keccak-f[1600] 的電路複雜度:                                   │
│                                                                  │
│  組件                    約束數量                               │
│  ─────────────────────────────────────────────────────────────  │
│  θ (Theta)               ~1,600                                 │
│  ρ (Rho)                 ~0 (只是重新排列)                      │
│  χ (Chi)                 ~800 (XOR + AND)                       │
│  π (Pi)                  ~0 (只是重新排列)                       │
│  ι (Iota)                ~1 (XOR 常數)                          │
│  ─────────────────────────────────────────────────────────────  │
│  總計                    ~2,400 約束/輪                         │
│  總輪數                  24 輪                                  │
│  總約束數                 ~57,600 約束                          │
│  ─────────────────────────────────────────────────────────────  │
│                                                                  │
│  對比:                                                          │
│  - 簡單的乘法-加法電路(~100個門)                              │
│  - ECDSA 簽名驗證電路(~10,000 個門)                           │
│  - Keccak-256 電路(~60,000 個門)                              │
│  - SHA-256 電路(~25,000 個門)  ← Keccak 更複雜              │
└──────────────────────────────────────────────────────────────────┘

4.2 Keccak 的「非線性層」約束

Keccak 的核心非線性操作是「χ」(Chi)函數:

Chi 函數的代數表達:

χ(a, b, c) = (a AND NOT b) XOR c

定義為:
χ(a, b, c) = a ⊕ c ⊕ (a ∧ b)

電路約束實現:

令:
- a, b, c 是三個「切片」(slice)的值
- o = χ(a, b, c) 是輸出

約束:
→ o = a XOR c XOR (a AND b)

注意:
→ XOR 是線性的,可以用「加法」約束實現
→ AND 是非線性的,需要「乘法」約束實現

4.3 Keccak 的「線性層」約束

Keccak 的「線性層」包括 θ(Theta)和 π(Pi)等操作。這些操作只涉及 XOR(線性運算),可以用更少的約束實現。

Keccak 線性層的約束優化:

θ (Theta) 函數:
C[x] = Σ a[x, y]  for all y
D[x] = C[x-1] XOR C[x+1]
a'[x, y] = a[x, y] XOR D[x]

約束優化策略:
→ 把 64 個切片打包成 1 個「大整數」
→ 使用「位元打包」技巧,減少約束數量
→ 將 5 個「切片」捆綁在一起,共享約束

第五章:實用建議與常見陷阱

5.1 電路設計的最佳實踐

如果你在設計 ZK 電路,以下是一些實用建議:

1. 最小化「public input」的數量

Public input 需要額外的約束來驗證。越多的 public input,電路越大。

2. 使用「查找表」來實現「昂貴的」運算

如果某個函數可以預先計算(例如雜湊表、轉換表),用查找表代替電路實現。

3. 避免「條件選擇」約束

if condition then a else b 這種操作在電路中很昂貴。如果可能的話,重新設計邏輯。

4. 利用「非均一結構」的靈活性

Halo2 允許你在不同區塊使用不同的佈局。善用這個靈活性來優化約束數量。

5.2 常見的錯誤和陷阱

陷阱一:忘記「範圍檢查」

電路約束不能檢查「範圍」。如果你需要確保某個值在 [0, n) 範圍內,需要額外添加「範圍檢查約束」。

陷阱二:忽略「copy constraints」的數量

Permutation Check 和 Copy Constraints 會消耗大量的「約束預算」。在大電路中,這些約束可能佔據總約束數的 30-50%。

陷阱三:選擇錯誤的多項式承諾方案

不同的 ZK 系統使用不同的多項式承諾方案(KZG、Halo2 的 IPA、STARKs 的 FRI)。選擇錯誤的方案會導致性能瓶頸。


結論

PLONK 和 Halo2 代表了 ZK 證明系統的「工程化」前沿。它們把抽象的密碼學理論,轉化成了實際可用的電路約束系統。

理解這些底層技術,不僅是為了「炫技」,更是為了:

ZK 技術還在快速發展。PLONK 和 Halo2 只是起點,未來會有更高效的約束系統、更快的證明生成、更小的電路大小。

持續關注這個領域,它會改變區塊鏈的遊戲規則。


參考資源


免責聲明:本網站內容僅供教育與資訊目的,不構成任何技術建議或投資推薦。ZK 技術涉及複雜的密碼學和工程實現,在實際應用前請諮詢專業人士意見。

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。

目前尚無評論,成為第一個發表評論的人吧!