上一讲那套"先信你,有异议再查"的机制,有一个绕不开的代价:你必须给挑战者留出时间。 这就是提款要等一周的原因。

那能不能不留这个窗口?

能——如果提交的时候就附上一份"我算对了"的证明,而且这份证明谁都能快速核验。

两者的差别,接着上一讲那个比方说最清楚。上一讲是报税 + 追溯期:先信你,事后可查。

这一讲是交材料时就附上审计报告:审计报告很贵、很难做(生成证明的成本高),但核验它只要几秒钟,而且核验通过就没有任何可争议的余地——不需要留追溯期,因为没有什么可追溯的。

一、把"证明我错"换成"证明我对"

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"几乎不提供信息。 该问的是:电路谁审的、有没有形式化验证、升级权在谁手里、数据在哪。

思考题

  1. 用一句话说清有效性证明和欺诈证明在"证明什么"上的区别,并推出各自的延迟特性。
  2. 为什么 Rollup 不需要零知识性?请写出它要证明的命题,指出其中哪些是公开的。
  3. 什么情况下 Rollup 会真正需要零知识性?举一个具体的应用。
  4. 比较 SNARK 和 STARK:如果你在设计一条打算运行五十年的链,你选哪个?为什么?
  5. 可信设置的"有毒废料"泄露会导致什么?为什么 14 万人的仪式比 10 人的安全得多?
  6. Type 1 和 Type 4 zkEVM 各自适合什么场景?一个已经部署在主网的复杂协议想迁移,该选哪个?
  7. 为什么 keccak 在算术电路里这么贵?把状态树的哈希换成 Poseidon 能省下多少?会带来什么兼容性问题?
  8. 递归证明如何让 L1 成本变成常数?请画出三层递归聚合 8 个批次的结构。
  9. 构造一个"电路漏掉约束"的具体例子,说明攻击者能做什么,以及为什么没人会发现。
  10. “我们用了零知识证明,所以是数学保证的安全”——请指出这句话在哪些方面成立、哪些方面不成立。