原文:https://notes.ethereum.org/@vbuterin/enshrined_zk_evm 译者:登链社区[1] 翻译小组
建立在以太坊之上的 Layer2 EVM 协议,包括 Optimistic Rollups 和 ZK Rollups,都依赖于 EVM 验证。然而,这需要它们信任庞大的代码库,如果代码库中存在漏洞,这些虚拟机就有被黑客攻击的风险。此外,即便是想要与 L1 EVM 完全等效的 ZK-EVM,也需要某种形式的治理机制,以便将 L1 EVM 的更改复制到其自身的 EVM 实现中。
这种情况并不理想,因为这些项目在复制已存在于以太坊协议中的功能,并且以太坊治理已经负责升级和修复错误的地方:ZK-EVM 基本上做的是验证 Layer1 以太坊区块的工作!此外,在未来几年中,我们预计 轻客户端[2] 会变得越来越强大,很快就会 使用 ZK-SNARKs 完全验证 L1 EVM 执行 。到那时, 以太坊网络将有效地拥有内置的 ZK-EVM 。因此,一个问题就出现了:为什么不让ZK-EVM原生地用于rollup呢?
本文将介绍几个可以实施的封装 ZK-EVM的版本 ,并详细介绍权衡和设计挑战,以及不采取特定方向的原因。实施协议特性的优势应该与留给生态系统并保持基础协议简单性的好处进行权衡。
封装 ZK-EVM 想要获得哪些关键特性? 基本功能 :验证以太坊区块 。协议特性(暂未确定是否为操作码、预编译或其他机制)应接受(至少)一个预状态根、一个区块和一个后状态根作为输入,并验证后状态根实际上是在预状态根上执行区块的结果。
与以太坊多客户端理念的 兼容性[3] ,这意味着我们希望避免使用单一的证明系统,而是允许不同的客户使用不同的证明系统。这反过来又意味着几点:
数据可用性要求 :对于通过封装的 ZK-EVM 进行的任何 EVM 执行,我们希望能 保证底层数据可用性[4] ,这样使用不同证明系统的证明者可以重新证明执行,并且依赖该证明系统的客户端可以验证新生成的证明。
证明存放在 EVM 和区块数据结构之外 :ZK-EVM 功能不会将 SNARK 直接作为 EVM 输入,因为不同客户端期望不同类型的 SNARK。相反,它可能 类似于 blob 验证 :交易可以包括(预状态、区块主体、后状态)需要证明的声明,一个操作码或预编译可以访问这些声明的内容,客户端共识规则将分别检查数据可用性和区块中所作每个声明的证明的存在。
可审计性 :如果任何执行被证明,我们希望底层数据可用,以便用户和开发者可以检查。实际上,这又增加了一个数据可用性要求很重要的原因。
可升级性 :如果发现某个特定的 ZK-EVM 方案存在漏洞,我们希望能够迅速修复,而 不需要硬分叉 。这又增加了 证明存放在 EVM 和区块数据结构之外的重要性 。
支持almost - EVMs :L2 的吸引力之一是在执行层面进行创新 ,并对 EVM 进行扩展 。如果给定 L2 的虚拟机与 EVM 仅略有不同,那么当 L2 与 EVM 相同的部分仍然可以使用原生的协议内 ZK-EVM 时,这将是很好的,只有对于与 EVM 不同的部分才会依赖他们自己的代码。这可以通过设计 ZK-EVM 功能的方式来完成,使其允许调用者指定位域(bitfield)、操作码或地址列表,由外部提供的表来处理而不是由 EVM 本身。我们还可以在有限的范围内使 gas 成本可定制。
开放与封闭的多客户端系统 多客户端理念可能是上述列表中最有主张的要求 。有放弃它并专注于一个 ZK-SNARK 方案的选择,这将简化设计,但代价是成为以太坊更大的理念转向 (因为它实际上是放弃以太坊长期以来的多客户端理念),并引入更大的风险。在长期的未来,例如形式验证技术变得更加完善时,可能更好的做法是走这条路线,但目前看来风险似乎太大。
另一种选择是 封闭的多客户端系统 ,在协议中已知一组固定的证明系统。例如,我们可能决定使用三个 ZK-EVM:PSE ZK-EVM[5] ,Polygon ZK-EVM[6] 和 Kakarot[7] 。一个区块需要来自这三个中的两个的证明才能被视为有效。这比单一证明系统要好,但它使系统更少适应性,因为用户必须维护每个证明系统的验证器,必然会对纳入新证明系统的政治治理程序等产生影响。
这促使 我倾向于开放的多客户端系统 ,其中证明被放置在「区块之外」并由客户端单独验证。个体用户将使用他们想要的客户端来验证区块,只要有一个证明者为该证明系统创建证明就可以。证明系统通过说服用户运行它们来获得影响力,而不是通过说服协议治理流程。然而,这种方法的复杂性成本更高,正如我们将看到的那样。
我们希望 ZK-EVM 实现具备哪些关键特性? 除了正确功能和安全性的基本保证外, 最重要的特性是速度 。虽然可以设计一个异步的协议内 ZK-EVM 功能,仅在经过 N 个槽之后才返回每个声明的答案,但如果我们能够可靠的保证可以在几秒钟内生成证明,那么问题就会变得容易的多,因此每个块钟发生的任何事情都是独立的。
虽然今天为以太坊区块生成证明需要很多分钟甚至小时,但我们知道没有理论上的理由阻止大规模并行化:我们总是可以组装足够多的 GPU 来分别证明区块执行的不同部分 ,然后使用递归 SNARKs 将证明合并在一起。此外,通过 FPGA 和 ASIC 的硬件加速可以帮助优化证明。然而,要实现这一点是一个重大的工程挑战,不应低估。
协议内的 ZK-EVM 功能具体是什么样的? 类似于 EIP-4844 blob 交易[8] ,我们引入了一种包含 ZK-EVM 声明的新交易类型:
与 EIP-4844 类似,传播于内存池中的对象将是交易的修改版本:
后者可以转换为前者,但反之则不然。我们还扩展了区块 side car 对象(在 EIP-4844[9] 中引入)以包含区块中所做声明的证明列表。
请注意,在实际操作中,我们很可能希望将 sidecar 分为两个独立的 sidecars,一个用于 blob,另一个用于证明,并为每种类型的证明设立一个独立的子网(另外还有一个子网用于 blobs)。
在共识层上,我们添加了一个验证规则 :只有当客户端看到区块中每个声明的有效证明后,才能接受该区块。证明必须是一个 ZK-SNARK,证明了 transaction_and_witness_blobs
的串联是(Block, Witness)对的序列化,以及使用 Witness(i)在 pre_state_root
上执行区块是有效的,并且(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 的 proof 版本。Polygon ZK-EVM 的证明节点看到了这一情况,计算并重新发布了具有 Polygon ZK-EVM proof 的对象。
这增加了最早接受区块的诚实节点和最后接受同一区块的最新诚实节点之间的总最大延迟,从 δ 到 2δ+Tprove (在这里假设 Tprove < 5s)。
然而,好消息是, 如果我们采用单个槽最终确定性,我们几乎可以肯定地将这种额外延迟与 SSF 中固有的多轮共识延迟一起"管道化"处理。 例如,在这个 4 子槽提案[10] 中,"头投票"步骤可能只需要检查基本区块的有效性,但"冻结并确认"步骤需要存在一个证明。
扩展:支持 almost-EVMs ZK-EVM 功能的一个理想目标是 支持almost-EVMs:他是是具有一些额外特性的 EVM 。这可能包括新的预编译器、新的操作码、有选项可以用 EVM 或完全不同的 VM(例如 Arbitrum Stylus[11] 中的情况)方式来编写合约,甚至具有同步交叉通信的多个并行 EVM。
一些修改可以以简单方式支持:我们可以定义一种语言,允许 ZKEVMClaimTransaction
传递修改后的 EVM 规则的完整描述。这可以应用于:
自定义 gas 成本表(用户不允许减少 gas fee,但可以增加)
禁用特定操作码
设置区块编号(这将意味着根据硬分叉而有不同的规则)
设置激活专门用于 L2 但不用于 L1 的一整套 EVM 变更的标志,或者其他简单的变更
为了允许用户通过引入新的预编译器(或操作码)以更加开放地引入新功能,我们可以在以下位置添加预编译的输入/输出脚本,其作为 ZKEVMClaimNetworkTransaction 中 blob 的一部分包含在:
EVM 执行将进行修改。一个数组 inputs
将被初始化为空。第 i 次调用 used_precompile_addresses
中的地址时,我们向 inputs
添加 InputsRecord(callee_address, gas, input_calldata)
,并将调用的 RETURNDATA
设置为 outputs[i]
。最后,我们检查 used_precompile_addresses
总共被调用了 len(outputs)
次,以及 inputs_commitments
是否与对 inputs
的 SSZ 序列化产生的 blob 承诺的结果相匹配。暴露 inputs_commitments
的目的是为了便于外部 SNARK 证明输入与输出之间的关系。
请注意输入(存储在哈希中)和输出(以字节形式存储)之间的不对称性。这是因为执行需要能够由只看到输入并理解 EVM 的客户端完成。EVM 执行已经为它们生成了输入,因此它们只需要检查生成的输入是否与声称的输入匹配,这只需要进行哈希检查。然而,输出必须完整提供给它们,因此必须具有数据可用性。
另一个有用的特性可能是 允许"特权交易" ,可以从任意发送方帐户进行调用。这些交易可以在两个其他交易之间运行,或者在另一个(可能也是特权的)交易中调用预编译器时运行。这可以用于允许非 EVM 机制回调到 EVM。
此设计可以修改以支持新的或修改后的操作码 ,除了新的或修改后的预编译器。即使只有预编译器,这种设计也非常强大。例如:
通过将 used_precompile_addresses
设置为包含在状态中具有某些标志的常规帐户地址列表,并生成一个 SNARK 证明以证明其正确构造,你可以支持像 Arbitrum Stylus[12] 风格的特性,其中合约可以在 EVM 或 WASM(或其他 VM)中编写其代码。特权交易可用于允许 WASM 帐户回调到 EVM。
通过添加外部检查来验证多个 EVM 执行的输入/输出记录和特权交易以正确方式匹配,你可以证明一种多个 EVM 的并行系统,这些系统通过同步通道进行通信。
Type 4 的 ZK-EVM[13] 可以通过多个实现来运行:一种将 Solidity 或其他更高级别的语言直接转换为 SNARK 友好的 VM 的实现,并另一种将其编译为 EVM 代码并在内置的 ZK-EVM中执行。第二种(不可避免地更慢)实现只能在出现故障证明者发送交易断言存在漏洞的情况下运行,并在提供一个两处处理不同的交易时,则收取赏金。
可以通过使所有调用返回零并将调用映射到添加到区块末尾的特权交易来实现纯异步 VM。
扩展:支持有状态的证明者 上述设计的一个挑战是它完全是无状态的,这使得它数据效率低下。使用理想的数据压缩,与仅使用无状态压缩相比,一个 ERC20 发送在使用有状态压缩时,空间效率最高可提高 3 倍。
除此之外,有状态的 EVM 不需要提供见证数据。在两种情况下,原则都是相同的:要求数据可用是一种浪费,因为我们已经知道该数据是可用的,因为它是在先前的 EVM 执行中输入或生成的。
如果我们想使 ZK-EVM 功能有状态,则有两种选择:
要求 σpre 为空 ,或者是一个的预先声明的键和值数据可用列表,或者是先前执行 σpost 的某个列表
向(σpre ,σpost ,Proof)元组添加一个与区块生成的 receipt R 的 blob 承诺。 在 ZKEVMClaimTransaction 中可以引用任何先前生成或使用的 blob 承诺,包括代表区块、见证、receipt,甚至常规的 EIP-4844 blob 交易,或许还有一些时间限制,可以在其执行期间访问(可能通过一系列指令:「在区块+见证数据的位置 j 插入承诺 i 的字节 N...N+k-1」)
(1) 基本是说:与其无状态 EVM 验证纳入其中(封装),不过将 EVM 子链纳入其中(封装)。(2)本质上是创建了一个最小的内置有状态压缩算法,该算法使用先前使用或生成的 blobs 作为字典。这两种方式都会给证明节点增加负担,并且只有证明节点才能存储更多信息;在情况(2)中,比情况(1)更容易使该负担有时间限制。
封闭式多证明系统和链下数据的论据 封闭式多证明系统,其中具有 M-of-N 结构的固定数量的证明系统,避免了上述许多复杂性。 封闭式多证明者系统特别是不需要担心确保数据在链上的问题。此外,封闭式多证明者系统将允许 ZK-EVM 证明链下执行;这使其与 EVM Plasma 解决方案[14] 兼容。
然而, 封闭式多证明者系统增加了治理复杂性并消除了可审计性 ,这些是需要权衡带来这些好处的高成本。
如果 ZK-EVM 作为协议功能,那Layer2 项目的持续作用是什么? 当前由 Layer2 团队实现的 EVM 验证功能将由协议处理,但 Layer2 项目仍将负责许多重要功能:
快速预确认 :单个槽最终性可能会使 Layer1 槽(slot)变慢,而 Layer2 项目已经为其用户提供了由 Layer2 自身安全性支持的「预确认」,延迟远低于一个槽。这项服务将继续纯粹由 Layer2 负责。
MEV 缓解策略 :这可能包括加密内存池、基于声誉的序列选择以及 Layer1 不愿意实施的其他功能。
对 EVM 的扩展 :Layer2 项目可以包含对 EVM 的重要扩展,为其用户提供巨大价值。这包括alomost-EVM 和诸如 Arbitrum Stylus[15] 的 WASM 支持以及 SNARK-friendly Cairo(https://www.cairo-lang.org/)语言等完全不同的方法。
面向用户和开发者的便利性 :Layer2 团队致力于吸引用户和项目进入其生态系统并使其感到受欢迎;他们通过在其网络内捕获 MEV 和拥堵费用来获得补偿。这种关系将继续存在。