“适当的ZK-EVM”可能是什么样子的?

 
 留言

以太坊之上的第 2 层 EVM 协议,包括乐观 rollup 和 ZK rollups,都依赖于 EVM 验证。但是,这需要他们信任大型代码库,如果该代码库中存在错误,这些 VM 就有被黑客入侵的风险。此外,这意味着即使是希望与 L1 EVM 保持完全相同的 ZK-EVM,也需要某种形式的治理,才能将对 L1 EVM 的更改复制到其自己的 EVM 实现中。

这种情况是次优的,因为这些项目正在复制以太坊协议中已经存在的功能,并且以太坊治理已经负责进行升级和修复错误:ZK-EVM 基本上与验证第 1 层以太坊区块的工作相同!此外,在接下来的几年里,我们预计轻量级客户端将变得越来越强大,并很快达到使用 ZK-SNARK 来全面验证 L1 EVM 执行的地步。届时,以太坊网络将有效地拥有内置的 ZK-EVM。那么问题来了:为什么不让 ZK-EVM 也原生地可用于 rollup?

本文将介绍几个可以实现的“供奉的 ZK-EVM”版本,并介绍权衡和设计挑战,以及不朝特定方向发展的原因。实现协议功能的好处应该与将事情留给生态系统和保持基本协议简单的好处进行权衡。

我们希望从封装的 ZK-EVM 中获得哪些关键特性?

  • 基本功能:验证以太坊区块。协议功能(到目前为止,无论是操作码、预编译还是其他机制都保持开放状态)应该接受(至少)一个状态前根、一个块和一个后状态根作为输入,并验证后状态根实际上是在前状态根之上执行块的结果。
  • 与以太坊的多客户端理念兼容。这意味着我们希望避免使用单一的证明系统,而是允许不同的客户使用不同的证明系统。这反过来又意味着几点:
    • 数据可用性要求:对于任何使用供奉的 ZK-EVM 进行验证的 EVM 执行,我们希望保证基础数据可用,以便使用不同证明系统的证明者可以重新证明执行,而依赖该证明系统的客户端可以验证这些新生成的证明。
    • 证明存在于 EVM 和块数据结构之外:ZK-EVM 功能不会从字面上将 SNARK 作为 EVM 输入,因为不同的客户端会期望不同类型的 SNARK。相反,它可能类似于 blob 验证:事务可以包括需要证明的(状态前、区块体、状态后)语句,操作码或预编译可以访问这些语句的内容,客户端共识规则将单独检查数据可用性和区块中每个声明的证明的存在。
  • 可审计性。 如果任何执行得到证实,我们希望底层数据可用,以便在出现任何问题时,用户和开发人员可以对其进行检查。在实践中,这又增加了一个数据可用性要求很重要的原因。
  • 可升级性。 如果发现某个特定的 ZK-EVM 方案存在错误,我们希望能够快速修复它。这意味着不需要硬分叉来修复。这又增加了一个原因,说明在EVM和块数据结构之外的证明很重要。
  • 支持几乎 EVM。L2s 的部分吸引力在于能够在执行层进行创新,并对 EVM 进行扩展。如果给定的 L2 VM 与 EVM 仅略有不同,如果 L2 仍能对与 EVM 相同的部件使用原生协议内 ZK-EVM,并且仅对不同的部件依赖自己的代码,那就太好了。这可以通过设计 ZK-EVM 功能来实现,该功能允许调用方指定由外部提供的表而不是 EVM 本身处理的位域或操作码或地址列表。我们还可以在有限的范围内使 gas 成本可以定制。

“开放”与“封闭”多客户端系统

“多客户理念”可能是此列表中最固执己见的要求。可以选择放弃它并专注于一个 ZK-SNARK 方案,这将简化设计,但代价是成为以太坊更大的“哲学支点”(因为它实际上是放弃以太坊长期以来的多客户端哲学),并以引入更大风险为代价。从长远来看,例如。形式验证技术变得更好,沿着这条路走可能会更好,但就目前而言,风险似乎太大了。

另一种选择是封闭的多客户端系统,其中有一组固定证明系统,这些系统在协议中是已知的。例如,我们可以决定使用三个 ZK-EVM:PSE ZK-EVMPolygon ZK-EVM 和 Kakarot。一个区块需要附带这三个中两个的证明才能有效。这比单一的证明系统要好,但它使系统的适应性降低,因为用户必须为每个现有的证明系统维护验证者,不可避免地会有一个政治治理过程来整合新的证明系统,等等。

这激发了我对开放多客户端系统的偏好,在这种系统中,证明被放置在“块之外”,并由客户端单独验证。个人用户将使用他们想要验证块的任何客户端,只要至少有一个证明者为该证明系统创建证明,他们就可以这样做。证明系统将通过说服用户运行它们来获得影响力,而不是通过说服协议治理过程来获得影响力。但是,正如我们将看到的,这种方法确实具有更高的复杂性成本。

我们希望从 ZK-EVM 实现中获得哪些关键特性?

除了对正确功能和安全性的基本保证外,最重要的属性是速度。虽然可以设计一个异步的协议内 ZK-EVM 功能,仅在延迟 N 个时隙后才返回每个声明的答案,但如果我们能够可靠地保证可以在几秒钟内生成证明,那么问题就会变得容易得多,因此每个块中发生的任何事情都是独立的。

虽然今天为以太坊区块生成证明需要几分钟或几小时,但我们知道,理论上没有理由阻止大规模并行化:我们总是可以将足够的 GPU 放在一起来分别证明区块执行的不同部分,然后使用递归 SNARK 将证明放在一起。此外,通过FPGA和ASIC进行硬件加速有助于进一步优化验证。然而,实际上达到这一点是一项重大的工程挑战,不容小觑。

协议内 ZK-EVM 功能具体是什么样子的?

与 EIP-4844 blob 事务类似,我们引入了一种包含 ZK-EVM 声明的新事务类型:

class ZKEVMClaimTransaction(Container):
    pre_state_root: bytes32
    post_state_root: bytes32
    transaction_and_witness_blob_pointers: List[VersionedHash]
    ...

与 EIP-4844 一样,在内存池中传递的对象将是事务的修改版本:

 
class ZKEvmClaimNetworkTransaction(Container):
    pre_state_root: bytes32
    post_state_root: bytes32
    proof: bytes
    transaction_and_witness_blobs: List[Bytes[FIELD_ELEMENTS_PER_BLOB * 31]]
    

后者可以转换为前者,但不能反过来。我们还扩展了区块 sidecar 对象(在 EIP-4844 中引入),以包含区块中声明的证明列表。

请注意,在实践中,我们可能希望将 sidecar 拆分为两个单独的 sidecar,一个用于 blob,一个用于证明,并且为每种类型的证明设置一个单独的子网(以及一个用于 blob 的附加子网)。

在共识层,我们添加了一个验证规则,即只有当客户端看到区块中每个声明的有效证明时,才会接受区块。证明必须是 ZK-SNARK 证明 的串联 是一对的序列化并且 使用 i) 有效,并且 (ii) 输出正确的 .潜在地,客户可以选择等待多种类型证明的 M-of-N。transaction_and_witness_blobs(Block, Witness)pre_state_rootWitnesspost_state_root

这里的一个哲学说明是,块执行本身可以简单地被视为 (���和,��或��,��或或�) 三元组,需要与对象中提供的三元组一起检查 ZKEVMClaimTransaction因此,用户的 ZK-EVM 实现可以取代其执行客户端;执行客户端仍将由 (i) 证明者和区块构建者使用,以及 (ii) 关心索引和存储数据以供本地使用的节点。

验证和重新验证

假设有两个以太坊客户端,其中一个使用 PSE ZK-EVM,另一个使用 Polygon ZK-EVM。假设此时,两个实现都已经发展到可以在 5 秒内证明以太坊区块执行的程度,并且对于每个证明系统,都存在足够多的独立志愿者运行硬件来生成证明。

不幸的是,由于个人证明系统没有被奉为圭臬,因此它们不能在协议中得到激励;然而,我们预计与研发成本相比,运行证明者的成本较低,因此我们可以简单地使用通用机构为证明者提供公共产品资金。

假设有人发布了一个 只不过他们发布了 PSE ZK-EVM 的一个版本 。Polygon ZK-EVM 的证明节点看到了这一点,并使用 Polygon ZK-EVM 的 a 计算并重新发布对象 ZKEvmClaimNetworkTransactionproofproof

这增加了最早的诚实节点接受区块和最新的诚实节点接受相同区块之间的总最大延迟。2�+���或在和(假设这里���或在和<5�).

然而,好消息是如果我们采用单槽终结性,我们几乎可以肯定地可以将这种额外的延迟与 SSF 固有的多轮共识延迟一起“管道化”。 例如在这个 4 子插槽提案,“头部投票”步骤可能只需要检查基本区块的有效性,但随后“冻结并确认”步骤将需要存在证明。

扩展:支持“几乎-EVM”

ZK-EVM 功能的一个理想目标是支持“几乎 EVM”:内置了一些额外功能的 EVM。这可能包括新的预编译、新的操作码、在 EVM 或完全不同的虚拟机(例如,在 Arbitrum Stylus 中)编写合约的选项,甚至是具有同步交叉通信的多个并行 EVM。

可以通过简单的方式支持一些修改:我们可以定义一种语言,允许 传递修改后的 EVM 规则的完整描述。这可以用于:ZKEVMClaimTransaction

  • 自定义 gas 成本表(用户不被允许降低 gas 成本,但他们可以增加成本)
  • 禁用某些操作码
  • 设置区块编号(这意味着根据硬分叉的不同规则)
  • 设置一个标志,用于激活一整套 EVM 更改,这些更改已针对 L2 使用而非 L1 使用进行标准化,或其他更简单的更改

为了允许用户通过引入新的预编译(或操作码)以更开放的方式添加新功能,我们可以在以下位置添加预编译输入/输出脚本,该脚本作为 blob 的一部分包含在ZKEVMClaimNetworkTransaction

class PrecompileInputOutputTranscript(Container):
    used_precompile_addresses: List[Address]
    inputs_commitments: List[VersionedHash]
    outputs: List[Bytes]

EVM 执行将按如下方式修改。数组 将被初始化为空。调用 in 中的地址时我们将 a 对象附加到 input 中, 并将调用设置为 。最后,我们检查 were 是否完全被调用 ,并且是否与生成 blob 承诺的结果匹配到 SSZ 序列化。公开的目的是 使外部 SNARK 能够轻松证明输入和输出之间的关系。inputsused_precompile_addressesInputsRecord(callee_address, gas, input_calldata)RETURNDATAoutputs[i]used_precompile_addresseslen(outputs)inputs_commitmentsinputsinputs_commitments

请注意输入(存储在哈希中)和输出(以字节形式存储)之间的不对称性。这是因为执行需要由仅看到输入并理解 EVM 的客户端执行。EVM 执行已经为他们生成了输入,因此他们只需要检查生成的输入是否与声明的输入匹配,这只需要进行哈希检查。但是,必须向他们全面提供输出,因此必须提供数据。

另一个有用的功能可能是允许从任意发件人帐户进行调用的“特权事务”。这些事务可以在另外两个事务之间运行,也可以在调用预编译时在另一个(也可能是特权)事务期间运行。这可用于允许非 EVM 机制回调到 EVM 中。

除了新的或修改的预编译之外,还可以修改此设计以支持新的或修改的操作码。即使只有预编译,这种设计也非常强大。例如:

  • 通过设置为 包含常规帐户地址列表,这些帐户地址在状态中的帐户对象中设置了一些标志,并创建一个 SNARK 来证明它是正确构造的,您可以支持 Arbitrum Stylus 风格的功能,其中合约可以在 EVM 或 WASM(或其他 VM)中编写代码。特权事务可用于允许 WASM 帐户回调到 EVM。used_precompile_addresses
  • 通过添加外部检查,确保多个 EVM 执行的输入/输出脚本和特权事务以正确的方式匹配,您可以证明多个 EVM 的并行系统通过同步通道相互通信。
  • 4 类 ZK-EVM 可以通过多种实现来运行:一种是将 Solidity 或其他更高级别的语言直接转换为 SNARK 友好的 VM,另一种是将其编译为 EVM 代码并在 ZK-EVM 中执行。第二种(不可避免地较慢)实现只能在以下情况下运行:故障证明者发送一个交易,断言存在错误,如果他们能够提供两者区别对待的交易,则收取赏金。
  • 纯异步 VM 可以通过使所有调用返回零并将调用映射到添加到块末尾的特权事务来实现。

扩展:支持有状态证明器

上述设计的一个挑战是它是完全无状态的,这使得它的数据效率低下。通过理想的数据压缩,ERC20 发送使用有状态压缩与仅使用无状态压缩相比,空间效率最高可提高 3 倍。

 

 

除此之外,有状态 EVM 不需要提供见证数据。 在这两种情况下,原则是相同的:当我们已经知道数据可用时,要求数据可用是一种浪费,因为它是在 EVM 的先前执行中输入或生成的。

如果我们想使 ZK-EVM 功能有状态,那么我们有两种选择:

  1. 需要���和要么是空的,要么是预先声明的键和值的数据可用列表,要么是��或��以前的一些执行。
  2. 将 blob 承诺添加到收据Add a blob commit to a receipt由块生成到(���和,��或��,��或或�) 元。任何以前生成或使用的 blob 承诺,包括表示区块、见证人、收据甚至常规 EIP-4844 blob 事务的 blob 承诺,可能有一些时间限制,都可以在 在其执行期间引用和访问(可能通过一系列指令:“插入 承诺字节数)ZKEVMClaimTransactionN...N+k-1在位置块+见证数据“)

(1)基本上是说:与其将无状态EVM验证纳入其中,不如将EVM子链纳入其中。(2) 本质上是创建一个最小的内置有状态压缩算法,该算法使用以前使用或生成的 blob 作为字典。两者都给证明者节点带来了负担,而且只有证明者节点才能存储更多信息;在情况(2)中,比在情况(1)中更容易使该负担有时间限制。

封闭式多证明器和链下数据的参数

一个封闭的多证明系统,在M-of-N结构中存在固定数量的证明系统,避免了上述相当多的复杂性。特别是,封闭的多证明系统不需要担心确保数据在链上。此外,封闭的多证明系统将允许 ZK-EVM 证明链下执行;这使其与 EVM 等离子体解决方案兼容

然而,封闭的多证明系统增加了治理的复杂性并消除了可审计性,这些都是需要权衡这些好处的高成本。

如果我们将 ZK-EVM 作为协议特性,那么“第 2 层项目”的持续作用是什么?

目前由第 2 层团队自行实现的 EVM 验证功能将由协议处理,但第 2 层项目仍将负责许多重要功能

  • 快速预确认:单插槽的最终确定性可能会使第 1 层插槽变慢,而第 2 层项目已经在为用户提供“预确认”,以第 2 层自身的安全性为后盾,延迟远低于一个插槽。这项服务将继续纯粹是第 2 层的责任。
  • MEV 缓解策略:这可能包括加密的内存池、基于信誉的测序器选择以及第 1 层不愿意实现的其他功能。
  • EVM 的扩展:第 2 层项目可以对 EVM 进行实质性扩展,从而为其用户提供重要价值。这包括“几乎 EVM”和完全不同的方法,例如 Arbitrum Stylus 的 WASM 支持和 SNARK 友好的 Cairo 语言。
  • 面向用户和开发人员的便利性:Layer 2 团队做了很多工作来吸引用户和项目加入他们的生态系统,并让他们感到受欢迎;他们通过在网络内捕获 MEV 和拥塞费用来补偿这一点。这种关系将继续下去。