ZK-SNARKS | 创建第一个零知识snark电路

前言:本文我们使用两个公开库circom、snarkjs尝试构建一个简单的零知识证明。其中,circom库用于构建和编译代数电路,snarkjs库是zk-snarks协议的独立实现。本文使用的方法主要参考的是snarkjs库0.4.6官方教程(英文)和博文circom与snarkjs经典教程(中文)。感谢这两篇文献的作者。

另,github上面也给出了一个较为完整的英文版的tutorial,感兴趣的盆友可以点击链接​​​​​​​学习。

目录

准备:安装Node.js

1. 安装circom&snarkjs

2. 可信设置

3.  构建电路 

4. 生成groth16算法密钥 

5. 计算见证(witness)

6. 证明与验证


准备:安装Node.js

具体方法参考我的另一篇博文

1. 安装circom&snarkjs

在终端输入如下安装命令:

npm install -g circom
npm install -g snarkjs

在执行第二条命令时出现git报错:

  上网搜索发现可能原因是(1) ipv6,(2) 之前开了网络代理,git默认走代理通道,导致现在关掉代理之后用不了了。

方法1:在终端输入如下命令禁用ipv6:

networksetup -setv6off Wi-Fi

方法2: 首先查看git配置,在终端输入“git config --global --list ”,若发现返回内容中包含http.https或者https.https字样,说明设置了网络代理。输入如下命令撤掉代理即可:

git config --global --unset http.proxy
git config --global --unset https.proxy

我遇到的是问题(1),使用方法1解决了。

2. 可信设置

2.1 创建一个新文件夹,用于包含后续所有文件:

mkdir factor
cd factor

2.2 执行new命令:

snarkjs powersoftau new bn128 12 pot12_0000.ptau -v

* 解释:

[new]:用于开启一个新的 powers of tau ceremony (该叫法摘自snarkjs库0.4.6官方教程

[bn128]:选择bn128曲线(可选的还有bls12-381曲线,bn和bls的简介见后面“补充”部分)

[12]:规定了我们接下来要构建的电路的两个限制。限制1:电路中constraints(稍后会解释)的数量不能多于2^{12}= 4096个;限制2:电路中parameter的数量不能多于2^{28}\approx 268\times 10^{6}个。

* 效果:

此条命令会创建一个pot12_0000.ptau文件,执行命令后会打印以下字段:

 * 补充

参考博文zk-SNARK零知识证明曲线选择Electric Coin Co. 官网的相关内容,Barreto-Naehrig (BN) 和Barreto-Lynn-Scott (BLS)都是pairing-friendly椭圆曲线。不同之处在于,BN曲线若想要达到128-bit的安全性,需要q≈2384,相应的BN曲线的阶数r也会提高到2384量级,r值的增大会影响multi-exponentiation、FFT等运算性能,从而影响zk-SNARK以及安全多方计算的执行效率,同时也会影响key文件不必要的增大。 而对于BLS曲线,当q≈2384 且 embedding degree k=12时,具有128-bit的安全性,而相应的阶数r≈2256,远小于BN曲线的2384量级。

2.3 执行contribute命令

snarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau --name="First contribution" -v

* 解释:

[contribute] 该命令将上一步创建的pot12_0000.ptau文件作为输入,并输出一个新的ptau文件pot12_0001.ptau。ptau文件包含所有已经进行过的challenge和response计算。

[name] 这一字段内你可以任意填入一些内容。在后面执行验证(第6步)的时候这个内容会被打印出来。

* 效果:

执行此条命令,会被要求输入一些随机内容,输入后打印如下内容:

2.4 第二次contribute

snarkjs powersoftau contribute pot12_0001.ptau pot12_0002.ptau --name="Second contribution" -v -e="some random text"

* 解释:

此条命令与上一条功能相同,不同点在于,加入了[-e]命令,直接输入了一些随机值(上一步是交互式地输入随机值,这一步直接将随机值写入了命令中)。

* 效果:

2.5 第三次contribute(第三方contribute)

snarkjs powersoftau export challenge pot12_0002.ptau challenge_0003
snarkjs powersoftau challenge contribute bn128 challenge_0003 response_0003 -e="some random text"
snarkjs powersoftau import response pot12_0002.ptau response_0003 pot12_0003.ptau -n="Third contribution name"

 不太确定这步跟上两步的异同,但是执行完成后会生成pot12_0003.ptau文件:

2.6 验证

snarkjs powersoftau verify pot12_0003.ptau

如果验证通过,在打印信息的第一行会显示“[INFO] snarkJS: Powers Of tau file OK!” :

2.7 引入random beacon

snarkjs powersoftau beacon pot12_0003.ptau pot12_beacon.ptau 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 10 -n="Final Beacon"

 此条命令会生成一个pot12_beacon.ptau文件。

2.8 生成公开信息

snarkjs powersoftau prepare phase2 pot12_beacon.ptau pot12_final.ptau -v

* 解释:

[prepare phase2]:生成多项式在点\tau、点\alpha \cdot \tau、点\beta \cdot \tau的值的密文。

此命令将pot12_beacon.ptau文件作为输入,生成一个新文件pot12_final.ptau。

2.9 最终验证

snarkjs powersoftau verify pot12_final.ptau

* 解释:

在开始下一步(构建电路)之前,执行一个最终验证。

* 效果:

执行此条命令,部分打印信息如下:

3.  构建电路 

我们准备证明的问题是:我们知道数字a和b(秘密),它们相乘得到c(公开值)。

3.1 创建一个circom文件:

vim circuit.circom

文件内容如下:

1. template Multiplier() {
2.    signal private input a;
3.    signal private input b;
4.    signal output c;
5.    c <== a*b;
6. }
7. 
8. component main = Multiplier();

* 解释:

2-4行:这个电路有两个private输入信号,即a和b;有一个输出信号,即c。

第5行:输入和输出使用<==运算符进行关联。 在circom中,<==运算符做两件事。 首先是连接信号。 第二个是施加约束。在本例中,我们使用<==c连接到ab,同时将c约束为a * b的值,即电路做的事情是让强制信号 c 为 a*b的值。

第8行:在声明 Multiplier 模板之后, 我们使用名为main的组件实例化它。编译电路时,必须始终有一个名为main的组件。

(对第5行和第8行的解释摘自博文circom与snarkjs经典教程

3.2 编译电路

circom circuit.circom --r1cs --wasm --sym -v

3.3 用snarkjs查看编译后的电路

snarkjs r1cs info circuit.r1cs

获得如下输出:

3.4 打印constraints

snarkjs r1cs print circuit.r1cs circuit.sym

打印信息如下:

3.5 将电路输出成json格式

snarkjs r1cs export json circuit.r1cs circuit.r1cs.json
cat circuit.r1cs.json

执行这两条语句后会打印json字符串。

4. 生成groth16算法密钥 

** 步骤4.2--4.7类似于上文步骤2.3--2.7, 2.9

4.1 设置

snarkjs groth16 setup circuit.r1cs pot12_final.ptau circuit_0000.zkey

* 解释:

此命令生成zkey,即零知识证明密钥,包含证明密钥(proving key)和验证密钥(verification key)。每个电路都单独生成一个zkey,我们可以验证一个zkey是否属于某个电路。

Note that circuit_0000.zkey (the output of the zkey command above) does not include any contributions yet, so it cannot be used in a final circuit.

——摘自snarkjs库0.4.6官方教程

4.2 zkey Contribute

snarkjs zkey contribute circuit_0000.zkey circuit_0001.zkey --name="1st Contributor Name" -v

此命令会生成一个新的circuit_0001.zkey文件,里面包含了一个contribution。这一步会要求输入一些随机内容,如下:

4.3 第二次contribute

snarkjs zkey contribute circuit_0001.zkey circuit_0002.zkey --name="Second contribution Name" -v -e="Another random entropy"

4.4 第三次contribution(第三方contribute)

snarkjs zkey export bellman circuit_0002.zkey  challenge_phase2_0003
snarkjs zkey bellman contribute bn128 challenge_phase2_0003 response_phase2_0003 -e="some random text"
snarkjs zkey import bellman circuit_0002.zkey response_phase2_0003 circuit_0003.zkey -n="Third contribution name"

4.5 验证

snarkjs zkey verify circuit.r1cs pot12_final.ptau circuit_0003.zkey

4.6 引入random beacon

snarkjs zkey beacon circuit_0003.zkey circuit_final.zkey 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 10 -n="Final Beacon phase2"

4.7 验证最终zkey

snarkjs zkey verify circuit.r1cs pot12_final.ptau circuit_final.zkey

4.8 输出验证密钥

snarkjs zkey export verificationkey circuit_final.zkey verification_key.json

5. 计算见证(witness)

witness中包含与已知电路所有constraints相匹配的信号,可以理解为问题的答案。在我们的例子中,一个见证包含a、b、c。我们先生成witness,然后再用witness生成零知识证明。

5.1 创建input文件

创建一个json文件:

vim input.json

在json文件中写入如下内容并保存:

{"a": 3, "b": 11}

5.2 运行计算命令

snarkjs wtns calculate circuit.wasm input.json witness.wtns

5.3 检查witness计算有无错误

snarkjs wtns debug circuit.wasm input.json witness.wtns circuit.sym --trigger --get --set

* 效果:

此命令会打印我们输入的a、b以及相应的输出c:

6. 证明与验证

6.1 构建零知识证明

snarkjs groth16 prove circuit_final.zkey witness.wtns proof.json public.json

* 解释:

这一命令生成文件proof.json和public.json,前者包含证明,后者包含公开输入和公开输出。

* 注:

第5步(计算witness)和第6.1步(生成证明)可以合并为一条语句:

snarkjs groth16 fullprove input.json circuit.wasm circuit_final.zkey proof.json public.json

6.2 验证

snarkjs groth16 verify verification_key.json public.json proof.json

* 效果:

若验证成功将打印“OK!”:

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值