卷 IV · 压短CH 14深度 14/23

短的代价

前面十三章我一直在说验证者有多轻松。这一章把账单翻过来。本机实测:证明一段 8192 步的计算,比直接把它跑一遍慢 164 倍;而验证那份证明比直接跑快 2.3 倍,且工作量只随长度按对数增长。而且我这台还是个只干了一半活的玩具——工业实现的证明开销在 10⁴ 到 10⁶ 倍量级。

164× / 2.3×544 次哈希本机实测

◻ 本章先赊三条
第一条。「简洁」不是省力气,是转移力气——而且转移的时候要乘一个三位数以上的系数。 第二条。证明的大小和被证计算的长度几乎无关;证明的生成时间则和它成正比。这两件事经常被混为一谈。 第三条。这笔交易只在一种情况下划算:一次证明,很多人(或很多次)验证。这一条决定了这门技术能落在哪里、不能落在哪里。

三个数,一起看

把卷 III 那台机器实装成代码,跑第 3 章那条 MiMC 记录,测三件事:直接执行生成证明验证证明

计算长度 n直接执行生成证明验证证明大小
10240.143 ms30.0 ms0.478 ms13.9 KB
20480.298 ms31.4 ms0.398 ms14.9 KB
40960.546 ms65.7 ms0.453 ms16.0 KB
81921.092 ms178.9 ms0.479 ms17.1 KB

三列各有各的脾气,值得逐列看:

★ n=8192:证明比执行慢          164×
★ n=8192:验证比执行快          2.3×
★ 验证做的全部工作              544 次 SHA-256
  证明大小(与 n 几乎无关)       13.9 → 17.1 KB
  验证工作量随 n 怎么长           对数:树高 13 / 14 / 15 / 16
  执行与验证打平的 n(本机)       3591
这一列随 n 怎么长说明
直接执行线性n 翻倍,时间翻倍。天经地义
生成证明n log n要做一次插值、一次 64 倍的求值、一整棵 Merkle 树。它比执行本身还长得快
验证log n34 条路径 × 树高。n 从 1024 涨到 8192,验证时间几乎没动
证明大小log n同上。这就是「简洁」

把执行推到玩具证不了的规模

n = 8192 的时候,验证只比执行快 2.3 倍——听起来不值一提。但那是因为 8192 步的计算本来就只要一毫秒。把执行推大:

光是执行 1e+5 步(不证明)        12 ms
光是执行 1e+6 步(不证明)        95 ms
光是执行 1e+7 步(不证明)       865 ms

而验证那一头呢?
  n = 8192      树高 16,544 次哈希,0.479 ms
  n = 10 亿     树高 33,1122 次哈希,约 1 ms

执行那一列在按线性往上冲,验证那一列几乎是平的。这才是这台机器的意义:它不在小规模上赢,它在大规模上赢,而且赢的幅度随规模无限增长。本机的打平点是 n ≈ 3591 步——超过这个长度,验证一份证明就比亲自跑一遍便宜。

◆ 这是一笔转移,不是一次节约

把三方的账放在一起:

角色没有证明系统有证明系统变化
做事的那个人1 份力气1 + 164 份力气×165
每一个验证者1 份力气0.44 份力气×0.44
N 个验证者时的总账1 + N165 + 0.44NN > 366 时开始划算

所以这门技术的适用范围,是由「有多少人要验证同一件事」决定的。N 很小的时候,它纯属浪费;N 很大的时候,它的收益随 N 线性增长。

这就解释了一个常被问的问题:为什么零知识证明先在区块链落地,而不是在别的地方?因为区块链是人类造出来的、N 最大的那个场景——几万个节点在验证同一件事。第 18 章会把这笔账算完。

诚实地说说我这台玩具

上面那个 164 倍是低估,必须说清楚。我这台只做了完整流程的一部分:

真实系统要做而我没做的大约会让证明者贵多少
FRI 低度测试(第 11 章那个洞)再来 log n 轮折叠,每轮一棵 Merkle 树
约束多项式的组合与商(第 12 章那个 H(x))几次额外的大规模求值
真实的域和真实的安全参数64 位或 256 位的域,而不是我这个 16 位的玩具
零知识所需的掺随机额外的约束和承诺

公开基准里,工业级 zkVM 生成证明的成本大约是原生执行的 10⁴ 到 10⁶ 倍(取决于工作负载和硬件)。也就是说:一个在你笔记本上跑 1 秒的程序,证明它可能要几个小时的 CPU 时间——或者几十秒的 GPU 集群时间。第 21 章会给出 2026 年的具体数字。

证明大小:另一条完全不同的曲线

「证明多大」和「证明多久」是两件事,经常被混在一起:

方案证明大小随计算长度验证成本
我这台玩具(Merkle + 抽查)17.1 KBlog n544 次哈希
典型 STARK45 – 200 KBlog² n几十万次哈希
Groth16128 字节完全无关3 次配对
PlonK约 400 – 500 字节完全无关常数次配对

Groth16 那 128 字节是这门技术最惊人的一个数字:无论你证的是 100 步还是 10 亿步的计算,证明永远是 128 字节,三个椭圆曲线上的点。验证是三次配对运算,几毫秒。

为什么工业界不全用它?因为它要一场仪式(第 15 章),而且换一个电路就要重办一次。这就是第 16 章那张选型表。

⌨ 自己跑一遍

这一章的数字是本机计时,换台机器就变,但三条曲线的形状不会变。你可以在自己机器上把形状跑出来:

import hashlib, time
P, G = 65537, 3
sha = lambda b: hashlib.sha256(b).digest()
# ntt()、lde() 见第 11 章;build()、open_at() 见第 13 章

def bench(n, blowup=8):
    C = [(i * 7919 + 31337) % P for i in range(n)]

    t = time.perf_counter()                       # ① 直接执行
    x, trace = 12345, []
    for i in range(n):
        trace.append(x); x = pow(x + C[i], 3, P)
    t_exec = time.perf_counter() - t

    t = time.perf_counter()                       # ② 生成证明
    ext = lde(trace, n * blowup)
    layers = build(ext)
    t_prove = time.perf_counter() - t

    t = time.perf_counter()                       # ③ 验证 34 次抽查
    root, depth = layers[-1][0], len(layers) - 1
    for q in range(34):
        i = (q * 7919) % (n * blowup)
        assert verify(root, i, ext[i], open_at(layers, i))
    t_verify = time.perf_counter() - t

    print('n=%5d  执行 %7.3f ms  证明 %8.1f ms  验证 %6.3f ms  '
          '证明 %.1f KB  慢 %.0f×' %
          (n, t_exec*1000, t_prove*1000, t_verify*1000,
           34*(depth*32+2)/1024, t_prove/t_exec))

for n in (1024, 2048, 4096, 8192):
    bench(n)

你会看到三件事,而且在任何机器上都成立:(1) 执行那一列严格随 n 翻倍;(2) 证明那一列涨得比线性还快;(3) 验证那一列几乎不动,证明大小每次只多 1 KB 左右。

再做一个实验:把 blowup 从 8 改成 64,看证明时间涨 8 倍、而抽查次数可以从 34 降到 17(第 11 章那张表)——证明大小反而变小。这就是那个旋钮的两端。

python3 bench.py

在线跑:python.org/shell(n 调到 1024 以内)。想看工业级基准,找 ecosystem benchmarks 类的公开榜单,注意看它们用的是 CPU 还是 GPU 集群——差别在两个数量级。

▸ 在现实里
  • 以太坊为一个区块生成证明。2025 年这件事要约 16 分钟,2026 年压到了约 16 秒,成本降了 45 倍(以太坊基金会公布的数字)。而验证那份证明只要几毫秒。整整一年的工程投入,全花在了本章这一列上——证明者那一列。
  • 硬件正在被专门造出来干这件事。这个领域已经有专用 ASIC/FPGA 加速器在做 NTT 和多标量乘法(证明者时间的大头)。以太坊 2026 年路线图里甚至写了硬性指标:本地证明设备成本 ≤ 10 万美元、功耗 ≤ 10 kW「证明者成本」已经变成了一个有采购单和电费账单的工程问题。
  • 把它当成一次「压缩」来理解。你压一个视频要几分钟,播放要几毫秒——没人觉得这不划算,因为压一次、播一万次。零知识证明是同一个经济结构,只是倍数更极端:压缩比是「一亿步 → 几十 KB」,而压缩耗时是播放的一百万倍。
  • 反面:不要给「只有一个验证者」的场景上这套东西。你和一个服务端一对一交互,让它验一份证明,总账是 165 份力气对 2 份——纯亏。这个场景该用的是普通的审计日志或签名。这本书里最容易犯的工程错误,就是把它用在 N 很小的地方。
✗ 这个直觉是错的

「zk-rollup 说自己能扩容一百倍,那零知识证明肯定是让计算变快了。」

正好相反:它让计算变慢了几千甚至上百万倍。那一百倍的扩容,来自完全不同的地方——它消掉的是「几万个节点各算一遍」的重复,不是单次计算的成本。

把账摊开就清楚了。原来的总成本是「1 次执行 × 几万个节点」;现在是「1 次执行 + 1 次证明(贵一万倍) + 几万次验证(每次几毫秒)」。贵的那一次被摊到了所有节点头上,于是人均反而便宜了。这是一次典型的「集中付出、分散受益」。

这个误解还有一个更常见的变体:「zk 让隐私变便宜了」。也不对。零知识那条性质在这套机制里几乎是白送的(第 13 章),但整台机器本身极其昂贵。判据是:任何时候看到「zk 让 X 变快了」,先问「快的是谁那一头」——这本书里唯一变快的永远是验证者,而且是以证明者慢几个数量级为代价的。

✓ 结账

这一章的一句话

「简洁」是一次成本转移而不是一次节约:证明者要多付三位数以上的力气,换来每个验证者只付零点几;因此这门技术的价值完全由「有多少人在重复验证同一件事」决定。

下一章讲那 128 字节要付的另一笔账,而它不是算力,是信任。Groth16 那种极短的证明,需要一场仪式来生成参数,仪式过程中会产生一个 32 字节的数——谁留着它,谁就能伪造任何证明,而且没有人能发现。这个数有个绰号叫「毒废料」。2016 年 Zcash 为了销毁它,六个人分散在世界各地,用与网络物理隔离的电脑、拆开的笔记本、事后被砸毁的硬件,办了一场后来被写成纪录片的仪式。