1. 引言
本文定义了如何借助递归、聚合和组合来实现polygon zkEVM证明。zkEVM的约束使用PIL语言定义多项式恒等式。然后,使用PIL规范来表示待证明execution trace,来构建用FRI协议证明的STARK。问题是STARK会产生big proofs。本文描述了如何将递归与组合一起使用以 缩短证明大小。
从高层来看:
- 1)基础递归模块:可将 PIL规范 转换为 其STARK验证电路规范(用Circom编写)。该(Circom)电路验证PIL规范的STARK。
- 2)然后,将 Circom规范 转换为 Plonkish PIL规范。
- 3)对以上过程循环调用进行迭代。
除了递归,还实现了聚合,以便Provers可聚合多个交易batches的证明。
2. 工具
2.1 PIL
Polynomial Identity Language(PIL)是一种新的领域特定语言,用于定义:
- 基于电路模型的计算
- 或 基于状态机模型的计算
的execution trace的约束。基于状态机的zkEVM execution trace的约束是用PIL指定的。
2.2 Circom
Circom架构如上图所示:
- 开发者使用Circom语言来定义算术电路
- 编译器生成:
- 具有电路相关R1CS约束集合的文件。即R1CS file。
- 以cpp或wasm编写的程序,该程序 可高效计算出该电路所有wires有效赋值。即 witness-calculator program。
- 基于提供了一组有效输入值的文件(即inputs file),运行witness-calculator program,可生成匹配该电路约束集合的所有signals。
对于有效的输入集,其中间值和输出值均称为witness,即组成witness file。
2.3 Non-recursive STARK
STARK proofs设置 是 类机器计算:
- 已知一组描述其正确执行的约束,可派生出特定的运算(算术化)。即算术化对应一组约束电路。
- 基于状态机自身输入构建的多项式,称为committed polynomials。根据定义可知,对于每个proof,需计算一次committed polynomials。
- committed polynomials 仅对Prover已知,对Verifier是未知的。
- 与状态机输入值无关的多项式,在同一状态机多次执行时,均保持为常量值的多项式,称为constant polynomials。根据定义,每次算术化,constant polynomials才仅需要计算一次。每次生成proof时,不需要计算constant polynomials。
- 即constant polynomials代表了所执行的计算,其应对Prover和Verifier都公开可得。
由于所有constant polynomials 不依赖于状态机所执行的某种计算的特定输入,因此可将证明生成的流程切分为2个阶段:
- 1)setup阶段:执行所有预处理。对于每个状态机定义,只执行一次。只要该状态机不变,后续可一直复用。
- 2)proving阶段:生成STARK proof,并提供验证该proof所需的一些public values。
2.3.1 setup阶段
setup阶段:执行所有预处理。对于每个状态机定义,只执行一次。只要该状态机不变,后续可一直复用 setup阶段生成的结果。
pil-stark中状态机的定义包含3部分:
- 1)
rom.json
文件:用于构建计算。由zkasm编译生成。 - 2)
starkstruct
文件:为用于STARK proof中的FRI配置信息,定义了:- blowup factor
- execution trace size
- execution trace的LDE(Low Degree Extension)
- 执行的query次数
- 3)
file.pil
文件:描述STARK状态机的PIL文件,即定义execution trace 正确性的约束。- 经PIL编译器(pilcom),可将PIL文件编译为
PIL.json
文件(即该PIL的解析JSON版)。【后续proving阶段也会使用编译后的PIL.json
文件来计算证明流程中的所有多项式。】
- 经PIL编译器(pilcom),可将PIL文件编译为
setup阶段内的流程有:
- 1)build STARK info 流程:使用
PIL.json
文件和starkstruct
文件来生成starkInfo
文件。在starkInfo
文件中,包含的信息有:- 所有的FRI相关参数
- 与PIL相关的有用域
- 约束形状
- 2)build constants 流程:使用
PIL.json
文件,来计算constant polynomials 基于,由starkstruct
文件所定义的evaluation domain,的evaluations。 - 3)build constant tree 流程:一旦build constants 流程 计算了constant polynomials 的evaluations,就会启动build constant tree 流程 来为生成相应Merkle tree(constTree,供Prover使用),并为Verifier生成constTree的root值——称为constant root(constRoot)。
2.3.2 Proving阶段
在Proving阶段,已知某输入input.json
,Prover会执行生成该计算proof所需的所有流程,
Proving阶段内的流程有:
-
1)STARK executor 流程:计算committed polynomials的所有evaluations。为此,其输入有:【由于committed polynomials的值严重依赖于
input.json
输入,因此需为每个proof执行一次本流程——不同于setup阶段(更改了状态机定义后才需要执行一次)。】PIL.json
文件 中的多项式名字和描述- 所提供的
input.json
输入
-
2)STARK prover 流程:其输入有:
- 之前步骤中生成的constant polynomials 的evaluations。
- 之前步骤中生成的committed polynomials 的evaluations。
starkInfo
文件中包含的所有信息。
来生成:
- 相应的STARK Proof(使用eSTARK协议——专门为proof PIL statements定制的)
- 以及与该STARK proof关联的可验证其有效性的public values。
STARK prover 流程 中运行的eSTARK协议主要包含2个阶段:
- 1)Low-Degree Reduction阶段:
- 首先获得FRI polynomial,FRI polynomial编码了与
PIL.json
对应的execution trace的有效值,使得FRI polynomial事实上是low degree的。 - 对FRI polynomial进行承诺,并将FRI polynomial承诺值发送给Verifier。
- 同时会对多个 用于一致性检查的多项式 进行承诺并发送给Verifier。
- 除多项式恒等式之外,PIL还支持:
- lookup argument
- permutation argument
- connection argument(又名copy-constraint)
因此在本阶段还需调整能生成这些argument正确性的证明。这也是构建eSTARK(extended)协议的主要动机。
- 首先获得FRI polynomial,FRI polynomial编码了与
- 2)FRI阶段:在获得FRI polynomial之后,Prover和Verifier会参与FRI协议,以致力于证明所承诺的多项式是low degree的(更准确来说,是证明多项式所承诺的值对应的函数与某low degree多项式足够接近)。
其中Low-Degree Reduction阶段,会切分为多轮,每个round的目标各不相同:
- 1.1)Round 1:对execution trace插值获得trace column polynomials,Prover对这些trace column polynomials进行承诺。
- 1.2)Round 2:Prover对 每个lookup argument(为plookup改进版)的 h h h-polynomials 进行承诺。
- 1.3)Round 3:Prover对 出现在
PIL.json
中的每种argument(lookup、permutation、connection)的grand-product多项式进行承诺,并结合使用一些中间多项式来降低grand product的degree。原因在于pil-stark中限定了所承诺多项式的degree上限。 - 1.4)Round 4:将quotient polynomial Q Q Q切分为2个多项式 Q 1 , Q 2 Q1,Q2 Q1,Q2,Prover对这2个多项式 Q 1 , Q 2 Q1,Q2 Q1,Q2进行承诺。
- 1.5)Round 5:Prover为Verifier提供其做相应检查所需的多项式evaluation值。
- 1.6)Round 6:Prover会收到Verifier发来的2个随机值,用于构建之前所描述的FRI polynomial。
然后进入FRI阶段,Prover和Verifier参与FRI写意思,最终Prover会发送相应的FRI proof给Verifier。Verifier会对FRI proof进行验证,来决定是accept还是reject。
3. 组合、递归和聚合
3.1 组合
如2.3节所示,Verifier会使用:
- proof
- public values
- 以及一些其它verifier参数
来对STARK proof进行验证。
composing proofs(proof组合)是指:
- 使用不同的证明系统一起来生成a proof。
通常,组合用于增强系统某部分的效率。如本文场景:
- 1)第一个证明系统为STARK
- 2)组合的核心思想在于,将验证STARK proof
π
S
T
A
R
K
\pi_{STARK}
πSTARK的流程,委托给,verification circuit
C
C
C。
若Prover提供了 verification circuit C C C正确执行的proof π C I R C U I T \pi_{CIRCUIT} πCIRCUIT,则足以验证原始的STARK proof π S T A R K \pi_{STARK} πSTARK。
这种组合的优势在于:
- 相比于 π S T A R K \pi_{STARK} πSTARK, π C I R C U I T \pi_{CIRCUIT} πCIRCUIT更小,且验证速度更快。
3.2 递归
递归过程也分为2个阶段:
- 1)Setup phase
- 2)Proving phase
3.2.1 Setup Phase
由于Verifiers要比Provers效率高得多,可利用这一事实创建Verifiers的递归级联,使得在每一个级联中,都可获得可更高效验证的proof。在本架构中,创建了STARK Verifiers链路,并使用中间电路来定义这些STARK Verifiers,如下图所示。使用电路而不是状态机的原因在于:
- 电路 适用于具有有限分支的计算,而Verifier就是这种类型的计算。
根据上图,假设已有描述首个STARK的参数(pil,constants和stark info),setup phase中的流程为:
- 1)将首个STARK表示为 STARK A \text{STARK}_A STARKA
- 2)然后将
STARK
A
\text{STARK}_A
STARKA 自动转换为其Verifier电路——该STARK verifier电路 以R1CS约束表示。
- 该转换过程称为S2C(STARK-to-CIRCUIT),会在setup phase执行该转换。
- 换句话说,就是STARK Verifier电路 的R1CS描述,可在计算proof之前,进行预处理获得。
- 本方案使用Circom intermediate representation语言 来描述 STARK Verifier电路。(详情见3.4节)
- 3)将R1CS电路自动转换为 新的STARK定义(即新的pil,新的constants,和,新的starkinfo)。
- 该转换过程称为C2S(CIRCUIT-to-STARK),也会在setup phase执行该转换。
- C2S也为预处理step,可在计算proof之前,进行预处理获得。
- 如上图所示,将该转换新生成的STARK表示为 STARK B \text{STARK}_B STARKB,其本质为Plonkish算术化表示,具有 STARK A \text{STARK}_A STARKA验证电路的某些custom gates。(详情见3.5节)
需注意,以上递归步骤可应用多次,每个步骤将压缩proof,使其验证更高效,但会增加Prover的复杂性。
最终,在setup phase,会为每个STARK Prover生成多个artifacts。
3.2.2 Proving Phase
Proving Phase流程为:
- 1)通过为首个STARK Prover提供合适的输入和public values,生成首个proof。
- 2)将前一output proof作为下一STARK Prover的输入,并结合public values一起,再生成proof。
- 3)递归重复以上流程。
下图展示了recursive STARK Provers 链的工作原理:
最终的final proof
π
f
i
n
a
l
\pi_{final}
πfinal实际为circuit-based proof(当前使用Groth16 proof)。更多proving phase详情见3.6节。
3.3 聚合
当生成proofs,本架构还支持聚合。
聚合是一种特殊的proof组合方式:
- 可通过将多个proofs压缩为单个proof(称为aggregated proof),并仅对aggregated proof进行验证,来证明所有proofs均是有效的,
在本架构中,aggregators定义在中间电路中。下图展示了以binary aggregators进行聚合:
3.4 Setup S2C
S2C表示的是:
- 将特定STARK 转换为 其Verifier电路 的过程。该Verifier电路以Circom表示,对应为R1CS约束。
S2C的转换流程见下图:【其中某
STARK
x
\text{STARK}_x
STARKx 被转换为 以
C
y
C_y
Cy表示的电路】
S2C step中的输入为:构建验证特定STARK 电路所需的所有信息。
在本架构中,S2C step的输入有:
- 定义STARK约束和多项式名的PIL文件,将验证PIL文件中的约束。
starkInfo
文件:包含了FRI相关参数,如blowup factor、query次数等- constRoot:constant polynomials’ evaluations组成的Merkle tree的root
S2C step中 generate circom 流程的输出为Circom描述。该电路实际是将:
- PIL定义的约束
- starkInfo中的FRI相关参数
- constRoot
填充到EJS模块的Circom描述。如下图所示,所生成的STARK Verifier电路 的输入可分为2类:
- public inputs
- private inputs
其中private inputs为前一STARK proof的参数:
- (rootC):为预处理的前一STARK的constant polynomials’ evaluations所构建的Merkle tree的root。(rootC) 由4个域元素组成。
- 在本架构所生成的某些中间电路中,rootC是电路输入,但在另一些电路中,rootC为将值硬编码在电路中的internal signals(这种特例情况后续将描述)。
- root1:为execution trace的所有trace column polynomials的evaluations所构建的Merkle tree的root。root1由4个域元素组成。
- root2:为 前一STARK中出现在每个lookup argument中的 h h h polynomials的evaluations所构建的Merkle tree的root。root2由4个域元素组成。若PIL中无lookup argument,则root2值为0。
- root3:为 前一STARK中每种argument(即lookup、permutation或connection argument)中出现的grand product polynomials的evaluations,和,切分这些grand product polynomials的中间多项式,的evaluations所构建的Merkle tree的root。root3由4个域元素组成。若PIL中无lookup、permutation和connection argument,则root3值为0。
- root4:为 前一STARK中 Q Q Q多项式所切分的 Q 1 和 Q 2 Q_1和Q_2 Q1和Q2多项式的evaluations所构建的Merkle tree的root。root4由4个域元素组成。
- evals:包含了,在challenge z z z和 g z gz gz,FRI验证过程中的所有多项式的所有必须的evaluations。
- si_root:为 第 i i i个folded FRI polynomial的evaluations所构建的Merkle tree的root。si_root由4个域元素组成。所谓第 i i i个folded FRI polynomial,是指在FRI verification的第 i i i个step出现的polynomial。
- si_vals:为用于检查所有queries的前一Merkle tree的叶子节点值。该值的总量取决于:
- query次数,
- 以及 与FRI当前step关联的reduction factor。
- si_siblings:为每个previous evaluations的Merkle proofs。
- finalPol:包含了 在FRI verification流程中最后一个step所构建的folding polynomial,在最后定义的domain(该domain size等于该多项式的degree),的所有evaluations。
其中的public inputs为:【更多public inputs信息见4.1节】
- Verifier用于check final proof所需的所有输入
- 以及,中间STARKs所需的所有输入
S2C step的最后一个流程是:compile circom 流程:将Circom描述(y.circom
)编译出:
- 1)一个文件:包含相关R1CS约束的文件
- 2)一个程序:根据指定输入可计算出该电路所有wires值的witness calculator程序
注意,在S2C step中会生成特殊的中间电路,上图中表示为 C y C_y Cy,若仅应用a recursion step,其仅为前一STARK(见上图中 STARK x \text{STARK}_x STARKx)的Verifier。不过更通用地,也可使用包含了Verifier,同时可提供更多功能的其它电路。后面将展示使用类似电路来verify aggregation of proofs。
3.5 Setup C2S
在proving phase中,会创建STARKs链。
根据S2C step,可获得circom电路,然后需将该circom电路再次转换为STARK——C2S预处理step可实现该转换。
通用C2S step见下图,其将circom circuit
C
y
C_y
Cy 转换为相应的 STARK
STARK
y
\text{STARK}_y
STARKy:
本方案证明过程中的中间电路的STARK arithmetization本质为a PlonKish arithmetization,其:
- 具有custom gates,从而使得完成特定任务的效率更高。
- 使用12个多项式来表示computation trace中gate wires的值。
当前支持的定制门类型有:
-
1)Poseidon定制门:可验证具有如下参数的Poseidon哈希函数:
- 输入为8个域元素
- capacity为4个域元素
- 输出为可变个域元素
Poseidon定制门电路中实现了MDS矩阵,和7-th power of field computations,以用于在Poseidon哈希Sponge构建的每个round执行。
-
2)Extend field operations扩域运算定制门:支持验证基于扩域 F p 3 \mathbb{F}_{p^3} Fp3的乘法和加法运算。其输入为3个元素 a , b , c ∈ F p 3 a,b,c\in\mathbb{F}_{p^3} a,b,c∈Fp3,输出为相应的元素:
a ⋅ b + c ∈ F p 3 a\cdot b+c\in\mathbb{F}_{p^3} a⋅b+c∈Fp3
其中运算都是基于 F p 3 \mathbb{F}_{p^3} Fp3的。观察可看出,若 c = 0 c=0 c=0则为纯粹的乘法运算,若 b = 1 b=1 b=1则为纯粹的加法运算。 -
3)FFT定制门:负责计算变量size在 F p \mathbb{F}_p Fp或扩域 F p 3 \mathbb{F}_{p^3} Fp3的FFT运算。
-
4)Polynomial Evaluation定制门:负责使用Horner’s rule来计算多项式在 F p 3 \mathbb{F}_{p^3} Fp3的单个evaluation。其输入为:【所谓Horner’s rule,是指可仅使用 n − 1 n-1 n−1次乘法运算 + n − 1 n-1 n−1次加法运算,就可求出某degree为 n − 1 n-1 n−1的多项式的evaluation值,即: a 0 + a z X + a 2 X 2 + ⋯ + a n − 1 X n − 1 = a 0 + X ( a 1 + X ( a 2 + ⋅ + X ( a n − 2 + X a n − 1 ) ) ) a_0+a_zX+a_2X^2+\cdots + a_{n-1}X^{n-1}=a_0+X(a_1+X(a_2+\cdot+X(a_{n-2}+Xa_{n-1}))) a0+azX+a2X2+⋯+an−1Xn−1=a0+X(a1+X(a2+⋅+X(an−2+Xan−1)))】
- z ∈ F p 3 z\in\mathbb{F}_{p^3} z∈Fp3
- 待evaluate多项式 p p p的系数
- 输出为evaluation p ( z ) ∈ F p 3 p(z)\in\mathbb{F}_{p^3} p(z)∈Fp3
实际使用selector polynomials来激活STARK中的以上定制门。selector polynomials为constant polynomials(即预处理的多项式)。事实上,引入的selectors有:
- POSEIDON12:用于激活Poseidon定制门。
- GATE:用于激活basic PlonK gate。
- CMULADD:用于激活扩域运算定制门。
- EVPOL4:用于激活Polynomial Evaluation定制门。
- FFT4:用于激活FFT定制门。
- PARTIAL:用于区分Poseidon中的partial layer和full layer,因为这会影响值之间的关系。
如上图所示,C2S step中的流程有:
-
1)PIL setup 流程:其输入为:某特定中间电路的R1CS约束,输出为所有STARK相关的artifacts,具体输出内容有:
- 1.1)相关STARK identity约束:存储于PIL文件(
y.pil
)中。该PlonKish arithmetization的identity约束,是通过向相关PIL的EJS模板(如compressor12.pil.ejs
)中填充获得的。完整的c12算术化描述见第6章。 - 1.2)相关computation constants:存储于constants文件(
y.const
)中。【仅依赖于circuit shape——即编码在 由Circom编译器生成的.r1cs
文件中,与特定输入无关(也即与根据特定输入计算的电路wires值无关)。】 - 1.3)定义了如何将circom circuit witness calculator生成的值,重新分配给合适的STARK execution trace值的重要文件:exec extension(
y.exec
)。【重新分配规则,仅依赖于circuit shape——即编码在 由Circom编译器生成的.r1cs
文件中,与特定输入无关(也即与根据特定输入计算的电路wires值无关)。】
后续将使用 重新分配规则文件(
.exec
),和,特定输入的witness值,一起来构建(生成STARK proof所需的)STARK execution trace。 - 1.1)相关STARK identity约束:存储于PIL文件(
-
2)build constants tree 流程:生成STARK constants Merkle tree。
-
3)build STARK info 流程:生成
starkInfo
文件。
3.6 Recursion Step Proof
如3.2.2节所示,为生成final proof,需计算每个中间STARK的proof。
每个中间STARK proof的生成需使用:
- 由相关circom circuit witness computation program执行所提供的witness值。而circom circuit witness computation program的输入为:前一proof的publics和values。
然后使用相应的.exec
文件,将circom circuit witness computation program执行生成的witness值进行合理重分配,来构建出STARK execution trace。
下图展示了中间STARK是如何生成proof的:
其主要包含2个流程:
-
1)STARK executor 流程:其输入参数有:
- 前一proof和public inputs:二者均在
x.zkin.proof
文件中。二者在x.zkin.proof
文件具有合适的格式,可供Circom编译器生成的witness calculator使用。 - 当前STARK的PIL:见
y.pil
文件。 - 关联电路的witness calculator program:见
y.witnesscalc
文件。 - 重新分配规则文件:见
y.exec
文件。用于生成STARK execution trace中的非预处理部分(y.commit
)。
- 前一proof和public inputs:二者均在
-
2)STARK prover 流程:其输入参数有:
- STARK execution trace:即committed polynomials和constant polynomials。
- constant tree
- 当前STARK的PIL:见
y.pil
文件。 - 由
zkevm.starkinfo.json
文件提供的信息
来生成STARK proof。在生成STARK proof时,STARK prover 流程的输出有:
- Proof文件(
y.proof.json
):该json文件中包含了整个STARK proof。 - Publics文件(
y.public.json
):该json文件中仅包含publics。 - zkIn文件(
y.zkin.proof.json
):该json文件中同时包含了STARK proof和publics。
参考资料
[1] Polygon zkEVM技术文档 Recursion, aggregation and composition of proofs v.1.1
附录:Polygon Hermez 2.0 zkEVM系列博客
- ZK-Rollups工作原理
- Polygon zkEVM——Hermez 2.0简介
- Polygon zkEVM网络节点
- Polygon zkEVM 基本概念
- Polygon zkEVM Prover
- Polygon zkEVM工具——PIL和CIRCOM
- Polygon zkEVM节点代码解析
- Polygon zkEVM的pil-stark Fibonacci状态机初体验
- Polygon zkEVM的pil-stark Fibonacci状态机代码解析
- Polygon zkEVM PIL编译器——pilcom 代码解析
- Polygon zkEVM Arithmetic状态机
- Polygon zkEVM中的常量多项式
- Polygon zkEVM Binary状态机
- Polygon zkEVM Memory状态机
- Polygon zkEVM Memory Align状态机
- Polygon zkEVM zkASM编译器——zkasmcom
- Polygon zkEVM哈希状态机——Keccak-256和Poseidon
- Polygon zkEVM zkASM语法
- Polygon zkEVM可验证计算简单状态机示例
- Polygon zkEVM zkASM 与 以太坊虚拟机opcode 对应集合
- Polygon zkEVM zkROM代码解析(1)
- Polygon zkEVM zkASM中的函数集合
- Polygon zkEVM zkROM代码解析(2)
- Polygon zkEVM zkROM代码解析(3)
- Polygon zkEVM公式梳理
- Polygon zkEVM中的Merkle tree
- Polygon zkEVM中Goldilocks域元素circom约束
- Polygon zkEVM Merkle tree的circom约束
- Polygon zkEVM FFT和多项式evaluate计算的circom约束
- Polygon zkEVM R1CS与Plonk电路转换
- Polygon zkEVM中的子约束系统
- Polygon zkEVM交易解析
- Polygon zkEVM 审计及递归证明
- Polygon zkEVM发布公开测试网2.0
- Polygon zkEVM测试集——创建合约交易
- Polygon zkEVM中的Recursive STARKs
- Polygon zkEVM的gas定价
- Polygon zkEVM zkProver基本设计原则 以及 Storage状态机
- Polygon zkEVM bridge技术文档
- Polygon zkEVM Trustless L2 State Management 技术文档
- Polygon zkEVM中的自定义errors
- Polygon zkEVM RPC服务
- Polygon zkEVM Prover的 RPC功能
- Polygon zkEVM PIL技术文档