#circuit #component #aggregation #compute #axiom #proof #subquery

nightly bin+lib axiom-query

此文件包含为 AxiomV2Query 智能合约生成证明的 ZK 电路

4 个稳定版本

2.0.17 2024 年 4 月 30 日
2.0.16 2024 年 3 月 18 日
2.0.15 2024 年 3 月 12 日
2.0.14 2024 年 1 月 21 日

#8#axiom

每月 39 次下载
2 个包中使用(通过 axiom-circuit

MIT 许可证

1.5MB
27K SLoC

AxiomV2Query ZK 电路

证明和验证密钥生成

有关如何在以太坊主网上生成我们使用的确切证明和验证密钥的说明,请参阅 此处

概述

子查询组件

这些是证明单个类型所有子查询的组件电路

这些电路都使用 组件电路框架。它们各自由一个包含 RlcCircuitBuilderComponentCircuitImpl 组成,一个用于 keccak 的单个 PromiseLoader,以及一个用于相关子查询类型(在 header 的情况下没有)的单个 PromiseLoader。每个案例中的 CoreBuildervirtual_assign_phase 中指定电路的业务逻辑,但没有特殊的原始赋值:所有的原始赋值都是由 RlcCircuitBuilderPromiseLoader 执行的。每个电路输出的虚拟表是 (subquery, value) 对的表,对于该子查询类型。每个电路中的 subquery 类型都不同,但我们为每种类型指定了一个 flatten 函数,该函数统一了计算基于 Poseidon 的对虚拟输出表的承诺的方式。

对于每个电路,需要指定

  • 虚拟表的类型
  • 用于进行承诺调用的组件类型
    • 标题:无(但取决于外部块哈希 MMR)
    • 账户:标题
    • 存储:账户
    • 交易:标题
    • 收据:标题
    • 以太坊智能合约:存储

CoreBuilder 实现中被隐藏的是 ComponentCircuitImpl 的其他部分

  • 正确的加载了承诺表和添加了动态查找的 PromiseLoader
  • 承诺表的计算是正确的

每个电路未经验证的假设是

  • keccak 和被调用组件电路的承诺表将与这些电路的实际输出承诺相匹配

免责声明:子查询电路实现之间仍然存在相当数量的复制粘贴代码。我们正在努力进一步减少这一现象。

结果根组件电路

这个电路也使用了 组件电路框架,但与子查询电路相比有些特殊。它是一个没有组件输出的组件电路。然而,它确实会对每个子查询组件电路进行承诺调用。这些承诺表是 事先 按子查询类型分组的。此外,它们可能包含仅用于检查用户子查询正确性的中间子查询(例如,交易子查询需要一个相应的标题子查询来检查交易根)。为了计算 queryHashresultsRoot,我们需要用户子查询和结果的 有序 列表。我们通过“连接”不同类型的承诺表到一个大的查找表,然后进行动态查找来检查。

连接目前是在 table 模块中完成的;它将在即将到来的 PR 中移动到 MultiPromiseLoader

这个组件电路没有组件输出的原因是因为电路的真实输出是:resultsRootresultsRootPoseidon,和 subqueryHash。这些是面向外部的用户输出,并且为了未来的兼容性,它们的格式取决于子查询的数量(例如,resultsRoot 是一个填充到 numSubqueries 的下一个 2 的幂的 Merkle 根)。因此,没有自动计算这些承诺的方法,我们为它们有自定义的实现。

Keccak 组件碎片电路

halo2-lib/zkevm-hashes 中的基本 KeccakComponentShardCircuit 是按照我们的 定义 的一种组件电路。我们为 axiom-eth 添加了适配器,以便它可以作为组件电路在我们的框架中被承诺调用。

Merkle 聚合电路

上面我们已经描述了组件 碎片 电路。对于任何组件类型,多个碎片电路将通过 InputMerkleAggregation 聚合在一起(确切的配置将在基准测试后确定)。因此,我们将为每个组件类型有组件聚合电路,其中输出承诺是碎片输出承诺的 Merkle 根。我们指出,这完全由子查询聚合电路和 Axiom 聚合 1 电路支持,因为给定组件类型的碎片和聚合电路的公共实例格式将完全相同,除了累加器。子查询聚合电路和 Axiom 聚合 1 电路知道何时从先前实例的聚合 snarks 中删除旧累加器,所以处理是统一的。

验证计算电路

此电路聚合用户提交的compute snark(形式为AxiomV2ComputeQuery)。然后它取消提交声明的resultsRootPoseidon和声明的Poseidon承诺到subqueryHashes。之后,它需要调用keccaks来组合子查询结果和computeQuery以计算完整的queryHash

这不是一个组件电路,但它使用EthCircuitImpl实现,该实现使用PromiseLoader调用keccak组件。

子查询聚合电路

这是一个通用聚合电路,聚合所有子查询电路和结果根电路。由于结果根电路调用每个子查询电路,因此此聚合电路将检查所有承诺承诺和子查询组件电路的输出承诺之间的公共实例等式。

它还将检查所有keccak承诺承诺是否相等,但此承诺承诺尚未检查。

子查询聚合电路的公共输出是

  • 结果根电路的输出
  • 来自标题电路的blockhash MMR
  • keccak承诺承诺
  • 通用聚合的累加器和聚合vkey哈希

在此聚合之后,可以忘记子查询和结果根电路。

Axiom聚合1电路

此电路将聚合

  • 验证计算电路
  • 子查询聚合电路
  • Keccak组件最终聚合电路

换句话说,它聚合了所有剩余的电路。它将检查resultsRootPoseidonsubqueryHashes在验证计算和子查询聚合电路中的提交是否匹配。它还将检查keccak承诺和输出承诺是否匹配。

Axiom聚合2电路

此聚合Axiom聚合1电路。它本质上是一个透明电路,但我们还添加了一个payee公共实例(这是为了防止交易在内存池中抢先执行)。

电路公共IO格式

我们从接触智能合同的电路开始,然后向依赖项工作。

Axiom聚合2(最终,用于EVM)

这是将在EVM上由固定验证器验证的snark。

公共IO

公共IO由以下给出

  • accumulator(384字节)
  • sourceChainId(uint64,在F中)
  • computeResultsHash(bytes32,在hi-lo中)
  • queryHash(bytes32,在hi-lo中)
  • querySchema(bytes32,在hi-lo中)
  • blockhashMMRKeccak(bytes32,在hi-lo中)
  • aggVkeyHash(bytes32,在F中)
  • payee(address,在F中)(它不保存任何EVM keccaks以在电路中将这些所有内容组合在一起进行哈希,因此我们可以保留多个公共实例。)

这将是一个固定的AggregationCircuit,具有Universality::Full,可以验证任何具有固定配置的电路。固定配置将是另一个AggregationCircuit(也称为单阶段BaseCircuitParams)。我们称先前的电路为最终EVM验证的AxiomAggregation1Circuit

  • AxiomAggregation2Circuit将只是传递它正在验证的AxiomAggregation1Circuit的公共实例,并添加一个收款人实例。
  • 它还使用AxiomAggregation1Circuit.aggVkeyHashAxiomAggregation1Circuit本身的k, preprocessed_digest计算一个新的aggVkeyHash
  • 本代码中的 k 和选择器必须是固定的 —— 我们链上验证器不允许通用性。
  • AxiomAggregation2Circuit 将配置为使用较少的列以实现最经济的链上验证。

Axiom聚合1电路

公共IO

这与Axiom Aggregation 2 的公共 IO相同,只是没有 收款人字段

  • accumulator(384字节)
  • sourceChainId(uint64,在F中)
  • computeResultsHash(bytes32,在hi-lo中)
  • queryHash(bytes32,在hi-lo中)
  • querySchema(bytes32,在hi-lo中)
  • blockhashMMRKeccak(bytes32,在hi-lo中)
  • aggVkeyHash(bytes32,在F中)

这是一个具有 Universality::FullAggregationCircuit

  • k 和选择器可以是可变的:这意味着我们可以有多个 ControllerAggregationCircuit(我认为这使其成为一个特质)
    • 任何此类电路都可以执行仅需要 BaseCircuitBuilder 的任何操作,特别是它可以验证任意数量的 snarks
    • 但它不能进行动态查找(需要新列),或者 RLC(除非我们决定添加固定数量的 RLC 列以支持)
  • 理想情况下,在 g5.48xl 上生成证明需要 <10 秒

此电路将聚合

  • VerifyComputeCircuit
  • SubqueryAggregationCircuit
  • KeccakFinalAggregationCircuit

如果我们在 EVM 中有一个通用验证器(例如这里),则可以将 AxiomAggregation2AxiomAggregation1 电路组合在一起,但以往的经验表明,AxiomAggregation1 电路足够大,以至于两层聚合比一层大层更快。

验证计算电路

公共IO

  • [未使用] 组件管理的 output_commit(F),应该忽略,因为此电路没有虚拟输出
  • promiseCommitment(F)——在这种情况下,这是 poseidon(promiseKeccakComponent)
  • accumulator(384字节)
  • sourceChainId(uint64,在F中)
  • computeResultsHash(bytes32,在hi-lo中)
  • queryHash(bytes32,在hi-lo中)
  • querySchema(bytes32,在hi-lo中)
  • resultsRootPoseidon(F)
  • promiseSubqueryHashes(F)

执行以下操作

  • 验证计算 snark。
    • snark 的 k 和 vkey 已在 queryHash 中提交。因此,我们没有其他(Poseidon)aggVkeyHash,因为我们正在聚合的唯一 snark。
  • subqueryHashes 计算出 dataQueryHash
  • dataQueryHashcomputeQuery 计算出 queryHash
  • 计算 querySchema
  • 计算 computeResultsHash
    • 需要使用 动态查找 在数据结果中查找计算子查询

依赖于外部对在 ResultsRoot 电路中完成的计算的提交,该电路计算实际的子查询结果和子查询哈希。

我们之所以将查询哈希的计算分开到这个电路,而不是将其放入下面由 SubqueryAggregationCircuit 聚合的电路中,是因为最终的 queryHash 计算不能并行化,而我们可以将 SubqueryAggregationCircuit 中的所有内容在未来并行化到多个数据分片中。

子查询聚合电路

我们可以有多个这些实现,每个都可以是任何电路——没有对列数、门、查找等的限制。这为我们提供了很多灵活性,并允许我们稍后添加新变体,而无需更改 FinalVerifierControllerAggregationCircuit

公共IO

  • accumulator(384字节)
  • promiseKeccakComponent(F)是先前聚合组件 snarks 中重新公开的 keccak 组件承诺
  • aggVkeyHash(F)
  • resultsRootPoseidon(F)
  • commitSubqueryHashes(F)
  • blockhashMMRKeccak(bytes32,在hi-lo中)

SubqueryAggregationCircuit

  • 聚合以下电路(对于每种类型,可以是分片电路或Merkle 聚合电路的电路组合)。
    • 结果根
    • 头部
    • 账户
    • 存储
    • 交易
    • 收据
    • Solidity
  • 约束组件“调用”之间数据组件提交的相等性。
  • 约束每个聚合组件中的keccak组件承诺相等,然后将此承诺重新公开为公共实例。

结果根组件电路

公共IO

  • [未使用] 组件管理的output_commit。此组件没有虚拟表作为输出,不应直接调用。
  • promiseComponentsCommit (F) - 包含keccak的所有承诺的poseidon哈希
  • resultsRootPoseidon(F)
  • commitSubqueryHashes(F)

commitSubqueryHashes是对numSubqueries个keccak子查询哈希的Poseidon承诺(变量数量)。我们选择使用可变长度的Poseidon以获得更多灵活性,因此该电路中的总子查询容量不必与VerifyCompute电路中的userMaxSubqueries相匹配。因此,此commitSubqueryHashes也承诺了numSubqueries

头部组件电路

公共IO

  • commitHeaderComponent (F)
  • promiseCommitment (F)
  • blockhashMMRKeccak(bytes32,在hi-lo中)

账户组件电路

公共IO

  • commitAccountComponent (F)
  • promiseCommitment (F)

存储组件电路

公共IO

  • commitStorageComponent (F)
  • promiseCommitment (F)

交易组件电路

公共IO

  • commitTxComponent (F)
  • promiseCommitment (F)

收据组件电路

公共IO

  • commitReceiptComponent (F)
  • promiseCommitment (F)

Solidity组件电路

公共IO

  • commitSolidityComponent (F)
  • promiseCommitment (F)

Keccak 组件碎片电路

公共IO

  • keccakComponentCommit (F)

Merkle聚合电路

如上所述,我们已指定分片电路组件的公共IO。我们将有多个配置,其中我们使用MerkleAggregationCircuit将多个相同组件类型的分片电路聚合到一个新的MerkleAggregationCircuit中。

新MerkleAggregationCircuit的公共IO将包括384字节的accumulator,后面是与分片电路完全相同的实例格式。输出提交现在是分片输出提交的Merkle根。所有分片承诺的承诺被约束为相等。

参考图

以下图仅作参考。确切的配置和电路数量将取决于使用的聚合配置。

diagram

依赖关系

~32–51MB
~1M SLoC