Skip to content

1. INTRO:Circom、SnarJS & zkrepl

此处参考SnarkJS官方文档

Circom

代码

下面以一个简单的布尔可满足性问题为例:

js
pragma circom 2.1.6;

// proof (a or b) and (not c) == 1
template BoolSatisfy () {
    signal input a;
    signal input b;
    signal input c; 
    signal output finalout;

    signal invC <== 1 - 1*c;
    signal orAB <== a + b - a * b;
    signal out <== orAB * invC;

    out === 1;
    finalout <== out;
    
    log("Assertion passed");
}

component main = BoolSatisfy();

/* INPUT = {
    "a": "1",
    "b": "0",
    "c": "0"
} */

编译

生成R1CS、WASM和符号文件:

bash
circom BoolSatisfy.circom --r1cs --wasm --sym -o output
  • --r1cs:生成R1CS文件
  • --wasm:生成WASM文件
  • --sym:生成符号文件
  • -o output:指定输出目录为output
sh
# output
template instances: 1
non-linear constraints: 2
linear constraints: 1
public inputs: 0
private inputs: 3 (2 belong to witness)
public outputs: 1
wires: 6
labels: 8
Written successfully: ./output\boolsatis.r1cs
Written successfully: ./output\boolsatis.sym
Written successfully: ./output\boolsatis_js\boolsatis.wasm
Everything went okay

output下会生成如下文件,在后面会讲如何使用

sh
./output
├── boolsatis_js
│   ├── boolsatis.wasm
│   ├── generate_witness.js
│   └── witness_calculator.js
├── boolsatis.r1cs
└── boolsatis.sym

生成witness

  1. 准备输入文件input.json
json
{
    "a": "1",
    "b": "0",
    "c": "0"
}
  1. 生成witness
bash
node output/boolsatis_js/generate_witness.js output/boolsatis_js/boolsatis.wasm input.json output/witness.wtns
# 或者
snarkjs wtns calculate output/boolsatis_js/boolsatis.wasm input.json output/witness.wtns

最后会在 output目录下生成witness.wtns文件

SnarkJS

检查输出信息

  1. 查看R1CS信息
bash
  snarkjs r1cs info output/boolsatis.r1cs
[INFO]  snarkJS: Curve: bn-128
[INFO]  snarkJS: # of Wires: 6
[INFO]  snarkJS: # of Constraints: 3
[INFO]  snarkJS: # of Private Inputs: 3
[INFO]  snarkJS: # of Public Inputs: 0
[INFO]  snarkJS: # of Labels: 7
[INFO]  snarkJS: # of Outputs: 0
  1. 查看约束信息
bash
  snarkjs r1cs print output/boolsatis.r1cs output/boolsatis.sym
[INFO]  snarkJS: [ main.a ] * [ main.b ] - [ main.a +main.b +21888242871839275222246405745257275088548364400416034343698204186575808495616main.orAB ] = 0
[INFO]  snarkJS: [ 21888242871839275222246405745257275088548364400416034343698204186575808495616main.orAB ] * [ main.invC ] - [ 218882428718392752222464057452572750885483644004160343436982041865758084956161 ] = 0
[INFO]  snarkJS: [  ] * [  ] - [ 1 +21888242871839275222246405745257275088548364400416034343698204186575808495616main.c +21888242871839275222246405745257275088548364400416034343698204186575808495616main.invC ] = 0
  1. 导出r1cs到json格式
bash
snarkjs r1cs export json output/boolsatis.r1cs output/boolsatis.json

生成可信设置(Trusted Setup)

  1. 生成zkey密钥

这里下载生成好的随机数文件,以下使用powersOfTau28_hez_final_12.ptau

zk-snark系统中,我们在前面提到了构建多项式承诺时需要一个可信设置的过程以生成公共参考字符串CRS,并且安全性由生成的随机数 α 保证,这就要确保参与者在生成随机数后确保这个数被丢弃,回想一下我们在将多项式承诺时 α 泄露的情况。此处使用MPC生成CRS并且把整个过程分为两个部分,第一部分叫做Powers of tau仪式,tau指一个随机的秘密值(trapdoor),常表示为 τ 。而这里的ptau文件就是这个过程Phrase 1的产物,ptau文件是一个多轮的可信设置过程的结果,可以被多个电路所使用,并且在这个基础上可以生成特定电路的Phrase 2zkey文件。

这里的12代表支持 212 个约束的电路,在这里我们的约束为3,所以显然是足够的。

Refer 1: Scalable Multi-party Computation for zk-SNARK Parameters in the Random Beacon Model

Refer 2: https://zkproof.org/2021/06/30/setup-ceremonies/

Refer 3: Powers of tau

Refer 4: https://github.com/ebfull/powersoftau

bash
# 验证ptau
snarkjs powersoftau verify powersOfTau28_hez_final_12.ptau
生成zkey
bash
# groth16
  snarkjs groth16 setup output/boolsatis.r1cs powersOfTau28_hez_final_12.ptau output/boolsatis_0000.zkey
[INFO]  snarkJS: Reading r1cs
[INFO]  snarkJS: Reading tauG1
[INFO]  snarkJS: Reading tauG2
[INFO]  snarkJS: Reading alphatauG1
[INFO]  snarkJS: Reading betatauG1
[INFO]  snarkJS: Circuit hash:
                9a5e0601 c3477687 e28476b5 b1edeffc
                10588950 5549d196 7a67bb6c fa1d6acc
                43b044af fbfe9de6 7ba63fba 35f05d4f
                07b21ef3 e265b3b8 fb15afef 3582aa99
# plonk
  snarkjs plonk setup output/boolsatis.r1cs powersOfTau28_hez_final_12.ptau output/boolsatis_final.zkey
[INFO]  snarkJS: Reading r1cs
[INFO]  snarkJS: Plonk constraints: 5
[INFO]  snarkJS: Setup Finished

对于Groth16来说,上面的命令会生成一个初始的zkey文件boolsatis_0000.zkey,这个文件还不包含任何贡献,对于每个电路要进行单独的可信设置。而对于Plonk来说,直接生成了最终的zkey文件boolsatis_final.zkey,因为Plonk的可信设置是通用的,不需要每个电路单独贡献,可以跳过下面的步骤2~5

原文对Goth16-zkey的描述:The zkey is a zero-knowledge key that includes both the proving and verification keys as well as phase 2 contributions.Importantly, one can verify whether a zkey belongs to a specific circuit or not.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.

IMPORTANT

Do not use this zkey in production, as it's not safe. It requires at least one contribution.

既我们还需再Contribute一次

  1. Contribute
第一次Contribute
bash
  snarkjs zkey contribute output/boolsatis_0000.zkey output/boolsatis_0001.zkey --name="First contribution" -v
Enter a random text. (Entropy): klizz
[DEBUG] snarkJS: Applying key: L Section: 0/5
[DEBUG] snarkJS: Applying key: H Section: 0/4
[INFO]  snarkJS: Circuit Hash:
                9a5e0601 c3477687 e28476b5 b1edeffc
                10588950 5549d196 7a67bb6c fa1d6acc
                43b044af fbfe9de6 7ba63fba 35f05d4f
                07b21ef3 e265b3b8 fb15afef 3582aa99
[INFO]  snarkJS: Contribution Hash:
                17555388 16bff776 834a25f9 c506b937
                864416db 681dc0d2 bfe65505 0db3b581
                24803f7c a75522f3 2f92dd45 2dc5f1e3
                e1950478 f568cb16 bfcc7275 d9abe6a5
当然你可以做第二次甚至更多次
bash
  snarkjs zkey contribute output/boolsatis_0001.zkey output/boolsatis_0002.zkey --name="Second contribution" -v -e="klizz"
[DEBUG] snarkJS: Applying key: L Section: 0/5
[DEBUG] snarkJS: Applying key: H Section: 0/4
[INFO]  snarkJS: Circuit Hash:
                9a5e0601 c3477687 e28476b5 b1edeffc
                10588950 5549d196 7a67bb6c fa1d6acc
                43b044af fbfe9de6 7ba63fba 35f05d4f
                07b21ef3 e265b3b8 fb15afef 3582aa99
[INFO]  snarkJS: Contribution Hash:
                74f3c314 54e4a761 eb6ce8d1 e4539b85
                df38f74f 408f49ce 2d87cea2 29902b69
                900a1454 f576ccf7 2a85d0e4 eb8ba825
                369a8600 4bcfb2d3 1dc69fcc 33f53203
  1. 验证latest zkey
bash
  snarkjs zkey verify output/boolsatis.r1cs powersOfTau28_hez_final_12.ptau output/boolsatis_0002.zkey
输出
输出
bash
[INFO]  snarkJS: Reading r1cs
[INFO]  snarkJS: Reading tauG1
[INFO]  snarkJS: Reading tauG2
[INFO]  snarkJS: Reading alphatauG1
[INFO]  snarkJS: Reading betatauG1
[INFO]  snarkJS: Circuit hash:
                9a5e0601 c3477687 e28476b5 b1edeffc
                10588950 5549d196 7a67bb6c fa1d6acc
                43b044af fbfe9de6 7ba63fba 35f05d4f
                07b21ef3 e265b3b8 fb15afef 3582aa99
[INFO]  snarkJS: Circuit Hash:
                9a5e0601 c3477687 e28476b5 b1edeffc
                10588950 5549d196 7a67bb6c fa1d6acc
                43b044af fbfe9de6 7ba63fba 35f05d4f
                07b21ef3 e265b3b8 fb15afef 3582aa99
[INFO]  snarkJS: -------------------------
[INFO]  snarkJS: contribution #2 Second contribution:
                74f3c314 54e4a761 eb6ce8d1 e4539b85
                df38f74f 408f49ce 2d87cea2 29902b69
                900a1454 f576ccf7 2a85d0e4 eb8ba825
                369a8600 4bcfb2d3 1dc69fcc 33f53203
[INFO]  snarkJS: -------------------------
[INFO]  snarkJS: contribution #1 First contribution:
                17555388 16bff776 834a25f9 c506b937
                864416db 681dc0d2 bfe65505 0db3b581
                24803f7c a75522f3 2f92dd45 2dc5f1e3
                e1950478 f568cb16 bfcc7275 d9abe6a5
[INFO]  snarkJS: -------------------------
[INFO]  snarkJS: ZKey Ok!
  1. 应用随机信标链生成final zkey
bash
  snarkjs zkey beacon output/boolsatis_0002.zkey output/boolsatis_final_groth16.zkey 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 10 -n="final Beacon"
[INFO]  snarkJS: Contribution Hash:
                938966da b531b627 d8ae01a4 fdcb5218
                f9beae18 1c5b446c 2d259275 6965ad34
                11b0f2d2 70d6e342 e3ece933 cc2bcf7d
                542d4f3e 9a938f8a 6e3fba23 a9e04d11
  1. 验证final zkey
bash
 snarkjs zkey verify output/boolsatis.r1cs powersOfTau28_hez_final_12.ptau output/boolsatis_final_groth16.zkey
输出
输出
bash
[INFO]  snarkJS: Reading r1cs
[INFO]  snarkJS: Reading tauG1
[INFO]  snarkJS: Reading tauG2
[INFO]  snarkJS: Reading alphatauG1
[INFO]  snarkJS: Reading betatauG1
[INFO]  snarkJS: Circuit hash:
                9a5e0601 c3477687 e28476b5 b1edeffc
                10588950 5549d196 7a67bb6c fa1d6acc
                43b044af fbfe9de6 7ba63fba 35f05d4f
                07b21ef3 e265b3b8 fb15afef 3582aa99
[INFO]  snarkJS: Circuit Hash:
                9a5e0601 c3477687 e28476b5 b1edeffc
                10588950 5549d196 7a67bb6c fa1d6acc
                43b044af fbfe9de6 7ba63fba 35f05d4f
                07b21ef3 e265b3b8 fb15afef 3582aa99
[INFO]  snarkJS: -------------------------
[INFO]  snarkJS: contribution #3 final Beacon:
                938966da b531b627 d8ae01a4 fdcb5218
                f9beae18 1c5b446c 2d259275 6965ad34
                11b0f2d2 70d6e342 e3ece933 cc2bcf7d
                542d4f3e 9a938f8a 6e3fba23 a9e04d11
[INFO]  snarkJS: Beacon generator: 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
[INFO]  snarkJS: Beacon iterations Exp: 10
[INFO]  snarkJS: -------------------------
[INFO]  snarkJS: contribution #2 Second contribution:
                74f3c314 54e4a761 eb6ce8d1 e4539b85
                df38f74f 408f49ce 2d87cea2 29902b69
                900a1454 f576ccf7 2a85d0e4 eb8ba825
                369a8600 4bcfb2d3 1dc69fcc 33f53203
[INFO]  snarkJS: -------------------------
[INFO]  snarkJS: contribution #1 First contribution:
                17555388 16bff776 834a25f9 c506b937
                864416db 681dc0d2 bfe65505 0db3b581
                24803f7c a75522f3 2f92dd45 2dc5f1e3
                e1950478 f568cb16 bfcc7275 d9abe6a5
[INFO]  snarkJS: -------------------------
[INFO]  snarkJS: ZKey Ok!
  1. 导出为json
groth16
bash
 snarkjs zkey export verificationkey output/boolsatis_final_groth16.zkey output/verification_key.json
[INFO]  snarkJS: EXPORT VERIFICATION KEY STARTED
[INFO]  snarkJS: > Detected protocol: groth16
[INFO]  snarkJS: EXPORT VERIFICATION KEY FINISHED
plonk
bash
  snarkjs zkey export verificationkey output/boolsatis_final.zkey output/verification_key_plonk.json
[INFO]  snarkJS: EXPORT VERIFICATION KEY STARTED
[INFO]  snarkJS: > Detected protocol: plonk
[INFO]  snarkJS: EXPORT VERIFICATION KEY FINISHED

生成证明Proof

groth16
bash
snarkjs groth16 prove output/boolsatis_final_groth16.zkey output/witness.wtns output/proof_groth16.json output/public_groth16.json
# 也可以使用如下命令 (直接使用input.json跳过circom生成witness阶段)
snarkjs groth16 fullprove input.json output/boolsatis_js/boolsatis.wasm output/boolsatis_final_groth16.zkey output/proof_groth16.json output/public_groth16.json

这里会生成proofpublic两个文件,分别存储证明和公开输入,proof里会包含 groth16 中的三个元素 πAπBπC ,体积较小,这里为 803bytes

plonk
bash
snarkjs plonk prove output/boolsatis_final.zkey output/witness.wtns output/proof_plonk.json output/public_plonk.json

对于Plonk来说,生成的proof文件会稍大一些,这里为 2.2kbytes

验证证明

groth16
bash
  snarkjs groth16 verify output/verification_key.json output/public_groth16.json output/proof_groth16.json
[INFO]  snarkJS: OK!
plonk
bash
  snarkjs plonk verify output/verification_key_plonk.json output/public_plonk.json output/proof_plonk.json -v
输出
输出
bash
[DEBUG] snarkJS: > Reading witness file
[DEBUG] snarkJS: > Reading zkey file
[DEBUG] snarkJS: ----------------------------
[DEBUG] snarkJS:   PLONK PROVE SETTINGS
[DEBUG] snarkJS:   Curve:         bn128
[DEBUG] snarkJS:   Circuit power: 3
[DEBUG] snarkJS:   Domain size:   8
[DEBUG] snarkJS:   Vars:          9
[DEBUG] snarkJS:   Public vars:   1
[DEBUG] snarkJS:   Constraints:   7
[DEBUG] snarkJS:   Additions:     2
[DEBUG] snarkJS: ----------------------------
[DEBUG] snarkJS: > Reading witness file data
[DEBUG] snarkJS: > Reading Section 3. Additions
[DEBUG] snarkJS: ··· Computing additions
[DEBUG] snarkJS: > Reading Section 12. Sigma1, Sigma2 & Sigma 3
[DEBUG] snarkJS: ··· Reading Sigma polynomials
[DEBUG] snarkJS: ··· Reading Sigma evaluations
[DEBUG] snarkJS: > Reading Section 14. Powers of Tau
[DEBUG] snarkJS:
[DEBUG] snarkJS: > ROUND 1
[DEBUG] snarkJS: > Computing A, B, C wire polynomials
[DEBUG] snarkJS: ··· Reading data from zkey file
[DEBUG] snarkJS: ··· Computing A ifft
[DEBUG] snarkJS: ··· Computing B ifft
[DEBUG] snarkJS: ··· Computing C ifft
[DEBUG] snarkJS: ··· Computing A fft
[DEBUG] snarkJS: ··· Computing B fft
[DEBUG] snarkJS: ··· Computing C fft
[DEBUG] snarkJS: > Computing A, B, C MSM
[DEBUG] snarkJS: Multiexp start: A: 0/10
[DEBUG] snarkJS: Multiexp end: A: 0/10
[DEBUG] snarkJS: Multiexp start: B: 0/10
[DEBUG] snarkJS: Multiexp end: B: 0/10
[DEBUG] snarkJS: Multiexp start: C: 0/10
[DEBUG] snarkJS: Multiexp end: C: 0/10
[DEBUG] snarkJS: > ROUND 2
[DEBUG] snarkJS: > Computing challenges beta and gamma
[DEBUG] snarkJS: ··· challenges.beta: 21dccc105f892709aa1498f0f527d56d6cec0f789821b2282370a2b5cd09a537
[DEBUG] snarkJS: ··· challenges.gamma: 1c61154c804c70dcca6961cf12b68b34849d194eb480d5e66e987e4e24fc26b2
[DEBUG] snarkJS: > Computing Z polynomial
[DEBUG] snarkJS: ··· Computing Z evaluations
[DEBUG] snarkJS: ··· Computing Z ifft
[DEBUG] snarkJS: ··· Computing Z fft
[DEBUG] snarkJS: > Computing Z MSM
[DEBUG] snarkJS: Multiexp start: Z: 0/11
[DEBUG] snarkJS: Multiexp end: Z: 0/11
[DEBUG] snarkJS: > ROUND 3
[DEBUG] snarkJS: > Computing challenge alpha
[DEBUG] snarkJS: ··· challenges.alpha: ad48a29166f8a9f02f53a5d12954253d12d9c7b8f555bd7776a6c8354a7cae0
[DEBUG] snarkJS: > Computing T polynomial
[DEBUG] snarkJS: ··· Reading sections 8, 9, 7, 10, 11. Q selectors
[DEBUG] snarkJS: ··· Computing T evaluations
[DEBUG] snarkJS: ··· Computing T ifft
[DEBUG] snarkJS: ··· Computing T / ZH
[DEBUG] snarkJS: ··· Computing Tz ifft
[DEBUG] snarkJS: ··· Computing T1, T2, T3 polynomials
[DEBUG] snarkJS: > Computing T MSM
[DEBUG] snarkJS: Multiexp start: T1: 0/9
[DEBUG] snarkJS: Multiexp end: T1: 0/9
[DEBUG] snarkJS: Multiexp start: T2: 0/9
[DEBUG] snarkJS: Multiexp end: T2: 0/9
[DEBUG] snarkJS: Multiexp start: T3: 0/14
[DEBUG] snarkJS: Multiexp end: T3: 0/14
[DEBUG] snarkJS: > ROUND 4
[DEBUG] snarkJS: > Computing challenge xi
[DEBUG] snarkJS: ··· challenges.xi: 4552349c75e650709f5ccd84198e8d640afa562491fc71eeedfb47bbb1c76aa
[DEBUG] snarkJS: > ROUND 5
[DEBUG] snarkJS: > Computing challenge v
[DEBUG] snarkJS: ··· challenges.v: 2cf9d00aca9272ce28db3f939dad109b47f5f2a54dbfe407cca7d7306297b930
[DEBUG] snarkJS: > Computing linearisation polynomial R(X)
[DEBUG] snarkJS: Lagrange Evaluations:
[DEBUG] snarkJS: L1(xi)=32b5992a742704f9221d67a86ac7e2c7c36686103d0d9748e249b8ba379edd3
[DEBUG] snarkJS: PI: 2d38f4e039ef2fda262e6f3bfad4da30abfd7fe775e8971cb5bd5a084c86122e
[DEBUG] snarkJS: r0: 1e78dcc7ee18384de2ce777db537a93c1f1ec4891810b09af14d51d180c17086
[DEBUG] snarkJS: > Computing opening proof polynomial Wxi(X) polynomial
[DEBUG] snarkJS: > Computing opening proof polynomial Wxiw(X) polynomial
[DEBUG] snarkJS: > Computing Wxi, Wxiw MSM
[DEBUG] snarkJS: Multiexp start: Wxi: 0/14
[DEBUG] snarkJS: Multiexp end: Wxi: 0/14
[DEBUG] snarkJS: Multiexp start: Wxiw: 0/11
[DEBUG] snarkJS: Multiexp end: Wxiw: 0/11
[DEBUG] snarkJS: PLONK PROVER FINISHED

Optional:导出为智能合约

bash
snarkjs zkey export solidityverifier output/boolsatis_final output/BoolSatisfyVerifier.sol

后面会讲如何调用

zk-repl

地址

简单来说就是省略了上面一些命令行的步骤,包括编译、生成witness、zkey和proof等,并且可以导出一个网页demo。

alt text

合约调用

groth16