1. 引言
前序博客有:
- Polygon zkEVM Hexens审计报告解读
- Polygon zkEVM Spearbit审计报告解读(2022年12月版本)
- Polygon zkEVM Spearbit审计报告解读(2023年1月版本)
- Polygon zkEVM Spearbit审计报告解读(2023年3月版本)
- Polygon zkEVM ROM Spearbit审计报告解读(2023年6月Dragon Fruit升级版本)
- Polygon zkEVM ROM Spearbit审计报告解读(2023年8月calldata bug修复)
主要内容见:
本轮审计历时2周,重点关注:
- PIL(Polynomial Interpolation Language)argument,具体包括:lookup argument、multiset equality argument、connection argument。
- STARK recursion pipeline,其proofs会被压缩并递归组合,以实现高效验证。
Spearbit团队审计了所提供的概述密码学证明系统的白皮书,并随后审查了其实施情况,以确保该协议在书面描述方面得到了忠实实施。总体而言,在密码学或实现审查中都没有发现重大的可靠性问题。一些较小的编辑、信息和优化问题浮出水面,但没有一个需要Polygon团队立即采取行动。
在论文和代码中发现:
- 5个是轻微漏洞,
- 4个是信息提示类,
- 2个是不一致问题,
- 3个是优化建议。
具体的审计内容为:
- 1)PIL论文:Polynomial Identity Language (PIL): A Machine Description Language for Verifiable Computation,2023年2月13日v1.0版本。
- 2)eSTARK论文:eSTARK: Extending the STARK Protocol with Arguments,2023年2月10日v1.0版本,和,2023年3月15日v1.2版本。
- 3)Recursion论文:Recursion, aggregation, and composition of proofs,2023年2月13日v1.0版本。
- 4)fflonk论文:fflonk: a Fast-Fourier inspired verifier efficient verson of PlonK,见Fflonk hackmd笔记-20230220 和 20211101:124505版本Fflonk论文。
- 5)Recursion pipeline:
- 见https://github.com/0xPolygonHermez/zkevm-proverjs/tree/v0.8.0.0-rc.2-forkid.2,即zkevm-proverjs的v0.8.0.0-rc.2-forkid.2版本。
- 合约验证文档见:Verification dragonfruit。会生成recursion pipeline中对c12a、rec1、rec2、recf、fflonk的STARK verifiers。
- 6)对PIL的STARK prover和verifier:
- 见https://github.com/0xPolygonHermez/pil-stark
- 具体文件为:stark_gen、stark_setup、stark_verify、starkinfo、starkinfo_cp_prover、starkinfo_cp_verifier、starkinfo_fri_prover、starkinfo_fri_verifier、starkinfo_step1、starkinfo_step2、transcript。
- 针对包含lookup argument、multiset equality argument和connection argument的某PIL描述,相应的STARK proof generation代码和verification代码。
2. 协议文档/白皮书审计
审计的文档有:
- 1)PIL论文:Polynomial Identity Language (PIL): A Machine Description Language for Verifiable Computation,2023年2月13日v1.0版本。
- 2)eSTARK论文:eSTARK: Extending the STARK Protocol with Arguments,2023年2月10日v1.0版本,和,2023年3月15日v1.2版本。
- 3)Recursion论文:Recursion, aggregation, and composition of proofs,2023年2月13日v1.0版本。
- 4)fflonk论文:fflonk: a Fast-Fourier inspired verifier efficient verson of PlonK,见Fflonk hackmd笔记-20230220 和 20211101:124505版本Fflonk论文。
2.1 PIL论文 + eSTARK论文
2.1.1 信息提示类:PIL中的connection argument定义,与eSTARK v1.0文档中的不一致
eSTARK中,1.5节的connection argument,应与PIL文档中1.9节的Definition 4(标记为Multi-Column Copy-Satisfiability)一致。但1.9节的Definition 3(标记为Connection Argument),指向的是Single-Column变种。
建议:
- 在PIL文档中,将Definition 3标记为Single-Column Connection Argument,并在eSTARK的1.5节的描述明确为Multi-Column Connection Argument。
2.1.2 不一致问题:eSTARK v1.0的connection argument定义中,包含了不一致的partition定义
eSTARK的1.5节connection argument中定义了某partition
T
=
{
T
1
,
⋯
,
T
k
}
T=\{T_1,\cdots,T_k\}
T={T1,⋯,Tk},暗示
T
1
,
⋯
,
T
k
T_1,\cdots,T_k
T1,⋯,Tk为partition sets。但是,并没有必要限制partition sets的数量为
k
k
k。如1.4节的Definition 4所莫奥数,列的数量可(且通常)不同于partition sets的数量。我们认为,这混淆了,partition sets,与,用于编码该partition permutation的向量。用于编码partition permutation的向量数,与,列数,是一样的。
修复:
- Polygon zkEVM团队已在eSTARK v1.2版本中解决。
2.1.3 轻微漏洞:lookup argument和multiset equality argument中的selection变量未被约束
eSTARK v1.0文档2.4节中,Step 1描述了Prover发送的selector多项式,其存在2个潜在问题:
- 1)若Verifier未将selector多项式,视为常量(预处理)多项式,则该关系将是trivially satisfiable的。Prover可简单设置这些selectors为相同的0值,使得Selected Vector Argument毫无意义。
- 2)此外,除上面的trivial satisfying selection问题之外,若Prover有意发送自己的selectors,则没有verification check来确认基于 G G G的selector多项式是 { 0 , 1 } \{0,1\} {0,1}。
建议:
- 完备的Selected Vector Argument中,应包含,基于 G G G的selector多项式是 { 0 , 1 } \{0,1\} {0,1},的verification check。
修复:
- Polygon zkEVM团队指出,在其zkEVM上下文中,存在额外的约束,来确保Prover所提供的selector多项式在 { 0 , 1 } \{0,1\} {0,1},即其为对某仅包含 { 0 , 1 } \{0,1\} {0,1}的预处理table的lookup结果。
2.1.4 轻微漏洞:在Verifier challenges中误用Poseidon哈希,导致unexploitable length-extension weakness
eSARK v1.0版本的2.2节,为根据第7、8、9个域元素生成第3个verifier challenge,需生成一组新的8个域元素(第9个域元素不包含在之前集合内)。为此, 8 zeroes are hashed with the previous capacity。这样的输出,与直接在消息中附加8个0值(即 M ∣ ∣ 00000000 M||00000000 M∣∣00000000)的哈希结果是一样的。
建议:
- STARK prover中这种特殊的误用情况,可能不会引起问题,因该transcript的输入可能不是length-extended的。推荐将Poseidon哈希函数看做是具有连续可变长度输出的XOF,来生成额外的verifier challenges。将完整的12个元素(capacity + output)用作下一轮Poseidon permutation的输入,然后使用前8个元素(without the capacity)作为partial output,根据需要可重复多次。从而可模仿sponge哈希函数的squeeze操作。
2.1.5 优化建议:使用Poseidon的XOF模式,来生成所需的verifier challenges
eSTARK v1.0中限定了所需的verifier challenges数量。不确定这种设计是否会影响可靠性,但若是基于生成额外verifier challenges的灵活性考虑,则可避免该限定。
- 1)eSTARK v1.0的2.2节中声称,其可生成的verifier challenges数量是有限定的。
- 2)eSTARK v1.0的2.5节中声称,难以为生成quotient多项式来生成大量的verifier challenges。
- 3)eSTARK v1.0的2.7节中声称,为生成FRI多项式来生成大量verifier challenges是个问题。
如果是为了降低recursion中STARK verifier的size,而将减少verifier challenges数量作为一种优化策略,则可忽略如下建议:
- 若使用Poseidon XOF模式,则以上都将不是问题。
回复:
- Polygon zkEVM团队确认,减少verifier challenges数量不是因为无法灵活生成更多,而是作为优化策略,以避免额外编码更多的Poseidon rounds,从而使recursive circuit最小化。
2.1.6 信息提示类:preprocessed多项式未包含在首个prover message内
在eSTARK v1.2的4.5节完整协议描述中,preprocessed多项式未包含在Merkle tree commitment内。
建议:
- 按之前章节所描述的那样,在首个prover message内包含preprocessed多项式。
2.2 Recursion论文
2.2.1 不一致问题:所使用与所描述的rootC不一致
在recursion论文的4.2.6节的图17中,public input rootC
,与hard-coded rec1 rootC
是复用的。图17中的描述有误。
建议:
- 遵循Jordi Baylina 300123 StarkwareSessions - Recursive STARK in the zkEVM context PPT中的图示,将hard-coded
rootC
和 inputrootC
,复用作为2个recursiveVerifier的输入。
2.3 fflonk论文
2.3.1 信息提示类:小的soundness bound错误
在fflonk论文的Lemma 6.4的soundness bound proof中,存在off-by-one error(差一错误)。注意
A
∣
(
p
−
1
)
A|(p-1)
A∣(p−1),其中
p
p
p为
F
F
F的size。
F
F
F的
A
A
A-th powers集合
S
S
S中包含
0
0
0,因此,
∣
S
∣
=
p
−
1
A
+
1
|S|=\frac{p-1}{A}+1
∣S∣=Ap−1+1。令
F
i
F_i
Fi为非零多项式。对于从
S
S
S中均匀采样的
s
s
s,其概率:
f
i
(
s
)
=
0
≤
def
F
i
p
−
1
A
+
1
<
def
(
F
i
)
⋅
A
p
−
1
f_i(s)=0\leq \frac{\text{def } F_i}{\frac{p-1}{A}+1}<\frac{\text{def}(F_i)\cdot A}{p-1}
fi(s)=0≤Ap−1+1def Fi<p−1def(Fi)⋅A
3. 代码审计
代码审计范围为:
- 1)Recursion pipeline:
- 见https://github.com/0xPolygonHermez/zkevm-proverjs/tree/v0.8.0.0-rc.2-forkid.2,即zkevm-proverjs的v0.8.0.0-rc.2-forkid.2版本。
- 合约验证文档见:Verification dragonfruit。会生成recursion pipeline中对c12a、rec1、rec2、recf、fflonk的STARK verifiers。
- 2)对PIL的STARK prover和verifier:
- 见https://github.com/0xPolygonHermez/pil-stark
- 具体文件为:stark_gen、stark_setup、stark_verify、starkinfo、starkinfo_cp_prover、starkinfo_cp_verifier、starkinfo_fri_prover、starkinfo_fri_verifier、starkinfo_step1、starkinfo_step2、transcript。
- 针对包含lookup argument、multiset equality argument和connection argument的某PIL描述,相应的STARK proof generation代码和verification代码。
zkEVM安全审计需对所有与zkEVM相关的密码学完整代码都进行审计,当前本报告形成时,未对如下代码进行审计:
- 1)将PIL文件编译为STARK prover输入数据架构。见:pilcom
- 2)将PIL-derived STARK verifier,编码为cricom
- 3)将circom-produced R1CS,编码为PlonK-like PIL
- 4)FRI (batched) polynomial commitment and opening
3.1 recursion pipeline 代码审计
根据Verification dragonfruit文档,对zkevm-proverjs的v0.8.0.0-rc.2-forkid.2版本进行build。检查了所有circom文件,是否与该文档中所描述的recursion pipeline已知。此外,审计了最终的fflonk verifier Solidity代码。
3.1.1 轻微漏洞:实际build与文档不匹配
zkevm-proverjs的v0.8.0.0-rc.2-forkid.2版本所生成的final.fflonk.verifier.sol文件,采用是snarkjs在commit之前的一个已过期的模板。该过期模板未正确计算verifier challenges(未包含preprocessed多项式,且未保持连续transcript state)。此外,https://github.com/0xPolygonHermez/zkevm-proverjs/blob/v0.8.0.0-rc.2-forkid.2/README.md,该README文档内信息也是过期的。
建议:
- 1)应双向检查所发布的zkevm-proverjs release版本使用的是更新后的模板,否则,所生成的fflonk verifier合约,可能有Fiat-Shamir vulnerabilities。
- 2)使用Felicia所提供的更新文档:Verification dragonfruit
回复:
- Polygon zkEVM团队确认其release build pipeline中使用了正确的版本。
3.1.2 轻微漏洞:batch number比较逻辑溢出
在recursive2 circuit中,使用mux来选择是将hardcoded root,还是将public input root,传送至subverifier circuits中。在recursivef circuit中,使用mux来选择2个hardcoded roots中哪个传入subverifier circuits中。
这2个mux都采用如下比较形式作为输入:
component test = IsZero();
test.in <== oldBatchNum - newBatchNum -1;
....
mux.s <== test.out;
由于bn128 scalar field 大于 goldilocks field,因此在以上field运算中,存在溢出的可能。这将影响基于goldilocks域的比较逻辑:
- 令 p p p为larger bn128 scalar域的order, q q q为goldilocks域的order。注意有 p > q p>q p>q,因bn128域远大于goldilocks域。定义整数 a , b a,b a,b,有 a q + b ≡ b ( m o d q ) aq+b\equiv b(\mod q) aq+b≡b(modq),但 a ⋅ q + b ≠ b a\cdot q +b\neq b a⋅q+b=b。若oldBatchNume为 b − 1 b-1 b−1,且newBatchNum为 a ⋅ q + b a\cdot q +b a⋅q+b,则以上比较将返回true,尽管这2个batch是不相邻的。Prover可让Verifier信服:其have done a ⋅ q + 1 a \cdot q + 1 a⋅q+1 iterations of work by using a valid final proof of an execution from b − 1 b − 1 b−1 to b b b。
回复:
- Polygon zkEVM团队,其在final.verifier.circom中,会将oldBatchNum和newBatchNum分解为63 bits。因为 2 63 < q 2^{63}<q 263<q( q q q为goldilocks域order),这样该比较逻辑不会出现溢出问题。
3.1.3 信息提示类:on-curve checks拒绝point-at-infinity的微小完备性问题
bn128曲线上的有效点,要么满足曲线方程式,要么为无穷远点。在EIP-196:预编译合约中,point-at-infinity编码为
(
0
,
0
)
(0,0)
(0,0)。https://github.com/iden3/snarkjs/blob/782894ab72b09cfad4dd8b517599d5e7b2340468/templates/verifier_fflonk.sol.ejs#L216中的checkPointBelongsToBN128Curve
函数,若该点满足曲线方程式,则返回true,其拒绝point-at-infinity。当某prover message为point-at-infinity,这存在有效性问题。
建议:
- 在on-curve check中增加point-at-infinity检查。
回复:
- Polygon zkEVM团队倾向于避免在on-curve check中增加point-at-infinity检查。由于协议中的随机blinding factors,以及随机verifier challenges,对于honest prover来说,出现该完备性问题的概率可忽略。
3.2 对PIL的STARK prover和verifier 代码审计
审计了根据parsed PIL对象,生成starkinfo对象,以相应的STARK prover和verifier实现。验证了STARK Prover遵循了所审计的eSTARK协议设计,特别地,其实现了新添加的lookup argument、multiset equality argument、connection argument。
3.2.1 细微漏洞:verifier challenges中误用Poseidon哈希。
具体见上面的“2.1.4 轻微漏洞:在Verifier challenges中误用Poseidon哈希,导致unexploitable length-extension weakness”。具体见https://github.com/0xPolygonHermez/pil-stark/blob/a934b3e3a2148f506fbd265f4d3333f36b913c15/src/transcript.js#L16中的第16-20行。建议也同上。
3.2.2 优化建议:在FRI多项式中,没必要包含所有committed多项式
当Prover计算FRI多项式时,具体见https://github.com/0xPolygonHermez/pil-stark/blob/a934b3e3a2148f506fbd265f4d3333f36b913c15/src/starkinfo_fri_prover.js#L12中第12-19行,该线性组合内包含了所有committed多项式。约束中已包含的所有committed多项式,将再次包含在该线性组合中,以证明其evaluation的正确性,以证实该committed多项式的degree bound。因此,添加所有committed多项式到该线性组合内的唯一好处为:
- 对不包含在任意约束中的多项式做degree bound检查。
检查:
- 根据线性组合计算FRI多项式时,可移除committed多项式。若因为某些原因,某committed多项式不包含在任何约束中,则需要将其添加到该线性组合内。符合这样条件的committed多项式很少。所有在约束内的committed多项式,无需再次包含在计算FRI多项式的线性组合内。
3.2.3 优化建议:verifier中无需对vanishing多项式进行evaluate
Verifier对 G G G的vanishing多项式在 g ⋅ z g\cdot z g⋅z点进行evaluate,其中 g g g为 G G G的generator, z z z为verifier evaluation challenge。但是,在验证时,无需做该evaluation。具体见https://github.com/0xPolygonHermez/pil-stark/blob/a934b3e3a2148f506fbd265f4d3333f36b913c15/src/stark_verify.js#L70第70行。
建议:
- 移除该evaluation。
附录: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技术文档
- Polygon zkEVM递归证明技术文档(1)【主要描述了相关工具 和 证明的组合、递归以及聚合】
- Polygon zkEVM递归证明技术文档(2)—— Polygon zkEVM架构设计
- Polygon zkEVM递归证明技术文档(3)——代码编译及运行
- Polygon zkEVM递归证明技术文档(4)—— C12 PIL Description
- Polygon zkEVM递归证明技术文档(5)——附录:借助SNARKjs和PIL-STARK实现proof composition
- eSTARK:Polygon zkEVM的扩展STARK协议——支持lookup、permutation、copy等arguments(1)
- eSTARK:Polygon zkEVM的扩展STARK协议——支持lookup、permutation、copy等arguments(2)
- eSTARK:Polygon zkEVM的扩展STARK协议——支持lookup、permutation、copy等arguments(3)
- Polygon zkEVM的Dragon Fruit和Inca Berry升级
- Polygon zkEVM协议治理、升级及其流程
- Polygon zkEVM 节点软件release日志
- Polygon zkEVM bridge服务 release日志
- Polygon zkEVM DataStreamer
- Polygon zkEVM Goldilocks域各项运算性能
- Polygon zkEVM Hexens审计报告解读
- Polygon zkEVM Spearbit审计报告解读(2022年12月版本)
- Polygon zkEVM Spearbit审计报告解读(2023年1月版本)
- Polygon zkEVM Spearbit审计报告解读(2023年3月版本)
- Polygon zkEVM ROM Spearbit审计报告解读(2023年6月Dragon Fruit升级版本)
- Polygon zkEVM ROM Spearbit审计报告解读(2023年8月calldata bug修复)