前言
最近因为工作需要研究了一下zk-Snark(非交互式零知识证明),写篇文章记录一下心得。下面是zk-snark的一些核心命令已经关键文件输出。
安装
本文主要参考snarkjs进行安装调试。要使用zk-Snark主要需要安装node.js、circom、snarkjs这三个东西。我用的是window11。
1、安装node.js,没啥好说的,就是版本不要太低,不然运行的时候容易出bug,我的版本是:v18.20.4
2、安装snarkjs,这个更简单就一行命令:npm install -g snarkjs@latest
3、安装circom,这个是零知识证明的核心之一,可以理解为电路编译器,将证明代码编译成电路。circom安装可以参考这篇文章,虽然有npm安装方式,但是不建议这么做,因为npm版本太低,安装之后用2.0.0的电路模板会有问题。其次,安装命令cargo build --release 在window上有问题的可以去掉--release,即在circom代码目录调用cargo build即可,然后就可以在/circom/target/debug目录中找到circom.exe可运行程序,如果嫌麻烦可以不用配置环境变量,直接将该exe文件copy到测试目录。
测试
首先初始化Tau
这个具体用处我也不是很清楚,先暂定为必要数据的初始化功能吧,跟着snarkjs的步骤执行即可
1、执行:snarkjs powersoftau new bn128 14 pot14_0000.ptau -v
2、执行snarkjs powersoftau contribute pot14_0000.ptau pot14_0001.ptau --name="First contribution" -v
3、执行:snarkjs powersoftau contribute pot14_0001.ptau pot14_0002.ptau --name="Second contribution" -v -e="some random text"
4、执行下面三条语句
snarkjs powersoftau export challenge pot14_0002.ptau challenge_0003
snarkjs powersoftau challenge contribute bn128 challenge_0003 response_0003 -e="some random text"
snarkjs powersoftau import response pot14_0002.ptau response_0003 pot14_0003.ptau -n="Third contribution name"
4、执行:snarkjs powersoftau beacon pot14_0003.ptau pot14_beacon.ptau 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 10 -n="Final Beacon"
5、执行:snarkjs powersoftau prepare phase2 pot14_beacon.ptau pot14_final.ptau -v
这个命令要执行很久,如果没出错最后会生成一个pot14_final.ptau的文件,这个就是后续需要使用到的关键文件之一了。
编译电路
1、创建电路代码,假定我们要验证A知道两个数,这两个数的乘积=33,我们假设A已经知道这个条件,我们将电路设计成A输入两个数值,并输出两个数值的乘积:
2、执行命令:circom circuit.circom --r1cs --wasm --sym
生成r1cs文件、sym文件、*_js目录,js目录下有三个文件,即运行脚本电路文件
生成见证文件
1、我们编译完电路之后,需要用户输入参数,然后生成一个见证文件,其实就是A要将数值输入到电路中得到一个中间文件。因此需要定义输入文件input.json
2、进入circuit_js目录,调用命令:node generate_witness.js circuit.wasm ../input.json ../witness.wtns
调用成功会在test目录生成一个wtns文件,这个就是一个见证文件了
创建公共参数
公共参数创建需要使用r1cs和ptau文件,大体上可以理解为会创建一个私钥,将这两个文件数据进行组合运算,加上公钥数据,进行签名,然后销毁私钥,最后导出zkey类型的公共数据文件。这里面有三种验证系统:Groth16、plonk和fflonk,我们这边只使用plonk进行举例
返回test目录,执行命令:snarkjs plonk setup circuit.r1cs pot14_final.ptau circuit_final.zkey
导出验证公钥
从公共数据文件中导出验证公钥数据,执行命令:snarkjs plonk prove circuit_final.zkey witness.wtns proof.json public.json
生成证明文件
证明文件需要公共参数文件zkey+见证文件wtns才能生成,然后生成proof.json,以及电路中定义的output等公共数据,执行命令:snarkjs plonk prove circuit_final.zkey witness.wtns proof.json public.json
数据验证
数据验证则需要公钥zkey+proof.json+public.json进行验证,然后返回验证成功或者失败,执行命令:snarkjs plonk verify verification_key.json public.json proof.json
结束
这里面只是简单试了一下zk-snark的调用,但是还有很多问题没有解决,比如电路文件是要由验证者编写,还是由证明者编写?如何确保证明者的输入是可靠的?题中的例子属于知道类型的证明,那么有/没有的类型应该如何设计电路?感觉要实际将零知识证明应用到项目中还有很多很多的问题啊,头大。