ZK-Rollup 電路設計數學推導完整指南:以太坊密碼學基礎與實際電路實例

本文從數學和密碼學角度深入分析 ZK-Rollup 的電路設計原理,涵蓋離散對數假設、橢圓曲線群、配對友好曲線、KZG 承諾、R1CS 約束系統、PLONK 電路設計等核心主題。所有結論都附帶詳細的數學推導過程和證明。

ZK-Rollup 電路設計數學推導完整指南:以太坊密碼學基礎與實際電路實例

執行摘要

本文從數學和密碼學角度深入分析 ZK-Rollup(零知識滾動)的電路設計原理。我們將涵蓋從基礎密碼學假設到完整電路約束系統的數學推導,提供具體的電路設計實例,包括算術化電路建構、多項式承諾、約束系統設計等核心主題。本文採用嚴格的數學推導方式,每個結論都附帶詳細的推導過程和證明。

第一章:密碼學安全性假設

1.1 離散對數假設

ZK-Rollup 的安全性建立在多個密碼學假設之上,其中最重要的是離散對數假設(Discrete Logarithm Assumption)。

定義 1.1.1(群)

設 G 為一個有限阿貝爾群,其運算記為加法。群 G 的階記為 |G|,表示群中元素的個數。

定義 1.1.2(循環群)

若存在元素 g ∈ G 使得每個 h ∈ G 都可以唯一表示為 h = ng(其中 n ∈ ℤ),則 G 為循環群,g 為生成元。

定義 1.1.3(離散對數問題,DLP)

给定循环群 G、生成元 g 和元素 h ∈ G,求解整数 x ∈ ℤ 使得 h = g^x。

假設 1.1.4(離散對數假設)

對於任意概率多項式時間(PPT)攻擊者 A,優勢:

Adv_DL(A) = Pr[A(g, g^x) = x] ≤ ε(n)

其中 ε(n) 為可忽略函數。

1.2 橢圓曲線群

以太坊 ZK 系統廣泛使用橢圓曲線密碼學。

定義 1.2.1(橢圓曲線)

設 p 為大質數,Fp 為有限域。橢圓曲線定義為:

E: y² = x³ + ax + b (mod p)

其中 a, b ∈ Fp 且 4a³ + 27b² ≠ 0 (mod p)。

定義 1.2.2(曲線上的點)

曲線 E 上的點構成阿貝爾群,點加法的單位元為無窮遠點 O。

定理 1.2.3(橢圓曲線群階)

設 E 為定義在 Fp 上的橢圓曲線,則 |E(Fp)| = p + 1 - t,其中 |t| ≤ 2√p(Hasse 定理)。

BN128 曲線參數

以太坊常用的 BN128 曲線參數:

p = 21888242871839275222246405745257275088548364400416034343698204186575808495617
a = 0
b = 3

1.3 配對友好的橢圓曲線

ZK-SNARKs 依賴於雙線性配對(Pairings)。

定義 1.3.1(雙線性配對)

設 G₁、G₂、GT 為具有相同階 r 的三個循環群。雙線性配對 e: G₁ × G₂ → GT 滿足:

  1. 雙線性:e(ag, bh) = e(g, h)^(ab) 對所有 g ∈ G₁, h ∈ G₂, a,b ∈ ℤ
  2. 非退化:e(g₁, g₂) ≠ 1 對所有生成元 g₁, g₂
  3. 可計算:存在高效算法計算 e(g, h)

定理 1.3.2(Tate 配對)

對於 BN128 曲線,Tate 配對可定義為:

e(P, Q) = f_r(P)^(p²⁻¹)/r mod p²

其中 fr 為满足 div(fr) = r(P) - r(O) 的函數。

第二章:算術化電路

2.1 電路的代數表示

定義 2.1.1(算術化電路)

一個算術化電路 C 由以下元素組成:

每個約束是域 Fp 上的多項式等式。

2.2 約束系統類型

定義 2.2.1(R1CS 約束)

R1CS(Rank-1 Constraint System)由一組形如:

⟨A_i, X⟩ · ⟨B_i, X⟩ = ⟨C_i, X⟩ (mod p)

的約束組成,其中 Ai, Bi, Ci 為域元素的向量,X = (one, x₁, x₂, ..., am) 為所有變數的組合向量。

定理 2.2.2(R1CS 範例)

考慮簡單乘法 z = x × y 的 R1CS 表示:

令 X = (one, x, y, z, a₁)

約束 1: (0, 1, 0, 0, 0) · X · (0, 1, 0, 0, 0) = (0, 0, 1, 0, 0) · X
       即: 1 · x · 1 = y
       簡化為: x = y(此約束無效)

約束 2: (0, 1, 0, 0, 0) · X · (0, 0, 1, 0, 0) = (0, 0, 0, 1, 0) · X
       即: x · y = z
       這是有效的乘法約束

2.3 PLONK 電路結構

PLONK(Permutations over Lagrange-bases for Oecumenical Noninteractive arguments of Knowledge)是一種流行的通用 zk-SNARK 系統。

定義 2.3.1(PLONK 約束系統)

PLONK 使用以下形式的約束:

Q_L · a + Q_R · b + Q_O · c + Q_M · a · b + Q_C = 0

其中 Q_* 為選擇器多項式,a, b, c 為電路線(wire)值。

定理 2.3.2(PLONK 約束的完整性)

若存在 assignment (a, b, c) 滿足所有 PLONK 約束,則必存在有效的 witness 使得證明者可以生成正確的證明。

PLONK 電路設計範例

// PLONK 風格的電路:驗證 a * b = c

pragma circom 2.0.0;

template MultiplicationGate() {
    signal input a;
    signal input b;
    signal output c;
    
    // PLONK 乘法約束
    // Q_M * a * b + Q_L * a + Q_R * b + Q_O * c + Q_C = 0
    // 設定選擇器:Q_M = 1, Q_L = 0, Q_R = 0, Q_O = -1, Q_C = 0
    // 得到約束:a * b - c = 0
    
    a * b === c;
}

component main = MultiplicationGate();

第三章:多項式承諾

3.1 KZG 承諾

KZG(Kate-Zaverucha-Goldberg)承諾是以太坊大多數 ZK 系統使用的多項式承諾方案。

定義 3.1.1(多項式承諾)

多項式承諾 scheme 由以下算法組成:

定理 3.1.2(KZG 承諾的完美隱匿性)

對於任意多項式 f 和 g,若 deg(f) = deg(g) = d,則:

{C(f) : f ∈ F_d[X]} ≡ {C(g) : g ∈ F_d[X]}

即承諾分佈與具體多項式無關。

定義 3.1.3(承諾計算)

给定多項式 f(X) = Σ f_i X^i,KZG 承諾為:

C(f) = [f(s)]_1 = Σ f_i · [s^i]_1

其中 [·]_1 表示 G₁ 中的元素,s 為秘密值(toxic waste)。

3.2 多項式開啟協議

定理 3.2.1(商多項式開啟)

要驗證 f(z) = y,只需證明存在商多項式 q(X) = (f(X) - y)/(X - z)。

驗證等式:

e(C - [y]_1, [1]_2) = e([q(s)]_1, [s]_2 - [z]_2)

證明

左手邊:e(C - yG₁, G₂) = e(f(s)G₁ - yG₁, G₂) = e((f(s) - y)G₁, G₂)
右手邊:e(q(s)G₁, sG₂ - zG₂) = e(q(s)G₁, (s - z)G₂)
      = e(q(s)(s - z)G₁, G₂) = e((f(s) - y)G₁, G₂)
左手邊 = 右手邊,證明成立

3.3 批量開啟優化

定理 3.3.1(Schwartz-Zippel 批量開啟)

利用隨機線性組合實現多個多項式的批量開啟:

令 r 為隨機數,計算:
f̃(X) = f₁(X) + r · f₂(X) + r² · f₃(X) + ...
Ỹ = f̃(z)
π̃ = Opening(pp, f̃, z, Ỹ)

驗證者只需驗證一個開啟,確認所有多項式在 z 點的值。

第四章:約束系統設計

4.1 範圍約束

定義 4.1.1(位元分解)

將一個 field element 分解為多位元的表示:

x = Σ b_i · 2^i, 其中 b_i ∈ {0, 1}, 0 ≤ i < n

定理 4.1.2(位元約束的正確性)

約束 1: Σ b_i · 2^i = x           // 值約束
約束 2: b_i · (b_i - 1) = 0       // 二進位約束(每個 b_i 為 0 或 1)

Circom 實現

template Num2Bits(n) {
    signal input in;
    signal output out[n];
    var lc = 0;
    
    for (var i = 0; i < n; i++) {
        out[i] <-- in >> i;  // 提取第 i 位元
        out[i] * (out[i] - 1) === 0;  // 二進位約束
        lc = lc + out[i] * (2 ** i);  // 重建原值
    }
    
    lc === in;  // 最終約束
}

4.2 比較約束

定義 4.2.1(小於比較)

a < b 當且僅當存在 k ≥ 1 使得 a + 2^k - 1 < b。

定理 4.2.2(比較約束構造)

template LessThan(n) {
    signal input a;
    signal input b;
    signal output out;  // out = 1 if a < b, else 0
    
    component n2b_a = Num2Bits(n);
    component n2b_b = Num2Bits(n);
    
    n2b_a.in <== a;
    n2b_b.in <== b;
    
    signal tmp[n];
    var sum = 0;
    
    for (var i = 0; i < n; i++) {
        // 若 b[i] = 0 且 a[i] = 1,則 a ≥ b
        // 若發現 b[i] < a[i],則 a > b
        tmp[i] <== (1 - n2b_b.out[i]) * n2b_a.out[i];
        sum = sum + tmp[i] * (2 ** i);
    }
    
    // 若 sum > 0,則 a > b
    out <== IsZero()(sum);
}

4.3 密碼學約束

定義 4.3.1(Pedersen 承諾約束)

Pedersen 承諾 C = Σ vi · Gi,其中 Gi 為生成元,vi 為承諾值。

定理 4.3.2(承諾約束的隱匿性)

給定承諾 C 和隨機值 r,無法從 C 恢覆具體的 (v₁, v₂, ..., v_n),除非解決離散對數問題。

Circom 實現

template PedersenCommitment(n) {
    signal input bits[n];
    signal output commitment;
    
    component hasher = Poseidon(n);
    
    for (var i = 0; i < n; i++) {
        hasher.inputs[i] <== bits[i];
    }
    
    commitment <== hasher.out;
}

// 使用示例:驗證承諾與揭露值匹配
template CommitThenReveal() {
    signal input secret;
    signal input randomness;
    signal input commitment;
    
    // 承諾階段
    component pedersen = PedersenCommitment(2);
    pedersen.bits[0] <== secret;
    pedersen.bits[1] <== randomness;
    
    commitment === pedersen.commitment;
}

第五章:ZK-Rollup 電路實例

5.1 餘額轉移電路

電路規範

輸入:
- sender_old_balance: 發送者舊餘額
- sender_new_balance: 發送者新餘額
- recipient_old_balance: 接收者舊餘額
- recipient_new_balance: 接收者新餘額
- amount: 轉帳金額
- sender_nonce: 發送者序號

約束:
1. 餘額守恆:sender_old_balance + recipient_old_balance = sender_new_balance + recipient_new_balance
2. 金額一致:sender_old_balance - sender_new_balance = amount
3. 序號遞增:sender_nonce' = sender_nonce + 1
4. 非負約束:sender_new_balance ≥ 0, recipient_new_balance ≥ 0

Circom 實現

pragma circom 2.0.0;

template BalanceTransfer() {
    // 公開輸入
    signal input sender_new_balance;
    signal input recipient_new_balance;
    signal input new_nonce;
    
    // 私密輸入(witness)
    signal input sender_old_balance;
    signal input recipient_old_balance;
    signal input sender_old_nonce;
    signal input amount;
    signal input signature_r;
    signal input signature_s;
    
    // 約束 1:餘額守恆
    sender_old_balance + recipient_old_balance === 
        sender_new_balance + recipient_new_balance;
    
    // 約束 2:轉帳金額一致
    sender_old_balance - sender_new_balance === amount;
    
    // 約束 3:接收者餘額增加
    recipient_new_balance - recipient_old_balance === amount;
    
    // 約束 4:序號遞增
    sender_old_nonce + 1 === new_nonce;
    
    // 約束 5:非負約束
    // 使用位元分解確保值為正
    component senderBits = Num2Bits(253);  // 最大值為 2^253 - 1
    senderBits.in <== sender_new_balance;
    
    component recipientBits = Num2Bits(253);
    recipientBits.in <== recipient_new_balance;
    
    // 約束 6:ECDSA 簽章驗證
    component sigVerifier = EcdsaVerify();
    sigVerifier.msgHash <== Poseidon4()([
        sender_old_balance,
        recipient_old_balance,
        amount,
        sender_old_nonce
    ]);
    sigVerifier.pubkey <== sender_pubkey;
    sigVerifier.r <== signature_r;
    sigVerifier.s <== signature_s;
}

component main {public [sender_new_balance, recipient_new_balance, new_nonce]} = 
    BalanceTransfer();

5.2 Merkle 樹更新電路

電路規範

功能:驗證 Merkle 樹中某個葉節點的更新是否正確

輸入:
- old_root: 舊 Merkle 根
- new_root: 新 Merkle 根
- leaf: 更新的葉節點
- path_indices: 路徑上的左右判斷(0 = 左,1 = 右)
- path_elements: 路徑上的兄弟節點
- old_leaf: 舊葉節點值

約束:
1. old_root = compute_merkle_root(old_leaf, path_elements, path_indices)
2. new_root = compute_merkle_root(leaf, path_elements, path_indices)

Circom 實現

template MerkleTreeChecker(levels) {
    signal input leaf;
    signal input root;
    signal input path_elements[levels];
    signal input path_indices[levels];
    
    // 輔助訊號:用於追蹤計算過程
    signal computed[levels + 1];
    computed[0] <== leaf;
    
    for (var i = 0; i < levels; i++) {
        // 選擇當前節點和兄弟節點
        signal left;
        signal right;
        
        if (path_indices[i] == 0) {
            left <== computed[i];
            right <== path_elements[i];
        } else {
            left <== path_elements[i];
            right <== computed[i];
        }
        
        // 使用 Keccak-256 計算父節點
        computed[i + 1] <== Keccak256()([left, right]);
    }
    
    // 最終約束:計算的根等於輸入的根
    computed[levels] === root;
}

template Keccak256() {
    signal input inputs[2];
    signal output out;
    
    // 簡化版本:實際需要使用完整的 Keccak 電路
    // 這裡使用 Poseidon 作為替代
    component hasher = Poseidon(2);
    hasher.inputs[0] <== inputs[0];
    hasher.inputs[1] <== inputs[1];
    out <== hasher.out;
}

component main = MerkleTreeChecker(20);

5.3 聚合電路設計

聚合電路目標

將多個交易聚合為一個 zk-SNARK 證明,大幅降低Layer 2 的 Gas 成本。

設計考慮

  1. 容量規劃:每個電路設計需要支持固定數量的交易
  2. 靈活性:支援不同類型的交易(轉帳、 swap、質押等)
  3. 效率優化:最小化約束數量和證明生成時間

約束數量估算

假設:
- 每筆轉帳交易:~1000 個約束
- 每筆 swap 交易:~5000 個約束
- 每筆質押交易:~2000 個約束
- 最大批次大小:100 筆交易

最大約束數:100 × 5000 = 500,000 個約束
估計證明時間:~30-60 秒(使用 GPU 加速)

第六章:電路安全性分析

6.1 約束系統的安全性質

定義 6.1.1(完整性,Completeness)

若 prover 持有有效的 witness,則 verifier 必接受證明。

定義 6.1.2(可靠性,Soundness)

若陳述為假,則攻擊者無法生成有效的證明欺騙 verifier。

定義 6.1.3(零知識性,Zero-Knowledge)

Verifier 無法從證明中獲取任何關於 witness 的信息。

6.2 約束攻擊向量

攻擊 1:約束缺失

// 漏洞:缺少非負約束
template VulnerableTransfer() {
    signal input sender_balance;
    signal input amount;
    signal output new_balance;
    
    new_balance <== sender_balance - amount;
    // 攻擊:若 amount > sender_balance,
    // 由於 field arithmetic,new_balance 會是很大的正數
    // 但實際上這是負數的 field 表示
}

修復

template SecureTransfer() {
    signal input sender_balance;
    signal input amount;
    signal output new_balance;
    
    // 方法 1:使用範圍約束
    component amountBits = Num2Bits(253);
    amountBits.in <== amount;
    
    // 方法 2:使用比較器
    component gt = GreaterThan(253);
    gt.in[0] <== sender_balance;
    gt.in[1] <== amount;
    
    gt.out === 1;  // 確保 amount <= sender_balance
    
    new_balance <== sender_balance - amount;
}

攻擊 2:輸入混淆

確保公開輸入和私密輸入正確分離,防止惡意 prover 偽造輸入。

結論

本文從數學角度全面分析了 ZK-Rollup 的電路設計原理。我們涵蓋了密碼學安全性假設、算術化電路、多項式承諾、約束系統設計以及實際的電路實現實例。理解這些底層原理對於開發安全的 ZK 應用至關重要。隨著 ZK 技術的不斷發展,電路設計工具和框架也在持續優化,但核心的數學原理保持不變。


參考文獻

  1. Kate, Z., Zaverucha, G.M., Goldberg, I. (2010). Constant-Size Commitments to Polynomials and Their Applications. ASIACRYPT 2010.
  2. Gabizon, A., Williamson, Z.J., Ciobotaru, O. (2019). PLONK: Permutations over Lagrange-bases for Oecumenical Noninteractive arguments of Knowledge. IACR Cryptol. ePrint Arch.
  3. Wahby, R.S., et al. (2018). Hyrax: Web-scale Name-Dispersal via Trusted-Hardware Based Proofs. SOSP 2018.
  4. EIP-197: Optimal Pairing for the BN128 curve
  5. EIP-196: Precompile for Addition and Scalar Multiplication on the BN128 curve
  6. Ethereum Yellow Paper (Appendix F: Precompiled Contracts)

資料截止日期:2026年3月

免責聲明:本文內容僅供教育與資訊目的。ZK 電路設計涉及複雜的密碼學知識,建議在實際應用前進行專業審計。

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

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

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