返回 Expert 笔记
Expert Day 267

论文精读 #4 — Halo / Halo2 (Recursion + IPA)

精读 Bowe-Grigg-Hopwood "Halo: Recursive Proof Composition without a Trusted Setup" (ePrint 2019/1021) + Halo2 book

2027-01-23
Phase 4 - 密码学工程 (Day 264-267 论文精读系列)
ZKHaloHalo2IPArecursioncycle-of-curvestransparent

日期: 2027-01-23 方向: 零知识证明 / 论文精读 阶段: Phase 4 - 密码学工程 (Day 264-267 论文精读系列) 标签: #ZK #Halo #Halo2 #IPA #recursion #cycle-of-curves #transparent


今日目标

类型内容
学习精读 Bowe-Grigg-Hopwood "Halo: Recursive Proof Composition without a Trusted Setup" (ePrint 2019/1021) + Halo2 book
实操在白板上推 IPA 折叠 + cycle of curves + amortization 三大技巧
产出halo-paper-reading.md — 完整 Halo/Halo2 流程 + zkSync/Scroll/Mina 部署对比

〇、为什么精读 Halo?

Halo 是 SNARK 演化中最具创造性的论文之一:它同时解决了两个 10 年悬而未决的问题:

  1. 如何做 SNARK recursion 但不需要 trusted setup?
  2. 如何让 IPA-based polynomial commitment 高效到能撑大电路?

精读到位的指标:

  • 不看论文能解释 cycle of curves 的精确意义。
  • 能在白板上推 IPA 一轮折叠(与 Bulletproofs 类似)。
  • 能讲 amortization:把 verifier 工作"延后"到下一个 proof 中。
  • 能说 Halo2 与原 Halo 论文的差异(Plonkish + 列设计)。

一、论文基本信息

1.1 Halo 主论文

字段内容
标题Halo: Recursive Proof Composition without a Trusted Setup
作者Sean Bowe, Jack Grigg, Daira Hopwood
隶属Electric Coin Company (Zcash)
首发ePrint 2019/1021,2019-09-10
引用截至 2026 约 750+
后续Halo2 (2020 实现 + book), zkSync Boojum (Halo2 fork), Scroll (Halo2 fork)

1.2 Halo2 Book

字段内容
标题The halo2 Book
维护Zcash + Privacy Scaling Explorations
主页https://zcash.github.io/halo2/
特点不是单篇论文,是工程实现文档 + Plonkish 算术化重构

Halo 原论文是"理论框架";Halo2 是"工业实现"。两者必须放一起精读。


二、历史定位

2.1 SNARK 演化中 Halo 的位置

              Bulletproofs'17 (IPA, no trusted setup, but no recursion)
                        │
                        │
             Halo'19 (今日) — IPA + cycle of curves + amortization → recursion
                        │
                        ├──► Halo2'20 (Zcash 实现, Plonkish 改造)
                        │           │
                        │           ├──► zkSync Boojum (重写 IPA → KZG-IPA mix)
                        │           ├──► Scroll Halo2 (优化 prover)
                        │           ├──► PSE Halo2 (Privacy Scaling Explorations 维护)
                        │           └──► Axiom (大规模 historical query)
                        │
                        └──► 影响 Plonky2 / Plonky3 (FRI + recursion 借鉴)

2.2 Recursion 的历史

  • 理论: BCCT'13 (Bitansky-Chiesa-Chong-Tromer) 首次定义 recursion proof composition
  • 工程: Coda Protocol (后来的 Mina) 2018 用 BCCT 实现 22KB 区块链,但需要 trusted setup
  • 突破: Halo 2019 — 第一次实现 transparent recursion

2.3 为什么 2020-2026 Halo2 大爆发?

  1. Zcash NU5 (2022):Zcash 升级用 Halo2 替代 Sapling 的 Groth16
  2. Privacy Scaling Explorations (PSE) 维护开源 Halo2,吸引大量项目使用
  3. zkSync / Scroll 都从 Halo2 fork 起步
  4. recursion friendly:light client、zkRollup proof aggregation 都需要 recursion

三、核心贡献

Halo 用三个互补的技术,第一次实现了"transparent recursion":

  1. Cycle of curves (Pasta = Pallas + Vesta):scalar field of one curve = base field of another,让 recursion 在两条 curve 间交替进行
  2. IPA polynomial commitment:仅依赖 ECDLP,无 trusted setup
  3. Amortization:把 IPA verifier 的 $O(N)$ 工作"延后"到下一个 recursive proof 中,使总验证时间是 $O(\log N)$

四、逐节精读

4.1 Halo 论文 — Section 1: Introduction

Halo Intro 抛出两个 motivating problem:

"We show how to perform recursive proof composition without a trusted setup using nested amortization and cycles of elliptic curves."

并解释三大动机:

  • Mina/Coda 的 22KB 区块链需要 recursion
  • 但传统 recursion 方案(BCCT'13, Coda 用 Pinocchio + cycle of pairing-friendly curves)需要 trusted setup
  • 想要 transparent recursion 就需要重新设计

4.2 Halo Section 2: Preliminaries

4.2.1 IPA (Inner Product Argument)

来自 Bulletproofs'17。给定 commitment $C = \langle a, G \rangle + \langle b, H \rangle + \langle a, b \rangle U$,prover 要证明 inner product $z = \langle a, b \rangle$。

每轮 fold:

  • prover 把 $a, b, G, H$ 长度减半
  • verifier 给 challenge $u$
  • new commitment $C' = u^2 L + C + u^{-2} R$

经 $\log n$ 轮后 vectors 长度变 1,prover 直接 reveal。

关键性质

  • proof size: $O(\log n)$ group elements
  • verifier work: $O(n)$(要做 $n$ 次 group operation 重组 base $G, H$)
  • 无 trusted setup:base $G_i, H_i$ 用 hash-to-curve 公开生成

4.2.2 IPA 用作 Polynomial Commitment

设 $f(X) = \sum a_i X^i$,要 commit。让 $b = (1, z, z^2, \dots, z^{n-1})$,则 $\langle a, b \rangle = f(z)$。

把 IPA 改成"polynomial commitment open at $z$":

  • commit: $C = \langle a, G \rangle$
  • open at $z$: 用 IPA 证明 $\langle a, b \rangle = y$ where $b_i = z^i$

注意:标准 IPA 验证时间 $O(n)$(需要 verifier 也算 $\langle a, b \rangle$ 的相关项)。

4.3 Halo Section 3: Cycle of Curves — 核心技巧 1

4.3.1 问题:recursion 需要在 SNARK 内部 verify SNARK

要让 SNARK proof 在另一个 SNARK 电路里被 verify,需要 verifier 算法用电路表达

但 verifier 算的是 elliptic curve 上的 scalar mul(field $F$ 上的 scalar),而 SNARK 电路本身是 base field $\mathbb{F}_p$ 上的算术——两个 field 不一致

4.3.2 Cycle of Curves

设两条椭圆曲线 $E_1, E_2$:

  • $E_1$ 的 base field = $\mathbb{F}_p$,scalar field = $\mathbb{F}_q$
  • $E_2$ 的 base field = $\mathbb{F}_q$,scalar field = $\mathbb{F}_p$

即 $E_1$ 的 scalar field 等于 $E_2$ 的 base field,反之亦然。

E_1:   base = F_p, scalar = F_q
E_2:   base = F_q, scalar = F_p
       ⇕
       cycle: 在 E_2 电路 (base F_q) 里可以原生算 E_1 上的 scalar mul (scalar 是 F_q)
              在 E_1 电路 (base F_p) 里可以原生算 E_2 上的 scalar mul (scalar 是 F_p)

这样在两条 curve 上交替做 recursion:每一层用一条 curve 上的 SNARK 证明上一层的 verifier 等式。

4.3.3 Pasta Curves: Pallas + Vesta

Halo2 找到了两条 prime-order, transparent, suitable 的 curve

Curve名称由来$p$ (base field bits)安全
PallasGoddess of wisdom$\mathbb{F}_p$, $p \approx 2^{255}$~128-bit
VestaGoddess of hearth$\mathbb{F}_q$, $q \approx 2^{255}$~128-bit

合称 PastaPallas + Vesta)。两条 curve 的阶相互嵌套: $$ |E_{\text{Pallas}}| = q, \quad |E_{\text{Vesta}}| = p $$

这是 transparent recursion 的物理基础。

4.3.4 与 pairing-friendly cycle 的对比

之前的 recursion 方案(BCCT, Coda)用 pairing-friendly cycle of curves(如 MNT4-298 + MNT6-298),但:

  • pairing-friendly 限制使曲线选择极少
  • 安全性较弱(MNT4-298 仅 ~80-bit 安全)
  • 需要 trusted setup(pairing-based SNARK)

Halo 使用非 pairing-friendly cycle(只需要离散对数难,不需要 pairing),曲线选择空间大、安全更强、无 trusted setup。

4.4 Halo Section 4: Amortization — 核心技巧 2

4.4.1 IPA 验证的 $O(N)$ 难题

IPA 的 verifier 在每轮 fold 后需要重组 $G^{(i+1)} = u_i G_{\text{lo}}^{(i)} + u_i^{-1} G_{\text{hi}}^{(i)}$。最终一层后需要算 $G^{(0)} = \prod_i (u_i G_{2i} + u_i^{-1} G_{2i+1})$,这是 $O(N)$ scalar mul。

要在 SNARK 电路里 verify IPA proof,等于要用电路 wire 表达 $O(N)$ 次 scalar mul——电路 size $O(N)$,与 SNARK succinctness 矛盾

4.4.2 Amortization 的核心 trick

关键观察:IPA 中最终的 $G^{(0)}$ 可以表达成 $$ G^{(0)} = \langle s, G \rangle $$ 其中 $s = (s_0, s_1, \dots, s_{N-1})$ 是 challenges $u_i$ 的乘积构成的"compact representation"——每个 $s_j$ 是 $\log N$ 个 $u_i$ 的乘积。

进一步,$\langle s, G \rangle$ 可以看作 commitment to a polynomial $g(X) = \prod_i (1 + u_i X^{2^i})$,evaluate 在某个 $z$ 处。

Amortization 步骤

  1. 当前层 IPA verify:把"$G^{(0)} = \langle s, G \rangle$"这个等式不直接计算,而是当作下一层电路里要 verify 的一个 commitment opening claim
  2. 下一层电路里 verify 这个 commitment opening——但下一层本身也是 IPA,又把 opening 推迟到下下一层。
  3. 经过 $K$ 层 recursion 后,留下一个 final IPA opening claim,这是 verifier 唯一需要做 $O(N)$ work 的地方。
  4. 注意:链上 light client 只需要 verify 当前最新的 SNARK + 那个 final opening claim ≈ $O(\log N)$ 工作。

这就是 "nested amortization":把昂贵的 verifier 工作不断推迟到下一层,直到最后一次性结算。

4.4.3 为什么不会"无限延后"?

两种结算方式:

  • 方式 A: 在某一层做完 final IPA verify($O(N)$)。这个电路开销大,但只在 light client 启动时做一次。
  • 方式 B: 用 outer SNARK 把 final claim 压成 $O(\log N)$ proof,进一步压缩。

Mina 用 方式 A:light client 启动时 verify 一次完整 SNARK。

4.5 Halo2 Book — Plonkish 改造

Halo 原论文用的是简单算术化(类似 R1CS)。Halo2 把它升级到 Plonkish IR

4.5.1 列设计

Halo2 把电路看作一个矩阵,每列是一个 polynomial:

  • Advice columns: prover-private wires
  • Fixed columns: 公开 selector / lookup tables
  • Instance columns: public inputs

每行是一个 cycle / step。每个 cell 是 field element。

4.5.2 Custom Gates

每个 gate 是一组 "polynomial constraint" 关于这些列: $$ q_{\text{gate}}(\text{adv}_1(X), \text{adv}_2(X), \dots, \text{fixed}_1(X), \dots) = 0 \text{ on rows where this gate is enabled} $$

不像 PlonK 固定 5 个 selector,Halo2 允许任意数量 selector + 任意 degree 的 gate equation。这极大方便了 custom optimization(例如 1 个 gate 处理 1 个 SHA256 round)。

4.5.3 Lookup Tables (Halo2-lookup)

Halo2 原生支持 lookup argument:

把某些 advice column subset 约束在某个 lookup table column 中。底层用 plookup 风格的 grand product 实现。

例:byte range check 用 256-row table;XOR table 256x256 共 65536 行。

4.5.4 与 Halo 原论文的关系

维度Halo (2019)Halo2 (2020+)
算术化R1CS-likePlonkish
Custom gates不支持原生支持
Lookup不支持原生支持
实现论文级工业级 Rust 库 (zcash/halo2)

4.6 安全性

Halo 在 AGM 下证明 knowledge soundness。基于:

  • Pasta curves 的离散对数难(~128-bit)
  • Sponge function(如 Poseidon)的随机性

关键:因为 Pallas/Vesta 都是非 pairing-friendly,安全性只依赖 ECDLP,不依赖 pairing assumption。


五、关键数学速查(白板版)

5.1 IPA 一轮 Fold

设 $a = (a_L, a_R), b = (b_L, b_R), G = (G_L, G_R), H = (H_L, H_R)$。

Prover 计算: $$ L = \langle a_L, G_R \rangle + \langle a_L, b_R \rangle U $$ $$ R = \langle a_R, G_L \rangle + \langle a_R, b_L \rangle U $$

verifier 给 challenge $u$。Prover 计算: $$ a' = a_L + u^{-1} a_R, \quad b' = b_L + u b_R $$

$G' = G_L + u G_R$, $H' = H_L + u^{-1} H_R$ 由 verifier 自己重组(这是后续 amortization 的难点)。

新 commitment: $$ C' = u^2 L + C + u^{-2} R $$

5.2 Cycle of Curves 形式化

$$ E_1 / \mathbb{F}_p, \quad |E_1(\mathbb{F}_p)| = q $$ $$ E_2 / \mathbb{F}_q, \quad |E_2(\mathbb{F}_q)| = p $$

即 $E_1$ 的 scalar field $\mathbb{F}_q$ = $E_2$ 的 base field;$E_2$ 的 scalar field $\mathbb{F}_p$ = $E_1$ 的 base field。

5.3 Amortization 公式

第 $k$ 层 IPA verify 留下 claim: $$ \text{claim}_k: \quad G^{(0)}_k = \langle s_k, G \rangle $$

下一层 SNARK 把这个 claim 当作输入,证明: $$ \text{my proof is valid} \land \text{claim}_{k-1} \text{ holds} $$

这样 $\text{claim}_{k-1}$ 不再需要直接 verify。

5.4 Halo2 Plonkish Identity

$$ \sum_{j=1}^{G} q_j(X) \cdot \text{constraint}_j(\text{adv}(X), \text{fixed}(X)) \stackrel{H}{=} 0 $$

其中 constraint_j 可以是任意 polynomial(不限于 PlonK 的 5-selector 形式)。


六、直觉理解

6.1 Cycle of Curves 的物理意义

想象两个相互嵌套的 stack:

  • Stack A 里的元素是 $\mathbb{F}_p$ 数(来自 Pallas)
  • Stack B 里的元素是 $\mathbb{F}_q$ 数(来自 Vesta)

Pallas verifier 算 IPA 时要做 $\mathbb{F}_q$ 上的 scalar mul(标量是 challenge $u_i \in \mathbb{F}_q$)。这个 scalar mul 在 Vesta 电路中是原生 wire 操作(因为 Vesta 的 base field 就是 $\mathbb{F}_q$)。

反之 Vesta verifier 算 IPA 时做 $\mathbb{F}_p$ scalar mul,在 Pallas 电路里原生。

所以 recursion 在 Pallas/Vesta 之间交替进行,每层只做"自己 native 的 field arithmetic"。

6.2 Amortization 的"借未来还现在"

类比信用卡:

  • 当前账单 $1000(IPA 的 $O(N)$ verifier 工作)
  • 不直接付,转到下个月 (next recursive proof)
  • 下个月又转走,一直转 $K$ 个月
  • 最后一个月一次性结算(或永远不结算,每次都 wrap 一层)

只要"转账成本"$O(\log N)$ 比"直接结算"$O(N)$ 便宜很多,amortization 就有意义。

6.3 Halo2 列设计的灵活性

PlonK 的 selector 数量固定 5。Halo2 让开发者自定义 advice columns 数量 + custom gates 复杂度。结果:

  • ECC point addition 用 1 个 custom gate(不再分解成几十个加法)
  • SHA256 一轮用一个 custom gate
  • Poseidon 一轮用一个 custom gate

代价:每个 custom gate 占用 selector,gate degree 越高 quotient polynomial degree 越大,prover 越慢。所以 Halo2 工程师要做"列宽 vs 行高"的 trade-off。


七、实施考量

7.1 Zcash NU5 (2022)

  • 替换 Sapling 的 Groth16 → Halo2
  • 第一次完全消除 trusted setup(Sapling 的 Powers of Tau 不再需要)
  • Orchard shielded pool 完全用 Halo2
  • proof size: ~2 KB
  • prover time: ~5 sec on mobile

7.2 zkSync Era (Boojum, 2023)

  • zkSync 1.0 用 PlonK + KZG
  • 2023 升级 Boojum:Halo2 fork + Goldilocks field + FRI(混合 STARK/SNARK)
  • TVL: $700M+ (2026)
  • prover GPU 加速:~40 sec / batch on RTX 4090

7.3 Scroll (2023)

  • Halo2 fork + KZG 替代 IPA(提高 verifier speed)
  • EVM-equivalent (Type 2)
  • TVL: $400M+ (2026)
  • 上线 mainnet beta 2023-10

7.4 Mina Protocol

  • Halo recursion 的最先进部署
  • 22 KB 区块链:每个 block 包含一个 recursive SNARK,证明所有历史区块有效
  • proof aggregation 在每个 block 跑一次
  • 市值: $300M+ (2026)

7.5 Axiom (2023)

  • 用 Halo2 做 Ethereum 历史数据查询的 ZK proof
  • 应用:把 Ethereum L1 链上历史数据用 zk proof 暴露给智能合约
  • TVL/活跃: 集成多个 DeFi 协议

7.6 真实性能数据(2026)

系统电路 sizeProver (CPU)Prover (GPU)Proof size
Zcash Halo2 (NU5)$2^{17}$5 sec (mobile)n/a~2 KB
Scroll Halo2$2^{20}$5 min30 sec~600 B (KZG)
zkSync Boojum$2^{20}$10 min40 sec~50 KB (FRI)
Minarecursiveper-block 1-2 minn/a22 KB total

八、被使用的真实案例

8.1 Zcash Orchard

  • 用户隐私交易
  • ~50K constraints / shielded action
  • 移动钱包 2-5 sec proof
  • TVL/市值: ~$3B (2026)

8.2 Scroll EVM

  • Type 2 zkEVM
  • 每批数百交易
  • Halo2 内部生成,KZG 包装上 L1
  • L1 verify ~700K gas

8.3 zkSync Era

  • 当前活跃 zkRollup
  • Boojum 架构(Halo2 + Goldilocks + FRI)
  • 生成器 GPU 集群
  • 累计交易 1B+ (2026)

8.4 Mina light client

  • 22 KB 完整区块链
  • 浏览器内 verify 一次 SNARK 即可同步全网
  • 适合 mobile / IoT 端

8.5 Axiom historical query

  • 例:DeFi 协议要查询某地址 6 个月前的余额
  • Axiom 提供 ZK proof + L1 contract verify
  • 节省 archival node 成本

8.6 Aleo (Halo2 + 自定义 IR)

  • 通用 zk smart contract 平台
  • Leo 语言 + Halo2 后端

九、局限性

局限说明
Proof size 较大IPA 是 $O(\log N)$ group element ≈ ~1.5 KB;KZG 替换后 ~600 B
Verifier 较慢$O(\log N)$ scalar mul,比 Groth16 的 $O(1)$ 慢
Recursion 工程难cycle of curves + 列设计 + amortization 三重抽象,工程门槛高
Halo2 学习曲线Rust + Plonkish + 列设计概念,很多团队需要 3-6 个月才上手

十、关键速查表

10.1 Halo / Halo2 数字事实

项目数据
Proof size (IPA)$O(\log N)$ ≈ 1.5 KB
Proof size (KZG fork)~600 B
Verifier 时间$O(\log N)$
Prover 时间$O(N \log N)$
SetupTransparent (IPA) 或 universal trusted (KZG)
后量子?(依赖 ECDLP)
Recursion?
FieldPasta (Pallas/Vesta), 各 ~256-bit
安全模型AGM + DLOG + Random Oracle

10.2 完整 SNARK/STARK 对比(4 天精读全表)

维度Groth16PlonKSTARKHalo2
Proof192 B656 B50 KB+1.5 KB
Setupper-circuit trusteduniversal trustednonenone (IPA) / universal (KZG)
Verifier$O(1)$$O(1)$$O(\log^2 n)$$O(\log n)$
Recursion困难中等容易 (Plonky2)原生
PQ-safe
Custom gates是 (UltraPlonk)是 (AIR)
Lookup后加 (plookup)原生

十一、面试题

Q1: 解释 cycle of curves 为什么 recursion 必需。

:SNARK recursion 需要在电路里 verify 上一层 SNARK 的 verifier 等式,verifier 等式涉及 elliptic curve scalar mul,scalar 来自一个 field(A),group element 在另一个 field(B)。如果只用一条 curve,电路 base field 是 B,但 verifier 算的 scalar 是 A——electrice circuit 里"用 B 表达 A 算术"是 non-native arithmetic,需要 ~10x 开销。

cycle of curves $E_1, E_2$ 满足 $E_1$ 的 scalar field = $E_2$ 的 base field 反之亦然。把 $E_1$ 上的 verifier 等式用 $E_2$ 电路表达——所有 scalar 在 $E_2$ 的 base field 中是 native 的,电路开销减少 10x

Q2: 详细解释 Halo 的 amortization。

:IPA verifier 工作 $O(N)$(重组 $G^{(0)}$)。Halo 不直接做这个工作,而是把"$G^{(0)} = \langle s, G \rangle$"作为下一层 recursive proof 的输入 claim。下一层 SNARK 证明:

  1. 自己的 IPA verify 通过
  2. 上一层的 claim 也成立

下一层又把自己的 claim 推到下下一层,依此类推。最终某一层(或永远不)做一次完整 $O(N)$ verify。这就是"借未来还现在"——每层只做 $O(\log N)$ 工作,把 $O(N)$ 工作摊销到链式 recursion 的最末端。

Q3: Halo2 与原 Halo 论文的核心差异?

  • 算术化: Halo 是 R1CS-like;Halo2 是 Plonkish (column-based)
  • Custom gates: Halo 不原生支持,Halo2 原生
  • Lookup: Halo 不支持,Halo2 原生(plookup 风格)
  • 实现: Halo 是论文,Halo2 是 Zcash 工业级 Rust 库
  • PCS 选择: Halo 强绑定 IPA,Halo2 允许 PCS 替换(zkSync/Scroll 都 fork 后改 KZG)

Q4: 为什么 zkSync 和 Scroll 把 Halo2 的 IPA 换成 KZG?

:IPA 的 verifier 是 $O(\log N)$,比 KZG 的 $O(1)$ pairing 慢,且 proof size 1.5 KB > KZG 的 ~600 B。在 L2 → L1 桥接场景下:

  1. L1 verify gas 比 setup ceremony 成本敏感得多
  2. 商业上可以接受 universal trusted setup(Powers of Tau 已经普遍可信)
  3. recursion 仍可用 KZG 实现(虽然失去 transparent 优势)

所以工程权衡:放弃 transparent 换更快 verifier。Mina/Zcash 仍坚持 IPA,因为 transparent 是它们的产品差异化。

Q5: Pasta curves 名字怎么来的?为什么用它们?

:Pasta = Pallas + Vesta,两条曲线名字来自希腊女神。由 Daira Hopwood 设计,满足三个条件:

  1. Cycle: $|E_{\text{Pallas}}| = q$, $|E_{\text{Vesta}}| = p$ 互为 scalar field/base field
  2. Prime order: 每条 curve 的阶是质数(避免小子群攻击)
  3. 2-adicity: 每条 curve 的 scalar field 有大的 $2^k | (p-1)$,方便 FFT

Halo2 用 Pasta 因为:transparent (无 pairing 需求) + 高安全 (~128-bit) + FFT 友好。

Q6: 为什么 Halo2 的 recursion 比 Groth16 的 recursion 实用得多?

  1. Trusted setup: Groth16 recursion 需要每层一次 phase 2 ceremony;Halo2 IPA 完全 transparent。
  2. Cycle of curves: Halo2 用 Pasta;Groth16 必须用 pairing-friendly cycle (MNT4-298),安全性弱(80-bit)且性能差。
  3. Amortization: Halo2 把 $O(N)$ verifier 工作推迟,Groth16 没有这一技巧。
  4. 生态: Halo2 已经被 Zcash/zkSync/Scroll/Mina 大量验证;Groth16 recursion 几乎没有商业部署(Coda 早期尝试过但很快转 Halo)。

Q7: 把 Halo2 部署到生产环境,最大的工程挑战是什么?

  1. 学习曲线: Plonkish IR + 列设计 + custom gates + recursion 多重概念,团队需要 3-6 个月。
  2. Prover 性能: Halo2 prover 内存大(10M constraint 需要 50+ GB RAM),需要分布式 prover。
  3. GPU 支持: 早期 Halo2 仅支持 CPU;Scroll/zkSync 各自重写 GPU MSM/NTT 库。
  4. 审计困难: 自定义 gate 越多 audit surface 越大。Trail of Bits / Veridise 这类专业 ZK 审计公司供不应求。
  5. 链上 verifier 合约: Halo2 verifier 合约 ~5K-10K Solidity 行,gas 优化极费时间。

十二、4 天精读总结 — SNARK/STARK 全景

经过 Day 264-267 的精读,我们走完了从 2016 到 2024 的 ZK 技术演化主线:

Day论文核心创新当前定位
264Groth16 (2016)192 B proof, 3 pairing verifierL1 verify wrapper 不可替代
265PlonK (2019)universal updatable setup, custom gates IRzkRollup 内部主流
266STARK + FRI (2017-2018)transparent + 后量子 + 大规模 proverStarkNet, Plonky2 内核
267Halo / Halo2 (2019-2020)recursion + transparent + IPAzkSync, Scroll, Mina, Zcash 主流

现代 ZK 栈典型组合

应用层 (zkRollup, zkApp, light client)
   │
   ▼
内部 prover (Plonky2 / Halo2 / Plonkish + STARK)  ← 速度优先, 后量子安全
   │
   ▼
recursion 聚合 (Halo2 amortization, Plonky2 recursion)
   │
   ▼
L1 verify wrapper (Groth16 / PlonK + KZG)  ← 192 B, 113K gas, 经济性最佳
   │
   ▼
Ethereum L1

一句话总结:现代 ZK 栈 = STARK/Halo2 内核(生产 + 后量子)+ Groth16/PlonK 包装(消费 + 经济)。没有任何单一 SNARK 是"最好"的——好的产品是合理组合


十二·五、补充:Halo2 工程模板与 cycle-of-curves 详解

A. Halo2 一个 Minimal Circuit 的 Rust 模板

use halo2_proofs::{
    arithmetic::Field,
    circuit::{Layouter, SimpleFloorPlanner, Value},
    plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Selector},
    poly::Rotation,
    pasta::Fp,
};

#[derive(Clone)]
struct MyConfig {
    advice: [Column<Advice>; 3],   // a, b, c columns
    s_mul: Selector,
    s_add: Selector,
}

struct MyCircuit {
    a: Value<Fp>,
    b: Value<Fp>,
}

impl Circuit<Fp> for MyCircuit {
    type Config = MyConfig;
    type FloorPlanner = SimpleFloorPlanner;

    fn without_witnesses(&self) -> Self {
        MyCircuit { a: Value::unknown(), b: Value::unknown() }
    }

    fn configure(meta: &mut ConstraintSystem<Fp>) -> MyConfig {
        let advice = [meta.advice_column(), meta.advice_column(), meta.advice_column()];
        let s_mul = meta.selector();
        let s_add = meta.selector();

        // Custom mul gate: a * b - c = 0 when s_mul is on
        meta.create_gate("mul", |meta| {
            let s = meta.query_selector(s_mul);
            let a = meta.query_advice(advice[0], Rotation::cur());
            let b = meta.query_advice(advice[1], Rotation::cur());
            let c = meta.query_advice(advice[2], Rotation::cur());
            vec![s * (a * b - c)]
        });

        // Custom add gate: a + b - c = 0 when s_add is on
        meta.create_gate("add", |meta| {
            let s = meta.query_selector(s_add);
            let a = meta.query_advice(advice[0], Rotation::cur());
            let b = meta.query_advice(advice[1], Rotation::cur());
            let c = meta.query_advice(advice[2], Rotation::cur());
            vec![s * (a + b - c)]
        });

        MyConfig { advice, s_mul, s_add }
    }

    fn synthesize(&self, cfg: MyConfig, mut layouter: impl Layouter<Fp>) -> Result<(), Error> {
        layouter.assign_region(|| "compute (a*b)+a", |mut region| {
            cfg.s_mul.enable(&mut region, 0)?;
            region.assign_advice(|| "a", cfg.advice[0], 0, || self.a)?;
            region.assign_advice(|| "b", cfg.advice[1], 0, || self.b)?;
            let mul_out = self.a.zip(self.b).map(|(a, b)| a * b);
            region.assign_advice(|| "a*b", cfg.advice[2], 0, || mul_out)?;

            cfg.s_add.enable(&mut region, 1)?;
            region.assign_advice(|| "a*b", cfg.advice[0], 1, || mul_out)?;
            region.assign_advice(|| "a", cfg.advice[1], 1, || self.a)?;
            let final_out = mul_out.zip(self.a).map(|(x, a)| x + a);
            region.assign_advice(|| "(a*b)+a", cfg.advice[2], 1, || final_out)?;
            Ok(())
        })
    }
}

要点:

  • advice 是 prover-private 列;fixed 是公开 selector(这里隐式由 Selector 处理)
  • meta.create_gate 添加 custom gate:返回的 expression 必须在所有 selector 启用的行上等于 0
  • Rotation::cur() 表示当前行,可以 Rotation::next() 引用下一行(适合 transition constraint)
  • synthesize 是 prover 把 wire value 填入 region("region" 是逻辑分配单位,最终被 floor planner 排到具体行)

B. Cycle-of-Curves 详细参数

Pasta 参数(Halo2 / Mina)

| Curve | Equation | $p$ (base prime) | $|E(\mathbb{F}_p)|$ | |-------|----------|------------------|---------------------| | Pallas | $y^2 = x^3 + 5$ | $p = 0x40000000\ 00000000\ 00000000\ 00000000\ 224698fc\ 094cf91b\ 992d30ed\ 00000001$ | $q$ (= Vesta's base) | | Vesta | $y^2 = x^3 + 5$ | $q = 0x40000000\ 00000000\ 00000000\ 00000000\ 224698fc\ 0994a8dd\ 8c46eb21\ 00000001$ | $p$ (= Pallas's base) |

注意两个素数高 128 位完全相同 (0x40000000...224698fc), 仅低 128 位不同 ——这是 Daira Hopwood 用 SEA 算法 + 大量计算搜索得到的。

其他常见 cycle

Cycle用途安全
MNT4-298 + MNT6-298Coda/Mina V1 (deprecated)~80-bit
Pasta (Pallas + Vesta)Halo2, Mina V2, zkSync Boojum~128-bit
BN254 + GrumpkinAztec Honk recursion~128-bit (Grumpkin 不是真 cycle, 是"half-cycle")

"Half-cycle" / "two-chain" 区别:完整 cycle 两条 curve 互为 scalar/base field;half-cycle 只在一个方向上 scalar = base,另一个方向不一致——recursion 必须每次都从 A 到 B 再到 A,不能链式。

C. Halo2 Prover 性能 dial

Halo2 工程师调优三个核心参数:

  1. k (log of rows): 决定 trace 大小 $2^k$。k 越大支持 constraints 越多,但 FFT 开销 $O(k \cdot 2^k)$。
  2. advice columns 数: 列越多 → 行越少(同样 constraint 数下)。但每列要 commit 一个多项式,proof size 增长。
  3. gate degree: 高 degree gate 减少行数但增加 quotient polynomial 度数 → split into more $t_i$ 段。

工程经验:典型 SHA256 circuit 用 k=17, ~10 advice columns, max gate degree 6.

D. zkSync Boojum 与 Halo2 的差异

维度Halo2 (Zcash)Boojum (zkSync)
FieldPasta (256-bit)Goldilocks (64-bit)
PCSIPAFRI (LogUp + LookUp)
Recursioncycle of curvesLogUp recursion 在同一 field 内
HashPoseidonPoseidon2 + custom
性能5-10 sec / 1M constraint (CPU)1-2 sec / 1M (CPU)

Boojum 几乎完全重写了 Halo2 内部,仅保留"列设计 + custom gates"的 IR 风格。


十三、明日预告

明天 Day 268 我们结束论文精读系列,进入"密码学工程实现"——精读两个已部署的开源代码

  1. Arkworks Rust crate(Groth16 / PlonK 通用 SDK)
  2. circom + snarkjs 工具链(Tornado Cash / Semaphore / Worldcoin 都用此)

从论文走到代码:精读论文教会我们"为什么这样设计",精读代码教会我们"工程上要怎么处理 corner case"。两者都做到,才是真正的密码学工程师。


今日心得:精读 Halo 后最深的体会是——好的密码学发明不是发明新原语,而是巧妙组合已有原语。Halo 没有发明 IPA(来自 Bulletproofs)、没有发明 cycle of curves(理论上 BCCT 早提过)、没有发明 amortization(在数据库 / 计算理论里早就常见)。但 Sean Bowe 等人把这三者合并成了"transparent recursion"——一个 10 年悬而未决的问题在 19 页论文里被解掉。

读完 4 天 ZK 经典论文,最大的感悟是:密码学的进步常常来自"工程审美"而非"数学突破"。Groth 把 8 个 element 砍到 3 个;Gabizon 把 ceremony 从 phase-2 升到 universal;Ben-Sasson 用 Reed-Solomon code 替代 pairing;Bowe 用 cycle 解 recursion。每一篇都不是新数学,而是新组合。

这给金融/零售背景的 PM 一个启示:架构师的真正稀缺能力,是看出"什么旧零件可以新组合"。这和我 10 年金融零售产品经验高度契合——支付系统、风控系统、营销系统每一代演化也都是"已有原语的新组合"。下一步的密码学工程精读,要重点关注模块边界设计抽象层选择——这才是从"会用"到"会造"的分水岭。