给一段程序生成零知识证明,听起来像一锤子买卖:程序跑完,证明出来。真正做过证明工程的人会告诉你,大程序的证明从来不是单个对象,而是一串分片证明折叠后的产物。SP1 这类 zkVM 把这条流水线摆得很直白:执行轨迹切成多个分片,每个分片单独出证明,最后递归折叠成一个提交物。看懂分片证明,才算看懂 zkVM 是怎么把一台机器的负载分给一段一段的算术承诺的。本文以 Succinct 官方文档 v6.0.0(Hypercube 证明系统)版本的记载为准来拆解这条链路。
先讲直觉:为什么一次执行要拆成多个证明
zkVM 的基本思路是把程序的每一步执行写进一张巨大的表:每一行对应一个时刻,每一列对应一个寄存器、内存单元或指令字段。验证者要做的事,是检查这张表满足两条性质——相邻行之间的状态转换符合 RISC-V 指令语义,以及同一时刻不同部件访问的是同一份全局内存。程序一长,表就跟着长,可能达到数百万甚至更多行。如果对整个表做一次性承诺,多项式的次数与轨迹规模同阶,无论生成还是递归验证都会越来越吃力。分片的动机由此而来:把大表横切成若干固定规模的段落,每段叫一个分片,各分片独立生成证明,把大问题的规模压回到与分片大小相关的常数级。
一个分片证明内部长什么样

按官方文档对 Hypercube 分片证明的描述,每个分片证明主要做三件事:先生成该分片的计算轨迹;再生成支撑证明所需的辅助数据,文档里称之为 witness;最后证明这份 witness 满足一组约束,这些约束同时对着两头——一边是 RISC-V 规范定义的指令语义,另一边是全局内存的一致性。轨迹在逻辑上按指令分表:ADDI、MUL、LSHIFT 各有各的表,表的列就是验证该指令被正确执行所需的全部操作数。Hypercube 是一个基于多项式的交互oracle证明系统,它不再像早期版本那样为每张表的每一列单独做承诺——那样递归成本会随列数线性膨胀——而是把整条轨迹拼接成一个多项式做一次承诺,再用一个名为 Jagged PCS 的适配层,把对单列的查询转换成对整体多重线性扩展的查询。分片与分片之间靠全局内存约束互相咬合:A 分片写入的单元,B 分片读取时必须读到同一个值,折叠阶段会核对这些跨片声明。
分片列表如何折叠成一个提交物
SP1 的文档把证明分成几档。默认的 core 模式输出的就是一串分片 STARK 证明,总体积与执行规模成正比,适合不关心验证成本的离线场景。compressed 模式则沿着递归路径把这些分片证明两两折叠,最终得到一个常数大小的 STARK——无论你原始执行跑了多少个分片,压缩证明的大小不再变化。再往下,Groth16 模式在压缩证明外面再套一层 SNARK 包装,产出约 260 字节的证明,文档标注链上验证开销约 27 万 gas;PLONK 模式产出的包装证明约 868 字节、约 30 万 gas,生成时间比 compressed 多一分钟左右。需要说明两者的信任前提差异:官方文档写明 Groth16 电路密钥的可信初始化沿用了 Aztec Ignition 仪式并叠加团队成员贡献的熵,而 PLONK 一档按文档表述不需要额外可信初始化。对不想接受任何仪式假设的集成方,这一档差异就是选型的分水岭。
对使用者意味着什么
把上面串起来看:程序越长,分片越多,生成阶段近似线性变慢,但折叠后的证明大小和链上验证成本几乎纹丝不动。这就是 zkVM 能同时接住轻负载桥验证和重量级虚拟机一致性检查的原因——规模压力被吸收在证明生成端,而不是暴露给以太坊验证合约。运维上值得留意的两件事:其一,分片让证明生成天然可并行,多卡拆分片是常见提速手段,但折叠路径是串行的收口点;其二,从 core 到 compressed 到 Groth16 是三级台阶,先本地验证折叠正确,再谈上链。本文是机制说明,涉及的性能与开销数字以官方当版本文档为准,不构成任何投资或选型建议。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。