上一讲那套"先信你,有异议再查"的机制,有一个绕不开的代价:你必须给挑战者留出时间。 这就是提款要等一周的原因。
那能不能不留这个窗口?
能——如果提交的时候就附上一份"我算对了"的证明,而且这份证明谁都能快速核验。
两者的差别,接着上一讲那个比方说最清楚。上一讲是报税 + 追溯期:先信你,事后可查。
这一讲是交材料时就附上审计报告:审计报告很贵、很难做(生成证明的成本高),但核验它只要几秒钟,而且核验通过就没有任何可争议的余地——不需要留追溯期,因为没有什么可追溯的。
一、把"证明我错"换成"证明我对"
Optimistic Rollup:提交状态根,⭐ 等别人来证明我【错了】
⟹ 需要挑战期,需要 1-of-N 假设
ZK Rollup: 提交状态根,同时附上一份证明说明我【是对的】
⟹ 不需要挑战期,不需要任何诚实假设
⭐ 差别的性质:
| Optimistic | 有效性证明 | |
|---|---|---|
| 安全假设 | 1-of-N 诚实且能上链 | 纯密码学,无诚实假设 |
| 提款延迟 | 约 7 天 | 证明生成时间(几十分钟内) |
| L1 成本 | 低(正常时不做任何验证) | 每批都要验证一个证明 |
| L2 计算成本 | 低(就是普通执行) | 高(生成证明比执行贵几个数量级) |
| 实现难度 | 中 | 高 |
⭐ 一句话概括这个权衡:Optimistic 把成本推给"万一",ZK 把成本预付在"每次"。
二、这个名字用错了词
“ZK Rollup"里的 ZK 指零知识(zero-knowledge)。但 Rollup 通常根本不需要零知识性。
一个证明系统可以有四个性质:
① 完备性(Completeness):真命题一定能被证明
② 可靠性(Soundness):⭐ 假命题【无法】被证明
③ 简洁性(Succinctness):证明很小,且验证远快于重新计算
④ 零知识性(Zero-Knowledge):证明【不泄露】任何除"命题为真"之外的信息
⭐ Rollup 真正需要的是 ② 和 ③。 它要证明的命题是:
"给定公开的初始状态根 S₀ 和公开的交易列表 T,
执行后的状态根确实是 S₁。"
⚠️ 这里面全部是公开信息——没有任何需要隐藏的东西。
⭐ 所以更准确的名字是「有效性 Rollup(validity rollup)」。 零知识性只有在做隐私应用(第 33 讲)时才被真正用到。
为什么名字仍然叫 ZK?因为所用的技术(SNARK/STARK)恰好来自零知识证明的研究传统——是工具的名字被搬到了用途上。
三、SNARK 与 STARK
SNARK = Succinct Non-interactive ARgument of Knowledge
STARK = Scalable Transparent ARgument of Knowledge
↑ ⭐ Transparent = 无需可信设置
| SNARK(Groth16 / PLONK) | STARK | |
|---|---|---|
| 证明大小 | 极小(几百字节到几 KB) | 大(几十到几百 KB) |
| L1 验证成本 | 低(几十万 Gas) | 高 |
| 可信设置 | 通常需要 | 不需要 |
| 密码学基础 | 椭圆曲线配对(第 8 讲) | 仅哈希 |
| 抗量子 | 否 | 是 |
| 证明生成速度 | 中 | 较快(可并行) |
⭐ 注意"抗量子"这一行:STARK 只依赖哈希函数的抗碰撞性,而量子计算对哈希的威胁有限(Grover 算法只能开平方根,第 4 讲)。SNARK 依赖离散对数,Shor 算法可以直接破解。
这和第 13 讲 Verkle 树面临的是同一个权衡:性能与抗量子之间的选择。
可信设置是什么
某些证明系统需要一组"公共参数”,生成时会产生一个秘密值:
⭐ 这个秘密值被称为"有毒废料(toxic waste)"。
谁知道它,谁就能【为假命题伪造出有效证明】——
而验证者无法察觉。
解法是多方计算仪式(MPC ceremony):
多个参与者依次贡献随机性,每人生成后销毁自己那份。
⭐ 只要【至少有一个】参与者诚实销毁,最终的秘密就无人知晓。
⟹ 又是一个 1-of-N 假设,但这次强得多:
参与者可以有成千上万个,且过程完全公开可审计。
⭐ 以太坊的 KZG 仪式(为 EIP-4844 准备)有超过 14 万名参与者。 要攻破它,需要这 14 万人全部串通并保留了自己的秘密——这是一个极其安全的 1-of-N。
四、zkEVM 的五个类型
要为 EVM 执行生成证明,必须把 EVM 的每一步"翻译"成算术电路约束。第 21 讲说过,EVM 对此极不友好。于是出现了一个兼容性与证明速度的连续谱(Vitalik 的分类):
Type 1 —— ⭐ 完全等价以太坊
连状态树、哈希函数、Gas 定价全部不改
✅ 可以直接为以太坊主网出块生成证明
最慢
Type 2 —— EVM 等价
字节码层面完全兼容,但换掉了对 ZK 不友好的底层结构
(比如用 ZK 友好的哈希代替 keccak 做状态树)
依赖 keccak 状态树的工具需要适配
Type 2.5 —— EVM 等价,但调高了对 ZK 不友好操作的 Gas 价格
用经济手段绕开最贵的电路
Type 3 —— 几乎等价
少数预编译和边缘特性不支持,多数合约无需改动即可部署
Type 4 —— 高级语言等价
直接把 Solidity 编译成一个【为 ZK 设计的】VM 的字节码
最快
字节码不兼容:手写汇编、依赖 CREATE2 地址计算、
或做字节码检查的合约会失效
⭐ 权衡非常清晰:越靠近以太坊,越慢;越远离,越快但越不兼容。
为什么 EVM 这么难证明
三个成本大项:
① 256 位运算(第 21 讲)
电路在有限域上工作,一次 256 位加法要拆段 + 处理进位 + 范围检查
② ⭐ keccak256 —— 最贵的一项
它是为【CPU】优化的哈希,大量位运算和置换。
在算术电路里,一次 keccak 可能要【上万个约束】。
而致命的是:MPT 到处都是 keccak(第 12 讲)——
每次状态读写都要验证一条 Merkle 路径,
每层一次 keccak。
⟹ 光是"证明状态访问是合法的",就吃掉了大部分证明成本。
③ 存储访问的不确定性
执行前不知道会访问哪些槽,电路必须处理所有可能
⭐ 这解释了 Type 2 为什么要换掉状态树的哈希函数:改用 Poseidon 这类"ZK 友好"哈希(专为算术电路设计,约束数少两个数量级),能直接砍掉最大的一块成本。
五、证明递归
一个关键技术:让一个证明去证明"另一个证明是有效的"。
证明 A 验证了区块 1
证明 B 验证了区块 2
⭐ 证明 C 验证了"A 和 B 都是有效的证明"
⟹ L1 只需验证 C
⭐ 三个收益:
① 分摊 L1 验证成本:一次验证覆盖任意多个批次
② ⭐ 并行生成:不同部分可以在不同机器上同时证明,最后聚合
③ 无限压缩:递归可以任意多层
⚠️ 代价是递归本身也要在电路里模拟验证算法,这需要特殊设计的曲线(如"曲线循环")或证明系统。
六、真正的风险不在密码学
⚠️ 审计报告本身是可靠的,出事的地方在别处:报告是不是真的对应这份材料(电路和 EVM 语义是否一致)、出报告的那套体系有没有后门(可信设置)、以及谁有权换掉这套体系(升级密钥)。密码学没问题,不代表这套东西没问题。
⭐ 这是本讲最重要的一节。
⭐ 有效性证明保证的是:
"这个【电路】被正确地执行了。"
它【不保证】:
"这个电路正确地实现了 EVM 的语义。"
于是最大的风险是电路 bug:
如果电路里漏掉了一个约束(比如忘记检查某个溢出条件),
⭐ 那么攻击者可以构造一个【违反 EVM 语义但满足电路约束】的状态转移,
并为它生成一个【完全有效】的证明。
⟹ L1 会欣然接受它。数学没有出错——是电路写错了。
⭐ 对比一下两种 Rollup 的失败模式,很有启发:
Optimistic Rollup 出 bug:⭐ 挑战者会发现并挑战它
⟹ 有一层【人的兜底】
ZK Rollup 电路出 bug: 证明照样验证通过,
【没有任何人会察觉】
⟹ 没有兜底
这是一个反直觉的结论:密码学保证越强,人为兜底的空间越小。
其他风险(与 OP Rollup 相同)
② 升级密钥:⭐ 谁能换掉验证合约或电路?(第 24 讲的四个问题)
③ 排序器中心化:审查与 MEV(第 27 讲)
④ 数据可用性:如果数据不在 L1,就是 Validium 而不是 Rollup(第 26、29 讲)
评估一个 ZK Rollup,“用了 ZK"本身几乎不提供任何信息。要问的是:电路被谁审计过?有没有形式化验证?升级权在谁手里?数据在哪?
七、Go:验证接口与递归
package validity
// Proof 是一个简洁证明。
// ⭐ SNARK 只有几百字节;STARK 几十到几百 KB。
type Proof []byte
// PublicInputs 是被证明的【公开】命题。
// 注意这里没有任何秘密——Rollup 用的是简洁性,不是零知识性。
type PublicInputs struct {
PrevStateRoot [32]byte
NewStateRoot [32]byte
TxDataHash [32]byte // 承诺了这批交易,与 L1 上的数据绑定
BatchIndex uint64
}
// Verifier 是部署在 L1 上的验证合约的抽象。
// 关键性质:验证成本与被证明的计算量【无关】——这就是"简洁性"。
type Verifier interface {
Verify(proof Proof, inputs PublicInputs) bool
}
// RollupContract 是 L1 上的 Rollup 合约。
type RollupContract struct {
stateRoot [32]byte
verifier Verifier
batches uint64
}
// SubmitBatch 提交一批状态转移。
// 与 Optimistic Rollup 的根本差别:这里【当场】验证,
// 通过即最终确定,没有挑战期。
func (r *RollupContract) SubmitBatch(newRoot [32]byte, txDataHash [32]byte, proof Proof) bool {
inputs := PublicInputs{
PrevStateRoot: r.stateRoot, // 必须以当前状态为起点,防止跳过批次
NewStateRoot: newRoot,
TxDataHash: txDataHash,
BatchIndex: r.batches,
}
if !r.verifier.Verify(proof, inputs) {
return false
}
// 这里还必须检查 txDataHash 对应的数据【确实已在 L1 上可得】。
// 若省掉这一步,它就退化成 Validium(第 26、29 讲)。
r.stateRoot = newRoot
r.batches++
return true
}
// ─────────── 递归聚合 ───────────
// Aggregator 把多个证明聚合成一个。
// 它内部运行的电路本身就是"验证算法",
// 于是"验证 N 个证明"这件事本身被证明了一次。
type Aggregator interface {
// Aggregate 生成一个证明,声称:这 N 个 (证明, 输入) 对全都有效。
Aggregate(proofs []Proof, inputs []PublicInputs) (Proof, PublicInputs, error)
}
// L1VerificationCost 说明递归的价值:
// 不递归时,L1 成本随批次数线性增长;
// 递归后,无论多少批次,L1 只验证【一个】证明。
func L1VerificationCost(batches int, recursive bool, perProofGas uint64) uint64 {
if recursive {
return perProofGas // 常数
}
return uint64(batches) * perProofGas
}
// CircuitRisk 列出有效性证明【无法】保证的东西。
// 证明保证"电路被正确执行",不保证"电路写对了"。
// 而电路 bug 不会被任何人察觉——这是与 OP Rollup 最本质的差别。
type CircuitRisk struct {
MissingConstraint bool // 漏掉约束 ⟹ 可为非法状态转移生成有效证明
UpgradeableKey bool // 谁能换验证合约或电路
DataOffChain bool // 数据不在 L1 ⟹ 是 Validium 不是 Rollup
CentralSequencer bool // 审查与 MEV
}
八、本讲小结
- ⭐ 有效性证明把"等别人证明我错"换成"当场证明我对”:无挑战期、无诚实假设、提款快。代价是每批都要付证明生成与链上验证成本。
- 权衡的本质:Optimistic 把成本推给"万一",ZK 把成本预付在"每次"。
- “ZK Rollup"这个名字用错了词:它需要的是可靠性 + 简洁性,不是零知识性——要证明的命题里全是公开信息。更准确的名字是"有效性 Rollup”。
- STARK 只依赖哈希 ⟹ 抗量子、无需可信设置,代价是证明大、L1 验证贵。SNARK 证明极小、验证便宜,但依赖椭圆曲线(Shor 可破)且通常需要可信设置。这与第 13 讲 Verkle 的权衡完全同构。
- 可信设置的"有毒废料"谁知道谁就能伪造证明。 MPC 仪式让它变成一个 1-of-N 假设——以太坊的 KZG 仪式有 14 万+ 参与者,要攻破需要他们全部串通。
- zkEVM 的五个类型是一条兼容性与速度的连续谱:Type 1 完全等价但最慢,Type 4 编译到 ZK 友好 VM 最快但字节码不兼容。
- EVM 难证明的最大成本项是 keccak:它为 CPU 优化,在算术电路里一次可能上万个约束——而 MPT 到处是 keccak,光"证明状态访问合法"就吃掉大部分成本。 这正是 Type 2 要换掉状态树哈希的原因。
- 递归证明的三个收益:分摊 L1 验证成本(变成常数)、并行生成、无限压缩。
- ⭐⭐ 最重要的一条:有效性证明保证"电路被正确执行",不保证"电路正确实现了 EVM"。 漏掉一个约束,攻击者就能为非法状态转移生成完全有效的证明。
- 反直觉的结论:OP Rollup 出 bug 时挑战者会发现——有一层人的兜底;ZK 电路出 bug 时证明照样通过——没有任何人会察觉。密码学保证越强,人为兜底的空间越小。
- 评估一个 ZK Rollup,“用了 ZK"几乎不提供信息。 该问的是:电路谁审的、有没有形式化验证、升级权在谁手里、数据在哪。
思考题
- 用一句话说清有效性证明和欺诈证明在"证明什么"上的区别,并推出各自的延迟特性。
- 为什么 Rollup 不需要零知识性?请写出它要证明的命题,指出其中哪些是公开的。
- 什么情况下 Rollup 会真正需要零知识性?举一个具体的应用。
- 比较 SNARK 和 STARK:如果你在设计一条打算运行五十年的链,你选哪个?为什么?
- 可信设置的"有毒废料"泄露会导致什么?为什么 14 万人的仪式比 10 人的安全得多?
- Type 1 和 Type 4 zkEVM 各自适合什么场景?一个已经部署在主网的复杂协议想迁移,该选哪个?
- 为什么 keccak 在算术电路里这么贵?把状态树的哈希换成 Poseidon 能省下多少?会带来什么兼容性问题?
- 递归证明如何让 L1 成本变成常数?请画出三层递归聚合 8 个批次的结构。
- 构造一个"电路漏掉约束"的具体例子,说明攻击者能做什么,以及为什么没人会发现。
- “我们用了零知识证明,所以是数学保证的安全”——请指出这句话在哪些方面成立、哪些方面不成立。