引言:在之前的文章里,我介绍了利用circom和snarkjs实现zkSNARK零知识证明,包含了snarkjs的使用步骤,并且我的毕业论文也全部采用snarkjs实现zkSNARK算法。

不过snarkjs里的signal信号的概念和高级语言变量之间的差别有点大,很多运算操作都不能直接进行,而且在执行circom库里的SHA256哈希算法时需要调整powersOfTau可信设置(snarkjs ptn bn128 10 powersOfTau10_0000.ptau,修改10为更大值),只能采用snark友好的MiMC哈希算法。于是我开始探索其他zkSNARK工具。

有些报告指出,snarkjs、libsnark和ZoKrates号称三大最常用的zkSNARKs零知识开发库。经过测试发现ZoKrates在编写代码的过程中更接近高级语言,算术电路的输入输出都是以变量的形式,天然支持comparator数值比较,更易实现零知识范围证明(Zero-Knowledge Range Proof,ZKRP),而且ZoKrates支持log输出利于debug。此外,ZoKrates实现了Remix插件,也就可以在线运行zkSNARK算术电路,特此记录下ZoKrates+Remix在线实现zkSNARK零知识证明的步骤。

ZoKrates是以太坊上zkSNARKs的工具箱。它可以帮助您在DApp中使用可验证的计算,从高级语言的程序规范到生成计算证明,再到在Solidity中验证这些证明。(ZoKrates官网介绍)

Remix官网:https://remix.ethereum.org/

1.安装插件

点击左下角的插件按钮,找到ZOKRATES插件,点击Activate激活插件:

2.编写zkSNARK算术电路

新建文件命名为main.zok,输入如下代码:

def main(private u8 p, private u8 q, u8 n) -> bool {return p * q == n;}

2.1代码解释

两个隐私输入p和q、一个公开输入n,u8代表8位无符号整型,返回bool类型。

根据“大整数质因子分解”是NP困难问题(Nondeterministic polynomial-time,非确定性多项式时间),给定两个素数p和q,他们的乘积是n,但是如果只提供这个数字n,找出n的两个素因子是困难的。

根据这个难题,利用zkSNARK向外界证明自己“知道n的两个素因子”,但是不向外界泄露p和q的真实值。因此,zkSNARK的隐私输入是p和q、公开输入是n、算术电路是p*q==n。

2.2在线测试

ZoKrates提供了在线编译算术电路的测试环境,进入官网https://play.zokrat.es:

3.编译与测试

进入ZOKRATES插件,点击compile编译:

输入错误样例进行测试,p=3、q=7、n=22,输出是false:

输入正确样例进行测试,p=3、q=7、n=21,输出是true:

4.初始化密钥verification_key.json

点击Run Setup进行初始化,得到verification_key.json作为验证密钥:

5.生成证明proof.json

点击Generate,生成proof.json:

复制Verifier inputs备用:

[[“0x1dc9038012cef119c740a52bffc3280d6ed125bbd9bfc474bcca78dd982a901d”,”0x0fa4945211306b5d0a50bbc80e5def88fe1224b927fcace75d725384d31755f9″],[[“0x15ae9c563fcfcb4cdf74780bbefd44bd54e6be9222170bd907bd962f0928c103″,”0x27ad25d6aa4089fd27622e8f17524b3bb05ffa67d2c099a1f880d69357a0b168”],[“0x297ea2971f2296ba60e9e4fe3b9535455e9130e14a0c973f584deec0437448d2″,”0x05484d4637c39f5b7eadf920686d3290f4f5dfeae3ae7d486a9f753521cc12c5”]],[“0x0760832bd07407205278074a131c8e67de0e90f8e45f6ac43c083ffa44873b34″,”0x014b52710266031a08b23d556f0ca1c64b4b579db8f6e0c4720ffe649bbd3bf9”]],[“0x0000000000000000000000000000000000000000000000000000000000000015″,”0x0000000000000000000000000000000000000000000000000000000000000001”]

0x0000000000000000000000000000000000000000000000000000000000000015对应十进制的21,就是zkSNARK的公开输入n。

6.导出验证合约verifier.sol

点击Export,生成verifier.sol智能合约:

7.编译并部署验证合约verifier.sol

点击Compile verifier.sol编译:

选择verifier.sol,点击Deploy部署:

8.运行验证合约

在Deployed Contracts里选择VERIFIER,在verifyTX函数的输入框里填写刚才复制备用的Verifier inputs,点击verifyTX。

右下角log出现了函数执行结果,input是21,输出true:

将verifyTX的input里的21改成22,即十六进制0x0000000000000000000000000000000000000000000000000000000000000016,再测试一下,输出false:

9.结语

至此便实现了大整数质因子分解的零知识证明,p和q是隐私输入,仅在生成证明的过程由证明者知道,n是公开输入,可以输入到公开的智能合约,智能合约自动验证零知识证明的有效性,并且修改n之后能检测出零知识证明已失效。

ZoKrates也有离线的命令行版本,结合Remix在线自动部署与运行较为方便,适合部署前测试。