把计算变成查表:Jolt 式 zkVM 用查找参数与内存检查替代写电路 图 1
把计算变成查表:Jolt 式 zkVM 用查找参数与内存检查替代写电路 · 图 1

给虚拟机做零知识证明,主流做法是把计算”写”进算术电路:程序里每一次运算都对应电路里的门,证明者对着电路生成证明。这条路有效,但工程上意味着开发者要么手搓电路,要么维护一层复杂的编译栈。Jolt 代表的另一条路几乎不建模计算本身——把虚拟机执行看成对查找表的查表操作,用查找参数(lookup argument)说服验证者”这些查表都是真的”。本文按官方仓库与其引用的论文,拆解这种 zkVM 的机制与位置。

从”算给验证者看”到”查表给验证者看”

虚拟机的指令集天然就是一张表:给定操作码与操作数,结果是什么,表里都写得下。查找奇点(lookup singularity)一词来自引用论文《Unlocking the lookup singularity with Lasso》提出的愿景——足够高效的多表查找论证可以让一切计算都归约为查表。Jolt 的名字就是 Just One Lookup Table 的缩写,官方仓库自述为面向 RISC-V 的 zkVM:编译器把程序编译成 RISC-V 指令,证明者不再为每条指令搭电路,而是把执行轨迹整理成若干查找关系,指令语义本身成为固定可复用的查找表,换程序不用换证明系统。

内存与寄存器也不能白拿:离线的内存检查

机制示意

查表只覆盖指令语义,还得回答”这条指令读的寄存器值确实是上一条指令写进去的”。官方 README 列出的论文清单里,《Twist and Shout: Faster memory checking arguments via one-hot addressing and increments》给出的就是这类内存检查论证:给每个寄存器地址配一串单调递增的标记,读取时证明”我读到的这个值挂着正确时刻的标记”。写一次、读多次的语义被压进一条不变式——写标记跳一步,之后的每次读必须落在当前标记上,任何乱序读写都会破坏递增性而被随机查询逮住。配合 sum-check 协议逐层核验查找关系,验证者不需要重放执行,只需做少量随机点查询。这就是所谓”离线内存检查”思路:把内存一致性问题从电路里拿出来,用专门的轻量论证解决,寄存器文件与内存不再是证明系统的负担,只是查找表的一种。

与电路路线的差异在哪

对比已经写过的手写电路与指令级建模路线,差异集中在三处。一是可复用性:指令查找表与程序无关,一次构造全网通用;电路则常随应用逻辑变化,程序改一行,算术化就要重来一轮。二是开发者接口:Jolt 走的是标准 RISC-V 工具链,Rust 或 C 编译出的普通程序重新编译即可进入证明,不要求作者懂算术化,也不需要专门的电路描述语言。三是证明系统的重心转移:验证成本从大电路上的多项式承诺验证,转向 sum-check 交互与内存论证的随机查询,验证者始终不需要重放执行本身。

代价也要摆出来。查找表覆盖整条指令集后,表的规模与稀疏性直接决定证明开销,稀疏表上的高效论证正是 Lasso 及后续论文迭代的主线;内存检查要在有限域里给每个地址维护单调标记,域大小与寄存器数量的权衡会成为新的性能瓶颈;RISC-V 上的浮点、系统调用与内存映射外设能否被完整、语义正确地建模,决定了一个真实程序能不能被证明执行。评估任何 zkVM 时值得逐项核对:指令集覆盖、是否可信初始化、证明延迟、递归支持,以及最容易被忽略的——内存与 I/O 语义如何被证明。

位置与阅读建议

Jolt 是开源项目,官方 README 自注仍处于更新阶段,参数与接口以当前代码为准;本文描述的是其论文层面的机制骨架,不代指任何生产链的采用状态。查找范式并不孤立:它建立在 sum-check 协议、多表查找论证与内存检查这条论文链上,读代码前把这三块补齐,比逐行啃实现更划算。对只想用 zkVM 的团队,决策变量通常是生态兼容性与证明成本,而不是范式之争——两条路线都在快速收敛,静态结论容易过期。本文内容为机制解释,不构成投资建议。