【零知识证明】Groth16
一 相关介绍
1 Groth16
Groth16是一种用于零知识证明系统中的简洁非交互式知识论证(SNARK)协议,是一种表示计算的方式,在算术电路上操作,使用加法和乘法门。使用配对友好的椭圆曲线来实现高效的证明生成和验证。
Groth16的主要特点包括:
--1. 简洁性:生成的证明非常小,通常只有几百字节。
--2. 高效验证:验证过程计算量小,速度快。
--3. 非交互式:证明者只需发送一个证明,无需与验证者进行多轮交互。
--4. 通用性:可以用于各种计算问题的零知识证明。
--5. 安全性:基于一些标准的密码学假设。
2 Powers of Tau
Powers of Tau是零知识证明系统中的一个重要概念,特别是在zk-SNARKs(零知识简洁非交互式知识论证)中。它是一个多方计算(MPC)仪式,用于生成zk-SNARK系统的初始可信设置。旨在创建一个通用的加密"材料",可以用于后续的零知识证明。这个名字来源于希腊字母τ(tau),在这个过程中,计算τ的不同幂次(powers)。主要特点包括:
--1.安全性:只要参与仪式的至少一方是诚实的,整个系统就是安全的。
--2.可累积:多个参与者可以依次贡献自己的随机性。
--3.通用性:生成的结构可以用于多个不同的电路和证明。
二 Groth16设置
Phase 1
1 启动一个新的Powers of Tau仪式
使用snarkjs工具创建Powers of Tau仪式的初始文件
snarkjs powersoftau new bn128 12 ceremoy_0000.ptau -v
snarkjs
: 用于生成和验证零知识证明的JavaScript库。powersoftau
: snarkjs中的一个子命令,用于执行Powers of Tau仪式。new
: 表示我们要创建一个新的Powers of Tau仪式。bn128
: 指定使用的椭圆曲线类型。BN128(也称为BN254)是一种常用于零知识证明的配对友好曲线。12
: 多项式的最大幂次,决定了电路的最大大小。2^12 = 4096,意味着这个设置最多可以支持4096个约束。ceremoy_0000.ptau
: 输出文件的名称,将数字附加到仪式词的末尾是传统做法,这样就可以跟踪哪些参与者为这个仪式文件贡献了随机性。。-v
: 表示"verbose"模式,会输出更详细的信息。
2 贡献阶段
多个参与者依次对ceremony文件进行贡献,其步骤为:
--1 下载当前的ceremony文件
--2 添加自己的随机性
--3 上传修改后的文件
snarkjs powersoftau contribute ceremoy_0000.ptau ceremoy_0001.ptau -v
输入随机数或者文字完成后,删除 ceremoy_0000.ptau ,继续提供随机性。
snarkjs powersoftau contribute ceremoy_0001.ptau ceremoy_0002.ptau -v
……
3 验证贡献
为确保该文件贡献随机性之前,仪式文件没有以任何方式被破坏,获取到仪式文件时可以验证完整性。
snarkjs powersoftau verify ceremoy_0001.ptau
打印出[INFO] snarkJS: Powers of Tau Ok!,则意味着仪式文件正确。
4 最终文件
文件随机性贡献完成后,生成最终文件:
snarkjs powersoftau prepare phase2 ceremoy_0002.ptau ceremoy_final.ptau -v
验证最后的生成文件:
snarkjs powersoftau verify ceremoy_final.ptau
Phase 2
针对特定电路的设置过程
1 准备电路
首先,准备好想要证明的具体电路,MIMC5哈希电路为例。
pragma circom 2.0.0;
// y = (x + k + c) ^ 5
// 输入信号x, k ,常量c
// base = x + k + c
// base2 = base * base
// base4 = base2 * base2
// base5 = base *base4
// 输出 y
template MIMC5(){
signal input x;
signal input k;
signal output y;
var nRounds = 10;
signal lastOutput[nRounds + 1];
signal base[nRounds];
signal base2[nRounds];
signal base4[nRounds];
var c[nRounds] = [
0,
108628498564530119400845211344465696619893215909509348621394122327540108068425,
97918840674612490766260259917122040983322146107578572117133348745818718934238,
37080288021783359382631708635481166595643657187023815953993753410034258263757,
73837458841121413400840196415753404416336899430626860296277530990112251638375,
14175455430092778326653438909353750763438980656611040223157546655455727686661,
85678297215287832106125129972569780982362546197552607669873965012182303538395,
37616746480726794097353991145016865625300747892258420087145463257639176364046,
96407012155233017139473625567546330731938257866046827176139377315631058571917,
35426948207998228380140847549475429358133108689610886291038432834368020538887
];
lastOutput[0] <== x;
for(var i = 0; i < nRounds; i++){
base[i] <== lastOutput[i] + k + c[i];
base2[i] <== base[i] * base[i];
base4[i] <== base2[i] * base2[i];
lastOutput[i+1] <== base[i] + base4[i];
}
}
component main = MIMC5();
2 生成zkey文件
编译电路,生成circuit.r1cs文件并导入Phase 1(即之前运行的Powers of Tau命令)的输出
circom circuit.circom --r1cs
启动Phase 2设置,使用编译后的电路和Phase 1输出的ptau文件生成一个初始的zkey文件。
snarkjs groth16 setup circuit.r1cs ceremoy_final.ptau setup_0000.zkey
zkey文件包含了特定于circuit.circom电路的证明和验证密钥
3 贡献随机性
与Phase 1类似,多方可以为zkey文件贡献随机性,以增加安全性。(可以重复多次)
snarkjs zkey contribute setup_0000.zkey setup_final.zkey
4 验证设置
完成贡献后,和Phase 1类似,需要验证最终的zkey文件以确保其正确性。
snarkjs zkey verify circuit.r1cs ceremoy_final.ptau setup_final.zkey
Phase 3
1 生成证明
先为电路添加输入x和k的值:
# 新建一个input.json文件
{
"x" : "156345341",
"k" : "28965346"
}
再编译电路为WebAssembly形式,用于生成证明。
circom circuit.circom --wasm
使用编译后的电路、输入数据和最终的zkey文件来生成证明。
snarkjs groth16 fullprove input.json circuit_js/circuit.wasm setup_final.zkey proof.json public.json
2 导出Solidity验证器合约
创建一个Solidity合约,可以在以太坊上验证证明
snarkjs zkey export solidityverifier setup_final.zkey Verifier.sol
3 生成验证调用数据
生成可以用来调用验证器合约的数据。
snarkjs zkey export soliditycalldata public.json proof.json
["0x05fe0d95b181b07d383313d4b458ff17ac2ab3e7ae8433fa4e3c5869875d653c", "0x28e17a78038c2cd2685f9c536c2be7423dd6e23f7e2061b6e27c5071b3f58c36"],[["0x0e5e1552b27bbd45dbf8bbfbcaee1bdc71fa6a9c016654dff27a1beea7b2f57d", "0x03160fb7373a40993cbc74d121ccd75f4910c543c75c65934f93fdde1a16cb6a"],["0x221e506d697c36f9d1bf5b2f12dd1b83986a3f479360f31faf17e215f982681f", "0x227a10c7abfa2c835fe9a3c42e63dc2a67dadb8556942f42e913c943d3e96e75"]],["0x095e86f10679e5f4d96220678e98dbb8cbbd6ec613568ae372e955d088304dce", "0x03c00703bd4dc41af417765c411c84d0a61f9d76b82e22a3215f9889f5edab42"],["0x0000000000000000000000000000000000000000000000000000000000000000"]
4 在合约中验证:
最后,可以将生成的验证器合约部署到以太坊,并使用生成的调用数据来验证证明。
这个过程的美妙之处在于,一旦Phase 1和Phase 2完成,就可以重复使用setup_final.zkey文件来为相同电路的不同输入生成多个证明,而不需要重新进行可信设置。