PLONK 與 Halo2 電路約束系統深度解析:從代數電路到零知識證明的視覺化理解
本文深入解析 PLONK 和 Halo2 的電路約束系統,從代數層面理解零知識證明的核心原理。涵蓋算術電路的基本概念、PLONK 的 Gate Constraints 和 Permutation Check 的代數推導、Halo2 的查找表和非均一化約束結構、以及 Keccak 雜湊函數的電路實現。我們提供完整的數學推導和視覺化解說,幫助讀者從密碼學理論到工程實踐全面理解 ZK Rollup 的底層技術基礎。
PLONK 與 Halo2 電路約束系統深度解析:從代數電路到零知識證明的視覺化理解
文章 metadata
| 欄位 | 內容 |
|---|---|
| fact_checked | true |
| factcheckeddate | 2026-03-26 |
| version | 1.0 |
| difficulty | advanced |
前言:為什麼要折騰電路約束?
零知識證明(ZKP)這幾年火得不行,但坦白說,大部人對它的理解還停留在「我知道某個秘密,但我不想讓你看到這個秘密」這種文科生式的解釋。
我想做點不一樣的。
這篇文章,我要幫你搞懂 ZK Rollup 最核心的技術基礎:PLONK 和 Halo2 的電路約束系統。不是那種「zkSNARK 是什麼」的科普,而是真正的、代數層面的、數學視角的深度解析。
你會知道:
- 為什麼電路要「約束」?
- 多項式承諾到底是什麼?
- PLONK 的「permutation check」在數學上是如何運作的?
- Halo2 的「查找表」(Lookup Table)是怎麼回事?
讀完這篇,你可能還是寫不出 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(概率極高)
第二步:驗證累加器
驗證者的任務是:
- 確認 Z(0) = 1
- 確認 Z(ω^n) = 1
- 確認 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 證明」的問題。但實際應用中,有些計算特別「昂貴」——比如:
- SHA-256 雜湊(需要大量乘法門)
- 位元運算(AND, OR, XOR)
- 查表操作(判斷某個值是否在集合中)
這些計算用「乘法門」實現,電路會變得非常大,生成和驗證證明的成本會很高。
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 Rollup 的性能和安全性
- 設計更高效的 ZK 電路應用
- 理解 ZK 技術的「極限」在哪裡
ZK 技術還在快速發展。PLONK 和 Halo2 只是起點,未來會有更高效的約束系統、更快的證明生成、更小的電路大小。
持續關注這個領域,它會改變區塊鏈的遊戲規則。
參考資源
- Gabizon, A., Williamson, Z. J., & Ciobotaru, O. (2019). PLONK: Permutations over Lagrange-bases for Oecumenical Noninteractive arguments of Knowledge.
- Halo2 GitHub: https://github.com/zcash/halo2
- Ethereum Research: https://ethresear.ch/
- ZKProof Standards: https://zkproof.org/
- Keccak Team: https://keccak.team/
免責聲明:本網站內容僅供教育與資訊目的,不構成任何技術建議或投資推薦。ZK 技術涉及複雜的密碼學和工程實現,在實際應用前請諮詢專業人士意見。
相關文章
- PLONK 與 Halo2 約束系統完整數學推導指南:從代數基礎到電路設計的深度實作 — 本文提供 PLONK 和 Halo2 約束系統的完整數學推導,從橢圓曲線和配對的代數基礎開始,逐步推導約束系統的核心機制,包括多項式承諾(KZG 方案的代數結構完整推導)、置換論證、查詢論證。同時提供完整的電路設計範例,涵蓋算術約束電路(加法、乘法)、範圍檢查電路、Verkle 樹承諾電路、私密餘額轉帳電路、ZKML 推論電路等實作範例。
- 零知識證明電路設計與開發完整指南:從 Circom 到 Noir 與 Halo2 實作教學 — 本篇文章提供從理論到實作的完整 ZK 電路開發指南,涵蓋 Circom、Noir 與 Halo2 三種主流電路開發框架。深入探討 Merkle 驗證電路、範圍證明、簽章驗證電路等常見模式的設計與實現,同時分析 Halo2 與 PLONK 的數學推導差異,並討論 ZK-Friendly Smart Contract 開發的安全注意事項。提供完整的 Circom/Noir/Halo2 程式碼範例。
- ZK-SNARKs 數學推導完整指南:從零知識證明基礎到 Groth16 協議工程實踐 — 本文從工程師的視角出發,提供零知識證明數學基礎的完整推導。從密碼學安全假設出發,逐步建立零知識證明的理論框架,深入分析 zk-SNARKs 的核心協議——包括 Groth16、PLONK 與 Halo2 的設計原理與數學推導,並提供完整的程式碼範例說明如何在以太坊上實際部署零知識證明系統。
- Halo2 累積機制與 PLONK 電路約束推導完整指南:零知識證明的進階實作 — 本文深入分析 Halo2 的累積機制和 PLONKish 約束系統的數學原理。涵蓋有限域基礎、KZG 多項式承諾、PLONK 約束系統完整推導、Halo2 的累積器設計、R1CS 與 PLONK 比較、以及如何使用 Halo2 SDK 實作零知識電路。提供完整的代數推導過程和 Rust 程式碼範例,是理解現代零知識證明系統的核心教材。
- KZG 承諾代數推導與 PLONK 電路約束完整指南:從多項式承諾到零知識電路的數學原理 — KZG 承諾方案是以太坊 Layer 2 生態系統中 ZK-Rollup 的核心密碼學基礎。本文從代數推導的角度系統性地介紹 KZG 承諾的數學構造、信任設置( Powers of Tau )、安全性證明,以及 PLONK 電路中約束系統的完整設計。我們提供詳細的代數推導過程:包括雙線性配對的數學基礎、BLS12-381 曲線參數、商多項式構造、估值驗證方程的推導、PLONK 門約束與排列約束的代數形式、以及實際部署中的 Gas 成本優化。同時包含 Circom 電路設計範例和 zkSync、Starknet 等項目的工程實踐分析。
延伸閱讀與來源
- zkSNARKs 論文 Gro16 ZK-SNARK 論文
- ZK-STARKs 論文 STARK 論文,透明化零知識證明
- Aztec Network ZK Rollup 隱私協議
- Railgun System 跨鏈隱私協議
這篇文章對您有幫助嗎?
請告訴我們如何改進:
評論
發表評論
注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。
目前尚無評論,成為第一個發表評論的人吧!