编者按:12 月 13 日,以太坊联合创始人 Vitalik Buterin 发文深入探讨了「ZK-EVM」(Zero-Knowledge Ethereum Virtual Machine)的可能实现形式,并对不同版本 ZK-EVM 的设计进行探讨。Vitalik 提出的 ZK-EVM 概念,旨在减少 Layer-2 项目对 Ethereum 协议功能的重复实现,并提高其在验证 Layer-1 Ethereum 区块时的效率。文章指出,当前的 Layer-2 EVM 协议(如 Optimistic Rollups 和 ZK Rollups)需要依赖于 EVM 的验证机制,但这同时意味着他们必须信任庞大的代码库。一旦代码库中存在漏洞,这些虚拟机可能面临被攻击的风险。此外,他还提到了对「almost-EVM」的支持,即允许 L2 的 VM 在与 EVM 只有微小差异的情况下,仍能使用协议内的 ZK-EVM,同时也为 EVM 的部分定制化提供了灵活性。摘要:这反过来又意味着一些要点:·数据可用性要求:对于使用被奉为圭臬的ZK-EVM证明的任何EVM执行,我们希望能够保证底层数据是可用的,以便使用不同证明系统的证明者可以重新证明执行,依赖该证明系统的客户端可以验证这些新生成的证明。...
以太坊上的 Layer-2 EVM 协议,包括 op rollup 和 ZK rollup,依赖于 EVM 验证。然而,这要求它们信任一个庞大的代码库,如果该代码库存在漏洞,这些虚拟机面临被黑客攻击的风险。此外,即使是希望与 L1 EVM 完全等同的 ZK-EVM,也需要一定形式的治理,以将 L1 EVM 的更改复制到它们自己的 EVM 实现中。
这种情况并不理想,因为这些项目正在复制以太坊协议中已经存在的功能,而以太坊治理已经负责升级和修复错误:ZK-EVM 基本上执行与验证 L1 以太坊区块相同的工作!此外,未来几年内,我们预计轻客户端将变得越来越强大,很快就会使用 ZK-SNARKs 完全验证 L1 以太坊执行。此时,以太坊网络将有效地拥有一个内置的 ZK-EVM。因此,问题出现了:为什么不将该 ZK-EVM 本地化提供给 rollup 项目呢?
本文将描述几个可能实现的「被奉为圭臬的 ZK-EVM」版本,并探讨权衡和设计挑战,以及不选择特定方向的原因。这些实现协议特性的优势应该与留给生态系统的好处和保持基础协议简单的利益相权衡。
我们对被奉为圭臬的 ZK-EVM 有哪些关键属性的期望?
基本功能:验证以太坊区块。该协议特性(目前仍未确定是操作码、预编译还是其他机制)应至少接受预状态根、区块和后状态根作为输入,并验证后状态根是否确实是在预状态根的基础上执行区块的结果。
与以太坊多客户端理念的兼容性。这意味着我们希望避免奉行单一的证明系统,而是允许不同的客户端使用不同的证明系统。这反过来又意味着一些要点:
· 数据可用性要求:对于使用被奉为圭臬的 ZK-EVM 证明的任何 EVM 执行,我们希望能够保证底层数据是可用的,以便使用不同证明系统的证明者可以重新证明执行,依赖该证明系统的客户端可以验证这些新生成的证明。
· 证明存在于 EVM 和区块数据结构之外:ZK-EVM 特性不会直接将 SNARK 作为 EVM 内输入,因为不同的客户端期望不同类型的 SNARK。相反,它可能类似于 blob 验证:交易可以包含需要证明的(预状态、区块主体、后状态)语句,操作码或预编译可以访问这些语句的内容,客户端共识规则将分别检查每个在区块中提出的声明的数据可用性和证明的存在。
可审计性。如果任何执行都得到证明,我们希望底层数据是可用的,以便在发生任何问题时,用户和开发者可以检查。在实践中,这增加了数据可用性要求重要性的另一个原因。
可升级性。如果发现特定的 ZK-EVM 方案存在漏洞,我们希望能够快速修复。这意味着不需要硬分叉来进行修复。这增加了证明存在于 EVM 和区块数据结构之外的重要性的另一个原因。
支持 almost-EVM 的网络。L2 的吸引力之一在于创新执行层的能力,并对 EVM 进行扩展。如果某个给定的 L2 的虚拟机(VM)与 EVM 仅有细微差异,那么如果 L2 仍然可以使用与 EVM 相同的原生协议内 ZK-EVM,仅对与 EVM 相同的部分依赖其自身代码,对于不同的部分则依赖于他们自己的代码,那将是很好的。这可以通过设计 ZK-EVM 特性的方式来实现,该特性允许调用者指定由外部提供的表处理的一些操作码、地址或位域,而不是由 EVM 本身处理。我们还可以在有限的范围内使燃气成本开放定制。
「开放」与「封闭」的多客户端系统
「多客户端理念」可能是这个列表中最有主张的要求。有放弃这一理念的选择,集中精力研究一个 ZK-SNARK 方案,这将简化设计,但代价是对以太坊的一个更大的「哲学转变」(因为实际上这将是对以太坊长期多客户端理念的放弃)和引入更大的风险。在长期未来,例如形式化验证技术变得更好的情况下,可能更好地选择这条道路,但目前来看,风险似乎太大。
另一种选择是封闭的多客户端系统,在协议内已知一组固定的证明系统。例如,我们可能决定使用三个 ZK-EVMs:PSE ZK-EVM、Polygon ZK-EVM 和 Kakarot。一个区块需要携带这三个中的两个的证明才能被视为有效。这比单一的证明系统要好,但它使系统变得不太适应性,因为用户必须为每个已知的证明系统维护验证器,必然会存在政治性的治理过程来纳入新的证明系统等等。
这促使我更倾向于采用开放的多客户端系统,其中证明被放置在「区块之外」,并由客户端分别验证。个别用户可以使用他们想要的客户端来验证区块,只要至少有一个生成该证明系统证明的证明者。证明系统将通过说服用户运行它们而获得影响力,而不是通过说服协议治理过程。然而,这种方法确实具有更多的复杂性成本,我们将会看到。
我们希望 ZK-EVM 实现具备哪些关键特性?
除了基本的正确功能和安全性保证之外,最重要的特性是速度。虽然可以设计一个协议内的 ZK-EVM 特性,其是异步的,仅在经过 N 个时隙的延迟后为每个声明返回一个答案,但如果我们可以可靠地保证在几秒内生成证明,那么每个区块中发生的一切都是自包含的问题将变得更容易。
尽管今天生成以太坊区块的证明需要很多分钟或小时,但我们知道没有理论上的阻止大规模并行化的原因:我们总是可以组合足够多的 GPU,分别证明区块执行的不同部分,然后使用递归 SNARKs 将这些证明组合在一起。此外,通过 FPGAs 和 ASICs 的硬件加速可能有助于进一步优化证明。然而,实际达到这一点是一个重要的工程挑战,不应该被低估。
协议内的 ZK-EVM 特性可能具体是什么样子?
类似于 EIP-4844 Blob 交易,我们引入了一种包含 ZK-EVM 声明的新交易类型:
与 EIP-4844 类似,在内存池中传递的对象将是交易的修改版本:
后者可以转换为前者,但反之则不行。我们还扩展了区块边车对象(在 EIP-4844 中引入)以包含在区块中所做声明的证明列表。
请注意,在实际操作中,我们可能会希望将边车分成两个独立的边车,一个用于 blob,一个用于证明,并为每种证明类型设置一个单独的子网(还有一个额外的子网用于 blob)。
在共识层上,我们添加了一个验证规则,即仅当客户端看到了区块中每个声明的有效证明后,该区块才会被接受。证明必须是 ZK-SNARK 证明声明,即
transaction_and_witness_blobs 的串联是(Block,Witness)对的序列化,执行块在 pre_state_root 上使用 Witness (i) 是有效的,并且 (ii) 输出正确的 post_state_root。潜在地,客户端可以选择等待多种证明类型的 M-of-N。
在这里有一个哲学性的注记,即区块执行本身可以被视为仅是需要与 ZKEVMClaimTransaction 对象中提供的(σpre,σpost,Proof)三元组之一一起检查的。因此,用户的 ZK-EVM 实现可以替换其执行客户端;执行客户端仍将被(i)证明者和区块构建者使用,以及(ii)关心索引和存储数据供本地使用的节点使用。
验证和重新证明
假设有两个以太坊客户端,其中一个使用 PSE ZK-EVM,另一个使用 Polygon ZK-EVM。假设到达这一点时,两个实现都已发展到可以在 5 秒内证明以太坊块执行的程度,并且对于每个证明系统,存在足够多独立的志愿者运行硬件以生成证明。
不幸的是,由于个别证明系统未被正式确立,它们无法在协议中获得激励;然而,我们预计运行证明节点的成本将较低,相比于研究和开发的成本,因此我们可以简单地通过通用机构为公共物品资助来资助证明节点。
假设有人发布了一个
ZKEvmClaimNetworkTransaction,除非他们只发布了 PSE ZK-EVM 版本的证明。Polygon ZK-EVM 的证明节点看到这一情况,计算并重新发布该对象,附带 Polygon ZK-EVM 的证明。
这将最早的诚实节点接受区块和最晚的诚实节点接受相同区块之间的总最大延迟从δ增加到 2δ+Tprove(在这里假设 Tprove
然而,好消息是,如果我们采用单槽确定性,我们几乎肯定可以将这种额外延迟与 SSF 固有的多轮共识延迟一起「流水线」处理。例如,在这个 4 子槽提案中,「头部投票」步骤可能只需要检查基本的区块有效性,但「冻结和确认」步骤将需要存在一个证明。
扩展:支持「almost-EVM」
ZK-EVM 功能的一个可取目标是支持「almost-EVM」:具有一些额外功能的 EVMs。这可能包括新的预编译,新的操作码,允许合约以 EVM 或完全不同的 VM(例如,在 Arbitrum Stylus 中)编写,甚至具有同步交叉通信的多个并行 EVMs。
一些修改可以以简单的方式进行支持:我们可以定义一种语言,允许 ZKEVMClaimTransaction 传递修改后的 EVM 规则的完整描述。这可以用于:
· 自定义 gas 成本表(用户不得减少 gas 成本,但可以增加)
· 禁用某些操作码
· 设置区块编号(这将意味着根据硬分叉而有不同的规则)
· 设置一个激活已为 L2 使用而非 L1 使用标准化的整套 EVM 更改的标志,或其他更简单的更改
为了以更加开放的方式允许用户通过引入新的预编译(或操作码)添加新功能,我们可以在
ZKEVMClaimNetworkTransaction 的 blob 的一部分中添加一个包含预编译输入/输出转录的内容:
EVM 执行将被修改如下。数组 inputs 将被初始化为空。每次调用 used_precompile_addresses 中的地址时,我们将 InputsRecord(callee_address、gas、input_calldata)对象附加到 inputs,并将调用的 RETURNDATA 设置为 outputs[i]。最后,我们检查 used_precompile_addresses 总共被调用了 len(outputs) 次,并且 inputs_commitments 匹配生成的 blob commitments 到 inputs 的 SSZ 序列化的结果。暴露 inputs_commitments 的目的是为了方便外部 SNARK 证明输入和输出之间的关系。
请注意输入和输出之间的不对称性,其中输入被存储在散列中,而输出被存储在必须提供的字节中。这是因为执行需要由仅看到输入并理解 EVM 的客户端完成。EVM 执行已经为它们生成了输入,因此它们只需检查生成的输入是否与声明的输入匹配,这仅需要进行散列检查。但是,输出必须以完整形式提供给它们,因此必须是数据可用的。
另一个有用的功能可能是允许「特权事务」,即从任意发件人账户发起调用的事务。这些事务可以在两个其他事务之间运行,或者在另一个(可能也是特权的)事务中调用预编译时运行。这可以用于允许非 EVM 机制调用回 EVM。
这个设计可以修改以支持新的或修改过的操作码,除了新的或修改过的预编译。即使只有预编译,这个设计也非常强大。例如:
· 通过设置 used_precompile_addresses,包括在状态中其帐户对象中设置了某些标志的常规账户地址列表,并制作一个 SNARK 来证明它被正确构建,您可以支持 Arbitrum Stylus 风格的功能,其中合约的代码可以用 EVM 或 WASM(或其他 VM)编写。特权事务可用于允许 WASM 账户回调到 EVM。
· 通过添加一个外部检查,确保多个 EVM 执行的输入/输出转录和特权事务以正确的方式匹配,您可以证明一个通过同步通道相互通信的多个 EVM 的并行系统。
· 第四类型的 ZK-EVM 可以通过拥有多个实现来运作:一个将 Solidity 或其他高级语言直接转换为 SNARK 友好的 VM 的实现,另一个将其编译为 EVM 代码并在被奉为圭臬的 ZK-EVM 中执行。第二个(不可避免地较慢的)实现仅在错误证明者发送声明存在错误的交易的情况下运行,如果他们能够提供两者不同处理的交易,则可以获得奖励。
· 一个纯异步的 VM 可以通过使所有调用返回零,并将调用映射到添加到块末尾的特权交易来实现。
扩展:支持有状态的证明者
上述设计的一个挑战是它完全是无状态的,这使得它在数据利用上效率较低。通过支持有状态的压缩,使用理想的数据压缩,ERC20 发送可以比仅使用无状态压缩时更节省空间,最多可以节省 3 倍的空间。
此外,有状态的 EVM 不需要提供见证数据。在两种情况下,原则是相同的:要求数据可用是一种浪费,因为我们已经知道该数据是可用的,因为它是由 EVM 的先前执行输入或产生的。
如果我们想让 ZK-EVM 功能成为有状态的,那么我们有两个选择:
1. 要求 σpre 要么为空,要么是一个预先声明的键值对的数据可用列表,或者是某个先前执行的 σpost。
2. 将一个由区块生成的收据 R 的 blob 承诺添加到 (σpre,σpost,Proof) 元组中。任何先前生成或使用的 blob 承诺,包括那些表示区块、见证、收据甚至是常规的 EIP-4844 blob 交易的承诺,可能带有一些时间限制,都可以在 ZKEVMClaimTransaction 中被引用,并在其执行过程中被访问(可能通过一系列指令实现:「在块+见证数据的位置 j 处插入承诺 i 的字节 N...N+k−1」)。
(1) 基本上是在说:与其将无状态的 EVM 验证固化,我们将固化 EVM 子链。(2)本质上是创建一个内置的最小有状态压缩算法,它使用先前使用或生成的 blob 作为字典。这两者都给证明节点,仅仅是证明节点,增加了存储更多信息的负担;在情况(2)中,比情况(1)更容易将这种负担限制在一定时间内。
封闭式多证明系统和链下数据的争论
封闭式多证明者系统在 M-of-N 结构中固定了一定数量的证明系统,避免了上述许多复杂性。特别是,封闭式多证明者系统不需要担心确保数据上链的问题。此外,封闭式多证明者系统将允许 ZK-EVM 证明链下执行;这使其与 EVM Plasma 解决方案兼容。
然而,封闭式多证明者系统增加了治理复杂性并且降低了可审查性,这些是需要权衡的高成本与这些好处之间的。
如果我们将 ZK-EVM 确立为协议功能,那么「L2 项目」将会有哪些持续的角色?
协议将处理目前 L2 团队自己实施的 EVM 验证功能,但 L2 项目仍将负责许多重要的功能:
快速预确认:单槽终局性可能会使 L1 槽变慢,而 L2 项目已经在为其用户提供由 L2 自身安全支持的「预确认」,延迟远低于一个槽。这项服务将继续是纯粹的 L2 责任。
MEV 缓解策略:这可能包括加密内存池、基于声望的顺序选择以及 L1 不愿意实施的其他功能。
对 EVM 的扩展:L2 项目可以整合对 EVM 的实质性扩展,为其用户提供重要价值。这既包括「几乎-EVMs」,也包括像 Arbitrum Stylus 的 WASM 支持和 SNARK 友好的 Cairo 语言等根本不同的方法。
面向用户和开发者的便利:L2 团队在吸引用户和项目进入其生态系统并使其感到受欢迎方面做了大量工作;他们通过在其网络内获取 MEV 和拥塞费用来获得补偿。这种关系将继续存在。