本文介绍了Zeth,一个基于RISC Zero zkVM的开源ZK块证明器,使得以太坊区块的验证过程在数分钟内完成,而不依赖于验证者或同步委员会。文章详述了Zeth的工作原理、性能、实现细节以及它对ZK技术和以太坊生态的影响,展现了其在ZK-rollup和zkEVM领域的应用潜力。
今天我们发布了 Zeth,一个基于 RISC Zero zkVM 的开源 ZK 区块证明器,用于以太坊。Zeth 使得可以 证明 给定的以太坊区块是有效的 而无需 依赖验证者或同步委员会,通过在 zkVM 内部做 所有 构建新块所需的工作。Zeth 已经被验证能够在以太坊主网的几个实际区块上运行,并且通过了官方 Ethereum 测试套件 的所有相关测试。基于 zkVM 的 Rust 支持和包括 revm,ethers,和 alloy 等强大库,我们能够在 不到 4 周的工作时间 内实现这一水平的兼容性。通过 zkVM 对 继续 和 Bonsai 证明服务 的支持,Zeth 能够在 分钟 内生成这些证明。并且,借助我们对 链上验证 的支持,任何人都可以廉价地 在链上验证这些证明。在这篇文章中,我们会填充细节,如果你希望深入研究代码,请查看 源代码 并访问 RISC Zero 开发者门户。
大约一年前,Vitalik 在 不同类型的 ZK-EVMs 中解释道:
以太坊最初并不是围绕 ZK 友好性设计的,因此以太坊协议的许多部分在 ZK 证明时需要大量计算。类型 1 旨在完全复制以太坊,因此无法缓解这些低效之处。
目前,证明以太坊块通常需要数小时。
虽然历史上确实如此,但今天我们高兴地宣布,现在使用 RISC Zero 的 zkVM 和 Bonsai 证明服务 ,可以在 几分钟 内证明以太坊区块的有效性,而不是小时。
今天我们发布了 Zeth,一个基于 RISC Zero zkVM 的开源 ZK 区块证明器。
Zeth 使得可以 证明 给定的以太坊区块是有效的(即,经过应用给定的交易列表至父块的结果) 而无需 依赖验证者或同步委员会。这是因为 Zeth 完成了构建新块所需的所有工作 来自于 zkVM,包括:
验证交易签名。
根据父块的状态根验证账户和存储状态。
应用交易。
向区块作者支付费用。
更新状态根。
等等。
在构建新块后,Zeth 计算并输出它的哈希。通过在 zkVM 中运行这个过程,我们获得了一个 ZK 证明,证明新块是有效的。
在 RISC Zero 的 zkVM 和流行的 Rust 库(如 revm,ethers,和 alloy)的基础上,我们能够在 不到 4 周 内编写出 Zeth 的第一个版本。通过 zkVM 对 继续 和 Bonsai 证明服务 的支持,我们可以廉价地在 分钟 内生成这些证明。并且借助我们对 链上验证 的支持,我们可以廉价地 在链上验证这些证明。
Zeth 已被验证在以太坊主网的多个现实区块上有效,并通过了官方 Ethereum 测试套件 的所有相关测试。
由于 Zeth 构建标准以太坊区块,它可以被视为 Type 1 zkEVM。但不仅仅如此:因为 Zeth 是使用标准 Rust 库构建的——与热门完整节点如 Reth 使用的库相同——我们更愿意将其视为 Type 0 zkEVM:完全的协议兼容性,以及显著的代码复用。
我们相信这个里程碑代表了 ZK 技术和以太坊生态系统的重大进步。在这篇文章中,我们讨论了如何能够在几周内编写出 Zeth 的第一个版本、其性能、工作原理,以及这对 ZK 项目的意义。
我们编写 Zeth 的原因有两个:
为其他团队构建其自己的 ZK 驱动基础设施提供方便:ZK Rollups、zkEVMs、ZK 轻客户端、ZK 桥梁等。Zeth 提供生成 EVM 基块所需的一切。这是任何 zkEVM 或桥梁中的关键组成部分。Zeth 是 开源 的,基于 revm,因此你可以轻松修改并在自己的项目中使用。证明可以 在链上验证(对于桥梁和 L2s 非常合适)或在本地应用中(对于完整节点和轻客户端非常合适)。
调查 EVM 在我们 zkVM 中的性能,特别是对于与以太坊相关的任务。(请见下方我们发现的分析。)
有兴趣与我们讨论 Zeth 吗?与我们联系!
作为 Type 0 zkEVM,Zeth 使开发者能够构建完全本地的 EVM 和以太坊支持的 ZK Rollups。结合我们对 链上证明验证 的支持,以前从未有如此简单的方式来构建由 ZK 驱动的 L2。
现有的 ZK rollups 和 zkEVM 电路在设计上是单块的,并且缺乏可升级性,开发者需要较高水平的 ZK 密码学理解。相比之下,我们基于 zkVM 的 Zeth 方法使任何开发者都能根据自己的需求进行自定义和修改。
Zeth 是 开源 的,基于 revm,可以轻松适配以支持其他 zkEVM 和 EVM 兼容链。这确保了对 Zeth 的更新简单,以迎合未来的 EIPs,并提供模块化,使开发者能将自己的区块构建逻辑集成到 Zeth 中。
我们希望这些基础能够使 ZK Rollups 和 zkEVM 普及,以前这些技术往往需要数年的开发和超过 1 亿美元的资金,使大多数项目无法成行。
信标链的引入无疑对轻客户端和桥梁是一大福音。这些技术建立在以太坊如今成熟的权益证明模型上,使轻客户端和桥梁可以轻松验证最近的区块 而无需 重建这些区块——假设所有人遵守规定。
当然,质押的整个目的在于提供经济激励以遵守规则。然而,分区的威胁并 不是 保证不会发生坏事。外部激励可以“倾斜天平”以支持恶作剧——设计能够正确处理这些恶作剧的轻客户端或桥梁是 困难 的。
有了像 Zeth 这样的工具,恶作剧的风险大大降低。轻客户端只需通过向我们的 zkVM 添加几个调用即可与 Zeth 集成;而像桥梁这样的链上应用可以通过使用 我们链上证明验证合约 来与 Zeth 集成。
在不久的将来,人们可能会想象轻客户端和桥梁能够使用 ZK 证明来 确定 给定区块是有效的。这种方法将显着减少风险 而不 显著增加验证区块的成本。
这对于应用链、模块化生态系统以及尚未享有以太坊庞大的完整节点社区提供的相同安全级别的新链尤其重要。
Zeth 构建在 RISC Zero zkVM 之上,该平台提供了熟悉的编程体验,并基于 RISC-V 指令集架构。但我们的 zkVM 不仅仅是一个 RISC-V 核心。我们还有用于常见密码学任务的加速器电路,例如 哈希 和 签名验证。
这种混合方法(通用 CPU 核心与加速器电路相结合)使我们兼顾了两者的优势:
支持主流编程语言。
对于关键密码学操作的性能没有妥协。
因此,我们能够迅速利用 revm、ethers 和 alloy 中现有的 Rust 库构建 Zeth。通过重用现有库,我们能够在 不到 4 周 内完成 Zeth 的第一个版本。在不够成熟的生态系统中,这种工程速度是不可想象的。
在性能方面,Zeth 利用我们的加速器电路进行 ECDSA 签名验证,以及 继续 ——我们 ZK 框架的一个新特性,使快速证明大型计算变得简单,该功能利用并行运行的 GPU 集群(使用 nVidia CUDA 或 Apple Metal)。继续功能易于使用:该功能会透明地提供给运行在 zkVM 内的所有客户端程序。你的代码不需要任何更改;它只是 工作。
借助我们的 zkVM,我们能够在 分钟 内廉价地生成以太坊区块的有效性证明,而不是几小时。
在本节中,我们描述 Zeth 区块构建器的性能。Zeth 仍然较新,所以这些数据可能会发生变化;尽管如此,我们仍希望提供一些具体的数据作为将来的基准。
在性能方面,需要考虑几个因素:
生成证明所需的计算资源。
生成证明所需的“实际时间”(即用户需要等待多久才能获得他们的证明)。
生成证明的总成本($)。
借助我们的 zkVM,可以通过使用 继续 来调整性能。因此,我们需要花些时间讨论继续的工作原理。
我们的 zkVM 实现了标准的 RISC-V 处理器。因此,执行是 以周期 为单位进行的。(在我们的电路中,大多数 RISC-V 指令只需 1 个周期即可执行,尽管有一些例外。)简单的程序通常只需要几百千个周期来执行,但更复杂的程序可能轻松地需要数十亿个周期。
在典型的 ZK 系统中,这些执行周期被汇总成一个单一的证明;随着周期数量的增加,生成该证明所需的时间和内存也会增加。但我们的 zkVM 并不典型。在今年早些时候,我们率先推出了一项新功能——继续——大大改善了这一范式。
有了继续,证明过程分为三个阶段:
我们在非证明模拟器中执行所需的计算。在此执行的同时,我们计算已运行的周期数。在可配置的时间间隔内,我们对程序状态进行快照。这有效地将执行分为多个 段。每个段都很小,通常表示 1M 周期或更少。
将这些段分配到一个工作者池。工作者为其对应的段生成 ZK 证明。重要的是,他们能够 并行 进行此操作。通过足够多的工作者, 所有 的段都可以在证明一个段所需的时间内完成证明。因为段很小,这个时间通常非常短(几秒钟)。
随着段证明的生成,它们被“压缩”。每个压缩操作需要一对连续的段证明,并为段的组合生成新的证明。例如,如果段 1 证明程序从状态 A 转换到状态 B,而段 2 证明程序从状态 B 转换到状态 C,则压缩证明程序证明程序从状态 A 转换到状态 C。通过足够的工作者,这个过程可以在 log(N) 时间内完成,其中 N 是段的数量。
我们将在深度剖析数据时看到这些阶段的实际应用。
不再废话,让我们看看一些数字!
首先,让我们看看构建以太坊块的复杂性。在下面的表格中,我们挑选了一些现实世界的以太坊区块,并使用 Zeth 从 zkVM 中重建它们。
区块编号 | 交易数量 | Gas | 段 | 总周期(上限) |
17034871 | 267 | 29,970,493 | 4675 | 4,902,092,800 |
17049942 | 206 | 29,987,306 | 3261 | 3,419,406,336 |
17095624 | 163 | 12,684,901 | 2095 | 2,196,766,720 |
17106222 | 105 | 10,781,405 | 1816 | 1,904,214,016 |
17181191 | 139 | 14,560,621 | 2007 | 2,104,492,032 |
17408122 | 135 | 26,256,143 | 2543 | 2,666,528,768 |
17495654 | 112 | 20,791,473 | 2986 | 3,131,047,936 |
17546837 | 168 | 17,279,191 | 2549 | 2,672,820,224 |
17606237 | 174 | 15,957,890 | 4079 | 4,277,141,504 |
17606771 | 139 | 12,595,376 | 2131 | 2,234,515,456 |
17640464 | 156 | 13,493,687 | 2167 | 2,272,264,192 |
17647876 | 101 | 10,542,312 | 2013 | 2,110,783,488 |
17682361 | 104 | 13,157,104 | 2105 | 2,207,252,480 |
17691128 | 112 | 14,838,663 | 9098 | 9,539,944,448 |
17735424 | 182 | 16,580,448 | 3242 | 3,399,483,392 |
例如,区块 17606771 生成了 2131 段。每个段最多表示 2^20 周期的执行,因此整个计算最多需要 2,234,515,456 周期的执行。
一般而言,我们看到典型的以太坊区块需要 20 亿到 40 亿个周期构建,但有时甚至需要多达 95 亿个。(起初我们惊讶于这些差异并 没有 反映在交易的 Gas 中。但进一步思考后,这是合理的:Gas 系统是以传统执行为设计基础的,而不是 ZK 证明。)
有了继续,这种规模变得易于管理。基于这些数据,运行 zkVM 证明器的对等网络中只需 10,000 个节点即可实现最大并行证明性能来处理最大的区块——这只是目前以太坊 700,000 验证者 的微小部分。
为了收集一些基本的性能数据,我们启动了一个包含 64 个 GPU 工作者的 Bonsai 测试实例。然后我们要求它使用 Zeth 证明块 17735424 (182 次交易,3242 段,或约 34 亿个周期)。
生成证明时,zkVM 首先必须将执行划分为段。在下面的截图中,Executor 任务的执行耗时 10 分钟。(很大一部分时间用于执行 AWS 相关任务,例如写入网络存储。在本地机器上,这个任务通常在 6 分钟内完成。我们预计在未来一年内显著缩短这个时间。)
最终,执行器将执行分割为 3242 段。对于仅 64 个 GPU 来说,这段数量是相当多的。因此,每个工作节点需要生成 50 个段证明。如下面的截图所示,这花费了 35 分钟。如果我们有 50 倍的工作者,这仅需 42 秒。
在段证明完成后,开始进行压缩。对于 3242 个段,我们需要进行 log_2(3242) = 12 轮压缩程序。在压缩的早期阶段,工作量大于工作者,因此第一阶段耗时 1 分钟,第二阶段耗时 35 秒,第三阶段耗时 25 秒,等等。到了第 7 阶段,时间稳定在 5 秒多一点。如果有更多的工作者,每个阶段都只需 5 秒钟。
最后,压缩过程完成后,结果最终确定,耗时又 1 分钟。
因此,借助我们规模不足的集群,我们能够在大约 50 分钟 内完成证明(有效速度为 1.1 MH)。在正确规模的集群上,我们估计可以更快生成证明:
在全部并行的情况下,证明步骤可以在 42 + 12 * 5 + 60 秒内完成,即 2 分 42 秒。
如果我们保守估算并包含执行者的时间,则这个时间在 9 到 12 分钟之间(有效速度为 4.7 MH - 6.3 MH)。
随着我们对执行器和证明框架的持续改进,我们乐观地认为这个时间将在未来一年内大幅度降低。
上述测试集群部署在 AWS 上。它由 64 个 g5.xlarge 证明节点和 1 个 m5zn.xlarge 执行节点组成。根据亚马逊数据,每个 g5.xlarge 节点具有:
1 个拥有 24 GiB GPU 内存的 GPU
4 个 vCPU 和 16 GiB 内存
在撰写此文时,这些实例的按需价格为 $1.006/小时,预留实例的减价为 $0.402/小时。同时,亚马逊的规范表 显示我们 m5zn.xlarge 节点的配置为:
在撰写时,这个实例的按需价格为 $0.3303/小时。
我们可以利用这些数据生成对上述区块 17735424 证明成本的粗略估计。
回忆一下,我们部署了 64 个证明节点,而生成证明的时间为 50 分钟(从头到尾)。忽略闲置工作的时间,64 个证明节点及一个执行节点的费用大约为 50/60 * (64 * $0.402 + $0.3303) = $21.72。这是一个高估,因为它假设我们在支付闲置工作者。如果不计算闲置工作者的费用(例如,通过关闭闲置机器或让他们做其他工作),成本大约为 $19.61。
这个区块有 182 笔交易,即每笔交易的费用为 $0.11。
总交易额为 1.125045057 Eth,约为 $2137.59。因此,每一美元的证明保障了 $109.01 的用户资金。
该区块的奖励为 0.117623263003047027 Eth(不包括交易费用)。在撰写时,这约为 $223.48。因此,我们的证明的生成成本大约为区块奖励的 8.7%。
交易费用总计为 0.03277635 Eth,也就是 $62.28,是我们证明成本的 3倍以上。
值得注意的是,这些美元成本的估计是 独立于 集群规模的!真正重要的是段的数量。这是因为 1 台机器连续做 2 项工作的成本和 2 台机器各自做 1 项工作时的成本是相同的。因此,在更大规模的集群中,证明的生成会 更快,但 不会更贵。
有几种方法可以进一步降低这一成本。除了继续对我们的 zkVM 进行性能改进,或许可以增添 Keccak 加速器,我们还可以竞争寻找更便宜的实例。重要的是,考虑到我们使用的机器规范低(并且 zkVM 支持 nVidia Cuda 和 Apple Metal),这工作可以轻松地由由普通消费者 PC 和 Mac 组成的 p2p 网络完成。
如上所述,我们已经通过 RISC Zero Groth16 验证器 在 Sepolia 上验证了一条 Zeth 证明。这是 RISC Zero 栈中的一个相对较新的部分, 本月早些时候宣布。它的工作原理是使用 Bonsai 将 zkVM 的原生 STARK 证明转换为等效的 SNARK 证明,并将该证明提交给链上 SNARK 验证器。
如果我们将 交易 输入视为 UTF-8 数据,则我们看到这条证明对应于区块 17735424。
使用 Bonsai,从 STARK 转换到 SNARK 大约花费了 40 秒。链上验证 SNARK 消耗了 245,129 gas(在撰写时,约为 $5.90)。
当然,zkVM 的一个好处在于它可以将多个证明汇聚成一个。借助此功能,整套证明可以 在没有 使用任何额外 gas 的情况下进行链上验证。这样,链上验证的成本可以在整个集合中分摊,从而减少所有参与者的费用。
如前所述,以太坊并不是为了 ZK 友好性而设计的。正如 zkEVM 的格局所示,还有许多方面可以做得不同,特别是在操作代码、数字签名和哈希函数方面。
虽然这些变化确实改善了性能,但我们仍然能够在没有它们的情况下取得良好的性能。当 Vitalik 去年谈到不同类型的 zkEVMs 时,证明以太坊区块的有效性需要数小时,而如今我们可以在 几分钟 内完成。ZK 性能正在迅速提高,并且有充分理由相信这一趋势将在未来几年持续。
查看这些资源,并在 Discord 上来打个招呼。
这一部分是为建设者们准备的。
粗略而言,Zeth 以与完整节点相同的方式构建区块:我们从一个父区块、一个事务列表和一个区块作者开始;然后我们进行一系列计算(验证签名,运行交易,更新全局状态等);最后返回(新块的哈希)。
但与完整节点不同的是,我们是在 zkVM 内部完成这一切。这意味着我们获得了一个 ZK 证明,证明具有给定哈希的区块是有效的。
当然,这不是没有挑战的。在这一部分中,我们描述这些挑战以及我们如何解决它们。
第一个挑战是 密码学。构建以太坊区块需要进行大量 的 密码学,特别是哈希(Keccak-256)和签名验证(使用 secp256k1 的 ECDSA)。
我们的 zkVM 支持 加速使用椭圆曲线进行处理,因此 ECDSA 签名检查并不困难。
但在哈希方面,我们没有那么幸运。我们的 zkVM 对 Sha2-256 具备 加速支持,但(在撰写时)对 Keccak-256 不支持。因此,目前,我们只是使用 sha3 Rust 库中的 Keccak 实现。通过分析 profiler,我们知道这一过程消耗了相当多的周期。这不是最优的,但我们的 zkVM 能够胜任,我们随时可以返回并添加 Keccak 加速器。
在以太坊中,账户和存储由全球的 Merkle Patricia Trie (MPT) 跟踪。
根据 Etherscan 的数据,在撰写时,这棵树包含近 250,000,000 的独特以太坊地址。在大局中,这并不是 大量 数据,但足以需要小心如何存储和使用。尤其是,MPT 的性能至关重要。
但性能并不是唯一的因素;我们还必须考虑 安全性。
Zeth 的区块构建器作为 zkVM 内部的一个客户程序运行。这意味着它没有直接访问以太坊 P2P 网络或其他 RPC 提供者的权限。因此,它必须依赖另一个在 zkVM 外部 运行的程序提供的数据。
在分析 ZK 应用的安全性时,必须假设外部程序是恶意的,因此可能提供恶意数据。为了防止这种情况,ZK 应用 必须 验证提供给它们的数据是有效的。
对于 Zeth 的区块构建器,这意味着验证所有相关账户和存储的状态(即,运行给定交易列表所需的账户和存储)。
幸运的是,有自 EIP-1186 的机制提供此验证,该机制定义了一种标准方式以证明给定账户(及其存储)的状态通过 Merkle 包含。
原则上,Zeth 的区块构建器可以通过验证一组 EIP-1186 包含证明简单地验证账户和存储状态。但这种方法并不是最优的。
替代方法是使用 EIP-1186 包含证明的数据构建一个 部分的 MPT。这个 MPT 只包含 相关 的节点,忽略的分支仅用其对应的哈希表示。你可以将部分 MPT 视为 Merkle 包含证明的某种“并集”;或者,如果更愿意,可以将其视为 Merkle 子集 证明。
验证部分 MPT 的过程基本上与验证普通 EIP-1186 证明相同:计算根哈希并与父块的状态根进行比较。如果它们相等,则可以信任其中包含的账户和存储的完整性。
在验证部分 MPT 后,可以应用事务并更新部分 MPT。通过计算部分 MPT 的新根哈希,可以得到新的状态根。
这就是我们采用的方法总结:
在运行 Zeth 区块构建器之前,我们会在一个沙箱中运行交易列表,以确定哪些账户和存储是相关的。(这一过程还让我们能够确定最新的相关前任块,这是支持 blockhash() 查询 所需的。)
我们抓取每个相关账户和存储的 EIP-1186 包含证明。 (我们还抓取相关的前任块。)
我们利用这些包含证明构建一个包含所有相关数据的部分 MPT。
我们启动 zkVM,指示其运行 Zeth 区块构建器,并提供部分 MPT 以及其他输入(父区块、交易列表等)。在 zkVM 内部,Zeth 区块构建器:
验证部分 MPT 根是否与父区块的状态根匹配。
验证前驱区块的哈希链,直到父区块。
应用交易。
更新部分 MPT。
使用部分 MPT 的新根哈希作为新区块的状态根。
当 Zeth 区块构建器完成时,它输出新区块的哈希。
该哈希包含对父区块的承诺,因此也包含父区块的状态根(这个状态根被用于验证原始部分 MPT)。这意味着恶意的证明者不能提供无效的账户和存储数据而不同时提供一个无效的父区块。
换句话说:如果父区块是有效的,那么 Zeth 生成的新区块也是有效的。
因此,如果有人给你一个新区块和一个由 Zeth 生成的 ZK 证明,你可以通过检查以下三件事来验证区块的有效性:
确保 ZK 证明是有效的,并且来自 Zeth。对于链下应用,可以使用 zkVM Rust crate 提供的函数进行检查。对于链上应用,可以使用我们的链上证明验证者进行检查。
确保 ZK 证明承诺了新区块的哈希。
确保父区块具有你期望的哈希。
如果以上所有检查都通过,那么新区块是有效的。
我们此项目的目标是调查区块构建的性能。为了实现这一目标,我们决定将范围限制在合并后的区块。
此外,虽然 Zeth 能够证明给定区块是有效的,但它并不目前证明共识(即,该区块实际上包含在规范链中)。这可能在未来发生变化,也许会通过添加检查来自 zkVM 的验证者或同步委员会签名来实现。
最后,Zeth 是一款新软件。尽管我们进行了某些测试(包括 Ethereum 测试套件 和各种现实世界的区块),但 Zeth 仍可能包含一些漏洞。在撰写时,应该将其视为实验性。
- 原文链接: risczero.com/blog/zeth-r...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!