PLONK/Halo2 電路約束推導完整指南:從代數電路到零知識證明系統

PLONK 與 Halo2 是當今區塊鏈領域最重要的零知識證明系統之一。本文從電路約束推導的視角出發,完整解析 PLONK 的約束系統、證明流程與 Halo2 的工程實現。讀者將理解為何 PLONK 能夠在「通用性」與「效率」之間取得優異平衡,以及如何在實際項目中設計與優化零知識電路。

PLONK/Halo2 電路約束推導完整指南:從代數電路到零知識證明系統

概述

PLONK(Permutations over Lagrange-bases for Oecumenical Noninteractive arguments of Knowledge)與其後續實現 Halo2 是當今區塊鏈領域最重要的零知識證明系統之一。PLONK 由 Ariel Gabizon、Zachary J. Williamson 與 Oana Ciobotaru 於 2019 年提出,其創新之處在於通用且可更新的可信設置,使其成為以太坊 Layer2 時代的核心技術基礎。zkSync、Polygon zkEVM、Aztec 等主流 zk Rollup 均基於 PLONK 或其變體構建。

本文從電路約束推導的視角出發,完整解析 PLONK 的約束系統、證明流程與 Halo2 的工程實現。讀者將理解為何 PLONK 能夠在「通用性」與「效率」之間取得優異平衡,以及如何在實際項目中設計與優化零知識電路。


第一部分:PLONK 約束系統的數學基礎

1.1 從代數電路到約束系統

零知識證明的核心任務是讓證明者(Prover)向驗證者(Verifier)證明「我知道一個秘密輸入 w,使得電路 C(x, w) = 0」,同時不洩露 w 的具體內容。這裡的 C 是一個算術電路。

定義 1.1.1(算術電路):

一個算術電路 C 定義在有限域 $\mathbb{F}_p$ 上,包含:

電路的計算可以用一系列約束(constraints)來描述。

定義 1.1.2(R1CS 約束):

Rank-1 Constraint System 是最常見的約束系統格式。每個約束是以下形式的方程:

$$(a1 \cdot q1 + a2 \cdot q2 + \ldots + an \cdot qn) \cdot (b1 \cdot q1 + b2 \cdot q2 + \ldots + bn \cdot qn) = (c1 \cdot q1 + c2 \cdot q2 + \ldots + cn \cdot qn)$$

其中 $qi$ 是 witness 變量,$ai, bi, ci$ 是線性組合係數。

PLONK 的創新點:

PLONK 採用「排列約束」取代傳統 R1CS 的乘法約束,實現了:

1.2 PLONK 約束系統的形式化定義

定義 1.2.1(PLONK 約束):

PLONK 電路包含三種約束:

1. 乘法約束(Multiplication Constraint):

$$qL \cdot ai + qR \cdot bi + qO \cdot ci + qM \cdot ai \cdot bi + qC = 0$$

其中:

2. 拷貝約束(Copy Constraint):

用於強制某些 witness 變量相等,例如將 $wi$ 和 $wj$ 設置為相同的值。

3. 排列約束(Permutation Constraint):

確保某些 witness 排列後滿足特定關係。

定義 1.2.2(PLONK 門):

┌─────────────────────────────────────────────────────────────┐
│                    PLONK 門結構                              │
├─────────────────────────────────────────────────────────────┤
│                                                               │
│  每個 PLONK 門連接三條線:                                    │
│                                                               │
│        left wire ──►│         │◄── right wire               │
│                     │  GATE   │                             │
│                     │         │                             │
│        output ─────►│         │◄── constant (optional)      │
│                                                               │
│  約束方程:                                                   │
│  q_L·a + q_R·b + q_O·c + q_M·a·b + q_C = 0                  │
│                                                               │
│  門類型通過係數配置:                                          │
│                                                               │
│  ┌────────────────┬────────────────────────────────────┐   │
│  │ 門類型         │ 係數配置                             │   │
│  ├────────────────┼────────────────────────────────────┤   │
│  │ 加法門         │ q_M = 0, q_O = 1                   │   │
│  │ 乘法門         │ q_L = q_R = 0, q_M = 1             │   │
│  │ 複製門         │ q_L = 1, q_O = -1, 其他 = 0        │   │
│  │ 常數門         │ q_C = constant                     │   │
│  └────────────────┴────────────────────────────────────┘   │
│                                                               │
└─────────────────────────────────────────────────────────────┘

1.3 約束推導:從電路到多項式

步驟 1:將電路映射為約束

假設我們要驗證以下計算:

電路佈局如下:

Wire:    w₁   w₂   w₃   w₄   w₅
         │    │    │    │    │
         ▼    ▼    ▼    ▼    ▼
Gate 1:  +    │    │    │    │     // w₃ = w₁ + w₂
         │    │    │    │    │
         ▼    ▼    ▼    ▼    ▼
Gate 2:  ×    │    │    │    │     // w₅ = w₃ × w₁
              ▼    ▼    ▼    ▼

步驟 2:編寫門約束

對於 Gate 1(加法門):

$$a1 + a2 - a3 = 0 \Rightarrow qL = 1, qR = 1, qO = -1, qM = 0, qC = 0$$

對於 Gate 2(乘法門):

$$a3 \cdot a1 - a5 = 0 \Rightarrow qL = 0, qR = 0, qO = -1, qM = 1, qC = 0$$

步驟 3:將約束多項式化

我們將每個門的約束係數組織成向量:

$$\mathbf{q}L = (1, 0), \mathbf{q}R = (1, 0), \mathbf{q}M = (0, 1), \mathbf{q}O = (-1, -1), \mathbf{q}_C = (0, 0)$$

使用拉格朗日基(Lagrange basis)構造多項式:

$$QL(X) = \sum{i=1}^{n} q{L,i} \cdot Li(X)$$

其中 $Li(X)$ 是拉格朗日基多項式,滿足 $Li(\omega^i) = 1$ 且 $L_i(\omega^j) = 0$($i \neq j$)。

步驟 4:約束多項式

PLONK 的總約束多項式為:

$$P{gate}(X) = QL(X) \cdot A(X) + QR(X) \cdot B(X) + QO(X) \cdot C(X) + QM(X) \cdot A(X) \cdot B(X) + QC(X)$$

約束在所有門位置 $\omega^i$ 上成立當且僅當:

$$P_{gate}(\omega^i) = 0, \forall i \in \{1, 2, \ldots, n\}$$

1.4 排列約束的推導

為什麼需要排列約束?

拷貝約束需要確保某些 wire 具有相同的值。PLONK 使用「排列論證」(Permutation Argument)來高效證明這點。

定義 1.4.1(排列論證):

設有兩個列表 $(a1, a2, \ldots, an)$ 和 $(b1, b2, \ldots, bn)$,我們要證明存在一個排列 $\pi$ 使得 $bi = a{\pi(i)}$。

PLONK 使用「乘積論證」:

$$\prod{i=1}^{n} \frac{X - ai}{X - b_i} = 1$$

當 $X$ 遍歷所有 $n$ 次單位根時成立。

推導過程:

考慮兩個多項式:

$$f(X) = \prod{i=1}^{n} (X - ai)$$

$$g(X) = \prod{i=1}^{n} (X - bi)$$

定義:

$$h(X) = \frac{f(X)}{g(X)} = \prod{i=1}^{n} \frac{X - ai}{X - b_i}$$

當排列成立時,$f(X) = g(X)$,因此 $h(X) = 1$。

但在有限域上直接計算乘積不可行。PLONK 採用「累積和」(Cumulative Sum)技巧:

$$Si = \prod{j=1}^{i} \frac{Zj}{Wj}$$

其中 $Zj$ 和 $Wj$ 是精心構造的值。

PLONK 的具體構造:

定義「副本類別」(Copy Class)標識哪些 wire 應該相等:

σ = (σ₁, σ₂, ..., σ₅ₙ)  // 排列,指定每個 wire 的配對目標

定義「標籤多項式」:

$$S\sigma(X) = \sum{i=1}^{5n} \sigmai \cdot Li(X)$$

約束確保:

$$\prod{i=1}^{n} \frac{(Xi - ai)}{Xi - b_i} = 1$$

其中 $X_i$ 是循環的群元素。

1.5 完整約束系統的數學推導

定理 1.5.1(PLONK 約束系統正確性):

設電路包含 $n$ 個門,witness 向量為 $\mathbf{w} = (w1, w2, \ldots, w_{5n})$,其中每個門使用 5 個 wire(左右輸入、輸出、常數、選擇)。

則以下三個條件等價:

  1. 存在有效 witness $\mathbf{w}$ 使得所有 PLONK 門約束成立
  2. 存在多項式 $A(X), B(X), C(X)$ 使得約束多項式 $P_{gate}(X)$ 在所有評估點為零
  3. 存在排列 $\sigma$ 使得拷貝約束成立

證明概要:

  1. $\Rightarrow$ 2:將 witness 值代入即可構造多項式
  2. $\Rightarrow$ 3:利用多項式恆等定理,若 $P_{gate}(X)$ 在 $n$ 個點為零,則存在公因子 $(X^n - 1)$
  3. $\Rightarrow$ 1:排列確定了 wire 間的相等關係,確保整個電路一致

第二部分:PLONK 信任設置協議

2.1 可更新信任設置的必要性

傳統 zk-SNARK(如 Groth16)需要一個「有毒廢料」(Toxic Waste)—— 一組秘密隨機數 $\tau$。如果攻擊者知道 $\tau$,可以構造假證明。

定義 2.1.1(有毒廢料):

$$g1^\tau, g2^\tau, \ldots, g_t^\tau$$

如果洩露,攻擊者可以:

PLONK 的創新:信任設置可以「更新」

PLONK 採用「Kate 承諾」 scheme,其信任假設是「至少有一個更新者是誠實的」。這意味著:

2.2 Powers of Tau 儀式

定義 2.2.1(Powers of Tau):

Powers of Tau 是 PLONK 的第一階段,提供用於承諾的結構化參考字符串(Structured Reference String, SRS):

$$SRS = ([\tau^0]1, [\tau^1]1, \ldots, [\tau^{2^k-1}]1, [\tau^0]2, [\tau^1]2, \ldots, [\tau^{2^k-1}]2)$$

其中 $[\cdot]1$ 和 $[\cdot]2$ 表示在兩個不同群中的承諾。

MPC 協議:

參與者 i 的貢獻:
1. 選擇隨機值 τᵢ
2. 計算新的 SRS 元素
3. 發布證明表明正確計算
4. 刪除 τᵢ

安全性:
如果攻擊者控制了 n-1 個參與者,
只要第 n 個參與者是誠實的,
整個設置就是安全的。

2.3 PLONK 電路特定設置

定義 2.3.1(電路特定 SRS):

第二階段將 Powers of Tau 轉換為電路特定格式:

$$SRS{circuit} = ([\tau^i \cdot s(\tau)]1, [\tau^i]_2)$$

其中 $s(X)$ 是電路的「selector polynomial」的目標多項式。

選擇多項式結構:

電路的選擇多項式定義了門的類型和連接:

$$QL(X), QR(X), QO(X), QM(X), Q_C(X)$$

這些多項式在設置時就需要確定,決定了電路的規模和類型。


第三部分:Halo2 工程實現深度解析

3.1 Halo2 的核心創新

Halo2 由 Zcash 基金會的 Sean Bowe 設計,是 PLONK 的後續實現,帶來了兩項核心創新:

創新 1:增量可驗證計算(IVC)

允許將大型計算分解為多個步驟,每個步驟可以獨立驗證。

創新 2:無需可信設置的遞歸

通過「女孩」(Daughter)電路實現遞歸驗證,不需要新的信任設置。

3.2 Halo2 電路框架

定義 3.2.1(Halo2 配置):

pub struct Circuit<F: Field> {
    fn configure(meta: &mut ConstraintSystem<F>) -> Config;
    fn synthesize(&self, config: Config, layouter: &mut impl Layouter<F>);
}

Config 包含:

代碼示例:電路配置

use halo2_proofs::{
    circuit::{Layouter, SimpleFloorPlanner, Value},
    plonk::{Circuit, ConstraintSystem, Error},
    poly::Rotation,
};

#[derive(Clone)]
struct MyConfig {
    advice: [Column<Advice>; 3],
    instance: Column<Instance>,
    selector: Selector,
}

impl<F: Field> Circuit<F> for MyCircuit<F> {
    fn configure(meta: &mut ConstraintSystem<F>) -> MyConfig {
        let advice = [0, 1, 2].map(|_| meta.advice_column());
        let instance = meta.instance_column();
        let selector = meta.selector();
        
        // 啟用可 permutation 約束
        for col in &advice {
            meta.enable_equality(*col);
        }
        meta.enable_equality(instance);
        
        MyConfig { advice, instance, selector }
    }
    
    fn synthesize(
        &self, 
        config: MyConfig, 
        mut layouter: impl Layouter<F>
    ) -> Result<(), Error> {
        // 放置電路元件
        layouter.assign_region(
            || "main region",
            |mut region| {
                // 約束定義
                region.assign_advice(|| "a", config.advice[0], 0, || Value::known(F::from(1)))?;
                
                // 啟用選擇器
                config.selector.enable(&mut region, 0)?;
                
                Ok(())
            },
        )
    }
}

3.3 約束指定

定義 3.3.1(Gate 約束):

meta.create_gate("multiplication gate", |meta| {
    let a = meta.query_advice(config.advice[0], Rotation::cur());
    let b = meta.query_advice(config.advice[1], Rotation::cur());
    let c = meta.query_advice(config.advice[2], Rotation::cur());
    let s = meta.query_selector(config.selector, Rotation::cur());
    
    // 約束:a * b = c(當選擇器開啟時)
    vec![("multiplication", s * (a * b - c))]
});

定義 3.3.2(排列約束):

// 拷貝約束:將 advice[0] 與 instance 列拷貝
region.assign_advice_from_instance(
    || "copy from instance", 
    config.instance, 
    0,
    config.advice[0], 
    0
)?;

3.4 遞歸證明驗證

定義 3.4.1(女孩電路):

Halo2 的核心特性是可以將驗證電路本身作為一個普通電路來證明。這稱為「女孩」(Daughter)電路。

結構:

┌─────────────────────────────────────────────────────────────┐
│              遞歸驗證結構                                    │
├─────────────────────────────────────────────────────────────┤
│                                                               │
│  外部電路(Parent)                                          │
│       │                                                      │
│       │ 產生 Proof₀                                         │
│       ▼                                                      │
│  ┌─────────────────────────────────────────────────────┐   │
│  │           女孩電路(Daughter Circuit)                │   │
│  │                                                      │   │
│  │  輸入:Proof₀, 公共輸入                              │   │
│  │  約束:驗證 Proof₀ 的有效性                          │   │
│  │  輸出:Advice columns(驗證結果)                    │   │
│  │                                                      │   │
│  │  產生 Proof₁                                          │   │
│  └─────────────────────────────────────────────────────┘   │
│       │                                                      │
│       ▼                                                      │
│  驗證 Proof₁                                                 │
│                                                               │
└─────────────────────────────────────────────────────────────┘

代碼示例:遞歸驗證

fn verify_proof_in_circuit(
    config: &VerifyingConfig,
    proof: &Proof,
    mut layouter: impl Layouter<F>
) -> Result<(), Error> {
    layouter.assign_region(
        || "verify recursive proof",
        |mut region| {
            // 1. 解碼證明
            let proof_commitments = assign_public_inputs(
                &config, 
                &proof, 
                &mut region
            )?;
            
            // 2. 計算配對檢查
            //    e(A, B) = e(C, D) 的約束形式
            let pair_check = compute_pairing_check(
                &proof_commitments,
                &config.srs_h,
                &mut region
            )?;
            
            // 3. 約束:pair_check 必須為 1
            //    (pair_check - 1) = 0
            region.assign_fixed(
                || "constant one",
                config.constant,
                0,
                || Value::known(F::one())
            )?;
            
            Ok(())
        },
    )
}

第四部分:實際電路設計案例

4.1 案例:MiMC 哈希電路

MiMC 是一個專為零知識證明優化的哈希函數。

MiMC 定義:

$$f(x) = x^n + c \quad \text{mod } p$$

其中 $n = 5$(exponent),$c$ 是輪常數。

PLONK 約束實現:

fn mimc_round<F: Field>(meta: &mut ConstraintSystem<F>) {
    let x = meta.query_advice(advice[0], Rotation::cur());
    let k = meta.query_fixed(fixed[0], Rotation::cur());
    let c = meta.query_fixed(fixed[1], Rotation::cur());
    let selector = meta.query_selector(selector[0], Rotation::cur());
    
    // 約束:x^5 + k + c = y
    // 分解為:
    // t = x + k
    // t^2 = w1
    // w1^2 = w2
    // w2 * t = w3
    // w3^2 = w4
    // w4 * w3 = y_sq
    // y_sq * x = y_cube
    // y_cube + c = y
    
    vec![
        ("round constraint", selector * (x.clone() + k + c - y))
    ]
}

4.2 案例:ECDSA 簽名驗證電路

ECDSA 驗證是以太坊 zkRollup 的核心功能。

驗證方程:

$$u1 \cdot G + u2 \cdot Q = (x, y)$$

$$s = k^{-1}(z + r \cdot d) \mod n$$

約束分解:

fn ecdsa_verify<F: Field>(
    meta: &mut ConstraintSystem<F>,
    r: Value<F>,
    s: Value<F>,
    msg_hash: Value<F>,
    pubkey: (Value<F>, Value<F>),
) {
    // 1. 計算 s 的模逆元
    let s_inv = inv_constraint(s);
    
    // 2. 計算 u1 = z * s^(-1) mod n
    let u1 = mul_mod_n(z.clone(), s_inv);
    
    // 3. 計算 u2 = r * s^(-1) mod n
    let u2 = mul_mod_n(r.clone(), s_inv);
    
    // 4. 點加法約束:u1*G + u2*Q
    let p1 = scalar_mul_fixed(G, u1);
    let p2 = scalar_mul_pubkey(pubkey, u2);
    let (rx, ry) = point_add(p1, p2);
    
    // 5. 約束:rx mod n = r
    let r_check = is_equal(rx.clone(), r);
}

第五部分:電路優化技術

5.1 約束優化策略

策略 1:選擇器分解

將複雜門拆分為多個簡單門 + 選擇器:

// 原始:自定義門需要 3 個乘法
// 優化:使用選擇器 + 簡單門
vec![
    ("gate 1", s1 * (a * b - c)),
    ("gate 2", s2 * (a + d - e)),
    ("gate 3", s3 * (f * g - h)),
]
// 總約束數:3 個乘法約束

策略 2:複製約束替代中間變量

// 原始:需要額外的 witness 和約束
let temp = a + b;
let result = temp * c;

// 優化:直接拷貝
// 拷貝約束自動確保相等性
// 減少 1 個 witness 列

5.2 witness 組織優化

列類型選擇:

列類型用途特性
AdviceWitness 值每行不同,可 permutation
Fixed常數/選擇器電路定義時確定
Instance公開輸入每行相同,驗證者提供

優化原則:

// 將常使用的值放在 Fixed 列
meta.enable_constant(|| "constants");

// 將需要拷貝的值放在 Advice 列
for col in advice_columns {
    meta.enable_equality(*col);
}

// 將公開值放在 Instance 列
meta.enable_equality(instance);

5.3 深度優化:查找表

定義 5.3.1(查找表約束):

Halo2 支持「排列查找」(Permutation Lookup),可用於實現查表:

fn configure_lookup<F: Field>(meta: &mut ConstraintSystem<F>) {
    let table = meta.fixed_column();
    let input = meta.advice_column();
    
    // 配置查找表
    meta.lookup("table lookup", |meta| {
        let input_expr = meta.query_advice(input, Rotation::cur());
        let table_expr = meta.query_fixed(table, Rotation::cur());
        
        Box::new(input_expr.into() - table_expr.into())
    });
}

應用:


第六部分:PLONK 與其他系統的比較

6.1 Groth16 vs PLONK

特性Groth16PLONK
信任設置電路特定、一次性通用、可更新
證明大小~200 bytes~400 bytes
驗證時間恆定依賴電路規模
約束效率中等
遞歸支持困難原生支持

6.2 STARKs vs PLONK

特性STARKsPLONK
信任設置無需需要
證明大小大(~100KB)小(~400B)
驗證速度慢(需要大量 hash)快(配對運算)
量子安全否(配對假設)
適用場景簡單計算複雜電路

結論

PLONK 與 Halo2 代表了零知識證明系統的重大進步,其核心創新包括:

  1. 通用且可更新的信任設置:解決了傳統 SNARK 的「有毒廢料」問題
  2. 統一的約束格式:簡化了電路設計和驗證
  3. 原生遞歸支持:Halo2 使得遞歸驗證電路成為可能
  4. 工程化實現:提供了、生產級的 Rust 庫

理解 PLONK 的約束推導過程對於設計高效的零知識電路至關重要。從電路到約束、從約束到多項式、從多項式到承諾——每一步都需要精確的數學推導和工程優化。

隨著 zkEVM、zkSync、StarkNet 等項目的成熟,PLONK/Halo2 將繼續在以太坊的擴容和安全方案中扮演核心角色。


參考文獻

PLONK 原始論文

Halo2 實現

密碼學基礎

實際應用


本網站內容僅供教育與資訊目的,不構成任何投資建議或推薦。

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

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

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