ZK-SNARK 電路設計深度實務:從數學推導到 Circom/Noir 完整實現

零知識證明電路設計是構建高效 ZK 系統的核心技術。本文專注於 ZK-SNARK 電路設計的數學推導與實際實現,涵蓋多項式承諾、KZG 方案、R1CS 約束系統等密碼學基礎,使用 Circom 和 Noir 語言的完整電路範例(範圍證明、Merkle 驗證、隱私轉帳)、電路優化策略與性能基準。我們提供可直接使用的程式碼範例,幫助開發者從理論到實踐全面掌握這項關鍵技術。

ZK-SNARK 電路設計深度實務:從數學推導到 Circom/Noir 完整實現

概述

零知識證明(Zero-Knowledge Proof)在區塊鏈領域的應用已經從理論走向大規模實際部署。要構建高效的 ZK 系統,必須深入理解底層的數學原理與電路設計技巧。本文專注於 ZK-SNARK 電路設計的數學推導、使用 Circom 和 Noir 語言的實際電路實現、以及優化策略,幫助開發者從理論到實踐全面掌握這項關鍵技術。

截至 2026 年第一季度,ZK 電路已經被廣泛應用於 zkRollup(zkSync、StarkNet、Polygon zkEVM)、隱私協議(Aztec、Tornado Cash)、身份驗證(Worldcoin)等場景。理解電路設計對於開發高效、安全的 ZK 應用至關重要。

一、ZK-SNARK 數學基礎深度解析

1.1 多項式理論與承諾

ZK-SNARK 的核心是將計算問題轉化為多項式問題。以下是詳細的數學推導:

多項式承諾基礎:

1. 多項式表示
   P(x) = a₀ + a₁x + a₂x² + ... + aₙxⁿ
   
   其中係數 aᵢ ∈ 𝔽ₚ(有限域)

2. 多項式承諾
   commit(P) = g^{P(s)} ∈ 𝔾₁
   
   其中:
   - g 是生成元
   - s 是秘密評估點(不可知)
   - 需要證明者知道 P(x) 的係數

3. KZG 承諾(KZG Commitment)
   - 基於配對的多項式承諾
   - 承諾大小:僅一個群元素
   - 證明大小:一個群元素
   
   承諾:
   commit(P) = g^{P(s)}
   
   證明:
   proof = g^{Q(s)}
   其中 Q(x) = (P(x) - P(y)) / (x - y),y 是評估點

以下是完整的數學推導:

KZG 承諾驗證推導:

1. 證明者擁有多項式 P(x)
   - 公開:commit(P) = g^{P(s)}
   - 私密:P(x) 的係數

2. 證明者在點 y 評估 P(y)
   - 計算 π = g^{Q(y)},其中 Q(x) = (P(x) - P(y)) / (x - y)
   - 注意:x - y 可以整除 P(x) - P(y),因為 P(y) 是已知值

3. 驗證者檢查:
   e(π, g^{s-y}) = e(commit(P) / g^{P(y)}, g)
   
   推導:
   e(π, g^{s-y}) = e(g^{Q(y)}, g^{s-y})
                  = e(g, g)^{Q(y)(s-y)}
                  
   e(commit(P) / g^{P(y)}, g) = e(g^{P(s) - P(y)}, g)
                                 = e(g, g)^{P(s) - P(y)}
                                 
   兩邊相等當且僅當 Q(y)(s-y) = P(s) - P(y)
   這正是多項式除法的性質

1.2 算術電路到代數執行跟蹤(Algebraic Execution Trace)

將計算轉換為 ZK 電路的第一步是構建代數執行跟蹤:

/**
 * 算術電路表示
 * 將計算表達為門電路的形式
 */

// 電路門類型
enum GateType {
    ADD,      // 加法門
    MUL,      // 乘法門
    CONSTANT, // 常數門
    PUBLIC    // 公開輸入門
}

interface Gate {
    type: GateType;
    inputs: number[];  // 輸入wire索引
    output: number;    // 輸出wire索引
    constant?: bigint; // 常數值(如果是CONSTANT門)
}

interface Wire {
    value: bigint;     // 線的值
    isPublic: boolean; // 是否為公開輸入
}

// 示例:將 z = (x + y) * 2 轉換為電路
function compileExpression(expr: string): Gate[] {
    // 表達式:(x + y) * 2
    
    /*
     * 電路結構:
     * 
     *     x ──┬──> ADD ──> mul.const(2) ──> z
     *         │                    ↑
     *     y ──┘                    │
     *                               
     * wires:
     * 0: x (公開輸入)
     * 1: y (公開輸入)
     * 2: x + y (ADD輸出)
     * 3: 2 (常數)
     * 4: (x + y) * 2 (MUL輸出)
     * 5: z (公開輸出)
     */
    
    return [
        { type: GateType.PUBLIC, inputs: [0], output: 0 },  // x
        { type: GateType.PUBLIC, inputs: [1], output: 1 },  // y
        { type: GateType.ADD, inputs: [0, 1], output: 2 },  // x + y
        { type: GateType.CONSTANT, inputs: [], output: 3, constant: 2n }, // 常數 2
        { type: GateType.MUL, inputs: [2, 3], output: 4 },  // (x + y) * 2
        { type: GateType.PUBLIC, inputs: [4], output: 5 },  // z
    ];
}

1.3 約束系統(R1CS 與 Plonkish)

約束系統是描述電路邏輯的核心:

R1CS(Rank-1 Constraint System):

1. 約束形式
   (a · w) * (b · w) = c · w
   
   其中:
   - w 是所有wire的值向量
   - a, b, c 是係數向量
   
2. 示例:z = x * y
   
   wire分配:
   w = [one, x, y, z, ...]
   
   約束:
   a = [0, 1, 0, 0]  // 選擇 x
   b = [0, 0, 1, 0]  // 選擇 y
   c = [0, 0, 0, 1]  // 選擇 z
   
   驗證:(x * 1) * (y * 1) = z * 1
        => x * y = z ✓
/**
 * R1CS 構建器
 */
class R1CSBuilder {
    private constraints: Constraint[] = [];
    private wireIndex: Map<string, number> = new Map();
    private nextWire: number = 0;
    
    // 創建新wire
    createWire(name: string, isPublic: boolean = false): number {
        const index = this.nextWire++;
        this.wireIndex.set(name, index);
        return index;
    }
    
    // 獲取wire索引
    getWire(name: string): number {
        const idx = this.wireIndex.get(name);
        if (idx === undefined) {
            throw new Error(`Wire ${name} not found`);
        }
        return idx;
    }
    
    // 添加乘法約束:a * b = c
    addMulConstraint(a: WireRef, b: WireRef, c: WireRef): void {
        // (a * 1) * (b * 1) = (c * 1)
        const constraint: Constraint = {
            a: this.toVector(a),
            b: this.toVector(b),
            c: this.toVector(c)
        };
        this.constraints.push(constraint);
    }
    
    // 添加加法約束:a + b = c
    addAddConstraint(a: WireRef, b: WireRef, c: WireRef): void {
        // (a * 1 + b * 1) * 1 = (c * 1)
        const constraint: Constraint = {
            a: this.addVectors(this.toVector(a), this.toVector(b)),
            b: this.oneVector(),
            c: this.toVector(c)
        };
        this.constraints.push(constraint);
    }
    
    // 添加等式約束:a = b
    addEqualityConstraint(a: WireRef, b: WireRef): void {
        // (a * 1) * 1 = (b * 1)
        const constraint: Constraint = {
            a: this.toVector(a),
            b: this.oneVector(),
            c: this.toVector(b)
        };
        this.constraints.push(constraint);
    }
    
    // 轉換為 R1CS 矩陣
    toMatrix(): R1CSMatrix {
        return {
            A: this.constraints.map(c => c.a),
            B: this.constraints.map(c => c.b),
            C: this.constraints.map(c => c.c)
        };
    }
}

二、Circom 電路設計實務

2.1 Circom 基礎語法

// SPDX-License-Identifier: MIT
pragma circom 2.0.0;

/**
 * 基礎門電路示例
 */

// 信號定義
// input: 公開或私有輸入信號
// output: 輸出信號
// signal: 中間信號

template Multiplier() {
    // 宣告輸入信號
    signal input a;
    signal input b;
    
    // 宣告輸出信號
    signal output c;
    
    // 約束:c = a * b
    c <== a * b;
    
    // 驗證約束(可選,但推薦)
    c === a * b;
}

// 模板使用示例
template Main() {
    signal input x;
    signal input y;
    signal output z;
    
    // 使用 Multiplier 模板
    component mult = Multiplier();
    mult.a <== x;
    mult.b <== y;
    z <== mult.c;
}

2.2 完整電路實現:範圍證明(Range Proof)

範圍證明是 ZK 應用中最常見的電路之一:

// SPDX-License-Identifier: MIT
pragma circom 2.0.0;

/**
 * 範圍證明電路
 * 證明值 a 在範圍 [0, 2^n) 內,但不透露具體值
 */

template RangeProof(n) {
    // n 是位元數
    
    // 輸入
    signal input value;        // 要證明的值
    signal input commitment;   // 值的承諾
    signal input randomizer;  // 隨機盲因子
    
    // 輸出
    signal output lower;
    signal output upper;
    
    // 約束:commitment = value + randomizer * 2^n
    // 這保證了 commitment 隱藏了 value
    commitment <== value + randomizer * (1 << n);
    
    // 約束:value 在範圍內
    // 通過確保 value * (value - 1) = 0 來保證 value 是 0 或 1
    // 這是基本思想,但實際實現需要更複雜的電路
    
    // 更高效的方法:位元分解 + 範圍檢查
    component bitDecomposition = Num2Bits(n);
    bitDecomposition.in <== value;
    
    // 輸出下界和上界
    lower <== 0;
    upper <== (1 << n) - 1;
}

/**
 * 更高效的範圍證明(使用 Poseidon 哈希)
 */
template EfficientRangeProof(n, levels) {
    // n: 位元數
    // levels: 哈希樹深度
    
    signal input value;
    signal input secret;
    signal input path[levels];
    signal input indices[levels];
    
    // 計算承諾
    component hasher = Poseidon(2);
    hasher.inputs[0] <== value;
    hasher.inputs[1] <== secret;
    
    signal commitment <== hasher.out;
    
    // 驗證路徑
    signal currentHash <== commitment;
    
    for (var i = 0; i < levels; i++) {
        component leafHash = Poseidon(2);
        leafHash.inputs[0] <== path[i];
        leafHash.inputs[1] <== indices[i];
        
        // 根據索引決定左右順序
        signal left;
        signal right;
        
        // 選擇邏輯
        left <== indices[i] == 0 ? currentHash : leafHash.out;
        right <== indices[i] == 0 ? leafHash.out : currentHash;
        
        // 計算父節點
        component parentHash = Poseidon(2);
        parentHash.inputs[0] <== left;
        parentHash.inputs[1] <== right;
        
        currentHash <== parentHash.out;
    }
    
    // 約束:value 在範圍內
    // 使用二次約束檢查
    value * (value - 1) === 0; // 這對大值不正確
    
    // 正確方法:確保每個位元是 0 或 1
    // 然後檢查總和小於 2^n
}

/**
 * 完整的安全轉帳範圍證明
 */
template SecureTransferRangeProof() {
    // 金額範圍:0 到 2^64 - 1
    var AMOUNT_BITS = 64;
    
    signal input amount;
    signal input amountBlinding;
    signal input senderPrivateKey;
    signal input senderPublicKeyHash;
    
    // 輸出公開承諾
    signal output amountCommitment;
    
    // 1. 金額承諾
    // commitment = Poseidon(amount, blinding)
    component amountCommit = Poseidon(2);
    amountCommit.inputs[0] <== amount;
    amountCommit.inputs[1] <== amountBlinding;
    amountCommitment <== amountCommit.out;
    
    // 2. 金額範圍證明
    component rangeCheck = RangeProof(AMOUNT_BITS);
    rangeCheck.value <== amount;
    rangeCheck.commitment <== amountCommitment;
    rangeCheck.randomizer <== amountBlinding;
    
    // 3. 發送者身份驗證
    component senderCheck = Poseidon(1);
    senderCheck.inputs[0] <== senderPrivateKey;
    
    // 約束:公鑰雜湊匹配
    senderCheck.out === senderPublicKeyHash;
    
    // 4. 金額非負
    amount === rangeCheck.lower + 0;
}

2.3 完整電路實現:Merkle 樹驗證

// SPDX-License-Identifier: MIT
pragma circom 2.0.0;

/**
 * Merkle 樹驗證電路
 * 證明某個葉節點存在於 Merkle 樹中
 */

template MerkleTreeChecker(levels) {
    // levels: 樹的深度
    
    // 公開輸入
    signal input leaf;
    signal input root;
    signal input pathElements[levels];
    signal input pathIndices[levels];
    
    // 臨時變數
    signal computedHash <== leaf;
    
    // 逐層計算
    for (var i = 0; i < levels; i++) {
        // 選擇左或右
        signal left;
        signal right;
        
        // 如果 pathIndices[i] = 0,則左=computedHash,右=pathElements[i]
        // 如果 pathIndices[i] = 1,則左=pathElements[i],右=computedHash
        
        // 使用選擇器電路
        component selectors[2];
        selectors[0] = Multiplier(); // 當 index = 0 時選擇
        selectors[1] = Multiplier(); // 當 index = 1 時選擇
        
        // 選擇 left
        left <== computedHash * (1 - pathIndices[i]) + pathElements[i] * pathIndices[i];
        
        // 選擇 right  
        right <== computedHash * pathIndices[i] + pathElements[i] * (1 - pathIndices[i]);
        
        // 計算父節點
        component hasher = Poseidon(2);
        hasher.inputs[0] <== left;
        hasher.inputs[1] <== right;
        
        computedHash <== hasher.out;
    }
    
    // 約束:計算的根等於輸入的根
    root === computedHash;
}

/**
 * 多葉節點 Merkle 證明
 */
template MultiMerkleChecker(levels, numLeaves) {
    signal input leaves[numLeaves];
    signal input root;
    signal input paths[numLeaves][levels];
    signal input indices[numLeaves][levels];
    
    // 驗證每個葉節點
    component checkers[numLeaves];
    
    for (var i = 0; i < numLeaves; i++) {
        checkers[i] = MerkleTreeChecker(levels);
        checkers[i].leaf <== leaves[i];
        
        for (var j = 0; j < levels; j++) {
            checkers[i].pathElements[j] <== paths[i][j];
            checkers[i].pathIndices[j] <== indices[i][j];
        }
    }
    
    // 約束:所有根相等(應為同一棵樹)
    for (var i = 1; i < numLeaves; i++) {
        checkers[0].root === checkers[i].root;
    }
    
    // 最終根約束
    root === checkers[0].root;
}

2.4 完整電路實現:隱私轉帳

// SPDX-License-Identifier: MIT
pragma circom 2.0.0;

/**
 * 隱私轉帳電路
 * 類似於 Tornado Cash 的設計
 */

template PrivateTransfer(levels) {
    // Merkle 樹深度
    var TREE_LEVELS = levels;
    
    // ============ 公開輸入 ============
    signal input root;
    signal input nullifierHash;
    signal input recipient;
    signal input fee;
    signal input refund;
    
    // ============ 私有輸入 ============
    // 存款承諾
    signal input commitment;
    signal input secret;
    signal input nullifier;
    
    // Merkle 證明
    signal input merklePathElements[TREE_LEVELS];
    signal input merklePathIndices[TREE_LEVELS];
    
    // ============ 約束 ============
    
    // 1. 承諾正確性
    // commitment = Poseidon(secret, nullifier)
    component commitmentHasher = Poseidon(2);
    commitmentHasher.inputs[0] <== secret;
    commitmentHasher.inputs[1] <== nullifier;
    commitmentHasher.out === commitment;
    
    // 2. Nullifier 雜湊正確性
    // nullifierHash = Poseidon(nullifier)
    component nullifierHasher = Poseidon(1);
    nullifierHasher.inputs[0] <== nullifier;
    nullifierHasher.out === nullifierHash;
    
    // 3. Merkle 根驗證
    component merkleChecker = MerkleTreeChecker(TREE_LEVELS);
    merkleChecker.leaf <== commitment;
    merkleChecker.root <== root;
    
    for (var i = 0; i < TREE_LEVELS; i++) {
        merkleChecker.pathElements[i] <== merklePathElements[i];
        merkleChecker.pathIndices[i] <== merklePathIndices[i];
    }
    
    // 4. 金額守恆(公開部分)
    // fee + refund 應該從某處扣除(這裡簡化處理)
    // 實際實現中需要驗證提款金額
    
    // 5. 接收者有效性
    // recipient 應該是有效的以太坊地址
    recipient === recipient; // 恆真約束,實際需更強約束
}

三、Noir 電路設計

3.1 Noir 語法基礎

// Noir 電路示例

// 1. 簡單函數
fn main(x: Field, y: Field) -> Field {
    x + y
}

// 2. 帶約束的函數
fn multiply(x: Field, y: Field) -> Field {
    let z = x * y;
    constrain z == x * y;  // 顯式約束
    z
}

// 3. 數組操作
fn sum_array(arr: [Field; 5]) -> Field {
    let mut sum = 0;
    for i in 0..5 {
        sum = sum + arr[i];
    }
    sum
}

// 4. 結構體定義
struct Point {
    x: Field,
    y: Field,
}

fn point_add(p1: Point, p2: Point) -> Point {
    Point {
        x: p1.x + p2.x,
        y: p1.y + p2.y,
    }
}

3.2 完整 Noir 實現:zkSNARK 驗證

// Noir 實現的範圍證明

fn check_bits(num: Field, bits: u32) {
    // 確保 num 在 2^bits 範圍內
    
    let limit = 1 << bits;
    constrain num < limit;
}

// 更複雜的範圍證明:使用二進制表示
fn check_bits_binary(num: Field, bits: u32) {
    // 驗證 num 的二進制表示
    
    let mut temp = num;
    let mut sum = 0;
    
    for i in 0..bits {
        let bit = temp & 1;
        constrain bit * (bit - 1) == 0;  // bit 必須是 0 或 1
        sum = sum + (bit << i);
        temp = temp >> 1;
    }
    
    constrain sum == num;
}

// 承諾驗證
fn verify_commitment(secret: Field, blinding: Field, commitment: Field) {
    // 簡單的 Pedersen 風格承諾
    // commitment = secret + blinding * G (在 Noir 中模擬)
    
    let computed = secret + blinding * 2^128;
    constrain computed == commitment;
}

// 完整隱私轉帳
fn private_transfer(
    // 公開輸入
    root: Field,
    nullifier_hash: Field,
    recipient: Field,
    fee: Field,
    
    // 私有輸入
    secret: Field,
    nullifier: Field,
    commitment: Field,
    path_elements: [Field; 16],
    path_indices: [Field; 16]
) {
    // 1. 驗證承諾
    let computed_commitment = secret + nullifier * 2^128;
    constrain computed_commitment == commitment;
    
    // 2. 驗證 nullifier hash
    let computed_nullifier_hash = nullifier * 3;  // 簡化版本
    constrain computed_nullifier_hash == nullifier_hash;
    
    // 3. 驗證 Merkle 證明(簡化版)
    let mut current_hash = commitment;
    
    for i in 0..16 {
        let left = (1 - path_indices[i]) * current_hash + path_elements[i] * path_indices[i];
        let right = path_elements[i] * (1 - path_indices[i]) + current_hash * path_indices[i];
        current_hash = left + right;  // 簡化版
    }
    
    constrain current_hash == root;
}

3.3 Noir 與以太坊整合

/**
 * Noir 電路編譯和部署
 */
import { compile, Noir } from '@noir-lang/noir_js';
import { ethers } from 'ethers';

class NoirCircuit {
    private noir: Noir;
    private abi: any;
    
    // 1. 編譯電路
    async compile(circuitPath: string) {
        const compiled = await compile(circuitPath);
        this.abi = compiled.program.abi;
        this.noir = new Noir(compiled.program);
    }
    
    // 2. 生成證明
    async generateProof(inputs: any) {
        const { witness } = await this.noir.execute(inputs);
        const proof = await this.noir.generateProof(witness);
        return proof;
    }
    
    // 3. 驗證證明(本地)
    async verifyProof(proof: any) {
        return await this.noir.verifyProof(proof);
    }
    
    // 4. 部署驗證合約
    async deployVerifier(network: string) {
        // 獲取驗證合約 ABI
        const verifierABI = this.abiVerifier;
        
        // 部署合約
        const factory = new ethers.ContractFactory(
            verifierABI.bytecode,
            verifierABI.abi,
            this.signer
        );
        
        return await factory.deploy();
    }
}

// 使用示例
async function main() {
    const circuit = new NoirCircuit();
    
    // 編譯
    await circuit.compile('./circuits/range_proof/src/main.nr');
    
    // 準備輸入
    const inputs = {
        value: 42,
        blinding: 12345678901234567890n,
        secret: 98765432109876543210n
    };
    
    // 生成證明
    const proof = await circuit.generateProof(inputs);
    console.log('Proof generated:', proof);
    
    // 驗證
    const isValid = await circuit.verifyProof(proof);
    console.log('Valid:', isValid);
}

四、電路優化策略

4.1 約束數量優化

// 優化前:約束數量過多
template UnoptimizedMultiplication(n) {
    signal input a;
    signal input b;
    signal output c;
    
    // 每個乘法需要一個約束
    // 但這裡有很多不必要的約束
    
    // 方法1:使用多個約束
    signal temp1 <== a * b;
    signal temp2 <== temp1 * 1;
    c <== temp2 * 1;
}

// 優化後
template OptimizedMultiplication(n) {
    signal input a;
    signal input b;
    signal output c;
    
    // 只需要一個約束
    c <== a * b;
}

4.2 複雜度優化技巧

/**
 * 電路複雜度優化策略
 */

// 1. 預先計算常量
class OptimizedCircuit {
    // 預先計算 2^n 值
    private precomputedPowers: bigint[] = [];
    
    constructor(private n: number) {
        for (let i = 0; i <= n; i++) {
            this.precomputedPowers.push(2n ** BigInt(i));
        }
    }
    
    // 2. 使用遞迴而非循環
    // 循環:在電路中需要展開,約束數量 = 循環次數
    // 遞迴:每次遞迴只需一次約束
    
    // 3. 選擇適當的哈希函數
    // Poseidon: 最電路友好,但較慢
    // SHA256: 需要較多門
    // Pedersen: 平衡選擇
}

4.3 信任設置優化

/**
 * 信任設置優化的 PLONK 電路
 */

interface TrustedSetup {
    provingKey: any;
    verificationKey: any;
    tau: bigint;  // 有毒廢物,必須銷毀
}

// 通用可信設置
class UniversalSetup {
    // 為最大電路大小生成一次
    private maxDegree: number;
    private powersOfTau: any[];
    
    async generate(maxDegree: number): Promise<any> {
        this.maxDegree = maxDegree;
        
        // 生成隨機 τ
        const tau = this.generateRandomScalar();
        
        // 計算 powers: [1, τ, τ², ..., τ^d]
        this.powersOfTau = [];
        let current = 1n;
        for (let i = 0; i <= maxDegree; i++) {
            this.powersOfTau.push(current);
            current = current * tau % this.prime;
        }
        
        return {
            powersOfTau: this.powersOfTau,
            G1: this.powersOfTau.map(t => g1 * t),
            G2: this.powersOfTau.map(t => g2 * t)
        };
    }
    
    // 為特定電路生成驗證金鑰
    generateVerificationKey(circuitDegree: number, setup: any): VerificationKey {
        return {
            commitment: setup.powersOfTau[circuitDegree] * g1,
            // ...
        };
    }
}

五、實際應用案例

5.1 Tornado Cash 電路分析

Tornado Cash 電路架構:

1. 存款電路
   - 輸入:秘密值、nullifier
   - 輸出:承諾、nullifier hash
   - 約束數:約 20,000

2. 提款電路
   - 輸入:Merkle 證明、接收者、費用
   - 約束數:約 40,000
   
3. 安全性
   - 使用 Pedersen 承諾
   - Merkle 樹深度:20
   - 零知識性質依賴於隨機盲因子

5.2 Semaphore 電路設計

// Semaphore 身份證明電路
template Semaphore(levels) {
    // 公開輸入
    signal input root;
    signal input nullifierHash;
    signal input externalNullifier;
    signal input signalHash;
    
    // 私有輸入
    signal input identityCommitment;
    signal input identityPathElements[levels];
    signal input identityPathIndices[levels];
    
    // 驗證 Merkle 證明
    component merkleChecker = MerkleTreeChecker(levels);
    merkleChecker.leaf <== identityCommitment;
    merkleChecker.root <== root;
    
    for (var i = 0; i < levels; i++) {
        merkleChecker.pathElements[i] <== identityPathElements[i];
        merkleChecker.pathIndices[i] <== identityPathIndices[i];
    }
    
    // 計算信號雜湊
    component signalHasher = Poseidon(1);
    signalHasher.inputs[0] <== signalHash;
    
    // 計算最終 nullifier
    // nullifier = hash(identityNullifier, externalNullifier)
    component finalNullifier = Poseidon(2);
    finalNullifier.inputs[0] <== nullifierHash;
    finalNullifier.inputs[1] <== externalNullifier;
    
    // 約束
    // 信號雜湊應該被包含在最終雜湊中(簡化)
    signalHash === signalHasher.out;
}

5.3 電路性能基準

電路性能對比(2026 年第一季度):

| 電路類型 | 約束數 | 證明大小 | 驗證時間 | 適用場景 |
|---------|-------|---------|---------|---------|
| 簡單範圍證明 | 1,000 | 200B | 5ms | 金額驗證 |
| Merkle 驗證 (20層) | 20,000 | 400B | 10ms | 存款/提款 |
| 隱私轉帳 | 50,000 | 800B | 25ms | Tornado Cash |
| zkRollup 區塊驗證 | 200,000 | 10KB | 100ms | 擴容 |
| 完整 EVM 驗證 | 1,000,000 | 50KB | 500ms | zkEVM |

結論

ZK-SNARK 電路設計是一個需要深入理解密碼學、數學和軟體工程的複雜領域。本文詳細介紹了從數學推導到實際電路實現的完整知識體系,包括:

  1. 數學基礎:多項式承諾、KZG 方案、R1CS 約束系統
  2. Circom 實現:範圍證明、Merkle 驗證、隱私轉帳
  3. Noir 語言:語法基礎、實際應用、與以太坊整合
  4. 優化策略:約束數量優化、信任設置優化

掌握這些技術將使開發者能夠構建高效、安全的 ZK 應用,推動隱私保護和區塊鏈擴容技術的進一步發展。

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

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

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