各种零知识虚拟机的对比
ChainWeaver zkEVM对比各常见的虚拟机:
虚拟机 | 兼容性 | 实现方案 | 技术路线 |
---|---|---|---|
ZKsync Era | 与高级语言兼容 | 自定义中间字节码、自定义基于寄存器的虚拟机、证明自定义虚拟机上执行字节码的正确性 | STARK, FRI, PLONK-style arithmetization |
Polygon zkEVM | 与EVM几乎兼容 | 自定义汇编代码、自定义虚拟机、证明自定义汇编代码执行的正确性 | eSTARK, FRI, FFLONK |
Scroll | 与EVM兼容 | 针对EVM大部分操作码的计算步骤以及状态改变设计通用证明电路来证明交易执行轨迹的正确性 | Halo2, KZG, Plonkish arithmetization |
Zeth | 与以太坊兼容 | 将EVM编译为RISC-V机器操作码、使用RISC Zero zkVM来证明RISC-V操作码执行的正确性 | STARK, FRI |
ChainWeaver | 与EVM兼容 | 针对EVM大部分操作码的计算步骤以及状态改变设计通用证明电路来证明交易执行轨迹的正确性 | Halo2, KZG, Plonkish arithmetization |
ChainWeaver与Zeth对比
ChainWeaver与Zeth,二者实现的原理不同,相应的性能也有差异。
虚拟机 | 机器 | 聚合度 | 生成证明耗时 | 验证证明gas消耗 |
---|---|---|---|---|
ChainWeaver zkEVM | 64核CPU、256GB内存 | 1 | 4025(second) | 432692 |
Zeth | 64 × (4核CPU、16GB内存 + 1核GPU、24GiB内存) | 12 | 2963(second) | 245129 |
当前表格中Zeth采用数据来源自Zeth官网。ChainWeaver zkEVM运算使用的是单机CPU,优点是部署简单,硬件成本较低。如何使用GPU的加速能力、如何使用较低配置的硬件集群进行运算也是我们的未来的工作方向。随着项目的迭代,相信两种虚拟机性能都会有提升。
ChainWeaver和Scroll对比
ChainWeaver和Scroll都是针对EVM操作码的计算步骤以及状态改变,设计通用证明电路,证明交易执行轨迹的正确性。二者整体思路相似,但具体到电路设计有所不同,由此也带来了相应的性能差别。以下表格为在同一机器上(64核CPU、256GB内存),运行相同的交易执行轨迹的结果列举。
虚拟机 | 度数(反映电路的行数规模) | 生成证明耗时 | 验证证明耗时 |
---|---|---|---|
Scroll zkEVM | 19 | 1906.934(second) | 355.071(millisecond) |
ChainWeaver zkEVM | 19 | 1603.769(second) | 470.817(millisecond) |
比较下来,ChainWeaver 生成证明的时间大约提升15%,验证时长较Scroll多耗费了大约34%(但仍然在0.5秒以内,并未形成量级上的延迟)。之所以有如此表现,在于ChainWeaver zkEVM针对具体电路的设计。
ChainWeaver zkEVM设计亮点
为处理智能合约执行的每一步,设计了Core子电路。
-
定义了执行状态,针对复杂的操作码将其拆分为多种执行状态的组合来对应多个执行步骤。这样设计的好处是可以让每一个执行状态尽量的简单化,便于处理和复用。举个例子,比如对
Log0
、Log1
这两个相似的操作码,我们可以将其分别拆分为以下执行状态序列:[LOG_BYTES, MEMORY_GAS, LOG_GAS, LOG_TOPIC_NUM_ADDR]
和[LOG_BYTES, MEMORY_GAS, LOG_GAS, LOG_TOPIC_NUM_ADDR, LOG_TOPIC]
。前四个状态依次处理Log数据的拷贝,memory相关的gas计算,Log操作最终的gas花费,Log数据地址的计算;LOG_TOPIC
则负责处理TopicHash的计算。这样二个相似的操作码共享了大多数状态,做到了状态的复用,而每一个执行状态又足够的简单有效。 -
动态选择器(Dynamic Selector)的设计。针对不同的执行状态,需要不同的约束。因此需要设计一个电路组件能根据若干advice列来控制N中执行状态的约束。按当前设计,我们可以做到仅使用
2\sqrt(N)
个输入变量完成N种执行状态的约束。 -
每个执行状态使用了多行、多功能列的设计来减小电路的列数,缩减电路规模。计算中所需的状态、变量等都存放到多功能列中以重复利用列。每个执行状态可能会使用多个行来处理更多的数据。比如我们的动态选择器就位于每个执行状态的第0行的多功能列中的0-17列来标识当前的执行状态。我们的aux辅助变量则位于每个执行状态的第0行的18-24列。又比如第1行通常用于存储操作数及其属性,继而可以作为来源到state子电路去做lookup。对每一个执行状态的每一行的每一个格子都做到了按需使用布局,在满足运算需求的同时尽量节约行数。
-
在Core电路中汇总所有执行状态的lookup,而不是每个执行状态分别去做lookup了,从而减少lookup的开销。设置了一个feature叫
no_lookup_merge
,不开启时,所有执行状态产生的lookup将会被汇总、分类、合并,最终产生少量的lookup,这样就减少了lookup的开销。
Arithmetic子电路用来处理(模)加法、减法、(模)乘法、(模)除法、有符号数比较、有符号除法取余运算,也支持长度判断(length)、内存拓展(memory expansion)、以及是否u64越界的运算。
- 当然我们可以在Core电路中执行数学运算的操作码所对应的执行状态中来做数学计算,但是那样的话就需要每个执行状态都要去做大量的u16的lookup。这样做是不经济的。统一在Arithmetic算术子电路中进行处理能大量减少lookup的开销。同时可以保持Core电路中处理数学运算的执行状态的简洁。举个例子,比如EVM有个
ADD
的操作码,其对应的Core电路中的执行状态为ADD_SUB_MUL_DIV_MOD
。这个执行状态中只需要关注操作数、计算结果、gas消耗等的正确性,而整个加法计算过程的正确性则交给了Arithmetic电路,仅需要根据(tag,[operand_hi_0,operand_lo_0,operand_hi_1,operand_lo_1,operand_hi_2,operand_lo_2,operand_hi_3,operand_lo_3])到Arithmetic电路中lookup验证查询即可。Exp计算幂指数电路也是同样的逻辑,相关数学计算的正确性都交给了Arithmetic子电路,仅在需要的时候通过lookup确认正确性即可。
附录(各常见的零知识虚拟机简介)
ZKsync Era
ZKsync Era是由 Matter labs 团队于2020年推出的零知识虚拟机。这一方案将Solidity语言编译为中间语言Yul,然后使用LLVM将中间语言Yul进一步编译为一套自定义的、和零知识证明电路兼容的字节码,然后在自定义的基于寄存器的虚拟机(ZKsync Era VM)上执行;设计相应的电路来证明自定义虚拟机上执行的字节码的正确性,从而实现对智能合约的零知识证明。由于这类方法将高级语言转化为零知识友好的语言并在专用的虚拟机上执行,其具有很好的性能表现,但这也导致了其与现有部分以太坊应用不兼容。
Polygon zkEVM
Polygon zkEVM是由 Polygon 团队于2021年推出的一款zkEVM。其使用了一种“基于操作码的方法”,将EVM的操作码直接转化为一组新的汇编代码(而非从高级语言层面开始转化),并生成新的汇编代码(即zkASM)在自定义的虚拟机上执行正确性的证明。之所以这么设计是想优化EVM解释,减少约束数量并直接证明EVM。核心挑战是在自定义虚拟机中重现每个EVM操作码,以便快速将EVM字节码转换为可验证格式。相比ZKsync,该方法与EVM具有较高的兼容性,但性能有所降低。
Scroll
Scroll由Zhang等人于2022年推出,此zkEVM项目采用了证明EVM执行轨迹的方法,直接针对EVM操作码的计算步骤以及对状态的改变(如栈、内部存储和外部存储的读写)设计通用的证明电路。这类方法能够准确地反映EVM,实现了和EVM的完全兼容;但尚未实现与以太坊的完全兼容。
Zeth
Zeth是 RISC Zero 团队在RISC Zero zkVM之上,针对以太坊的推出的开源零知识区块证明器。原理是将EVM的Go或Rust语言实现编译为RISC-V操作码,然后使用RISC Zero zkVM来证明RISC-V操作码,从而证明某特定以太坊区块的有效性。