作者:Justin Thaler,a16z研究合伙人;翻译:金色财经xiaozou
自去年夏天的主题论文和Lasso部署开始,到上个月的完全开源的Jolt实现的发布,我们一直都在致力于Lasso Jolt(我们的全新简便的高性能lookup argument和zkVM)技术的研究并取得稳步进展。
与现有技术相比,这一实现显示了Jolt的光明前景,并对SNARK设计中的许多传统智慧发起挑战。自发布以来,我们陆续进行更新,增加了对Rust标准库的支持,整合了来自10多名贡献者的改进,合并了近50个pull请求,并且改进了代码库的模块化性能和可扩展性。
在我们继续增强Jolt的同时,我想回应外界的质疑和困惑,澄清误解,分享我对一些关键问题的看法。我在本文要探讨的四部分内容是:(1)sum-check协议与Binius承诺方案之间的关系,(2)sum-check和lookups在Jolt中的作用,(3)椭圆曲线与哈希,(4)与zkVM相关的预编译。
Commitment schemes通常被视为SNARK的关键组成部分。但还需注意另一个组件的作用也很重要,那就是多项式IOP。例如,多线性多项式的Binius承诺方案是一个重大进步,但它必须与多项式交互式oracle证明(polynomial interactive oracle proof,PIOP)配对,才能证明所提交的数据实际上验证了证明者的声明。
Binius的承诺与使用sum-check协议的PIOP高度兼容。原因很清楚(sum-check依赖于多线性多项式,而不是单变量多项式;FRI-Binius甚至在内部使用sum-check),也很微妙(sum-check PIOP天然地跨任何特征字段运行,这对于充分利用Binius的新性能至关重要)。Binius的承诺与目前最常见的PIOP不兼容,很遗憾,这些PIOP不使用sum-check。
设计一个快速的PIOP需要更多的洞察力,而不仅仅是“应用sum-check”这一句话而已。Binius使用sum-check协议来实现高效的多项式IOP。Binius论文的第4和第5部分致力于设计新的高效的基于sum-check的PIOP,以与承诺方案相结合。
Binius承诺和Jolt的搭配就像花生酱和果酱一样,因为Jolt是目前唯一一个完全基于sum-check协议的zkVM。如今,Jolt使用基于椭圆曲线加密的承诺方案,但将Binius承诺纳入Jolt是我们工作的重中之重。
是什么让Jolt与众不同?是因为Jolt是第一个(也是目前唯一一个)专门使用基于sum-check的多项式IOP的zkVM,还是因为Jolt实现了lookup奇点(几乎所有的事情都是通过lookups而非约束(constraint)系统或电路来完成的)?答案是,两者兼有。与之前的zkVM相比,Jolt的大部分的简洁性优势都来自于lookups,而它的性能优势来自于lookups和sum-check的使用。
单纯的lookup方法对于某些指令(没有非常小的电路的指令)更好些,但是对于具有非常小的电路的其他指令可能要更差。但总的来说,单纯的lookup方法对性能来说只有好处没有坏处,至少在处理256位字段时如此。如今,Jolt prover投入20%的时间在“指令执行”lookup上,40%的时间用于验证约束信息。添加更多约束来减少lookups是没有任何帮助的。
大概说来,Jolt使用lookups来实现CPU获取-解码-执行循环的“获取”和“执行”部分。这些lookups速度足够快,以至于prover的大部分时间都用于证明它运行了“解码”,这是通过传统的约束来处理的。
单纯的lookup方法还会促进更简洁、更可审计的实现。这些好处很难被量化,需要时间才能被看见和认可。但在代码行数(Jolt代码库约为2.5万行代码,比之前的RISC-V zkVM少2到4倍)和开发时间等方面,Jolt表现出色。这样的改进要比性能上的改进难得多:虽然我预计zkVM prover在未来几个月的速度将比2023年8月差不多快百倍,但很难想象zkVM的代码行数什么时候能减少10倍。
公共话语低估了拥有针对椭圆曲线的快速zkVM的好处,部分原因是大家普遍对基于哈希的承诺方案(如Binius)热情满满。
在证明关于椭圆曲线加密的声明时,基于曲线的zkVM可以避开非原生字段算法,而非原生字段算法会增加成百上千倍的证明时间开销。这些应用包括很多数字签名(与区块链轻客户端和基于SNARK的桥接相关的主要工作)的证明,Plonk/Groth16/Nova/Honk证明的聚合,以及Verkle树认证路径的证明。
我乐观地认为,社区将关注基于sum-check的PIOP与FRI-Binius承诺方案的结合,将其作为在许多应用程序中执行SNARK的正确方法。即使发生这种情况,基于曲线的快速SNARK仍然有用,除非这个世界完全弃用椭圆曲线加密(例如,在社会完成从非量子安全的加密系统转移之后)。
小结:
基于曲线的承诺与目前的所有其他zkVM相竞争(所有现存其他zkVM都已经使用哈希承诺方案处理小字段)。
在证明关于椭圆曲线的声明时(至少在证明非原生字段算法没有重大进展的情况下),人们会想要使用结合曲线的Jolt。
作为一个纯zkVM,Jolt和Binius相结合的承诺将比其他替代方案快很多,除非是证明关于曲线的声明或小字段证明(在这种情况下,人们将使用结合曲线的Jolt),否则人们将使用Jolt和Binius相结合的承诺方案。
在将证明发布到链上之前,基于椭圆曲线的SNARK将继续用于压缩证明大小和验证者成本。在这种情况下,处理大字段的zkVM将发挥作用。即使在今天,人们认为基于哈希的zkVM项目实际上是使用在BN254曲线上定义的zkVM作为递归过程的一部分。
关于预编译及其在zkVM和基准测试中的作用已存在一些讨论。在我进行解释之前,先来解释一下什么是预编译应该会有所帮助,因为预编译这个词的含义在不同的上下文中有所不同。
在以太坊虚拟机(EVM)中,预编译是一个经常执行的操作,并且受原生支持以提高效率。这就避免了通过冗长的EVM操作码序列执行这些操作所带来的大量开销和过高的gas成本。
“EVM预编译”和“初始指令”(操作码)之间的区别主要是语义上的区别。例如,Keccak哈希函数是一个EVM操作码,而SHA-2则是EVM预编译。预编译和操作码都是经常执行的操作,以太坊出于相同的目的对它们提供原生支持:优化效率和gas成本。不可否认,预编译是EVM的一部分,EVM通常用于广泛地描述以太坊执行环境,包含的不仅仅是操作码。
如果EVM的功能与操作码基本相同,为什么还要有预编译呢?主要在于惯例问题。另一个可能的原因是,预编译由相对复杂的操作组成,比如将来可能需要更改的加密原语,如果它们没有分配操作码,则将来更改起来会更容易一些。
在zkVM设计中,预编译是指针对特定函数(如Keccak或SHA哈希)或特定一组椭圆曲线操作的具有特殊用途的SNARK。如今的SNARK预编译通常是通过手动优化的约束系统来实现的(尽管随着社区转向基于sum-check的SNARK,这些约束系统的性质以及它们被证明的方式将会改变)。
EVM预编译器zkVM预编译之间具有深度相似性。在Jolt发布之前,zkVM通过手动优化的约束系统实现初始指令,每个指令一个,就像它们实现预编译一样。所谓的zkVM预编译和所谓的初始指令之间的区别纯粹是语义上的。他们之间没有实际的区别。
在Jolt中,我们使用lookups来实现初始指令,而不使用传统的约束。但是选择通过约束来实现一些初始指令并没有什么大问题。(事实上,lookups甚至可以被视为一种约束。)实际上,正如我之前说过的,一旦我们转向Binius承诺方案,我们可能不得不使用传统的约束来实现RISC-V的加法和乘法。
有了这些背景了解,下面我来谈谈我对预编译的看法,因为它们与zkVM和基准测试有关。
首先,在没有预编译的情况下对各种RISC-V zkVM进行基准测试正是对RISC-V zkVM进行基准测试的意义。“zkVM”一词是一个非正式的叫法,因此必然产生分歧,但在我看来,具有一个或多个预编译的RISC-V zkVM不再是RISC-V的zkVM:它是基于RISC-V的新指令集的zkVM,将每个预编译添加为初始指令。至少,添加到zkVM的每个预编译都会削弱zkVM范式的价值主张——每添加一个电路都会增加潜在的bug表面积,并且现有程序将无法开箱即用地利用这些新的预编译。
有些人还将zkEVM的EVM预编译概念与zkVM的预编概念混为一谈。但这是两个截然不同的东西。虽然zkEVM的一些关键操作——比如Merkle哈希和数字签名验证——确实比初始的RISC-V指令更复杂,但这并不能改变EVM预编译和初始EVM指令之间没有功能差异这样一个事实。zkEVM必须支持EVM预编译,以声明与EVM对等。换句话说,不支持EVM预编译的zkEVM不同于像Jolt这样的RISC-V zkVM,后者将使用预编译扩展RISC-V以外的指令集。
另一个问题是如何选择一组“公平”的函数来对zkVM进行基准测试。但是对于RISC-V zkVM来说,任何函数集都是公平的。Prover时间几乎完全取决于RISC-V CPU运行的周期数,原因有两点。首先,prover在“获取-解码-执行”循环的“执行”部分花费了一小部分时间。其次,不同的RISC-V指令,以及内存访问,证明时间都高度相似。(在Jolt中,它们都是通过离线内存检测技术来处理的。)
最后,如果使用预编译,Jolt的表现可能不会比其他替代方案差。事实上,我预计它会表现更好,因为基于sum-check的预编译将是最快的,并且可以集成到Jolt中而没有开销,因为它专门使用了基于sum-check的PIOP。在这一点上,有些人担心使用椭圆曲线承诺方案的预编译将比使用基于哈希方案的预编译差很多。如今,Jolt使用曲线,但这并不是必须的,我们一直对转向Binius的计划持开放态度。
我们进行基准测试的主要目标是确定不同证明系统的内在性能情况,在某种程度上,它们可以与它们的实现拆分开。这种方法使社区能够理解并聚焦于设计高性能且安全的SNARK的正确技术。但是,当试图比较两个不同的SNARK时,数不尽的混淆因素往往导致不可能进行严丝合缝的对比。
工程方面的努力是这些混淆因素之中的一个,尽管社区中的许多人似乎持对立观点。想法似乎是这样的:如果一个项目添加了“特性”,比如针对特定硬件的预编译或进行了优化,那么它应该在任何基准测试中都拥有“荣誉”表现。
两种观点都有其可取之处。但长远来看,后一种观点显然站不住脚。新方法在任何基准测试中都将永远处于劣势,因为那些新方法没有与旧项目可比的时间。这样的观点是对进步的阻碍。
随着时间的推移,我预计基准测试相关的混淆因素将减少。随着SNARK的开发工具的成熟,SNARK获得良好的性能所需的工程方面的工作量将变少。zkVM的成本主要取决于周期数,而不是任何特定应用程序的特性,这是一个小小的奇迹(至少对于RISC-V如此)。如果人们关注约束系统的选择(而不是今天的R1CS、AIR、Plonkish等碎片化状态),针对约束系统的SNARK可能也会出现类似的情况,使用约束系统大小的简单度量方法来代替周期数。
在此之前,很难在混杂因素控制不足和过度控制之间取得适当的平衡。分歧是不可避免的,而建设者们将必须提供任何一个基准背后的全部背景、细节信息和基本原理,以便社区能够理解和探讨。
来源:金色财经