Polygon zkEVM PIL-STARK Spearbit审计报告解读(2023年6月版)

1. 引言

前序博客有:

具体内容见:

本轮审计历时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中。

实际审计的代码库为:

本轮审计未发现可靠性问题:

  • 有一些对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=<w>,H=256 H=<w>,H=256
  • H 4 = < w 3 > , H 3 = 3 H_4=<w_3>,H_3=3 H4=<w3>,H3=3
  • H 4 = < w 4 > , H 4 = 4 H_4=<w_4>,H_4=4 H4=<w4>,H4=4
  • H 8 = < w 8 > , H 8 = 8 H_8=<w_8>,H_8=8 H8=<w8>,H8=8
  • r ← F , ξ ← r 24 r\leftarrow \mathbb{F},\xi\leftarrow r^{24} rF,ξ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=h2H3h3H3=r8H3r8w1/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)=8h07w87i1Xh0w8iX8h08,起算其分母在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(yh0w8i)}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)=4h13w43i1Xh1w4iX4h14,起算其分母在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(yh1w4i)}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)+XqR(X8)+X2qO(X8)+X3qM(X8)+X4qC(X8)+X5Sσ1(X8)+X6Sσ2(X8)+X7Sσ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(ξ)+eqR(ξ)+e2qO(ξ)+e3qM(ξ)+e4qC(ξ)+e5Sσ1(ξ)+e6Sσ2(ξ)+e7Sσ3(ξ)方式,对于每个 e ∈ S 0 = h 0 H 8 e\in S_0=h_0H_8 eS0=h0H8,来计算evaluation值集合: { C 0 ( e ) ∣ e ∈ S 0 = h 0 H 8 } \{C_0(e)| e\in S_0=h_0H_8\} {C0(e)eS0=h0H8}
    • 计算分子: y 8 − h 0 8 y^8-h_0^8 y8h08
    • 为计算 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(Xh0w8i)1(X8h08) 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(yh0w8i)1(y8h08)}i[8] 可根据 LiS0dens \text{LiS0dens} LiS0dens的倒数值和分子 y 8 − h 0 8 y^8-h_0^8 y8h08值,来计算,然后将其与 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)+Xb(X4)+X2c(X4)+X3T0(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=<w> 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,,rn1,将 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=0n1riLi(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=0n1riLi(cH)(X)=i=0n1riLi(H)(cX)=i=0n1nriwiXwi(X)n1=n(X)n1i=0n1Xwiriwi

对于 y ∈ F y\in\mathbb{F} yF,为计算:
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)n1i=0n1ywiriwi

需计算以下值:

  • 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)n1:将 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]} {riwi}i[n]:为特例情况,将在下一小节展开。
  • 4) { 1 y ′ − w i } i ∈ [ n ] \{\frac{1}{y'-w^i}\}_{i\in [n]} {ywi1}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]} {riwi}i[n]

可使用快速傅里叶变换来高效计算分子 { r i ⋅ w i } i ∈ [ n ] \{r_i\cdot w^i\}_{i\in [n]} {riwi}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)+Xf1(Xn)+X2f2(Xn)++Xn1fn1(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 riwi=C(cwi)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(cwi)wi=f0(cn)wi+(cwi)f1(cn)wi++(cwi)n1fn1(cn)wi=f0(cn)wi+(cf1(cn))(wi)2++(cn1fn1(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)=cn1fn1(cn)+f0(cn)X+cf1(cn)X2++cn2fn2(cn)Xn1
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[cn1fn1(cn),f0(cn),cf1(cn),,cn2fn2(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),,fn1(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)={riwi}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=<w> 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=c1Hc2H为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)n1,s2(c2/c1)n1
定义 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,n1],则有: 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(X1wi)(X1)n1s1(X2)n1
  • i ∈ [ n , 2 n − 1 ] i\in [n,2n-1] i[n,2n1],则有: 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(X2wi)(X2)n1s2(X1)n1

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,,r2n1,可基于 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]riLi(S)(X)=i[n]riLi(S)(X)+i[n,2n1]riLi(S)(X)=i=0n1nwi(X1wi)(X1)n1s1(X2)n1+j=n2n1nwj(X2wj)(X2)n1s2(X1)n1=n[(X1)n1][(X2)n1](s11i=0n1(X1wi)riwi+s21j=n2n1(X2wj)rjwj)

对于 y ∈ F y\in\mathbb{F} yF,为计算:
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)n1][(y2)n1](s11i=0n1(y1wi)riwi+s21j=n2n1(y2wj)rjwj)
需计算以下值:

  • 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)n1][(y2)n1]:策略与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)n1,s2=(c2/c1)n1:计算 ( 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]} {riwi}i[n],{rjwj}j[n,2n1]:需采用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/(y1wi)}i[n],{1/(y2wj)}j[n,2n1]:策略与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) (p1)可整除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 (p1)=22832132998311003237073405928799167083640170462913818364434197438864469338081

H ⊆ F × H\subseteq\mathbb{F}^{\times} HF×为某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.<x> = 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=223213,对应的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版本为:

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(1a[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系列博客

  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值