zkSnarks:证明问题到QAP的转换

许多待证明的问题可以表示为多项式函数的形式,而一个多项式函数可以转化为一个算术电路,已经有文献证明算术电路可以转换成QAP问题,基于QAP问题可以构造zkSNARKs,所以基于QAP问题构造zkSNARKs的第一步是将待证明问题转换成QAP问题,本文主要讲解如何将待证明问题转换成QAP问题。

QAP定义:

给一系列多项式以及一个目标多项式,是否能根据这一系列的多项式,求得它们的一个线性组合,刚好可以整除目标多项式,如下描述,给定一个解 { a i } i = 0 − > n \{a_i\}_{i=0->n} {ai}i=0>n,那么验证很简单,直接除t(x)即可,但是想求解就很难:

  • 给定一系列多项式 { l i ( x ) , r i ( x ) , o i ( x ) } i = 0 − > n \{l_i(x),r_i(x),o_i(x)\}_{i=0->n} {li(x),ri(x),oi(x)}i=0>n ,以及目标 t ( x ) t(x) t(x)

  • 求一个线性组合 { a i } i = 0 − > n \{a_i\}_{i=0->n} {ai}i=0>n,使得:
    ∑ i = 0 n { ( a i ∗ l i ( x ) ) ( a i ∗ r i ( x ) ) − ( a i ∗ o i ( x ) ) } = t ( x ) h ( x ) \sum_{i=0}^{n}\{(a_i*l_i(x))(a_i*r_i(x))-(a_i*o_i(x))\}=t(x)h(x) i=0n{(aili(x))(airi(x))(aioi(x))}=t(x)h(x)

下面以 a*(b+2) = c 为例,讲解QAP的构造过程

1.多项式拍成电路,首先将多项式的所有操作转化为算术电路形式,即 x ( o p ) y = z x(op)y =z x(op)y=z,根据算术电路可以画出相应的电路图

sum1 = b + 2
c = a * sum1

在这里插入图片描述

2.电路转换成R1CS,R1CS描述了向量组之间的约束关系,把算术电路变量包括中间变量组成一组向量 :s = [one,c,a,b,sum1]T,s即为R1CS中的解向量,其中one表示数字1,对上面的电路进行转换:

(b+2) * 1 = sum1

x = [2 0 0 1 0]
y = [1 0 0 0 0]
z = [0 0 0 0 1]

a * sum1 = c

x = [0 0 1 0 0]
y = [0 0 0 0 1]
z = [0 1 0 0 0]

由上可得X 、Y 、Z向量
在这里插入图片描述

3.R1CS to QAP,我们已经得到X 、Y 、Z向量,满足:
X ⋅ S ∗ Y ⋅ S − Z ⋅ S = 0 X\cdot S*Y\cdot S - Z\cdot S =0 XSYSZS=0
代入如x=1、2 ,即t(x) =(x-1)(x-2)由拉格朗日差值定理可以计算出 li(x),ri(x),oi(x)

在这里插入图片描述

​ 由(1,2) (2,0) 得 l0(x) = 4 - 2x , 取有限域GF(11)上的多项式计算,则l0(x) = 4 + 9x,下同

​ 由(1,0) (2,0) 得 l1(x) = 0

​ 由(1,0) (2,1) 得 l2(x) = 10 +x

​ 由(1,1) (2,0) 得 l3(x) = 2 + 10x

​ 由(1,0) (2,0) 得 l4(x) = 0

—————————————

​ 由(1,1) (2,0) 得 r0(x) = 2 + 10x

​ 由(1,0) (2,0) 得 r1(x) = 0

​ 由(1,0) (2,0) 得 r2(x) = 0

​ 由(1,0) (2,0) 得 r3(x) = 0

​ 由(1,0) (2,1) 得 r4(x) = 10 + x

—————————————

​ 由(1,0) (2,0) 得 o0(x) = 0

​ 由(1,0) (2,1) 得 o1(x) = 10 +x

​ 由(1,0) (2,0) 得 o2(x) = 0

​ 由(1,0) (2,0) 得 o3(x) = 0

​ 由(1,1) (2,0) 得 o1(x) = 2 + 10x
—————————————

​ 由上可得li(x)、ri(x)、oi(x)

在这里插入图片描述

下面进行验证:

a*(b+2) = c,取 a = 3 、b=2 ,得sum1=4、c=12

s = [1,12, 3,2,4],t(x) = (x-1)(x-2) = 2 + 8x + x2

L(x) = 5 +10x ,R(x) = 9 + 3x , O(x) = 7+ 8x

P(x) = L(x)R(X) - O(x) = 5 + 9x + 8x2

h(x) = P(x)/t(x) = 8


Coding 验证

package main

import (
	"fmt"
	"github.com/arnaucube/go-snark/circuitcompiler"
	"github.com/arnaucube/go-snark/fields"
	"github.com/arnaucube/go-snark/r1csqap"
	"math/big"
	"strings"
)

func main() {
	str := `
       func main(private a, private b,public c):
		 s1 = b + 2
		 c = a * s1
    `

	fmt.Printf("code of the circuit: %s\n", str)
	parser := circuitcompiler.NewParser(strings.NewReader(str))
	circuit, _ := parser.Parse()

	fmt.Println("\ncode to R1CS")
	a, b, c := circuit.GenerateR1CS()
	fmt.Printf("a: %s\n", a)
	fmt.Printf("b: %s\n", b)
	fmt.Printf("c: %d\n\n", c)

	fmt.Println("\nR1CS to QAP")
	r, _ := new(big.Int).SetString("11", 10)
	pf := r1csqap.NewPolynomialField(fields.NewFq(r))
	alphas, betas, gammas, _ := pf.R1CSToQAP(a, b, c)

	fmt.Printf("As: %d\n\n", alphas)
	fmt.Printf("Bs: %d\n\n", betas)
	fmt.Printf("Cs: %d\n\n", gammas)

	// witness
	privateVal := []*big.Int{big.NewInt(int64(3)), big.NewInt(int64(2))}
	publicVal := []*big.Int{big.NewInt(int64(12))}
	w, _ := circuit.CalculateWitness(privateVal, publicVal)
	fmt.Println("\nWitness: ", w)

	ax, bx, cx, px := pf.CombinePolynomials(w, alphas, betas, gammas)
	fmt.Printf("\nax: %d\n", ax)
	fmt.Printf("\nbx: %d\n", bx)
	fmt.Printf("\ncx: %d\n", cx)
	fmt.Printf("\npx: %d\n", px)
}

在这里插入图片描述


why R1CS -> QAP ?

  上述构造过程中需要将R1CS约束转换成QAP问题,但是 why R1CS -> QAP ?

  我们知道R1CS约束矩阵是一个m行矩阵,m代表电路中门电路的数量,如前面例子中,下面三个矩阵就是原问题对应电路的R1CS约束矩阵,每个矩阵包含了两个行向量,代表了电路中的两个电路门
在这里插入图片描述
  此时如果我们想证明我们知道原始计算的一个解,那么就需要证明X,Y,Z矩阵中的每个行向量与解向量S的内积之后的值是符合R1CS约束的:
在这里插入图片描述
  在大规模电路下,存在成千上万个电路门,R1CS验证效率会十分低下,于是我们把向量的内积计算转化为多项式的形式,多项式具有良好的性质,可以通过一次计算来验证所有约束的正确性,比如 prover 声称他知道一些 verifier 也知道的多项式,通过一次抽样验证就行

  对于约束矩阵X,我们假设存在这样一个多项式l1(x) ,经过点(1,2)、(2,0), 通过拉格朗日插值定理 ,可以计算出

           l 1 ( x ) = 4 + 9 x l_1(x) = 4+9x l1(x)=4+9x

  同理我们可以得到 l i ( x ) 、 r i ( x ) 、 o i ( x ) l_i(x)、r_i(x)、o_i(x) li(x)ri(x)oi(x),然后可以用多项式去表示R1CS约束:

( 1 ∗ l 1 ( x ) + 12 ∗ l 2 ( x ) + 3 ∗ l 3 ( x ) + 2 ∗ l 4 ( x ) + 4 ∗ l 5 ( x ) ) (1*l_1(x) +12*l_2(x) +3*l_3(x)+2*l_4(x)+4*l_5(x)) (1l1(x)+12l2(x)+3l3(x)+2l4(x)+4l5(x))

∗ ( 1 ∗ r 1 ( x ) + 12 ∗ r 2 ( x ) + 3 ∗ r 3 ( x ) + 2 ∗ r 4 ( x ) + 4 ∗ r 5 ( x ) ) * (1*r_1(x) +12*r_2(x) +3*r_3(x)+2*r_4(x)+4*r_5(x)) (1r1(x)+12r2(x)+3r3(x)+2r4(x)+4r5(x))

− ( 1 ∗ o 1 ( x ) + 12 ∗ o 2 ( x ) + 3 ∗ o 3 ( x ) + 2 ∗ o 4 ( x ) + 4 ∗ o 5 ( x ) ) - (1*o_1(x) +12*o_2(x) +3*o_3(x)+2*o_4(x)+4*o_5(x)) (1o1(x)+12o2(x)+3o3(x)+2o4(x)+4o5(x))

= 0 = 0 =0

  令上式左边等于 p ( x ) p(x) p(x)

  当x=1时,即验证第一个门电路( p ( 1 ) = 0 p(1)=0 p(1)=0

  当x=2时,即验证第二个门电路 ( p ( 2 ) = 0 p(2)=0 p(2)=0 )

  根据多项式的因式分解:一个多项式只要它有解,就可以将它分解成线性多项式

  所以 p ( x ) p(x) p(x)可以 表示成 :
         p ( x ) = ( x − 1 ) ( x − 2 ) . . . = t ( x ) h ( x ) , t ( x ) = ( x − 1 ) ( x − 2 ) p(x) = (x-1)(x-2)... = t(x)h(x) ,t(x) = (x-1)(x-2) p(x)=(x1)(x2)...=t(x)h(x),t(x)=(x1)(x2)

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值