SNARK超详细解释,从GGPR13到Groth16

初学零知识证明,准备从SNARK开始入手,还是自己做个整理会印象深刻一些

目前看来GGPR13是最先提出基于QAP的SNARK这个框架的工作,而Groth16则是目前效率表现最好的SNARK方案。话说Craig Gentry大佬也太牛了吧,不止是全同态加密的鼻祖,这边SNARK的提出原来也有他的关系啊。

文章目录

  • 零知识证明
  • SNARK的基本思路
  • 为什么现在SNARK的证明要基于多项式(QAP)
  • 零知识地证明一个多项式
    • 简化版的证明过程
    • 通过混淆的计算来优化上述多项式证明
      • 使用具有同态性质的加密方法
      • 计算一个加密的多项式值
    • 对多项式的运算进行承诺
    • 如何做到零知识性
    • 如何构造一个非交互的方案
      • 建立 CRS
        • 双线性配对
        • 通过双线性配对建立CRS
        • 通过CRS构造一个非交互的协议
        • 多方共同生成CRS
  • 通用的零知识证明
  • GGPR13
  • Groth16

零知识证明

首先回答一个问题,零知识证明(ZK)是什么,为什么要学他。关于零知识证明的基础框架可以戳这里。

ZK是解决了这样一个问题:我知道一个 Y Y Y,满足 F ( X , Y ) = Z F(X,Y)=Z F(X,Y)=Z,要怎么在不公开 Y Y Y的情况下证明这个式子成立。其中 F F F是任意函数(也叫做CIrcuit), X X X是公开的输入(也叫做Instance), Y Y Y是私有的输入(叫做Witness), Z Z Z是公开的输出(和X一样叫做Instance)。把 F ( X , Y ) = Z F(X,Y)=Z F(X,Y)=Z这一个句子叫做一个statement。

这里我给出三个常见的场景:

  1. 机器学习(可验证计算)
    很显然,ZK可以用来做可验证的计算,比如机器学习模型训练里面,我把数据外包给一家公司进行训练,这家公司训练完之后,对我来说,我得知道这个模型( Y Y Y)是确实用我要的方法( F F F)以及我给的数据( X , Z X,Z X,Z)训练出来的才能付钱,对于公司来说,我付钱之前不能把模型的参数给我。所以这时候就可以进行一个零知识证明来让我相信他们确实诚实的进行了训练。

  2. 交易凭证(隐私保护)
    如果说我要进行一笔电子支付,假设我要付 3 3 3块钱,那么我就需要证明我确实有3块钱,即我钱包里有 Y Y Y元,我要证明 Y > 3 Y>3 Y>3,但同时我也不希望别人知道这个 Y Y Y具体是多少,这时候也可以使用一个零知识证明来做。

  3. 区块链扩容
    这里 Y Y Y除了可以当做一个隐私信息来做可验证外,还可以作为一个大信息量的信息源,比如 X X X Z Z Z都是几+十byte,而 Y Y Y是几MB的消息。比如在区块链中, F F F可以是验证交易以及更新账本, X X X是先前值的Merkle root, Z Z Z是当前值的Merkle root, Y Y Y是一整个Merkle tree。那么就可以使用较少的数据对大量信息进行验证了。

SNARK的基本思路

SNARKs的基本思路是Computation → \to Arithmetic Circuit → \to R1CS → \to QAP → \to SNARKs

SNARK:succinct non-interactive arguments of knowledge

用人话说的话,就是将证明知道一个函数的结果,变成证明知道一个满足某种性质的多项式。

下面会简略的过一遍这整个流程,只需要有个大概的理解就行了。后续会具体地说明为什么要把计算变为多项式来做ZK,怎么对多项式做ZK,以及里面涉及到的原理和细节。最后会说明一下为什么可以把证明一个函数变为证明一个多项式。


由一个算式,比如 x ∗ y + 4 = 10 x*y+4=10 xy+4=10,要不暴露 x , y x,y x,y的情况下证明这个算式是成立的。


先把他转换为算数电路:

SNARK超详细解释,从GGPR13到Groth16_第1张图片


再由算数电路变为R1CS:

R1CS是一种描述电路的语言。具体来说,一条R1CS由四个向量组成,分别为三个描述向量 ( L , R , O ) \left(L,R,O\right) (L,R,O),以及一个解向量 v v v,要满足
⟨ L , v ⟩ ∗ ⟨ R , v ⟩ = ⟨ O , v ⟩ \langle L, v\rangle *\langle R, v\rangle=\langle O, v\rangle L,vR,v=O,v

如果不考虑细节,那么就记住电路能等价的转换为一种向量语言R1CS

首先这个算数电路中的Constraint有3个,分别是:

  1. output 1 = x ∗ y \text{output}_1=x*y output1=xy
  2. output 1 + 4 = 10 \text{output}_1+4=10 output1+4=10

将其转换为R1CS,则令 v = [ 1 , x , y , o u t p u t 1 ] v=[1,x,y,output_1] v=[1,x,y,output1],对于两个Constraint,分别取:

  1. L = [ 0 , 1 , 0 , 0 ] , R = [ 0 , 0 , 1 , 0 ] , O = [ 0 , 0 , 0 , 1 ] L=[0,1,0,0],R=[0,0,1,0],O=[0,0,0,1] L=[0,1,0,0],R=[0,0,1,0],O=[0,0,0,1]

⟨ L , v ⟩ = x , ⟨ R , v ⟩ = y , ⟨ O , v ⟩ = o u t p u t 1 \langle L, v\rangle=x,\langle R, v\rangle=y,\langle O, v\rangle=output_1 L,v=x,R,v=y,O,v=output1

⟨ L , v ⟩ ∗ ⟨ R , v ⟩ = ⟨ O , v ⟩ ⟺ x ∗ y = o u t p u t 1 \langle L, v\rangle *\langle R, v\rangle=\langle O, v\rangle \Longleftrightarrow x*y = output_1 L,vR,v=O,vxy=output1

  1. L = [ 4 , 0 , 0 , 1 ] , R = [ 1 , 0 , 0 , 0 ] , O = [ 10 , 0 , 0 , 0 ] L=[4,0,0,1],R=[1,0,0,0],O=[10,0,0,0] L=[4,0,0,1],R=[1,0,0,0],O=[10,0,0,0]

⟨ L , v ⟩ = o u t p u t 1 + 4 , ⟨ R , v ⟩ = 1 , ⟨ O , v ⟩ = 10 \langle L, v\rangle=output_1 +4,\langle R, v\rangle=1,\langle O, v\rangle=10 L,v=output1+4,R,v=1,O,v=10

⟨ L , v ⟩ ∗ ⟨ R , v ⟩ = ⟨ O , v ⟩ ⟺ ( o u t p u t 1 + 4 ) ∗ 1 = 10 \langle L, v\rangle *\langle R, v\rangle=\langle O, v\rangle \Longleftrightarrow (output_1+4) * 1 = 10 L,vR,v=O,v(output1+4)1=10


从R1CS得到QAP:

如果不考虑细节,那么就记住R1CS可以等价的转换为一种多项式的表达

QAP的构造方式如下,L,R,O都是长度为4的向量,我们构造3*4个多项式 L i ( X ) , R i ( X ) , O i ( X ) , i ∈ [ 1 , 4 ] L_i(X),R_i(X),O_i(X), i\in[1,4] Li(X),Ri(X),Oi(X),i[1,4]

L i ( X ) L_i(X) Li(X)举例,他代表着 L L L向量的第 i i i个元素,在不同的Constraint下的多项式,也就是说 L 1 ( 1 ) = 0 , L 1 ( 2 ) = 4 L_1(1)=0,L_1(2)=4 L1(1)=0,L1(2)=4,通过多项式插值可以得到 L 1 ( X ) = 4 X − 4 L_1(X)=4X-4 L1(X)=4X4

罗列一下所有 L i ( X ) L_i(X) Li(X)的可得:
C o n s t r a i n t   1 : L ( 1 ) = [ 0 , 1 , 0 , 0 ] C o n s t r a i n t   2 : L ( 2 ) = [ 4 , 0 , 0 , 1 ] L 1 ( 1 ) = 0 , L 1 ( 2 ) = 4 , L 1 ( X ) = 4 X − 4 L 2 ( 1 ) = 1 , L 2 ( 2 ) = 0 , L 2 ( X ) = − X + 2 L 3 ( 1 ) = 0 , L 3 ( 2 ) = 0 , L 3 ( X ) = 0 L 3 ( 1 ) = 0 , L 3 ( 2 ) = 1 , L 4 ( X ) = X − 1 Constraint~1:L^{(1)}=[0,1,0,0]\\ Constraint~2:L^{(2)}=[4,0,0,1]\\ \begin{aligned} L_1(1)&=0,&&L_1(2)=4,&&L_1(X)=4X-4\\ L_2(1)&=1,&&L_2(2)=0,&&L_2(X)=-X+2\\ L_3(1)&=0,&&L_3(2)=0,&&L_3(X)=0\\ L_3(1)&=0,&&L_3(2)=1,&&L_4(X)=X-1\\ \end{aligned} Constraint 1:L(1)=[0,1,0,0]Constraint 2:L(2)=[4,0,0,1]L1(1)L2(1)L3(1)L3(1)=0,=1,=0,=0,L1(2)=4,L2(2)=0,L3(2)=0,L3(2)=1,L1(X)=4X4L2(X)=X+2L3(X)=0L4(X)=X1
可以看出 L i ( n ) = L ( n ) [ i ] L_i(n)=L^{(n)}[i] Li(n)=L(n)[i]

L ( X ) → = ( L 1 ( X ) , L 2 ( X ) , L 3 ( X ) , L 4 ( X ) ) \overrightarrow{L(X)}=(L_1(X),L_2(X),L_3(X),L_4(X)) L(X) =(L1(X),L2(X),L3(X),L4(X))

R ( X ) → = ( R 1 ( X ) , R 2 ( X ) , R 3 ( X ) , R 4 ( X ) ) \overrightarrow{R(X)}=(R_1(X),R_2(X),R_3(X),R_4(X)) R(X) =(R1(X),R2(X),R3(X),R4(X))

O ( X ) → = ( O 1 ( X ) , O 2 ( X ) , O 3 ( X ) , O 4 ( X ) ) \overrightarrow{O(X)}=(O_1(X),O_2(X),O_3(X),O_4(X)) O(X) =(O1(X),O2(X),O3(X),O4(X))

很容易验证 L ( 1 ) → = L ( 1 ) , L ( 2 ) → = L ( 2 ) \overrightarrow{L(1)}=L^{(1)},\overrightarrow{L(2)}=L^{(2)} L(1) =L(1),L(2) =L(2)

L ( X ) = ⟨ L ( X ) → , v ⟩ L(X)=\langle \overrightarrow{L(X)},v \rangle L(X)=L(X) ,v

R ( X ) = ⟨ R ( X ) → , v ⟩ R(X)=\langle \overrightarrow{R(X)},v \rangle R(X)=R(X) ,v

O ( X ) = ⟨ O ( X ) → , v ⟩ O(X)=\langle \overrightarrow{O(X)},v \rangle O(X)=O(X) ,v

由此可以得到 L ( X ) ∗ R ( X ) − O ( X ) = 0   f o r   X ∈ { 1 , 2 } L(X)*R(X) - O(X)=0~for~X\in\{1,2\} L(X)R(X)O(X)=0 for X{1,2}

P ( X ) = L ( X ) ∗ R ( X ) − O ( X ) P(X)=L(X)*R(X)-O(X) P(X)=L(X)R(X)O(X),将 P ( X ) P(X) P(X)拆为两个因子多项式 P ( X ) = T ( X ) ∗ H ( X ) P(X)=T(X)*H(X) P(X)=T(X)H(X)

其中 T ( X ) T(X) T(X)公开。

这样的 T ( X ) T(X) T(X)其实很容易找,因为 X = 1 , X = 2 X=1,X=2 X=1,X=2 P ( X ) = 0 P(X)=0 P(X)=0的两个根,所以可以令 T ( X ) = ( X − 1 ) ( X − 2 ) T(X)=(X-1)(X-2) T(X)=(X1)(X2),用多项式的除法得到 H ( X ) H(X) H(X)即可。


现在要向外部证明的其实是:

P ( X ) = L ( X ) ∗ R ( X ) − O ( X ) = T ( X ) ∗ H ( X ) P(X)=L(X)*R(X)-O(X)=T(X)*H(X) P(X)=L(X)R(X)O(X)=T(X)H(X)这样一个式子在所有 X X X上成立。

也就是证明某个多项式成立

但是公开的多项式只有 T ( X ) T(X) T(X),也就是说,如果取一个数 X = s X=s X=s,那么其他人最多能知道 T ( s ) T(s) T(s)的值。那如何在不暴露 L ( s ) , R ( s ) , O ( s ) , H ( s ) L(s),R(s),O(s),H(s) L(s),R(s),O(s),H(s)的情况下证明 L ( s ) ∗ R ( s ) − O ( s ) = T ( s ) ∗ H ( s ) L(s)*R(s)-O(s)=T(s)*H(s) L(s)R(s)O(s)=T(s)H(s)成了现在要考虑的问题。

那这里就用到了一种具有同态性质的加密: E ( s ) E(s) E(s)

这样的加密如下性质:

  1. 单项性:给定 x x x,很容易计算 y = E ( x ) y=E(x) y=E(x),但给定 y y y,很难找到一个 x x x满足 y = E ( x ) y=E(x) y=E(x)
  2. 线性: E ( α x + β y ) = α E ( x ) + β E ( y ) E(\alpha x+\beta y)=\alpha E(x) + \beta E(y) E(αx+βy)=αE(x)+βE(y)
  3. 单射: x ≠ y ⟶ E ( x ) ≠ E ( y ) x\neq y \longrightarrow E(x) \neq E(y) x=yE(x)=E(y)

所以Prover可以直接计算出 P ( E ( s ) ) = E ( P ( s ) ) P(E(s))=E(P(s)) P(E(s))=E(P(s))的值。

SNARKs的协议如下:
1. Setup: 将 E ( s ) E(s) E(s)公开, T ( s ) T(s) T(s)公开, s s s本身丢弃
2. Prover自己有 L , R , O , H L,R,O,H L,R,O,H四个多项式
3. Prover发送 E ( L ( s ) ) , E ( R ( s ) ) , E ( O ( s ) ) , E ( H ( s ) ) E(L(s)),E(R(s)),E(O(s)),E(H(s)) E(L(s)),E(R(s)),E(O(s)),E(H(s))
4. 任何人都可以验证:
E ( L ( s ) ) ∗ E ( R ( s ) ) − E ( O ( s ) ) = E ( H ( s ) ) ∗ E ( T ( s ) ) E(L(s))*E(R(s)) - E(O(s)) = E(H(s)) * E(T(s)) E(L(s))E(R(s))E(O(s))=E(H(s))E(T(s))

最后证明了多项式的值就相当于证明了这个电路成立。

为什么现在SNARK的证明要基于多项式(QAP)

考虑一种最简单的交互式零知识证明:我有一个数组 b b b,我想证明它里面全是 1 1 1。一个很简单的方法就是,每次交互时打乱这个数组,让验证者来每次随机查看打乱后的数组中的一个值,如果这个值是 1 1 1,数组的长度是 d d d,那验证者就有 1 d \frac{1}{d} d1的信心相信这个数组全是 1 1 1。一般来说这样的交互过程要重复 d 2 d^2 d2次,那么验证者才会接近 100 % 100 \% 100%地相信这个数组里面全是 1 1 1

但如果我要证明我知道一个多项式呢?
假设Verifier已经知道了一个多项式 f 1 ( x ) f_1(x) f1(x),我知道一个多项式 f 2 ( x ) f_2(x) f2(x),我想要证明 f 1 = f 2 f_1=f_2 f1=f2
假设这两个多项式都是 d d d阶的,如果 f 1 ≠ f 2 f_1 \ne f_2 f1=f2,则 f 1 ( x ) − f 2 ( x ) = 0 f_1(x)-f_2(x)=0 f1(x)f2(x)=0最多只有 d d d个解。


Verifier可以随机选取 s ∈ [ 0 , 2 77 ) s\in[0,2^{77}) s[0,277),并计算得到 f 1 ( s ) f_1(s) f1(s),然后将 s s s发给我。
我本地计算出 f 2 ( s ) f_2(s) f2(s),发送给Verifier。
Verifier可以验证这两个值是否相等。
因为 f 1 ( x ) − f 2 ( x ) f_1(x)-f_2(x) f1(x)f2(x)只有 d d d个解,
那么如果 f 1 ≠ f 2 f_1\neq f_2 f1=f2,则 f 1 ( s ) = f 2 ( s ) f_1(s)=f_2(s) f1(s)=f2(s)的概率只有 d 2 77 \frac{d}{2^{77}} 277d


可以注意到使用多项式进行验证的话,只需要验证一次,就可以有极大概率可以相信这个证明是正确的。而使用普通的交互式证明则需要 n 2 n^2 n2次。
而且可以注意到,无论多项式本身有多大,他的证明是只需要给出 f ( s ) f(s) f(s)这一个值的。依旧是说证明的大小与计算本身的复杂度是无关的,即满足了succinct性质。
因此可以考虑把实际要证明的问题转换为多项式验证的问题。

零知识地证明一个多项式

在上面的场景里面,我们是证明了自己拥有的 f 2 f_2 f2与Verifier拥有的 f 1 f_1 f1一致。现在考虑我要想Verifier证明我知道满足某个性质的一个多项式。

“知道一个多项式”的概念如何定义呢? n n n阶的多项式可以被表达为:
c n x n + . . . + c 1 x 1 + c 0 x 0 c_n x^n + ...+c_1x^1 + c_0x^0 cnxn+...+c1x1+c0x0
所谓的知道一个多项式的意思就是,知道所有的 ( c 0 , . . . , c n ) (c_0,...,c_n) (c0,...,cn)

那么,如果我说我知道一个3阶多项式,满足的性质是 x = 1 x=1 x=1 x = 2 x=2 x=2是这个多项式的两个根,那么这样一个多项式可以是 p ( x ) = x 3 − 3 x 2 + 2 x = 0 p(x)=x^3-3x^2+2x=0 p(x)=x33x2+2x=0。那么 p ( 1 ) = 1 − 3 + 2 = 0 , p ( 2 ) = 8 − 3 ∗ 4 + 2 ∗ 2 = 0 p(1)=1-3+2=0,p(2)=8-3*4+2*2=0 p(1)=13+2=0,p(2)=834+22=0

根据多项式的分解规则,一个可解的多项式可以写为多个一次多项式的组合: p ( x ) = ( x − x 1 ) ( x − x 2 ) . . . ( x − x n ) p(x)=(x-x_1)(x-x_2)...(x-x_n) p(x)=(xx1)(xx2)...(xxn),其中 ( x 1 , . . . , x n ) (x_1,...,x_n) (x1,...,xn)是这个多项式的根。那么我们上述的 p ( x ) = x 3 − 3 x 2 + 2 x p(x)=x^3-3x^2+2x p(x)=x33x2+2x也可以写为 p ( x ) = ( x − 0 ) ( x − 1 ) ( x − 2 ) p(x)=(x-0)(x-1)(x-2) p(x)=(x0)(x1)(x2)。如果说我要证明 x = 1 , x = 2 x=1,x=2 x=1,x=2 p ( x ) p(x) p(x)的两个根,那就相当于证明 p ( x ) p(x) p(x)可以整除 t ( x ) = ( x − 1 ) ( x − 2 ) t(x)=(x-1)(x-2) t(x)=(x1)(x2)。即 p ( x ) = t ( x ) h ( x ) p(x)=t(x) h(x) p(x)=t(x)h(x),其中 h ( x ) = p ( x ) t ( x ) h(x)=\frac{p(x)}{t(x)} h(x)=t(x)p(x)

简化版的证明过程

现在要证明的是,我知道一个 n n n次的多项式 p ( x ) p(x) p(x),其中 ( x 1 , . . . x d ) (x_1,...x_d) (x1,...xd)是这个多项式的根。即证明 p ( x ) = t ( x ) h ( x ) , t ( x ) = ( x − x 1 ) . . . ( x − x d ) p(x)=t(x)h(x),t(x)=(x-x_1)...(x-x_d) p(x)=t(x)h(x),t(x)=(xx1)...(xxd) h ( x ) h(x) h(x)是一个整系数多项式。

那么证明 p ( x ) p(x) p(x)有两个根的问题就变为了证明 p ( x ) = t ( x ) h ( x ) p(x)=t(x)h(x) p(x)=t(x)h(x)的问题,其中 t ( x ) t(x) t(x)是公开给Verifier, p ( x ) p(x) p(x) h ( x ) h(x) h(x)保密。

证明过程如下:
P r o v e r V e r i f i e r ←                        r                     r a n d o m   r , g e t   t = t ( r ) h = h ( r ) , p = p ( r ) →                      h , f                   Check  p = t ⋅ h \begin{aligned} &\quad\quad\quad\bold{Prover} &&\quad\quad\quad\bold{Verifier}\\ &&\xleftarrow{~~~~~~~~~~~~~~~~~~~~~~r~~~~~~~~~~~~~~~~~~~}&\quad random~r,get~t=t(r)\\ &h=h(r),p=p(r)&\xrightarrow{~~~~~~~~~~~~~~~~~~~~h,f~~~~~~~~~~~~~~~~~}& \quad \text{Check } p= t\cdot h\\ \end{aligned} Proverh=h(r),p=p(r)                      r                                        h,f                  Verifierrandom r,get t=t(r)Check p=th

例子, p ( x ) = x 3 − 3 x 2 + 2 x , t ( x ) = ( x − 1 ) ( x − 2 ) , h ( x ) = x p(x)=x^3-3x^2+2x,t(x)=(x-1)(x-2),h(x)=x p(x)=x33x2+2x,t(x)=(x1)(x2),h(x)=x
P r o v e r V e r i f i e r ←                    r = 23                 r = 23 , g e t   t = t ( 23 ) = 462 h = h ( 23 ) = 23 , p = p ( 23 ) = 10626 →                      h , f                   Check  10626 = 462 ⋅ 23 \begin{aligned} &\quad\quad\quad\bold{Prover} &&\quad\quad\quad\bold{Verifier}\\ &&\xleftarrow{~~~~~~~~~~~~~~~~~~r=23~~~~~~~~~~~~~~~}&\quad r=23,get~t=t(23)=462\\ &h=h(23)=23\\&,p=p(23)=10626&\xrightarrow{~~~~~~~~~~~~~~~~~~~~h,f~~~~~~~~~~~~~~~~~}& \quad \text{Check } 10626=462 \cdot 23\\ \end{aligned} Proverh=h(23)=23,p=p(23)=10626                  r=23                                    h,f                  Verifierr=23,get t=t(23)=462Check 10626=46223

考虑如果 t ( x ) t(x) t(x)不是 p ( x ) p(x) p(x)的根的情况, p ( x ) = 2 x 3 − 3 x 2 + 2 x , t ( x ) = ( x − 1 ) ( x − 2 ) , h ( x ) = 2 x + 3 + 7 x − 6 t ( x ) p(x)=2x^3-3x^2+2x,t(x)=(x-1)(x-2),h(x)=2x+3+\frac{7x-6}{t(x)} p(x)=2x33x2+2x,t(x)=(x1)(x2),h(x)=2x+3+t(x)7x6

P r o v e r V e r i f i e r ←                    r = 23                 r = 23 , g e t   t = t ( 23 ) = h = h ( 23 ) = 49.33 , p = p ( 23 ) = 22793 →                      h , f                   Failed since h is not Integer \begin{aligned} &\quad\quad\quad\bold{Prover} &&\quad\quad\quad\bold{Verifier}\\ &&\xleftarrow{~~~~~~~~~~~~~~~~~~r=23~~~~~~~~~~~~~~~}&\quad r=23,get~t=t(23)=\\ &h=h(23)=49.33\\&,p=p(23)=22793&\xrightarrow{~~~~~~~~~~~~~~~~~~~~h,f~~~~~~~~~~~~~~~~~}& \quad \text{Failed since h is not Integer}\\ \end{aligned} Proverh=h(23)=49.33,p=p(23)=22793                  r=23                                    h,f                  Verifierr=23,get t=t(23)=Failed since h is not Integer

注意:当上述的方案限制很大,首先多项式得是整数系数的,要不然无法通过是否是小数来判断,其次Prover也必须是按照协议执行,否则:

  1. Prover直接用 r r r算出 t = t ( r ) t=t(r) t=t(r),并根据 t t t来找两个数 p ′ = t ⋅ h ′ p'=t \cdot h' p=th,而不是通过多项式计算出 p = p ( r ) , h = h ( r ) p=p(r),h=h(r) p=p(r),h=h(r)
  2. 这样的方案对于 p ( x ) p(x) p(x)的次数没有限制,如果Prover直接取一个高次的多项式,那么 t ( x ) t(x) t(x)是这个高次多项式的因子的概率就很高。

通过混淆的计算来优化上述多项式证明

上面的问题1的来源是Prover知道 r r r t ( r ) t(r) t(r)的值,所以可以根据他们来构造 p , h p,h p,h,那如果有一个方法使得Prover只能把 r r r当做黑盒来使用,没办法得知 r r r的值就能解决问题1了。

使用具有同态性质的加密方法

在这里使用一个简化的同态加密,即 E ( v ) = g v   m o d   p E(v)=g^v \bmod p E(v)=gvmodp,其中 g g g是素数 p p p的一个生成元, v v v是要加密的数。
那这个加密满足:
E ( v 1 ) ⋅ E ( v 2 ) = g v 1 ⋅ g v 2 = g v 1 + v 2   m o d   p = E ( v 1 + v 2 ) E ( v ) 2 = ( g v ) 2 = g 2 v   m o d   p = E ( 2 v ) E(v_1)\cdot E(v_2)=g^{v_1} \cdot g^{v_2} =g^{v_1+v_2} \bmod p=E(v_1+v_2)\\ E(v)^2=(g^v)^2=g^{2v}\bmod p=E(2v) E(v1)E(v2)=gv1gv2=gv1+v2modp=E(v1+v2)E(v)2=(gv)2=g2vmodp=E(2v)
可以看到这样的加密可以进行密文之间同态的加法,以及密文和明文的乘法。

可能有人注意到了,这个加密方案是没办法解密的

计算一个加密的多项式值

那么如果Verifier使用加密了 E ( r ) E(r) E(r)然后发送给Prover,Prover要如何计算 E ( p ( r ) ) E(p(r)) E(p(r))呢?

假设 p ( x ) = x 3 − 3 x 2 + 2 x p(x)=x^3-3x^2+2x p(x)=x33x2+2x是一个三次的多项式,那么Verifier就发送 E ( r 3 ) , E ( r 2 ) , E ( r ) E(r^3),E(r^2),E(r) E(r3),E(r2),E(r)给Prover,然后Prover计算:
E ( r 3 ) 1 ⋅ E ( x 2 ) − 3 ⋅ E ( x ) 2 = ( g r 3 ) 1 ⋅ ( g r 2 ) − 3 ⋅ ( g r ) 2 = g r 3 ⋅ g − 3 r 2 ⋅ g 2 r = g r 3 − 3 r 2 + 2 r = E ( p ( r ) ) E(r^3)^1\cdot E(x^2)^{-3}\cdot E(x)^2\\ =(g^{r^3})^1 \cdot (g^{r^2})^{-3}\cdot (g^r)^2\\ =g^{r^3}\cdot g^{-3r^2}\cdot g^{2r}\\ =g^{r^3-3r^2+2r}=E(p(r))\\ E(r3)1E(x2)3E(x)2=(gr3)1(gr2)3(gr)2=gr3g3r2g2r=gr33r2+2r=E(p(r))

那么通过混淆方法构造的证明过程如下:
:因为之前 r r r是随机数(random),而现在是一个秘密值(secret),所以这里用 s s s符号来代替 r r r

Prover要向Verifier证明 p ( x ) p(x) p(x)是一个 d d d次多项式,且 p ( x ) = t ( x ) ⋅ h ( x ) p(x)=t(x)\cdot h(x) p(x)=t(x)h(x)

p ( x ) = c 0 + c 1 x + c 2 x 2 + . . . + c d x d p(x)=c_0+c_1x+c_2x^2+...+c_dx^d p(x)=c0+c1x+c2x2+...+cdxd
P r o v e r V e r i f i e r r a n d o m   s , g e t   t = t ( s ) ←          { E ( s 0 ) . . . E ( s d ) }        E ( s i ) = g s i , i ∈ [ d ] Get  E ( p ( s ) ) , E ( h ( s ) ) →               E ( p ) , E ( h )             Check  E ( p ) = E ( h ) t \begin{aligned} &\quad\quad\quad\bold{Prover} &&\quad\quad\quad\bold{Verifier}\\ &&&\quad random~s,get~t=t(s)\\ &&\xleftarrow{~~~~~~~~\{E(s^0)...E(s^d)\}~~~~~~}&\quad E(s^i)=g^{s^i},i \in [d]\\ &\text{Get } E(p(s)),E(h(s)) &\xrightarrow{~~~~~~~~~~~~~E(p),E(h)~~~~~~~~~~~}& \quad \text{Check } E(p)=E(h)^{t}\\ \end{aligned} ProverGet E(p(s)),E(h(s))        {E(s0)...E(sd)}                    E(p),E(h)            Verifierrandom s,get t=t(s)E(si)=gsi,i[d]Check E(p)=E(h)t

Verifier最后的验证就相当于是在指数上做了 p = t ⋅ h p=t\cdot h p=th的验证,因为:
E ( p ) = E ( h ) t g p = ( g h ) t g p = g t h \begin{aligned} E(p)&=E(h)^t\\ g^p &= (g^{h})^t\\ g^p &=g^{th} \end{aligned} E(p)gpgp=E(h)t=(gh)t=gth

虽然这里Prover并不能知道 s s s的值,所以没办法根据 s s s来构造结果。但还是没有对于Prover进行约束,也就是说,Prover仍然可以用其他方式来给出 z p , z h z_p,z_h zp,zh使得 z p = ( z h ) t z_p = (z^h)^t zp=(zh)t,而不是使用 E ( s i ) E(s^i) E(si)来算出 z p = E ( p ( s ) ) , z h = E ( h ( s ) ) z_p=E(p(s)),z_h=E(h(s)) zp=E(p(s)),zh=E(h(s))

对多项式的运算进行承诺

所以需要Prover能给出一个证明,就是他给出的 z p z_p zp z h z_h zh确实是用 E ( s i ) E(s^i) E(si)算出来的,而不是通过别的手段伪造出来的。这里就用到了一种类似于同态消息认证码的方法:

比如Alice和Bob进行交互,Alice拥有数据 a a a,发送 a a a给Bob,Bob返回 b = a c b=a^c b=ac,Alice希望Bob返回的数据是 a a a的某个幂次,而不是别的东西,就可以通过加上一个承诺 α \alpha α来做,具体交互过程如下:

B o b A l i c e α ∈ [ 1 , n ] ←                   a , a ′                     a ′ = a α   m o d   n b = a c   m o d   n , b ′ = ( a ′ ) c   m o d   n →                     b , b ′                   Check  b ′ = b α   m o d   n \begin{aligned} &\quad\quad\quad\bold{Bob} &&\quad\quad\quad\bold{Alice}\\ &&&\quad \alpha \in [1,n]\\ &&\xleftarrow{~~~~~~~~~~~~~~~~~a,a'~~~~~~~~~~~~~~~~~~~}&\quad a' = a^\alpha \bmod n\\ &b = a^c \bmod n,\\ &b' = (a')^c \bmod n&\xrightarrow{~~~~~~~~~~~~~~~~~~~b,b'~~~~~~~~~~~~~~~~~}& \quad \text{Check } b' = b^{\alpha} \bmod n\\ \end{aligned} Bobb=acmodn,b=(a)cmodn                 a,a                                       b,b                  Aliceα[1,n]a=aαmodnCheck b=bαmodn

根据离散对数难题,Bob就算得到了 a , a α a,a^\alpha a,aα,也无法计算出 α \alpha α,因此没办法随便给出一个 b b b,然后计算 b ′ = b α b' = b^\alpha b=bα这样来伪造。

那可以使用类似的方法来保证在多项式的证明中Prover是使用 p ( x ) , h ( x ) p(x),h(x) p(x),h(x)计算出结果,而不是使用其他的方法来返回 z p , z h z_p,z_h zp,zh的值。

加上消息认证后的方法如下:

Prover要向Verifier证明 p ( x ) p(x) p(x)是一个 n n n次多项式,且 p ( x ) = t ( x ) ⋅ h ( x ) p(x)=t(x)\cdot h(x) p(x)=t(x)h(x)

p ( x ) = c 0 + c 1 x + c 2 x 2 + . . . + c d x d p(x)=c_0+c_1x+c_2x^2+...+c_dx^d p(x)=c0+c1x+c2x2+...+cdxd

P r o v e r V e r i f i e r r a n d o m   s , g e t   t = t ( s ) ←          { E ( s 0 ) . . . E ( s d ) }        E ( s i ) = g s i , i ∈ [ d ] ←       { E ( α s 0 ) . . . E ( α s d ) }      E ( α s i ) = ( g s i ) α , i ∈ [ d ] E ( p ( s ) ) = ∏ i ∈ [ d ] E ( s i ) c i →                  E ( p ( s ) )               E ( p ( α s ) ) = ∏ i ∈ [ d ] E ( α s i ) c i →                 E ( p ( α s ) )              Same for  E ( h ( s ) ) →                  E ( h ( s ) )                Check  E ( p ( s ) ) = E ( h ( s ) ) t E ( p ( α s ) ) = E ( p ( s ) ) α \begin{aligned} &\quad\quad\quad\bold{Prover} &&\quad\quad\quad\bold{Verifier}\\ &&&\quad random~s,get~t=t(s)\\ &&\xleftarrow{~~~~~~~~\{E(s^0)...E(s^d)\}~~~~~~}&\quad E(s^i)=g^{s^i},i \in [d]\\ &&\xleftarrow{~~~~~\{E(\alpha s^0)...E(\alpha s^d)\}~~~~}&\quad E(\alpha s^i)=(g^{ s^i})^{\alpha},i \in [d]\\ &E(p(s))=\prod_{i \in [d]} E(s^i)^{c_i} &\xrightarrow{~~~~~~~~~~~~~~~~E(p(s))~~~~~~~~~~~~~}& \quad \\ &E(p(\alpha s))=\prod_{i \in [d]} E(\alpha s^i)^{c_i} &\xrightarrow{~~~~~~~~~~~~~~~E(p(\alpha s))~~~~~~~~~~~~}& \quad \\ &\text{Same for }E(h(s)) &\xrightarrow{~~~~~~~~~~~~~~~~E(h(s))~~~~~~~~~~~~~~}& \quad \text{Check }E(p(s))= E(h(s))^t\\ &&& \quad E(p(\alpha s)) = E(p(s))^\alpha \end{aligned} ProverE(p(s))=i[d]E(si)ciE(p(αs))=i[d]E(αsi)ciSame for E(h(s))        {E(s0)...E(sd)}            {E(αs0)...E(αsd)}                     E(p(s))                             E(p(αs))                             E(h(s))               Verifierrandom s,get t=t(s)E(si)=gsi,i[d]E(αsi)=(gsi)α,i[d]Check E(p(s))=E(h(s))tE(p(αs))=E(p(s))α
这样下来就能保证Prover按照协议执行,而不是用其他方式取两个值返回。但零知识性质无法保证,Verifier可以通过穷举的方式来试验出 p ( x ) p(x) p(x)的系数,因为系数的取值范围往往比较小,且最高次数已经确定,因此这样的攻击是可能的。具体来说,Verifier选择 p ′ ( x ) p'(x) p(x),计算 p ′ ( s ) = p ′ p'(s)=p' p(s)=p,看一下 g p ′ g^{p'} gp与Prover发过来的 g p g^{p} gp是否相等,如果相等的话,就可能是找到了p’(x)=p(x)。

如何做到零知识性

其实和之前的做承诺的方法类似,使用承诺的方法里面Verifier发送了 g s i g^{s^i} gsi以及 g α s i g^{\alpha s^i} gαsi,通过离散对数难题的假设来保证Prover无法得到 α \alpha α。类似的,Prover在最后返回的时候,可以不选择返回 E ( p ( s ) ) = g p , E ( p ( α s ) ) = g α p E(p(s))=g^{p},E(p(\alpha s))=g^{\alpha p} E(p(s))=gp,E(p(αs))=gαp,而是在外面再套一个 δ \delta δ,返回 g δ p , g δ α p , g δ h , g δ α h g^{\delta p},g^{\delta \alpha p},g^{\delta h},g^{\delta \alpha h} gδp,gδαp,gδh,gδαh。由于返回的是 g δ p g^{\delta p} gδp,Verifier通过穷举只能得到 p ′ p' p使得 g p ′ = g δ p g^{p'}=g^{\delta p} gp=gδp。而根据离散对数难题, δ \delta δ是Verifier不可知的。

那协议就变为了:

Prover要向Verifier证明 p ( x ) p(x) p(x)是一个 n n n次多项式,且 p ( x ) = t ( x ) ⋅ h ( x ) p(x)=t(x)\cdot h(x) p(x)=t(x)h(x)

p ( x ) = c 0 + c 1 x + c 2 x 2 + . . . + c d x d p(x)=c_0+c_1x+c_2x^2+...+c_dx^d p(x)=c0+c1x+c2x2+...+cdxd

P r o v e r V e r i f i e r r a n d o m   s , g e t   t = t ( s ) ←          { E ( s 0 ) . . . E ( s d ) }        E ( s i ) = g s i , i ∈ [ d ] ←       { E ( α s 0 ) . . . E ( α s d ) }      E ( α s i ) = ( g s i ) α , i ∈ [ d ] E ( p ( s ) ) = ∏ i ∈ [ d ] E ( s i ) c i = g p g δ p = ( g p ) δ →                      g δ p                   E ( p ( α s ) ) = ∏ i ∈ [ d ] E ( α s i ) c i g δ α p = E ( p ( α s ) ) δ →                ⋅       g δ α p                 Same for  h →                      g δ h                   Check  g δ p = ( g δ h ) t g δ α p = ( g δ p ) α \begin{aligned} &\quad\quad\quad\bold{Prover} &&\quad\quad\quad\bold{Verifier}\\ &&&\quad random~s,get~t=t(s)\\ &&\xleftarrow{~~~~~~~~\{E(s^0)...E(s^d)\}~~~~~~}&\quad E(s^i)=g^{s^i},i \in [d]\\ &&\xleftarrow{~~~~~\{E(\alpha s^0)...E(\alpha s^d)\}~~~~}&\quad E(\alpha s^i)=(g^{ s^i})^{\alpha},i \in [d]\\ &E(p(s))=\prod_{i \in [d]} E(s^i)^{c_i}=g^{p}\\&g^{\delta p} = (g^{p})^\delta &\xrightarrow{~~~~~~~~~~~~~~~~~~~~g^{\delta p}~~~~~~~~~~~~~~~~~}& \quad \\ &E(p(\alpha s))=\prod_{i \in [d]} E(\alpha s^i)^{c_i}\\ &g^{\delta \alpha p}=E(p(\alpha s))^\delta &\xrightarrow{~~~~~~~~~~~~~~·~~~~~g^{\delta \alpha p}~~~~~~~~~~~~~~~}& \quad \\ &\text{Same for } h &\xrightarrow{~~~~~~~~~~~~~~~~~~~~g^{\delta h}~~~~~~~~~~~~~~~~~}& \quad \text{Check } g^{\delta p}= (g^{\delta h})^t\\ &&& \quad g^{\delta \alpha p}= (g^{\delta p})^{\alpha}\\ \end{aligned} ProverE(p(s))=i[d]E(si)ci=gpgδp=(gp)δE(p(αs))=i[d]E(αsi)cigδαp=E(p(αs))δSame for h        {E(s0)...E(sd)}            {E(αs0)...E(αsd)}                         gδp                                     gδαp                                    gδh                  Verifierrandom s,get t=t(s)E(si)=gsi,i[d]E(αsi)=(gsi)α,i[d]Check gδp=(gδh)tgδαp=(gδp)α

这样构造的方案满足零知识性质,而且相比之前的方法,基本上没有额外的开销,所以这种构造方法叫做"free" zero-knowledge

如何构造一个非交互的方案

上面的方案是一个交互式的零知识证明方案,因为除了和Prover交互的Verifier,其他人看到他们之间的交互脚本,并不能相信Prover确实有用 p ( x ) p(x) p(x)的知识。因为Prover和Verifier完全可以合谋,比如Verifer直接将 α , s \alpha,s α,s告诉Prover。

所以要向其他人证明的时候,Prover和那个人之间要再跑一次上述的零知识证明协议,那效率就太差了。

而且呢,Verifier在协议执行过程中,要保留 t t t α \alpha α,最后用来做验证,那就可能会导致潜在的信息泄露。

建立 CRS

假如有一个可信的第三方,随机选取了 α , s \alpha,s α,s,计算并公开了 g α , g s i , g α s i g^\alpha,g^{s^i},g^{\alpha s^i} gα,gsi,gαsi,然后删除 α , s \alpha,s α,s,那么这些 { g α , g s i , g α s i } i ∈ [ d ] \{g^{\alpha},g^{s^i},g^{\alpha s^i}\}_{i\in [d]} {gα,gsi,gαsi}i[d]就是CRS。

双线性配对

这里要引入基于椭圆曲线的双线性配对。 g g g是椭圆曲线的一个生成元, g a g^a ga表示 a a a g g g相加。双线性配对指一个映射, e ( g ∗ , g ∗ ) e(g^*,g^*) e(g,g),满足 e ( g a , g b ) = e ( g , g ) a b e(g^a,g^b)=e(g,g)^{ab} e(ga,gb)=e(g,g)ab

注意到使用双线性配对的一个优势:在原来Verifer要存储 α \alpha α,最后验证的时候计算 g α p = ( g p ) α g^{\alpha p}=(g^{p})^{\alpha} gαp=(gp)α。这会带来严重的信息泄露问题以及不信任的问题。而使用椭圆曲线之后,就不需要存储 α \alpha α,只需要存 g α g^{\alpha} gα,最后的验证变成了 e ( g p , g α ) = e ( g p α , g ) e(g^{p},g^{\alpha})=e(g^{p\alpha},g) e(gp,gα)=e(gpα,g)

通过双线性配对建立CRS

假设存在一个可信的参与方,让他挑选 s s s α \alpha α,然后计算出 ( g α , g s i , g α s i ) i ∈ [ d ] (g^{\alpha},g^{s^i},g^{\alpha s^i})_{i \in [d]} (gα,gsi,gαsi)i[d]之后把 s s s α \alpha α删除。这个可信的参与方就广播他计算出的 ( g α , g s i , g α s i ) i ∈ [ d ] (g^{\alpha},g^{s^i},g^{\alpha s^i})_{i \in [d]} (gα,gsi,gαsi)i[d]

在优化后的证明的情况下,会把 g t ( s ) g^{t(s)} gt(s)也作为CRS的一部分存起来,可以在验证的时候少计算一些东西。所以现在的CRS是可以分为两部分:

  1. Proving Key: ( g s i , g α s i ) i ∈ [ d ] (g^{s^i},g^{\alpha s^i})_{i \in [d]} (gsi,gαsi)i[d]
  2. Verification Key: ( g t ( s ) , g α ) (g^{t(s)},g^{\alpha}) (gt(s),gα)

通过CRS构造一个非交互的协议

这里的非交互的协议并不是指Prover和Verifier没有互动,而是指Prover生成一次证明之后,可以广播这个证明,那所有的Verfier都可以相信这个证明。交互式的协议指的是,每有一个Verifer,Prover都需要重新执行一遍协议来使这个Verifier相信这个证明。

我们通过CRS构造出来的零知识证明协议如下:

  • 初始化阶段:
    • 一个可信第三方生成一些CRS,其中包含了:
    • Proving Key: { g s i , g α s i } i ∈ [ d ] \{g^{s^i},g^{\alpha s^i}\}_{i \in [d]} {gsi,gαsi}i[d]
    • Verification Key: ( g t ( s ) , g α ) (g^{t(s)},g^{\alpha}) (gt(s),gα)
  • 证明阶段:
    • Prover使用 { g s i } i ∈ [ d ] \{g^{s^i}\}_{i \in [d]} {gsi}i[d]来计算出 g p ( s ) , g h ( s ) g^{p(s)},g^{h(s)} gp(s),gh(s).
    • 通过 { g α s i } i ∈ [ d ] \{g^{\alpha s^i}\}_{i \in [d]} {gαsi}i[d]来计算出 g α p ( s ) g^{\alpha p(s)} gαp(s).
    • 随机选取 δ \delta δ,并广播 π = ( g δ p ( s ) , g δ h ( s ) , g δ α p ( s ) ) \pi = (g^{\delta p(s)},g^{\delta h(s)},g^{\delta \alpha p(s)}) π=(gδp(s),gδh(s),gδαp(s)).
  • 验证阶段
    • Verifier记 π = ( g p , g h , g p ′ ) \pi = (g^p,g^h,g^{p'}) π=(gp,gh,gp).
    • 验证 e ( g p ′ , g ) = e ( g p , g α ) e(g^{p'},g)=e(g^p,g^{\alpha}) e(gp,g)=e(gp,gα).
    • 验证 e ( g p , g ) = e ( g t ( s ) , g h ) e(g^p,g)=e(g^{t(s)},g^h) e(gp,g)=e(gt(s),gh).

到次为止我们已经构造出了一个对于多项式的非交互式零知识证明方案,但还需要补充一些细节。下面的章节可以略过,可以直接看通用的零知识证明部分。

多方共同生成CRS

待补充…

通用的零知识证明

待补充…

GGPR13

待补充…

Groth16

待补充…

你可能感兴趣的:(零知识证明,阅读笔记,密码学,零知识证明,区块链,SNARK,以太坊,可信计算)