关于Jolt初始实施的常见问题解答

本文介绍了a16z的Jolt项目,这是一个新的SNARK设计方法,已实现比当前技术快2倍,并探讨了其性能、架构以及未来发展。文中详细比较了Jolt与其他zkVM的性能优缺点,尤其是在指令集架构和承诺方案方面的不同选择及其对项目的影响。

Today, a16z crypto research and engineering teams released an initial implementation of Jolt , a new approach to SNARK design that is already up to 2x faster than the state of the art, with more improvements still to come. See this post for a high-level overview to this body of work, as well as this post for benchmarks and code, and this post for technical specifics about Jolt’s architecture and performance.

下面,我将详细讲解 Jolt 的技术细节,比较它的架构和性能与现有 zkVM 的不同之处,并讨论未来的开发计划。

分类 1: Jolt 的性能

1. Jolt 和 sum-check 协议的哪些好处未被初始实现的原始速度数据所捕捉?

开发者好处。 由于 Jolt 实现了查找奇点,向 Jolt 的 VM 添加新的原始指令相比于其他 zkVM 设计方案要简单得多。

在大域上工作的好处。 尽管付出了使用 256 位域的 prover 时间,Jolt 已经是迄今为止最快的 zkVM。(大多数其他项目使用 31 位或 64 位字段。)作为已经支付这笔成本的回报,Jolt prover 获得了以下好处:

  • 更便宜的折叠递归 . 如今,许多 zkVM 使用续发,这意味着它们将计算机程序的执行拆分成多个块(有时称为“分片”),并独立地证明每个块,然后将证明递归汇总为一个。没有续发的情况下,除非计算机程序很小,否则 prover 空间成本会变得不可承受。

使用曲线基础承诺的 SNARKs 可以通过 折叠 方案 实现非常高效的聚合。结果是,尽管 Jolt 目前尚未实现递归,但它相对 SP1 项目更少受到递归的开销影响(SP1 也没有完全实现递归,尽管为了这个目标已经取得了 部分进展)。 (详见下面的 #22。)

  • 即使没有递归也有用。 目前 Jolt 的证明大小为 3-10 MB,但一旦我们添加对其他基于曲线的多项式承诺方案的支持,如 Zeromorph (详见下面的 #2),其大小将下降到仅仅几十 KB。 使用 FRI 和“扩展因子”为 2 的 zkVM,如 SP1,无法在没有递归的情况下实现小于 500KB 的证明。与 Jolt 不同,基于 FRI 的 zkVM 涉及超线性时间程序,如 FFT,当 zkVM 直接应用于大计算时,这会成为 prover 的瓶颈。
  • 当转向 64 位数据类型时的开销更小 . 由于 Jolt 的当前实现已经支付了 256 位域的费用,因此可以在单个字段元素中表示 64 位值,甚至可以在不溢出字段模数的情况下降乘两个 64 位值。这意味着 Jolt 一旦扩展支持 64 位数据类型,每个指令的速度将不超过处理 32 位数据类型时的 2 倍。因此,随着转向 64 位数据类型,Jolt 相比今天的 zkVM 的加速效果将更显著。

小字段的性能好处仍然有待实现。 如我在 我另外一篇文章 中提到的,我们将从基于曲线的承诺切换到基于哈希的承诺方案 Binius,从而为 Jolt 带来至少 5 倍的加速(详见下面的 #4)。

这个切换 适用于基于 sum-check 的 SNARKs,这些 SNARKs 使用多线性而非单变量多项式。例如,Binius 承诺方案利用了对于多线性多项式评估查询的“张量结构”,这一结构在拉格朗日基上的单变量多项式中不存在。 在拉格朗日基上工作对于 Jolt 的性能至关重要,因为它确保了 SNARK prover 仅承诺小值,从而避免了成本高昂的基变换操作。

Binius 上周 进展甚至更快,Diamond 和 Posen 将其证明大小从承诺多项式数量的平方根降至多对数。

更具性能的预编译。 今日的 zkVM 部署大量使用预编译。 基于 sum-check 协议的预编译尤其高效。例如,Binius 论文 描述了一个基于 sum-check 的 SNARK 用于 Keccak 和其他标准哈希函数,我预计它的 prover 性能比其他方法快得多。 此类预编译最有效地融合到像 Jolt 这样基于 sum-check 的 SNARKs 中。

此外,许多 SNARK 应用涉及证明对椭圆曲线数字签名的知识。如果 SNARK 能够直接在适当的椭圆曲线组的 基础域 上运行,这将极大提高效率,而 Jolt 使用曲线基础承诺正好可以做到(详见 我之前帖子 的 #14 进行更多讨论)。

未来优化。 Jolt 是一种新的 zkVM 设计方法,由两位工程师( MichaelSam)和一位研究生( Arasu)在五个月的时间里实现。 除了我和 Srinath 之外,没有其他人尝试优化协议或代码库,我们也还没有实现所有已识别的 优化。 随着时间和审查的进行,新的改进一定会到来。

2. 为什么选择 Hyrax 作为初始 Jolt 实现的多项式承诺方案?

Hyrax 简单、透明,并且对于 prover 而言速度上也相对合理。特别地,Hyrax 中的展开证明对 prover 来说不涉及 任何 密码学工作,因此我们知道这些展开证明不会成为 prover 的瓶颈。

(更确切地说,我们现在使用的是 Hyrax-commitment 的简化版,该版本并不是零知识的。)

使用 Hyrax 的缺点是它导致验证者成本相对较大。(Jolt 使用 Hyrax 时的证明大小范围从几 MB 到大约十几 MB。)

我们可以将 Hyrax 替换为任何其他适用于多线性多项式的承诺方案。特别是,我们将支持 ZeromorphHyperKZG,这两者都是 KZG 承诺的多线性多项式适配版本。它们具有常数的承诺大小和对数大小的评估证明,验证涉及对 G 1 操作、3 次配对评估的对数数量(Zeromorph 验证器已经在 Solidity 中实现,用于链上验证。Rust 实现的 prover 请参考 这里)。

具体而言,这将产生大约几十 KB 的证明大小,而与当前实现的 prover 时间没有降级。这一证明大小的实现还需要切换到 Lasso 组件中称为 grand product argument 的一部分。 Jolt 目前 使用一个,它的证明大小为 log( n)2。 Quarks 论文第6节 中描述的变体具有大约对数大小的证明,且 prover 时间的增加非常有限。

如若实现不当,Zeromorph 和 HyperKZG 的展开证明可能会成为 Jolt prover 的瓶颈,因为它们要求 prover 承诺随机字段元素。但我们可以将其与 Hyrax 所基于的(标准)技术结合,以降低这一成本,只需适度增加验证者的工作。请参阅 我的书的第14.3节获取(简单)详细信息,这涉及以“较小大小的块”承诺多项式,然后使用同态属性为所有这些块提供一个单独的展开证明。

3. 能否给出 Jolt 的工作原理和 prover 成本的粗略拆分?

一个 VM 会做两件事:

  1. 不断执行其指令集架构的取址-解码-执行逻辑。
  2. 执行对随机存储器 (RAM) 的读写操作。

因此,Jolt 有三个组成部分:

  1. 为了处理每个取址-解码-执行循环迭代的“执行”部分,它调用 Lasso 查找证明。
  2. 为了处理对 RAM(和寄存器)的读/写操作,它使用来自 Spice 的内存校验证明,这与 Lasso 密切相关。它们都基于“离线内存检查”技术,主要的区别在于 Lasso 支持只读内存,而 Spice 支持读写内存,因此稍微更昂贵。
  3. 为了处理每个取址-解码-执行循环迭代的“取址-解码”部分,以及捕获一些 Lasso 本身没有直接处理的额外约束,使用了一个最小 R1CS 实例(大约每次 RISC-V VM 的约 60 个约束)。

为了证明 (3) 中的 R1CS 满足性,我们使用了为约束系统的高度结构化特性优化的 Spartan (例如,R1CS 约束矩阵是区块对角式,其中区块的大小只有大约 60 x 80)。

粗略而言,今天的 Jolt prover 将 25% 的时间花费在 (1) 中,25% 在 (2) 中以及 50% 在 (3) 中。

约 ⅕ 的时间用于计算承诺,而 ½ 的时间用于 sum-check 协议的各种调用。其余时间分配用于如内存分配、见证生成、序列化内存等各种任务。

随着我们继续优化 Jolt,这些比率将会发生变化。

4. 你如何估计切换到 Binius 多项式承诺将带来至少 5 倍的加速?

根据上述 #3,Jolt prover 当前花费大约 1/5 的时间用于计算承诺,½ 的时间用于计算 sum-check 协议中的消息(这主要涉及字段操作:在 sum-check 协议中的内存读写涉及在每一轮中对少量数组的一次流式传输,因此 prover 不会受到内存限制)。这些是 Jolt prover 的核心任务。其余的 30% prover 时间则在大量的“管道”任务中分配,例如内存分配和见证生成(见证生成占 Jolt prover 的运行时间不到 2%)。

切换到 Binius 应该会使计算承诺的时间减少 超过 10 倍

因为 Binius 是在 GF[2128] 字段上工作(而不是像 BN254 那样的椭圆曲线的标量域,这是 Jolt 当前使用的),所以 sum-check 协议中的字段操作成本会大大减少。具体减少的多少取决于硬件,但 Ulvetanna 正在努力确保速度提升显著。例如,在 ASICs 和 FPGAs 上,这可能会达到 30 倍或更多(即使无需引入 算法优化 来最小化 prover 在小特征字段上的工作)。在 ARM machines 上,速度提升也应显著:虽然 Binius 是面向 GF[2128] 的“塔基础”,但 prover 的许多工作可以在 POLYVAL 基础上完成,而 ARM 芯片可支持在该基础上进行快速乘法。

最大的问题是我们可以在多大程度上优化掉管道任务。我们还没有努力去做,因为这些任务目前只占 prover 运行时间的 30%。但在承诺和字段操作的成本下降超过 10 倍或更多后,这些任务将主导,除非进一步优化。由于从 256 位域切换到 128 位域,它们的成本应该至少下降一倍。如果降幅远超该值,我们将获得超过 10 倍的端到端 prover 加速。

最后一个复杂因素是,处理特征为 2 的字段使得 RISC-V 加法和乘法的查找不那么友好。因此,这些操作将由 Binius 论文 中的协议 5.3 和 5.5 提供的专门 SNARKs 处理,而不是通过查找完成。加法的专门 SNARK 是 更便宜的,而不是 Jolt 当前基于查找的方法。乘法的专门 SNARK 要求 prover 承诺比在高特征域上的纯查找方法更多的数据。但这一点将因 Binius 承诺方案本身相较于基于曲线的承诺每个承诺位更快而得到补偿。

5. 随着你向原始指令集添加更多指令,Jolt prover 成本(每个 CPU 循环)是否会增加?

不太可能。只要每个原始指令是可拆分的,Jolt prover 的成本主要取决于 每个指令的输入大小,而不是 ISA 中指令的数量。

这是因为在计算的每一步,正确执行在该步骤被执行的指令是通过查找包含 所有 原始指令的所有评估结果的表来处理的。 此表的大小随着原始指令数量线性增长,但在所用的查找证明(即,Lasso)中,prover 的成本随着表大小的增加 极其缓慢

验证者 的字段工作将随着 ISA 中原始指令数量的增加而增加。但由于字段操作的成本远低于密码学工作(如哈希或组操作,验证者都必须执行这些),因此该字段工作对于合理的指令集大小不会成为验证者的瓶颈。

6. Jolt 能否像其他 zkVM 一样受益于 GPU?

我预计可以。例如,Ingonyama 的 sum-check 协议的 GPU 实现 已经完成,且将很快集成到它们的主 GPU 库 ICICLE 中。 ICICLE 已支持 Jolt prover 执行的另一个核心操作,即 MSM(尽管尚未针对 Jolt 的设置进行优化,其中所有 MSM 批量处理的数据都较小)。

当 Jolt 切换到 Binius 承诺方案时,可能会出现一些复杂性。具体而言,要在 GPU 上实现非常快速的 GF[2128] 算法可能会需要一些努力(而根据上面的 #4,显而易见的是,在 ARM 芯片、ASIC 和 FPGA 上可以快速获取该领域的操作)。

随着基于 sum-check 的 SNARK 的实现不断成熟,可以肯定的是,将会出现极其高效的 GPU 实现,正如当前流行的 SNARK 一样。

分类 2: Jolt 在更广泛的 zkVM 生态中

7. Jolt、SP1 和 RISC Zero 之间的关系如何,它们在更广泛的 zkVM 生态中有何地位?

Jolt、SP1RISC Zero 都是面向 RISC-V 指令集架构 (ISA) 的 zkVM。这是一个在设计时并未考虑 SNARK 的 ISA,并且其周围有一个强大的工具生态系统。其他 zkVM 的目标明显是“友好”于 SNARK 的 ISA(尽管我认为这些其他 ISA 的实际友好程度没有 RISC-V 更高)。

SP1 和 RISC Zero 都依赖于应用于 AIR 约束系统的 STARK 后端。这里所说的“STARK”,指的是组合了行数为二的多项式 IOP 和 univariate 多项式的 FRI 承诺方案。 Jolt 基于不同的证明方法:它使用基于 sum-check 协议的多轮多项式 IOP,以及多线性多项式的承诺方案。

更多SP1的细节。 SP1 于2024年2月发布,借鉴了许多项目。它的 Rust 工具链和 SDK 来自 RISC Zero,它的预编译集成架构也是如此。并且它使用来自 plonky3 的 STARK 实现。

简而言之,SP1 的贡献是设计 AIR,以实现每个 RISC-V 指令,以便可以将 plonky3 应用于这些 AIR。 就连这些 AIR 也大幅基于另一个 zkVM 叫做 Valida 的代码:(Valida 针对的是一种受 RISC-V 启发的 ISA,但对其进行了修改,使其在表面上更友好于 SNARK)。

CPU、GPU 和扩展因子。 RISC Zero 通常专注于 GPU 实现:其 CPU 实现似乎并未得到完全优化。 SP1 到目前为止仍然专注于 CPU。 SP1 zkVM 在 CPU 上的性能约为 RISC Zero 的 5 倍。然而,在这 5 倍的加速中,约 1.5 倍来自 SP1 仅使用 FRI 展开因子为 2,而不是 RISC Zero 使用的 展开因子为 4。这使得 SP1 的递归更昂贵,尽管 SP1 当前的基准测试未对这一部分“收费”(因为 SP1 目前尚未完全实现递归)。因此,实际上 SP1 与 RISC Zero 在 CPU 上的加速因子更接近 3,而不是 5。

尽管如此,Jolt 与 SP1 的有利比较显示,Jolt 相对早期 zkVM 的加速并不是由于优化 CPU 而是 GPU,而是证明系统本身的特性。

8. 针对(显然)SNARK友好的 ISA 的 zkVM 存在什么缺点,而等同于 RISC-V 的 ISA 凭什么可以作为对比?

首先,已有的 ISA 可以利用现有编译器从高级语言(如 Rust)到 ISA 的汇编代码。设计新的“SNARK友好”指令集的人必须自行构建其自定义 ISA 的编译器。 不仅这极具挑战性且耗时,同时也引入了大规模的错误风险。

其次,许多“SNARK友好”的 ISA 比 RISC-V 早期实现简单得多(寄存器更少、没有按位操作、限制每个内存单元的写入次数等)。因此,每个原始指令的“有用工作”要远低于 RISC-V 指令。相对于 RISC-V,任何给定计算机程序根据其自定义 ISA 编译时所需的原始指令数量要更多。

除非 SNARK 友好 ISA 中的每个原始指令的证明成本 _确实_低于 RISC-V 指令,否则总的 prover 时间会更高,因为需要证明的原始指令增多,并且每个自定义指令的证明成本与 RISC-V 指令一样昂贵。

Jolt 相对于满意满足自然的“可分解性”属性的 任何 指令集一样快。因此,针对薄弱指令集的目标是非常不利的:它削弱了每个原始指令所做的有用工作的数量,而没有降低调用它的成本。

一个相关的问题是,无论是否实现完整的 zkVM 解决方案,许多项目都引入了新的“SNARK友好”编程语言来暴露给开发者。 这有三个缺点。首先,开发者必须学习新语言,在成为专家之前更容易编写出有错误的程序。其次,所有用于确保任何有价值的事物的程序都应最终进行形式验证以确保其正确性,正如自定义 ISA 需要新的编译器一样,自定义 DSL 也需要新的验证工具。第三,如果围绕自定义语言的生态系统未能蓬勃发展或扩展,则使用该语言构建的任何应用程序都将失效。

总之,zkVM 项目坚持使用自定义 DSL 达成高效编译自显然“SNARK友好” VM 的目标是背负重任的每一种选择。每一个设计决策都是错误——一个糟糕的 VM,运行该 VM 的低效 SNARK,新的高级语言以确保相对 VM 的编译,新的编译器执行编译。每个错误都会增加显著的效率低下,并且有易出错的漏洞。

9. 2023年8月,Starkware 表示 FRI 比基于曲线的承诺方案快 50 倍,尽管 Jolt基本上的数值较小,又如何兼容?

50倍的说法 后来被 修正 为 10 倍。 这个调整是在 批评 之后进行的,因为最初的主张高估了多标量乘法 (MSM) 的成本,调整了 5 倍。

但是即使更新后的说法,还是与 Jolt 使用基于曲线的承诺速度已是迄今为止最快的 zkVM 这之间也大于一个数量级的差距,如何来完成确保的解释?

答案是双重的。首先,这个说法忽视了 Jolt prover 提交的数据比其他 zkVM 少得多。(由于 Jolt 使用 sum-check 协议,所以 Jolt 无法直接利用 FRI,因为 FRI 针对的是单变量多项式,而 sum-check 协议使用的是多变量多项式。)例如,Jolt 每执行一次 RISC-V CPU 提交大约 1200 位的数据,而 RISC Zero 则超过 8500 位。

第二,prover 提交的数据越多,证明这些数据的良好形态所需的工作越多。这些说法并没有考虑到在避免 sum-check 协议的 SNARKs 中大量存在的“非承诺成本”。

总之,StarkWare 的这些说法仅关注在给定数据量情况下的提交时间,而未关注需要提交的数据量及证明这些提交的数据是有效所需的工作量。因此,所谓的 10 倍慢(最初宣称为 50 倍)实际上变成了 加速

10. StarkWare 将“Circle STARKs”描述为一项突破。 Circle STARKs 将改变 Jolt 和基于 STARK 的 zkVM 之间的比较吗?

不会。 Circle STARKs 允许 prover 在“ M31 域”上运行,该域的大小为 231 - 1,计算速度稍快于当前SP1/plonky3 和 RISC Zero 使用的 BabyBear 域。 切换到 M31 域最多也只会改善 prover 运行时间,改进因子的 1.4 倍。

StarkWare 最近 表示 他们预计一种基于 Circle-Stark 的证明系统 Stwo 可在 罕有的 Cairo 虚拟机上,它在速度上约 100 倍快于 Stone prover。但 根据我们的实验,Jolt 已经比 Stone 快 35 倍,而这段时间的 Stone 与运行储存程序中仔细编写的 Cairo-VM 汇编程序相比 Jolt 则是在 Rust 上运行并编译成 RISC-V。

而且,即使是 Stwo 也会在某种程度上整合我所倡导的技艺,作为使用基于 sum-check 的查找证明 应借鉴 Lasso。

不过,所有这些中,Circle STARKs 所寄予的 1.4 倍的加速仅在 STARK prover 操作主要集中于计算的一定条件下才能实现,而不是依赖内存。 Circle STARK 论文 只实现了 FFT,目前的实现依然依赖内存。至今在多线程下并未清楚地展示出性能的益处(见论文附录中的表 1,C 部分)。

11. STIR 将改变 Jolt 与 STARK-based zkVM 之间的比较吗?

不会。STIR 是一项令人印象深刻的成果,在很大程度上降低了在 128 位域的 FRI 证明大小,减少的比例约为 1.5 倍,同时提高的 prover 时间相对较小。然而,它并没有改变这一事实,即(与广泛的观点相反)FRI 和 STIR 以及调用它们的 SNARKs 主要优化的是验证成本,而非 prover 时间。

多项式承诺方案如 Ligero/ Brakedown/ Binius 为 prover 相对于 FRI 和 STIR 具有诸多优势(关于详细信息, 请查看我之前翻译的文章中的 #7 和下面的 #20)。这些优势 除了 实际上 FRI 和 STIR 针对的是单变量多项式,而非多线性多项式,且无法与基于 sum-check 协议直接结合以外。这些都是 SNARK 设计者应使用的多项式承诺方案,以达到可扩展的 prover。同时使用适合多线性多项式的基于曲线的承诺方案与适当的多项式 IOP 结合时,也是快速可行的(正如 Jolt、Nova 在之前所示,尽管有广泛的误解)。

在需要证明较为简单的陈述或通过 SNARK 在链上发布证明之前压缩证明大小和验证者成本时,优化验证者成本的 SNARK 仍将发挥重要作用。

12. Jolt prover 的空间使用情况与其他 zkVM 相比如何?

如今,Jolt prover 的空间使用情况大约是 SP1 的 5 倍。然而,Jolt 的空间使用量将在未来几周减少约 8 倍。

当前在 Jolt 中实现的 Lasso,prover 存储着大量的 256 位字段元素矢量,其中超过 90% 为 1。我们目前为每个矢量元素分配 256 位,即使是 1。 我们可以让 prover 存储这些矢量的“稠密化”表现,即仅存储 1 的项。 一旦我们实现这一点,prover 的总空间将减少约 8 倍,而且 prover 的时间也会稍有减少(例如,可能会下降约 10%)。

长期来看,我预计 Jolt 的空间使用量将在未来 降低 10 倍,而对 prover 的时间几乎没有影响。 这一空间上的改进将来自两个方面。 首先,切换到 Binius 承诺方案将有效降低存储向量成本(任何字段元素的最大大小将从 256 位减少到 128 位,而 Jolt 中产生的许多字段元素将落在更小的子域范围内,因此用更少的位进行表示)。第二,一直以来都被 认知 知道这一点,有一些相对空间高效且适用于 sum-check 协议证明人与各种 多项式 承诺 方案。在大特征域的改进会以对 prover 时间的对数影响增大,但是在小特征域(Jolt 切换为 Binius 之后将用到的领域),对 prover 时间的影响似乎相对比较小 明显 便是。

13. 以前对现有 zkVM 的 prover 开销估计有时低至 100,000,你是如何解释这一点以不冲突于你认为超过 500 万的估算的?

正确的方法是根据情况来测量 zkVM 的 prover 开销。在最广泛的情况中,最有意义的度量方法是证明的 CPU 时间与计算的 CPU 时间之比。根据该衡量,现有 zkVM 的 prover 开销为 500 万及以上。

在区块链可扩展性的特定上下文中,影响因素是证明程序执行的货币成本与在链上运行相同程序的成本之间的数量关系。 由于证明工作完全是集中的,prover 可以在 GPU 集群上运行,而区块链节点运行在 CPU 上。

因此,有些人通过对 zkVM prover 在 GPU 上的运行电能成本进行报告(规范化为在 CPU 执行程序的电能成本)来估算现有 zkVM 的 prover 开销。这导致的估算会低至 100,000。

这个数字并非错误,但重置出现在集中证明服务对区块链可扩展性的问题上。在实质上的其他情况下,500 万才是相对计算的更多工作。

分类 3: 预编译

14. 关于预编译有什么需要我注意的?

所有 zkVM 都给 prover 引入了巨大的性能开销。例如,我估算当前版本的 Jolt 约 Sixtyfold(约 500,000 倍)速度比未生成有效校验证明直接运行的 RISC-V 程序要慢(详见 我的解读文章)。

就性能而言,手动为特定计算(如 SHA2 或 Keccak 评估、验证椭圆曲线数字签名)设计协议通常比编写 Rust 程序、将其编译为 zkVM 的汇编语言并证明 zkVM 执行的正确务实得多。

这些专用协议被称为预编译(也称为“内置”或“设备”)。

因此,为了最大化性能,每个 zkVM 都应针对 SNARK 应用程序中反复出现的操作使用预编译。截至目前,这几乎也是在大多数场景中,性能可以接受的唯一途径。

但依赖于预编译也有重大缺点。例如,今天的预编译都是根据手动指定的电路或约束系统(在 SP1/plonky3、RISC Zero 或 Cairo 的情况下为 AIR)。这正是 zkVM 希望消除的过程,这一过程常常充满出错和时间消耗。

将有非常强烈的趋势,倾向于依赖预编译来掩盖 zkVM 具有的巨量性能开销。但这可能会把我们拉回到目前所处的状态,伴随着随处可见的安全漏洞与数以千计的人力资耗费在实际约束规范的操控上。

从长远来看,zkVM 将快速增长,以致于在许多应用中完全避免预编译的范围将会产生。有关大多数应用的所有应用的强烈利益份额将持续存在,并且这些应用将被正式审核以确保其正确性。 这与新一代的 CPU 新添加的原始指令以加速常见加密操作的情形是非常类似的。

这些普遍的预编译将包括一些哈希函数与数字签名算法,以及在特定应用领域中,例如流行非线性和机器学习应用的矩阵乘法等常见操作。

15. SP1 宣称在 CPU 上的速度最高可提升 28 倍相对 RISC Zero。那么 Jolt 如何能够在速度上超260倍于 SP1,却仅最高 6 倍地比 RISC Zero 更快?

SP1 报告 相对 RISC Zero 的加速为约 4 倍到 28 倍,具体取决于基准测试。然而,任何超过 5 倍的加速并不是由于 zkVM 的改善,而是加权预编译的效果。预编译的改进与 zkVM 的进步不对立,每个位 에 iyi zkVM 都得其益处。所以例如,RISC Zero 同样能从 SP1/plonky3 中的更佳预编译直接受益,就如 SP1 其自身能从中获益一样。

我们的基准测试旨在评估 zkVM,因此排除了预编译的使用。 (此外,将 Jolt 扩展为支持预编译是近期的工作,详见下文 #16)。

从长期来看,基于 sum-check 协议的预编译将最快,并且这些与基于 sum-check zkVM(如 Jolt)结合最为紧密。此类预编译的典型例子是 由2013年Thing提供的超高效的 sum-check 基础协议 或来自 zkCNN 的 FFT 例子。 另一个例子是来自 Binius 论文 基于 sum-check 的 SNARK,待这一点完全优化,预计其产品将远超现有最优证明方案(作为起点,该实现已是 Keccak 预编译 的 2 倍快,后者来自 plonky3,并且仍存在实力不足的提升)。

除了以上讨论的内容外,自从 SP1 的初步发布后,RISC Zero 在 CPU 上的速度已经基本改善约 2 倍(推断出改进的总结见 此处)。

16. 你计划如何将预编译集成到 Jolt?

将预编译整合至 Jolt 对于实现开发者的采用来说至关重要,因为今天所有 zkVM(包括 Jolt)没有预编译的性能都太慢(尽管 Jolt 没有 预编译的情况下感觉已经比大多数现有 zkVM 更快)。The simplest approach is to have the prover “collect” all the inputs to the various invocations of the precompile together and apply (a data-parallel version) of the precompile to the collected inputs. Even this collection step can likely be avoided using techniques already incorporated into the current Jolt implementation.

如果预编译由手动指定的约束系统组成(这就是当前一代 zkVM 对预编译的实现方式),我们会让开发者用适当的约束规范语言指定该约束系统,然后应用该约束系统的后端来证明可满足性。如今的 zkVM 都使用 AIR 作为约束系统。我们可以通过使用 BabySpartanSuperSpartan(我们基于求和检查的 SNARK,用于 AIR 和 Plonkish 约束系统)来重用这些预编译,以证明它们的可满足性。

从长远来看,最快的预编译将是专用的基于求和检查的 SNARK,完全避免约束系统。在这种情况下,我们可能会要求开发者通过直接在 Rust 中表达证明者和验证者来指定它们。

类别 4:递归和续延

17. 对于 Jolt 和 SP1,我应该了解关于递归的哪些信息?

请回想一下,如今许多 zkVM 使用续延,这意味着它们将计算机程序的执行拆分成多个块,并在递归聚合证明之前独立证明每个块。

SP1 和续延。 SP1/plonky3 目前没有实现递归聚合步骤(尽管为此已取得了部分进展)。SP1 仅针对每个块输出一个证明。这意味着 SP1 目前的验证者成本非常高——每个块 的证明超过 500KB,每当 RISC-V CPU 运行 219 个周期时就会产生一个块。因此,针对运行 1000 万周期及以上的程序,证明总大小数十 MB。验证者必须对证明中的大部分数据进行哈希处理。

因此,SP1 的基准测试对递归证明聚合(即,根本没有实现此功能)不向证明者收费,尽管在未实际部署之前,必须启用递归以降低验证者成本(有关更多讨论,请参见上述 #1)。这是完全合理的,因为基准测试使用 Poseidon2 作为哈希函数,这“对递归友好”。因此,尽管实现递归会使证明者付出一些成本,但它应该不会是天文数字。

然而,可能仍然存在一些挑战。例如,有人已经转向 较慢的 plonky2 系统,以获得 plonky3 的递归变体,或许是由于 plonky3 对 AIR 约束系统的独占支持所带来的限制。

而 SP1 则配置为在成本上激进优化证明者的时间,使得递归变得更加昂贵。默认情况下,SP1 的“分片大小”为 219,FRI 的“膨胀因子”为 2,而 RISC Zero 的默认分片大小为 220,FRI 膨胀因子为 4。最终效果是,SP1 的递归证明对于 RISC Zero 大约将是四倍的成本,但 SP1 的基准测试对此不向证明者收费。

Succinct 提出,通过使用 Blake3 哈希函数而不是 Poseidon2,可以实现进一步的证明者速度提升。然而,这仅能将证明者的速度提升约 30%。此外,目前尚不清楚在未使递归证明聚合成为重大瓶颈的情况下,Blake3 是否可以使用。SP1 的哈希聚合需要证明者证明它正确哈希了每个块 500 KB 以上的数据。当前的 Blake3 预编译根本没有足够快,无法阻止这一点成为主要瓶颈。

Jolt 和续延。 与 SP1 相似,Jolt 目前尚未实现续延。但是,由于 Jolt 的实现已“支付”以使用 256 位字段和基于椭圆曲线的承诺,Jolt 适合通过折叠快速实现续延(请参见上述 #1 和下面 #22 的额外讨论)。一旦 Jolt 切换到 Binius 承诺方案,续延将通过递归证明聚合实现,而不是折叠。递归将不会成为证明者的瓶颈,如我在之前的帖子中描述的那样(因为 Binius 的证明大小 已经降低 到多对数级别)。

比较性能的复杂性。 当前的 Jolt 并没有将计算拆分为多个块。SP1 拆分了,但没有递归聚合这些证明,因此当存在许多块时,其证明会变得非常庞大。

在运行单个块时,今天的 Jolt 比 SP1 快超过 3 倍,但随着 SP1 使用的块数量增加,速度提升会下降。这是因为 SP1 的“块内”并行化尚未完全优化(尽管它不久就会得到改善:证明者执行的插值过程是可并行化的,但尚未实现并行化)。相反,“块间”并行化是微不足道的(即,证明者可以独立生成每个块的证明,同时处理多个块)。

块内并行化的挑战性和不完美性较高,而块间并行化则要简单得多(其中证明者理所当然地以并行方式证明多个块)。今天,Jolt 根本不利用块间并行化(因为 Jolt 仅在一个块上运行)。因此,一旦 Jolt 也将大型计算拆分为多个块,它可能会看到适度的性能提升。

18. 你最近不是说使用 Keccak 哈希函数的 Binius 承诺方案的续延会很不错吗?为什么你担心与 Blake3 的 FRI 不适合递归?

Binius 论文 提供了一个针对 Keccak 的非常快的 SNARK,它使用求和检查协议,结合了 Binius 承诺方案。这个协议一旦全面优化,将比非求和检查基于 SNARK 的 Keccak 要快得多。要使续延奏效,至少需要这种极高的性能,最终避免使用导致很多 GB 的证明者空间和其它性能瓶颈的大分片大小。

19. StarkWare 不在生产中使用 Blake2s 哈希函数吗?这不是与你声称的 FRI-与-Blake3 不适合递归相矛盾吗?

StarkWare 在构建 Merkle 树时使用 Blake2s 作为哈希函数,在 Merkle 树的大层中使用,并在其他层使用较慢的“友好的 SNARK”哈希函数。这样,任何特定的根到叶路径中的大多数哈希都是“友好的 SNARK”的(保持递归成本低),但构建 Merkle 树所需的证明者时间受限于使用更快哈希函数的大层。

然而,大多数基于 STARK 的 zkVM 在 Merkle 树的每个叶子处存储大量字段元素向量。在这个背景下,StarkWare 的把“仅对大层应用 Blake2s 散列”的技术并没有太大帮助,因为验证者的工作大部分涉及对存储在叶子处的向量应用 Blake2s。

StarkWare 的生产证明者比 Jolt 慢数十倍,即使在手动编写的 Cairo-VM 汇编上运行。它与递归一起使用 Blake2s 的事实并不意味着这在其他 zkVM 中会有帮助。

20. Blake3 难道不是比 Poseidon2 快数十倍吗?为什么在 SP1 中使用 Blake3 只加速 30%?

Blake3 在对大文件进行哈希时最快。SP1 使用的 Merkle 树在叶子处存储中等大小的向量。这些实际上是小文件,每个文件都需要进行哈希。在这个背景下,Blake3 显示出比 Poseidon2 仅快约 3x-4x。

对于证明者来说,Ligero/ Brakedown/ Binius 的承诺方案相比 FRI 有另一个好处:使用 Ligero/Brakedown/Binius 承诺时,Merkle 树的叶子处始终有大型向量。这使得在使用像 Blake3 这样的哈希函数时,哈希时间的减少更大。

在使用 Poseidon2 时,Merkle 哈希大约占 SP1 的证明者时间 30%,而在使用 Blake3 时约占 10%。因此,哈希时间减少 3x-4x 仅转换为约 30% 的总体证明者时间的减少。

这突显出,使用 Blake3 而不是 Poseidon2 在减少承诺时间的同时,对证明已提交数据的良构性所需的时间没有任何降低。像 Jolt 这样的基于求和检查的 SNARK 不仅因为提出的数据更少而意味着承诺计算更快,还因为证明数据良构性时需要的成本更便宜。

21. 最近对“无同态积累方案”的研究是否解决了你对 SP1-与-Blake3 的续延的担忧?

没有。通过新提出的积累方案实现续延,对证明者来说比使用 Poseidon2 和应用朴素 SNARK 递归(即,像 plonky2 或 RISC Zero 续延风格的递归)要差。

这至少有两个原因。首先,每当将 m 个分片聚合在一起时,新的方案要求证明者计算并承诺额外数据。这些额外数据在现有的基于同态承诺的积累方案中并不需要承诺。额外数据是一种随机线性组合,来自每个分片单独承诺的数据,其中随机系数来自一个“大字段”(至少 128 位),即使被组合的数据都来自一个小字段。因此,单纯计算这种线性组合会使证明者的时间显著增加,可能超过使用 Poseidon2 以确保朴素递归不是瓶颈而带来的 30% 增加。

其次,实现续延的主要原因是控制证明者空间以证明大型计算,但使用新的积累提案时,对于证明者空间能够有多小存在限制。这是因为新提出的积累方案仍然需要证明者证明它正确计算了许多哈希评估,具体来说为 O( d λ log n),其中 d 是积累的深度,λ 是安全参数。作为比较,使用 STIR 的朴素递归涉及证明 O(λ log( n) loglog( n)) 次哈希。因此,新折叠方案相对于朴素递归的改进是一个 d/loglog( n) 的因子,这意味着如果 d 大于 loglog n,它实际上更差,即使对于常数 d,它也仅以小因子改善。

d 可以通过两种方式保持小。首先是“同时”积累非常大量的承诺数据,但这将保持证明者的空间较大。另一种方式是使用混合方案——在不一次性积累大量数据的情况下,积累少量级别,然后应用朴素递归将这些聚合结果组合。如果 Blake3 对 STIR 的朴素递归不切实际,那么在混合积累方案中也可能不切实际,因为相对于 STIR,证明的哈希减少很小。在这种混合方案中,证明者继承了朴素递归而非标准同态折叠方案的空间瓶颈:即递归证明 STIR 或 FRI 验证是否正确。

22. 你能解释一下在使用基于曲线的承诺方案实例化 Jolt 时,积累/折叠方案的潜在好处吗?

如上所述,续延是指将 VM 的执行分割成多个块,每个块包含数百万个周期,分别对每个块应用 Jolt,然后将这些块聚合在一起。而聚合这些块有两种高层次的方法。一种是“朴素递归”:这意味着为每个块生成完整的 Jolt 证明,但不是输出所有这些证明(这将导致庞大的证明和高昂的验证者成本,如今天的 SP1),而是证明者递归地证明它知道这些证明。

另一种方法是折叠(有时称为积累)。折叠相对于朴素递归的主要好处在于,通过折叠,你可以省略所有已提交多项式的评估证明,而是使用基于曲线的承诺的同态属性,将所有已承诺多项式跨所有块聚合为一个单一的已承诺多项式。省略这些评估证明有两个潜在好处:(1)证明者永远不必计算这些证明,(2) Jolt 验证者必须通过适当的约束系统(或 RISC-V 程序)来表达,以实现递归,因此永远不必检查它们。

Jolt 确保这些评估证明不会成为证明者的瓶颈,因此(1)并不是大问题。但是(2)很重要:这正是我不认为可以在 SP1-与-Blake3 下实现递归而不产生显著成本的原因。由于(2),折叠可以帮助确保递归不会对证明者的成本产生重要影响。它还可以通过使块更小来减少证明者空间,从而在不使递归成为证明者瓶颈的情况下实现这一点。

\\*\

Justin Thaler 是 a16z 的研究合伙人及乔治城大学计算机科学系的副教授。他的研究兴趣包括可验证计算、复杂性理论和大规模数据集的算法。

\\*\

  • 原文链接: a16zcrypto.com/posts/art...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
a16z Crypto
a16z Crypto
https://a16zcrypto.com/