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修复)
- Polygon zkEVM PIL-STARK Spearbit审计报告解读(2023年3月版)
具体内容见:
- Polygon zkEVM Cryptography Security Review (Pil-stark and Snarkjs cryptography review), June 20, 2023
本轮审计历时2天,Spearbit团队重点审计了Polygon zkEVM proving pipeline的2大部分:
-
1)审计了在该pipeline的final stage,对fflonk verifier合约的优化修改。
-
2)审计了STARK verifier中的一些定制PIL约束,包括:
- Fp3 multiplication
- 1-of-4 Fp3 selector
- Poseidon hash evaluation
这些约束用于proving pipeline的recursive composition stage中。
实际审计的代码库为:
- PIL-Stark的PR—— New recursion #39,具体的分支为:https://github.com/0xPolygonHermez/pil-stark/tree/bb2404acd221083f0efa0b3ab8fa50bb421e686e
- snarkjs的Feat lagrange verifier (#368)
本轮审计未发现可靠性问题:
- 有一些对fflonk verifier的进一步优化建议。
- 对定制PIL约束的一些小的文档/优化建议。
2. fflonk verifier优化
对https://github.com/iden3/snarkjs/blob/e70271b30a6392a34f664e6bececddad284c8854/test/fflonk/verifier.sol FFlonk verifier合约进行审计和优化。
定义了乘法群、其order、相关常量以及cosets:
- H = < w > , H = 256 H=,H=256 H=<w>,H=256
- H 4 = < w 3 > , H 3 = 3 H_4=,H_3=3 H4=<w3>,H3=3
- H 4 = < w 4 > , H 4 = 4 H_4=,H_4=4 H4=<w4>,H4=4
- H 8 = < w 8 > , H 8 = 8 H_8=,H_8=8 H8=<w8>,H8=8
- r ← F , ξ ← r 24 r\leftarrow \mathbb{F},\xi\leftarrow r^{24} r←F,ξ←r24
- h 0 = r 3 , h 1 = r 6 , h 2 = r 8 , h 3 = r 8 w 1 / 3 h_0=r^3,h_1=r^6,h_2=r^8,h_3=r^8w^{1/3} h0=r3,h1=r6,h2=r8,h3=r8w1/3
- h 0 8 = ξ , h 1 4 = ξ , h 2 3 = ξ , h 3 3 = ξ h_0^8=\xi,h_1^4=\xi,h_2^3=\xi,h_3^3=\xi h08=ξ,h14=ξ,h23=ξ,h33=ξ
- S 0 = h 0 H 8 = r 3 H 8 S_0=h_0H_8=r^3H_8 S0=h0H8=r3H8
- S 1 = h 1 H 4 = r 6 H 4 S_1=h_1H_4=r^6H_4 S1=h1H4=r6H4
- S 2 = h 2 H 3 ∪ h 3 H 3 = r 8 H 3 ∪ r 8 w 1 / 3 H 3 S_2=h_2H_3\cup h_3H_3=r^8H_3\cup r^8w^{1/3}H_3 S2=h2H3∪h3H3=r8H3∪r8w1/3H3
https://github.com/iden3/snarkjs/blob/e70271b30a6392a34f664e6bececddad284c8854/test/fflonk/verifier.sol FFlonk verifier合约内有:
- 常量值:
- w , w 1 / 3 w,w^{1/3} w,w1/3
- { w 3 , w 3 2 } \{w_3,w_3^2\} {w3,w32}
- { w 4 , w 4 2 , w 4 3 } \{w_4,w_4^2,w_4^3\} {w4,w42,w43}
- { w 8 , w 8 2 , ⋯ , w 8 7 } \{w_8,w_8^2,\cdots,w_8^7\} {w8,w82,⋯,w87}
- fflonk_verify.js中的computeChallenges,会计算集合 S 0 , S 1 , S 2 S_0,S_1,S_2 S0,S1,S2中的每个元素。
- fflonk_prove.js中的computeLiS0,为对langrange多项式: L i ( S 0 ) ( X ) = 1 8 h 0 7 w 8 7 i ⋅ X 8 − h 0 8 X − h 0 w 8 i L_i^{(S_0)}(X)=\frac{1}{8h_0^7w_8^{7i}}\cdot \frac{X^8-h_0^8}{X-h_0w_8^i} Li(S0)(X)=8h07w87i1⋅X−h0w8iX8−h08,起算其分母在challenge y y y处的evaluation值: LiS0dens { 8 h 0 7 w 8 7 i ⋅ ( y − h 0 w 8 i ) } i ∈ [ 8 ] \text{LiS0dens }\{8h_0^7w_8^{7i}\cdot (y-h_0w_8^i)\}_{i\in[8]} LiS0dens {8h07w87i⋅(y−h0w8i)}i∈[8]
- fflonk_prove.js中的computeLiS1,为对langrange多项式: L i ( S 1 ) ( X ) = 1 4 h 1 3 w 4 3 i ⋅ X 4 − h 1 4 X − h 1 w 4 i L_i^{(S_1)}(X)=\frac{1}{4h_1^3w_4^{3i}}\cdot \frac{X^4-h_1^4}{X-h_1w_4^i} Li(S1)(X)=4h13w43i1⋅X−h1w4iX4−h14,起算其分母在challenge y y y处的evaluation值: LiS1dens { 4 h 1 3 w 4 3 i ⋅ ( y − h 1 w 4 i ) } i ∈ [ 4 ] \text{LiS1dens }\{4h_1^3w_4^{3i}\cdot (y-h_1w_4^i)\}_{i\in[4]} LiS1dens {4h13w43i⋅(y−h1w4i)}i∈[4]
- fflonk_prove.js中的computeLiS2的当前算法复杂,将在
Polygon zkEVM Cryptography Security Review (Pil-stark and Snarkjs cryptography review), June 20, 2023 的5.1.4节展示优化版本。
- 计算 LiS0dens \text{LiS0dens } LiS0dens 、 LiS1dens \text{LiS1dens } LiS1dens 、 LiS2dens \text{LiS2dens } LiS2dens 这些分母项的倒数。
- fflonk_verify.js中的computeR0:
- 对多项式 C 0 ( X ) = q L ( X 8 ) + X ⋅ q R ( X 8 ) + X 2 ⋅ q O ( X 8 ) + X 3 ⋅ q M ( X 8 ) + X 4 ⋅ q C ( X 8 ) + X 5 ⋅ S σ 1 ( X 8 ) + X 6 ⋅ S σ 2 ( X 8 ) + X 7 ⋅ S σ 3 ( X 8 ) C_0(X)=q_L(X^8)+X\cdot q_R(X^8)+X^2\cdot q_O(X^8)+X^3\cdot q_M(X^8)+X^4\cdot q_C(X^8)+X^5\cdot S_{\sigma_1}(X^8)+X^6\cdot S_{\sigma_2}(X^8)+X^7\cdot S_{\sigma_3}(X^8) C0(X)=qL(X8)+X⋅qR(X8)+X2⋅qO(X8)+X3⋅qM(X8)+X4⋅qC(X8)+X5⋅Sσ1(X8)+X6⋅Sσ2(X8)+X7⋅Sσ3(X8),根据已知evaluation值: q L ( h 0 8 ) = q L ( ξ ) , q R ( h 0 8 ) = q R ( ξ ) , q O ( h 0 8 ) = q O ( ξ ) , S σ 1 ( h 0 8 ) = S σ 1 ( ξ ) , S σ 2 ( h 0 8 ) = S σ 2 ( ξ ) , S σ 3 ( h 0 8 ) = S σ 3 ( ξ ) q_L(h_0^8)=q_L(\xi),q_R(h_0^8)=q_R(\xi),q_O(h_0^8)=q_O(\xi),S_{\sigma_1}(h_0^8)=S_{\sigma_1}(\xi),S_{\sigma_2}(h_0^8)=S_{\sigma_2}(\xi),S_{\sigma_3}(h_0^8)=S_{\sigma_3}(\xi) qL(h08)=qL(ξ),qR(h08)=qR(ξ),qO(h08)=qO(ξ),Sσ1(h08)=Sσ1(ξ),Sσ2(h08)=Sσ2(ξ),Sσ3(h08)=Sσ3(ξ),按 C 0 ( e ) = q L ( ξ ) + e ⋅ q R ( ξ ) + e 2 ⋅ q O ( ξ ) + e 3 ⋅ q M ( ξ ) + e 4 ⋅ q C ( ξ ) + e 5 ⋅ S σ 1 ( ξ ) + e 6 ⋅ S σ 2 ( ξ ) + e 7 ⋅ S σ 3 ( ξ ) C_0(e)=q_L(\xi)+e\cdot q_R(\xi)+e^2\cdot q_O(\xi)+e^3\cdot q_M(\xi)+e^4\cdot q_C(\xi)+e^5\cdot S_{\sigma_1}(\xi)+e^6\cdot S_{\sigma_2}(\xi)+e^7\cdot S_{\sigma_3}(\xi) C0(e)=qL(ξ)+e⋅qR(ξ)+e2⋅qO(ξ)+e3⋅qM(ξ)+e4⋅qC(ξ)+e5⋅Sσ1(ξ)+e6⋅Sσ2(ξ)+e7⋅Sσ3(ξ)方式,对于每个 e ∈ S 0 = h 0 H 8 e\in S_0=h_0H_8 e∈S0=h0H8,来计算evaluation值集合: { C 0 ( e ) ∣ e ∈ S 0 = h 0 H 8 } \{C_0(e)| e\in S_0=h_0H_8\} {C0(e)∣e∈S0=h0H8}。
- 计算分子: y 8 − h 0 8 y^8-h_0^8 y8−h08。
- 为计算 r 0 ( X ) = ∑ i = 0 7 C 0 ( h 0 w 8 i ) L i ( S 0 ) ( X ) = ∑ i = 0 7 C 0 ( h 0 w 8 i ) 1 8 h 0 7 w 8 7 i ⋅ ( X − h 0 w 8 i ) ⋅ ( X 8 − h 0 8 ) r_0(X)=\sum_{i=0}^{7}C_0(h_0w_8^i)L_i^{(S_0)}(X)=\sum_{i=0}^{7}C_0(h_0w_8^i)\frac{1}{8h_0^7w_8^{7i}\cdot (X-h_0w_8^i)}\cdot (X^8-h_0^8) r0(X)=∑i=07C0(h0w8i)Li(S0)(X)=∑i=07C0(h0w8i)8h07w87i⋅(X−h0w8i)1⋅(X8−h08)在 y y y处的evaluation值,其中 { 1 8 h 0 7 w 8 7 i ⋅ ( y − h 0 w 8 i ) ⋅ ( y 8 − h 0 8 ) } i ∈ [ 8 ] \{\frac{1}{8h_0^7w_8^{7i}\cdot (y-h_0w_8^i)}\cdot (y^8-h_0^8)\}_{i\in[8]} {8h07w87i⋅(y−h0w8i)1⋅(y8−h08)}i∈[8] 可根据 LiS0dens \text{LiS0dens} LiS0dens的倒数值和分子 y 8 − h 0 8 y^8-h_0^8 y8−h08值,来计算,然后将其与 C 0 ( X ) C_0(X) C0(X)在 S 0 S_0 S0各点值相乘求和,即可计算出 r 0 ( y ) r_0(y) r0(y)值。
- fflonk_verify.js中的computeR1,采用类似的策略,计算 r 1 ( X ) = ∑ i = 0 3 C 1 ( h 1 w 4 i ) L i ( S 1 ) ( X ) r_1(X)=\sum_{i=0}^{3}C_1(h_1w_4^i)L_i^{(S_1)}(X) r1(X)=∑i=03C1(h1w4i)Li(S1)(X)在 y y y处的evaluation值,其中 C 1 ( X ) : = a ( X 4 ) + X ⋅ b ( X 4 ) + X 2 ⋅ c ( X 4 ) + X 3 ⋅ T 0 ( X 4 ) C_1(X):=a(X^4)+X\cdot b(X^4)+X^2\cdot c(X^4)+X^3\cdot T_0(X^4) C1(X):=a(X4)+X⋅b(X4)+X2⋅c(X4)+X3⋅T0(X4)。已知evaluation值 a ( h 1 4 ) = a ( ξ ) , b ( h 1 4 ) = b ( ξ ) , c ( h 1 4 ) = c ( ξ ) , T 0 ( h 1 4 ) = T 0 ( ξ ) a(h_1^4)=a(\xi),b(h_1^4)=b(\xi),c(h_1^4)=c(\xi),T_0(h_1^4)=T_0(\xi) a(h14)=a(ξ),b(h14)=b(ξ),c(h14)=c(ξ),T0(h14)=T0(ξ),即可计算出 r 1 ( y ) r_1(y) r1(y)值。
- fflonk_verify.js中的computeR1,采用类似的策略,来计算 r 1 ( y ) r_1(y) r1(y),将在
Polygon zkEVM Cryptography Security Review (Pil-stark and Snarkjs cryptography review), June 20, 2023 的5.1.4节展示优化版本。
2.1 优化建议:优化fflonk verifier中的 r 0 , r 1 r_0,r_1 r0,r1计算
之前的 r 0 ( y ) , r 1 ( y ) , r 2 ( y ) r_0(y),r_1(y),r_2(y) r0(y),r1(y),r2(y)计算,需要 O ( n 2 ) O(n^2) O(n2)次域运算,其中 n n n为相应的domain size。本节,提供了一种策略,将该计算量降低为 O ( n log n ) O(n\log n) O(nlogn),并降低了常量因子的子。相比于https://github.com/iden3/snarkjs/blob/e70271b30a6392a34f664e6bececddad284c8854/test/fflonk/verifier.sol中的现有方案,本解决方案,需要更少的乘法、加法和模运算:
- 1)使用基于cosets的不同形式的lagrange多项式,可避免在computeChallenges中计算其coset values。此外,去掉了在旧的拉格朗日多项式表示中计算复杂分母所需的多余乘法和模运算。这是特别相关的,因为可将底层group元素作为常量访问。
- 2)当直接使用拉格朗日插值来evaluate r ( y ) r(y) r(y)时,需要拉格朗日多项式在 y y y处的完整evaluation值。与之不同,本方案直接使用barycentric evaluation,可降低重复计算。更值得注意的是,在之前的方案中,可将求和中重复的乘因子移除出去。
- 3)大量的计算量节约,源自,将(evaluate r ( y ) r(y) r(y)所需的) C ( X ) C(X) C(X)多项式evaluations,看成是某快速傅里叶转换。将该快速傅里叶转换展开为具体运算,可将乘法次数由 n 2 n^2 n2降低为 n log n n\log n nlogn。
- 4)对 r 2 r_2 r2多项式的处理方式有所不同,有望进一步降低某些运算次数。
2.1.1 lagrange多项式及基于Cosets的Barycentric Evaluation
令group H = < w > H= H=<w>的order为 n n n,某coset表示为 c c c。用于 r 0 , r 1 r_0,r_1 r0,r1计算的策略是通用的。
将 r ( X ) r(X) r(X)多项式看成是degree小于 n n n的多项式,其基于coset c H cH cH的evaluation值为 r 0 , r 1 , ⋯ , r n − 1 r_0,r_1,\cdots,r_{n-1} r0,r1,⋯,rn−1,将 r ( X ) r(X) r(X)的以lagrange basis唯一表示为:
r ( X ) = ∑ i = 0 n − 1 r i ⋅ L i ( c H ) ( X ) r(X)=\sum_{i=0}^{n-1}r_i\cdot L_i^{(cH)}(X) r(X)=∑i=0n−1ri⋅Li(cH)(X)
注意,可将对coset c H cH cH的lagrange多项式,表示为对 H H H的具有shifted X ′ = X / c X'=X/c X′=X/c的lagrange多项式:
r ( X ) = ∑ i = 0 n − 1 r i ⋅ L i ( c H ) ( X ) = ∑ i = 0 n − 1 r i ⋅ L i ( H ) ( X c ) = ∑ i = 0 n − 1 r i w i n ⋅ ( X ′ ) n − 1 X ′ − w i = ( X ′ ) n − 1 n ⋅ ∑ i = 0 n − 1 r i ⋅ w i X ′ − w i r(X)=\sum_{i=0}^{n-1}r_i\cdot L_i^{(cH)}(X)=\sum_{i=0}^{n-1}r_i\cdot L_i^{(H)}(\frac{X}{c})=\sum_{i=0}^{n-1}\frac{r_iw^i}{n}\cdot \frac{(X')^n-1}{X'-w^i}=\frac{(X')^n-1}{n}\cdot \sum_{i=0}^{n-1}\frac{r_i\cdot w^i}{X'-w^i} r(X)=∑i=0n−1ri⋅Li(cH)(X)=∑i=0n−1ri⋅Li(H)(cX)=∑i=0n−1nriwi⋅X′−wi(X′)n−1=n(X′)n−1⋅∑i=0n−1X′−wiri⋅wi
对于 y ∈ F y\in\mathbb{F} y∈F,为计算:
r ( y ) = ( y ′ ) n − 1 n ⋅ ∑ i = 0 n − 1 r i ⋅ w i y ′ − w i r(y)=\frac{(y')^n-1}{n}\cdot \sum_{i=0}^{n-1}\frac{r_i\cdot w^i}{y'-w^i} r(y)=n(y′)n−1⋅∑i=0n−1y′−wiri⋅wi
需计算以下值:
- 1) y ′ = y / c y'=y/c y′=y/c:对 c c c做一次倒数运算,然后与 y y y做一次乘法运算获得。
- 2) ( y ′ ) n − 1 n \frac{(y')^n-1}{n} n(y′)n−1:将 1 / n 1/n 1/n看成是已知常量值,需一次减法, log ( n ) + 1 \log(n)+1 log(n)+1次乘法运算。
- 3) { r i ⋅ w i } i ∈ [ n ] \{r_i\cdot w^i\}_{i\in [n]} {ri⋅wi}i∈[n]:为特例情况,将在下一小节展开。
- 4) { 1 y ′ − w i } i ∈ [ n ] \{\frac{1}{y'-w^i}\}_{i\in [n]} {y′−wi1}i∈[n]:将 w i w^i wi看成是已知常量值,需要 n n n次减法,和 n n n次倒数运算,当然,所有的倒数运算可batch处理,可进一步降低计算量。
2.1.2 高效计算分子 { r i ⋅ w i } i ∈ [ n ] \{r_i\cdot w^i\}_{i\in [n]} {ri⋅wi}i∈[n]
可使用快速傅里叶变换来高效计算分子 { r i ⋅ w i } i ∈ [ n ] \{r_i\cdot w^i\}_{i\in [n]} {ri⋅wi}i∈[n]。
某多项式 C ( X ) C(X) C(X)形如:
C ( X ) : = f 0 ( X n ) + X ⋅ f 1 ( X n ) + X 2 ⋅ f 2 ( X n ) + ⋯ + X n − 1 ⋅ f n − 1 ( X n ) C(X):=f_0(X^n)+X\cdot f_1(X^n)+X^2\cdot f_2(X^n)+\cdots +X^{n-1}\cdot f_{n-1}(X^n) C(X):=f0(Xn)+X⋅f1(Xn)+X2⋅f2(Xn)+⋯+Xn−1⋅fn−1(Xn)
忽略 r 2 ( X ) r_2(X) r2(X)特例情况,FFlonk verifier,对于 i ∈ [ n ] i\in [n] i∈[n],有:
r i ⋅ w i = C ( c ⋅ w i ) ⋅ w i r_i\cdot w^i=C(c\cdot w^i)\cdot w^i ri⋅wi=C(c⋅wi)⋅wi
其中:
C ( c ⋅ w i ) ⋅ w i = f 0 ( c n ) ⋅ w i + ( c ⋅ w i ) ⋅ f 1 ( c n ) ⋅ w i + ⋯ + ( c ⋅ w i ) n − 1 ⋅ f n − 1 ( c n ) ⋅ w i = f 0 ( c n ) ⋅ w i + ( c ⋅ f 1 ( c n ) ) ⋅ ( w i ) 2 + ⋯ + ( c n − 1 ⋅ f n − 1 ( c n ) ) C(c\cdot w^i)\cdot w^i=f_0(c^n)\cdot w^i+(c\cdot w^i)\cdot f_1(c^n)\cdot w^i+\cdots +(c\cdot w^i)^{n-1}\cdot f_{n-1}(c^n)\cdot w^i=f_0(c^n)\cdot w^i+(c \cdot f_1(c^n))\cdot (w^i)^2+\cdots +(c^{n-1} \cdot f_{n-1}(c^n)) C(c⋅wi)⋅wi=f0(cn)⋅wi+(c⋅wi)⋅f1(cn)⋅wi+⋯+(c⋅wi)n−1⋅fn−1(cn)⋅wi=f0(cn)⋅wi+(c⋅f1(cn))⋅(wi)2+⋯+(cn−1⋅fn−1(cn))
其等价为对多项式:
C ′ ( X ) = c n − 1 f n − 1 ( c n ) + f 0 ( c n ) X + c f 1 ( c n ) X 2 + ⋯ + c n − 2 f n − 2 ( c n ) X n − 1 C'(X)=c^{n-1}f_{n-1}(c^n)+f_0(c^n)X+cf_1(c^n)X^2+\cdots+c^{n-2}f_{n-2}(c^n)X^{n-1} C′(X)=cn−1fn−1(cn)+f0(cn)X+cf1(cn)X2+⋯+cn−2fn−2(cn)Xn−1
在 w i w^i wi处的evaluation值。
因此,为计算该分子,需:
- 1)计算系数向量: coeffs [ c n − 1 f n − 1 ( c n ) , f 0 ( c n ) , c f 1 ( c n ) , ⋯ , c n − 2 f n − 2 ( c n ) ] \text{coeffs}[c^{n-1}f_{n-1}(c^n),f_0(c^n),cf_1(c^n),\cdots,c^{n-2}f_{n-2}(c^n)] coeffs[cn−1fn−1(cn),f0(cn),cf1(cn),⋯,cn−2fn−2(cn)]。假设计算 r 0 , r 1 r_0,r_1 r0,r1时已知 f 0 ( c n ) , f 1 ( c n ) , ⋯ , f n − 1 ( c n ) f_0(c^n),f_1(c^n),\cdots,f_{n-1}(c^n) f0(cn),f1(cn),⋯,fn−1(cn),则计算该系数向量需 2 n 2n 2n次乘法运算。
- 2)以 n log n n\log n nlogn次乘法运算来计算基于 H H H的快速傅里叶变换:
C ′ ( H ) = F F T ( H , c o e f f s ) = { r i ⋅ w i } i ∈ [ n ] C'(H)=FFT(H,coeffs)=\{r_i\cdot w^i\}_{i\in [n]} C′(H)=FFT(H,coeffs)={ri⋅wi}i∈[n]
从而可获得相应的分子。具体来说,在solidity中可将该快速傅里叶变换展开为具体的运算。
这将避免当前,在verifier中的重复计算coset中每个domain点的 C ( X ) C(X) C(X)值。
2.2 优化FFlonk verifier中的 r 2 r_2 r2计算
2.2.1 对union of two cosets的lagrange多项式
令group H = < w > H= H=<w>的order为 n n n,某coset表示为 c 1 , c 2 c_1,c_2 c1,c2。定义集合 S = c 1 H ∪ c 2 H S=c_1H\cup c_2H S=c1H∪c2H为2个cosets集合,定义如下常量:
s 1 ( c 1 / c 2 ) n − 1 , s 2 ( c 2 / c 1 ) n − 1 s_1(c_1/c_2)^n-1,s_2(c_2/c_1)^n-1 s1(c1/c2)n−1,s2(c2/c1)n−1
定义 X 1 ′ = X / c 1 , X 2 ′ = X / c 2 X_1'=X/c_1,X_2'=X/c_2 X1′=X/c1,X2′=X/c2,对于 i ∈ [ 2 n ] i\in [2n] i∈[2n],定义对 S S S的lagrange多项式为:
- 若 i ∈ [ 0 , n − 1 ] i\in [0,n-1] i∈[0,n−1],则有: L i ( S ) ( X ) = w i n ⋅ ( X 1 ′ ) n − 1 ( X 1 ′ − w i ) ⋅ ( X 2 ′ ) n − 1 s 1 L_i^{(S)}(X)=\frac{w^i}{n}\cdot \frac{(X_1')^n-1}{(X_1'-w^i)}\cdot \frac{(X_2')^n-1}{s_1} Li(S)(X)=nwi⋅(X1′−wi)(X1′)n−1⋅s1(X2′)n−1
- 若 i ∈ [ n , 2 n − 1 ] i\in [n,2n-1] i∈[n,2n−1],则有: L i ( S ) ( X ) = w i n ⋅ ( X 2 ′ ) n − 1 ( X 2 ′ − w i ) ⋅ ( X 1 ′ ) n − 1 s 2 L_i^{(S)}(X)=\frac{w^i}{n}\cdot \frac{(X_2')^n-1}{(X_2'-w^i)}\cdot \frac{(X_1')^n-1}{s_2} Li(S)(X)=nwi⋅(X2′−wi)(X2′)n−1⋅s2(X1′)n−1
2.2.2 对 S S S的barycentric evaluation
令 r ( X ) r(X) r(X)为degree小于 n n n的多项式,其基于 S S S的evaluation值为 r 0 , r 1 , ⋯ , r 2 n − 1 r_0,r_1,\cdots,r_{2n-1} r0,r1,⋯,r2n−1,可基于 S S S的lagrange basis,将 r ( X ) r(X) r(X)唯一表示为:
r ( X ) = ∑ i ∈ [ 2 n ] r i ⋅ L i ( S ) ( X ) = ∑ i ∈ [ n ] r i ⋅ L i ( S ) ( X ) + ∑ i ∈ [ n , 2 n − 1 ] r i ⋅ L i ( S ) ( X ) = ∑ i = 0 n − 1 w i n ⋅ ( X 1 ′ ) n − 1 ( X 1 ′ − w i ) ⋅ ( X 2 ′ ) n − 1 s 1 + ∑ j = n 2 n − 1 w j n ⋅ ( X 2 ′ ) n − 1 ( X 2 ′ − w j ) ⋅ ( X 1 ′ ) n − 1 s 2 = [ ( X 1 ′ ) n − 1 ] ⋅ [ ( X 2 ′ ) n − 1 ] n ⋅ ( 1 s 1 ⋅ ∑ i = 0 n − 1 r i ⋅ w i ( X 1 ′ − w i ) + 1 s 2 ⋅ ∑ j = n 2 n − 1 r j ⋅ w j ( X 2 ′ − w j ) ) r(X)=\sum_{i\in[2n]}r_i\cdot L_i^{(S)}(X)=\sum_{i\in[n]}r_i\cdot L_i^{(S)}(X) + \sum_{i\in[n,2n-1]}r_i\cdot L_i^{(S)}(X)\\ =\sum_{i=0}^{n-1}\frac{w^i}{n}\cdot \frac{(X_1')^n-1}{(X_1'-w^i)}\cdot \frac{(X_2')^n-1}{s_1} + \sum_{j=n}^{2n-1}\frac{w^j}{n}\cdot \frac{(X_2')^n-1}{(X_2'-w^j)}\cdot \frac{(X_1')^n-1}{s_2}\\=\frac{[(X_1')^n-1]\cdot [(X_2')^n-1]}{n}\cdot (\frac{1}{s_1}\cdot \sum_{i=0}^{n-1}\frac{r_i\cdot w^i}{(X_1'-w^i)}+\frac{1}{s_2}\cdot \sum_{j=n}^{2n-1}\frac{r_j\cdot w^j}{(X_2'-w^j)}) r(X)=∑i∈[2n]ri⋅Li(S)(X)=∑i∈[n]ri⋅Li(S)(X)+∑i∈[n,2n−1]ri⋅Li(S)(X)=∑i=0n−1nwi⋅(X1′−wi)(X1′)n−1⋅s1(X2′)n−1+∑j=n2n−1nwj⋅(X2′−wj)(X2′)n−1⋅s2(X1′)n−1=n[(X1′)n−1]⋅[(X2′)n−1]⋅(s11⋅∑i=0n−1(X1′−wi)ri⋅wi+s21⋅∑j=n2n−1(X2′−wj)rj⋅wj)
对于 y ∈ F y\in\mathbb{F} y∈F,为计算:
r ( y ) = [ ( y 1 ′ ) n − 1 ] ⋅ [ ( y 2 ′ ) n − 1 ] n ⋅ ( 1 s 1 ⋅ ∑ i = 0 n − 1 r i ⋅ w i ( y 1 ′ − w i ) + 1 s 2 ⋅ ∑ j = n 2 n − 1 r j ⋅ w j ( y 2 ′ − w j ) ) r(y)=\frac{[(y_1')^n-1]\cdot [(y_2')^n-1]}{n}\cdot (\frac{1}{s_1}\cdot \sum_{i=0}^{n-1}\frac{r_i\cdot w^i}{(y_1'-w^i)}+\frac{1}{s_2}\cdot \sum_{j=n}^{2n-1}\frac{r_j\cdot w^j}{(y_2'-w^j)}) r(y)=n[(y1′)n−1]⋅[(y2′)n−1]⋅(s11⋅∑i=0n−1(y1′−wi)ri⋅wi+s21⋅∑j=n2n−1(y2′−wj)rj⋅wj)
需计算以下值:
- 1) y 1 ′ = y / c 1 , y 2 ′ = y / c 2 y_1'=y/c_1,y_2'=y/c_2 y1′=y/c1,y2′=y/c2:策略与2.1.1节的类似。
- 2) [ ( y 1 ′ ) n − 1 ] ⋅ [ ( y 2 ′ ) n − 1 ] n \frac{[(y_1')^n-1]\cdot [(y_2')^n-1]}{n} n[(y1′)n−1]⋅[(y2′)n−1]:策略与2.1.1节的类似。
- 3) s 1 = ( c 1 / c 2 ) n − 1 , s 2 = ( c 2 / c 1 ) n − 1 s_1=(c_1/c_2)^n-1,s_2=(c_2/c_1)^n-1 s1=(c1/c2)n−1,s2=(c2/c1)n−1:计算 ( c 1 / c 2 ) n (c_1/c_2)^n (c1/c2)n,对其求倒数获得 ( c 2 / c 1 ) n (c_2/c_1)^n (c2/c1)n,然后各自减一。
- 4) 1 / s 1 , 1 / s 2 1/s_1,1/s_2 1/s1,1/s2:对 s 1 , s 2 s_1,s_2 s1,s2求倒数。
- 5) { r i ⋅ w i } i ∈ [ n ] , { r j ⋅ w j } j ∈ [ n , 2 n − 1 ] \{r_i\cdot w^i\}_{i\in[n]},\{r_j\cdot w^j\}_{j\in[n,2n-1]} {ri⋅wi}i∈[n],{rj⋅wj}j∈[n,2n−1]:需采用2.1.2节的类似技巧来高效计算分子,其包含对 H H H的2次傅里叶变换。
- 6) { 1 / ( y 1 ′ − w i ) } i ∈ [ n ] , { 1 / ( y 2 ′ − w j ) } j ∈ [ n , 2 n − 1 ] \{1/(y_1'-w^i)\}_{i\in[n]},\{1/(y_2'-w^j)\}_{j\in[n,2n-1]} {1/(y1′−wi)}i∈[n],{1/(y2′−wj)}j∈[n,2n−1]:策略与2.1.1节的类似。
2.3 基于smooth domain的FFT
令 F \mathbb{F} F为FFT-friendly域,其order ∣ F ∣ = p |\mathbb{F}|=p ∣F∣=p,使得 ( p − 1 ) (p-1) (p−1)可整除powers of small primes。如,FFlonk verifier solidity合约内的scalar域,其order为:
p = 21888242871839275222246405745257275088548364400416034343698204186575808495617 p= 21888242871839275222246405745257275088548364400416034343698204186575808495617 p=21888242871839275222246405745257275088548364400416034343698204186575808495617
有:
( p − 1 ) = 2 28 ∗ 3 2 ∗ 13 ∗ 29 ∗ 983 ∗ 11003 ∗ 237073 ∗ 405928799 ∗ 1670836401704629 ∗ 13818364434197438864469338081 (p-1)=2^{28}*3^2*13*29*983*11003*237073*405928799*1670836401704629* 13818364434197438864469338081 (p−1)=228∗32∗13∗29∗983∗11003∗237073∗405928799∗1670836401704629∗13818364434197438864469338081
令 H ⊆ F × H\subseteq\mathbb{F}^{\times} H⊆F×为某smooth乘法子群,其order ∣ H ∣ = n |H|=n ∣H∣=n可分解为powers of small primes。
Cooley-Tukey FFT算法 或 (对有限域通用的)Mixed-radix FFT算法,可基于 H H H对degree小于 n n n的多项式进行高效evaluate。其domain size无需为a power of two,可将其看成是某FFT算法。
其核心思想为:
- 不同于每个FFT step中的对半(奇偶)切分,而是将每个FFT step切分为 r r r个chunks,其中 r r r为当前迭代的素因子。通常将 r r r称为radix。如,标准FFT的radix总为2。
在线上SageMath脚本执行环境中执行如下代码:
p = 21888242871839275222246405745257275088548364400416034343698204186575808495617
# F is a field whose size is p
F = GF(p)
# define x to be a variable
R. = PolynomialRing(F)
# g is the multiplicative generator with order (p-1)
g = F.multiplicative_generator()
# Implementation of Mixed-Radix FFT / Cooley-Tukey FFT for finite fields
# vals are the coeffs
# w is the multiplicative generator
# For n = p1^e1 * p2^e2 * ..., factors = [(p1, e1), (p2, e2), ...]
def fft_helper(vals, w, factors):
n = len(vals)
# Base case
if n == 1:
return vals
# r is the current radix
r = factors[0][0]
# decrementing exponent
# [(p1, e1), (p2, e2), ...]
# goes to [(p1, e1-1), (p2, e2), ...]
# or [(p2, e2), ...] if e1 = 1
factors = list(factors)
factors[0] = (factors[0][0], factors[0][1]-1)
if factors[0][1] == 0:
factors = factors[1:]
# Recursive Step
# acc = [fft0, fft1, fft2, ...]
acc = list()
for i in range(r):
acc.append(fft_helper(vals[i::r], w^r, factors))
# Allocate list for evaluations
evals = [0 for _ in range(n)]
# Accumulate recursive steps
shift = n // r
# acc = [fft0, fft1, fft2, ...]
# Iterate as [t0 = (fft0[0], fft1[0], fft2[0]), t1 = (fft0[1], fft1[1], fft2[1]),...]
for i, t in enumerate(zip(*acc)):
for j in range(r):
evals[i + shift * j] = sum((w^(i+shift*j))^k * t[k] for k in range(r))
return evals
# w is the multiplicative generator
# vals are the coeffs
def fft(w, vals):
factors = list(factor(w.multiplicative_order()))
return fft_helper(vals, w, factors)
# Domain Size
n = 2^2 * 3^2 * 13
# w is generator for group of size n
w = g^((p-1)/n)
coeffs = [F.random_element() for _ in range(n)]
poly = sum([c*x^i for i,c in enumerate(coeffs)])
fft_evals = fft(w, coeffs)
true_evals = [poly(w^i) for i in range(n)]
print(fft_evals == true_evals)
以上代码中,使用的是FFlonk verifier中的scalar域,并取其subgroup size n = 2 2 ∗ 3 2 ∗ 13 n=2^2*3^2*13 n=22∗32∗13,对应的radix为 2 , 3 , 13 2,3,13 2,3,13。
该代码可调整为任意subgroup size和radix,但若已知某特定subgroup因式分解,则可定制该代码为特定radix。当subgroup order n n n为a power of 2 2 2时,该算法与标准FFT算法一致。
3. 定制PIL约束
在本轮审计中,验证了STARK verifier circom descripto中所使用的定制模板中相应定制PIL约束的正确性。
该proving pipeline流程为:
- 1)使用包含定制模板的circom descriptor来描述某STARK verifier。
- 2)将STARK verifier circom descriptor编译为R1CS约束,其中定制模板不生成约束。
- 3)将Circom-generated R1CS约束,编写为某STARK verifier PIL descriptor的PIL约束。
- 4)添加定制PIL约束,以完善STARK verifier PIL descriptor,以捕获circom定制模板。
本轮审计主要关注以上proving pipeline流程的第4)步,检查3个定制模板的定制PIL约束:
- Fp3乘法(circuits.gl/cmul.circom)
- 1-of-4 Fp3 selector(circuits.gl/treeselector4.circom)
- Poseidon hash evaluation(circuits.gl目录下的poseidon.circom和poseidon_constants.circom)
本轮审计还包含,(指向committed witness多项式数量的)与C12和C18 PIL descriptors相关的PIL约束文件:
- src/compressor目录下的compressor12.pil.ejs和compressor12_setup.js
- src/compressor目录下的compressor18.pil.ejs和compressor18_setup.js
所审计的pil-stark版本为:
- https://github.com/0xPolygonHermez/pil-stark/tree/bb2404acd221083f0efa0b3ab8fa50bb421e686e
3.1 Fp3乘法(CMUL)
未发现问题。
3.2 1-of-4 Fp3 selector(TreeSelector4)
注意,后面的“keys”约束,是指binary约束。
https://github.com/0xPolygonHermez/pil-stark/blob/bb2404acd221083f0efa0b3ab8fa50bb421e686e/src/compressor/compressor18.pil.ejs#L326,326、335、344、353中的注释,声明了:
- 仅当key bit多项式a[12]和a[13]设置了合适的bits,相应的“keys”多项式才为1。
若限制了a[12]和a[13]为 { 0 , 1 } \{0,1\} {0,1},则以上声明成立。但该约束并不存在。事实上,TreeSelector4函数中也未限制a[12]和a[13]。
更准确来说,现有PIL约束提供了如下bijection:
- keys1=0 a[12]=1或a[13]=1
- keys2=0 a[12]=0或a[13]=1
- keys3=0 a[12]=1或a[13]=0
- keys4=0 a[12]=0或a[13]=0
这强化了:不存在a[12]和a[13]的设置,使得所有 keys{1,2,3,4} 都可设置为0,这意味着该selector应用于至少一个分支。
建议:
- 为不失通用性,将注释替换为:“keys1 will be non-zero unless a[12]=0 or a[13]=0”。
3.3 Poseidon hash evaluation(Poseidon/CustPoseidon)
3.3.1 可能的可靠性问题:对CustPoseidon Selection Key无binary enforcement
在https://github.com/0xPolygonHermez/pil-stark/blob/bb2404acd221083f0efa0b3ab8fa50bb421e686e/src/compressor/compressor18.pil.ejs#L93的93-100行,witness多项式a[8]用于选择custom Poseidon input order,但其假设了a[8]值为二进制值 { 0 , 1 } \{0,1\} {0,1}。若未约束a[8],prover可设置a[8]为其它值。不清楚在该上下文中,利用该漏洞,是否会引起Poseidon的碰撞问题。
建议:
- 当读取custom Poseidon输入时,添加约束a[8]为二进制值的多项式约束:
P O S E I D O N C U S T F I R S T ∗ ( 1 − a [ 8 ] ) ∗ a [ 8 ] = 0 POSEIDONCUSTFIRST * (1-a[8])* a[8]=0 POSEIDONCUSTFIRST∗(1−a[8])∗a[8]=0
3.3.2 优化建议:POSEIDONM多项式可用于capture multiple rounds
在https://github.com/0xPolygonHermez/pil-stark/blob/bb2404acd221083f0efa0b3ab8fa50bb421e686e/src/compressor/compressor18.pil.ejs#L196第196行,POSEIDONM、POSEIDONAFTERPART、POSEIDONFIRST、POSEIDONCUSTFIRST用作selector,用于将poseidonM多项式中的值传递给下一行。而POSEIDONAFTERPART、POSEIDONFIRST和POSEIDONCUSTFIRST具有其它重要功能,POSEIDONM仅用于当Round 30 -> output row的情况。
建议:
- 可在定义POSEIDONAFTERPART、POSEIDONFIRST、POSEIDONCUSTFIRST的同时,定义POSEIDONM额外设置为1,来简化该多项式约束:
POSEIDONM * poseidonM<%-i + 12 + 1 %> = 0;
附录: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修复)
- Polygon zkEVM PIL-STARK Spearbit审计报告解读(2023年3月版)