zkSnark教程:从方程到验证

使用zkSnark(一种非交互的自适应知识论证),我们就可以向一个或多个验证者提供一个简短的证明,证明我们对某些私人数据和函数(f)有特定的知识。

使用zkSnark(一种非交互的自适应知识论证),我们就可以向一个或多个验证者提供一个简短的证明,证明我们对某些私人数据和函数(f)有特定的知识。现在让我们一起来了解使用 zkSnark 创建零知识证明的步骤吧。

要运行本教程,你需要安装两个Node.js程序:

npm install snarkjs

npm install circom

创建电路

在zkSnark中创建零知识证明的第一部分是将函数分解成逻辑步骤。这涉及到创建一个算术电路,它将由基本的加法、减法、乘法和除法运算组成。在本例中,我们将使用:

d = a²+ b

其中a和b是private输入值。然后,我们想证明我们知道输入 a 和 b 的方程的结果,但不会实际给出a、b或d。例如,如果a=3和b=11,答案将是:

d = 3×3 + 11 = 20

我们证明,当 a=3 和 b=11 时(但不泄露这些值),我们知道 d=20。首先,我们将用这个等式(来自名为 mult.circom 的文件)创建一个电路:

pragma circom 2.0.0;template Mult() {
    signal input a;
    signal input b;    signal output d;
    var c=0;    c = a*a;
    d <== c+b;
 } component main = Mult();

电路如下:

1.jpg

接下来,我们可以编译电路:

> circom mult.circom --r1cs --wasm --sym --ctemplate instances: 1
non-linear constraints: 0
linear constraints: 0
public inputs: 0
public outputs: 1
private inputs: 2
private outputs: 0
wires: 2
labels: 5
Written successfully: .\mult.r1cs
Written successfully: .\mult.sym
Written successfully: .\mult_cpp\mult.cpp and .\mult_cpp\mult.dat
Written successfully: .\mult_cpp/main.cpp, circom.hpp, calcwit.hpp, calcwit.cpp, fr.hpp, fr.cpp, fr.asm and Makefile
Written successfully: .\mult_js\mult.wasm

Everything went okay, circom safe

接下来,我们创建一个输入文件(input.json)来定义我们的证明:

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

我们还可以使用以下命令将 R1CS 文件导出为 JSON 文件格式:

> snarkjs r1cs export json mult.r1cs mult.json{
 "n8": 32,
 "prime": "21888242871839275222246405745257275088548364400416034343698204186575808495617",
 "nVars": 4,
 "nOutputs": 1,
 "nPubInputs": 0,
 "nPrvInputs": 2,
 "nLabels": 4,
 "nConstraints": 1,
 "useCustomGates": false,
 "constraints": [
  [
   {
    "2": "21888242871839275222246405745257275088548364400416034343698204186575808495616"
   },
   {
    "2": "1"
   },
   {
    "1": "21888242871839275222246405745257275088548364400416034343698204186575808495616",
    "3": "1"
   }
  ]
 ],
 "map": [
  0,
  1,
  2,
  3
 ],
 "customGates": [],
 "customGatesUses": []
}

创建一个witness

接下来我们必须做的是为电路中给定输入的所有值创建witness。为此,我们可以进入mult_js文件夹,并创建一个witness文件:

\> node generate_witness.js mult.wasm input.json witness.wtns

这就产生了witness.wtns,它将在电路中创造witness的值。我们还可以将我们的witness导出为JSON文件格式:

\> snarkjs wtns export json witness.wtns witness.json

如果我们列出 witness.json,我们会得到:

[ "1", "20", "3", "11" ]

Powers of Tau

我们现在可以通过Powers of Tau Ceremony:

> snarkjs powersoftau new bn128 12 pot12_0000.ptau -v[DEBUG] snarkJS: Calculating First Challenge Hash
[DEBUG] snarkJS: Calculate Initial Hash: tauG1
[DEBUG] snarkJS: Calculate Initial Hash: tauG2
[DEBUG] snarkJS: Calculate Initial Hash: alphaTauG1
[DEBUG] snarkJS: Calculate Initial Hash: betaTauG1
[DEBUG] snarkJS: Blank Contribution Hash:
786a02f7 42015903 c6c6fd85 2552d272
912f4740 e1584761 8a86e217 f71f5419
d25e1031 afee5853 13896444 934eb04b
903a685b 1448b755 d56f701a fe9be2ce
[INFO]  snarkJS: First Contribution Hash:
9e63a5f6 2b96538d aaed2372 481920d1
a40b9195 9ea38ef9 f5f6a303 3b886516
0710d067 c09d0961 5f928ea5 17bcdf49
ad75abd2 c8340b40 0e3b18e9 68b4ffef

和:

> snarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau --name="My name" -vEnter a random text. (Entropy): tteesstt112233[DEBUG] snarkJS: Calculating First Challenge Hash
[DEBUG] snarkJS: Calculate Initial Hash: tauG1
[DEBUG] snarkJS: Calculate Initial Hash: tauG2
[DEBUG] snarkJS: Calculate Initial Hash: alphaTauG1
[DEBUG] snarkJS: Calculate Initial Hash: betaTauG1
[DEBUG] snarkJS: processing: tauG1: 0/8191
[DEBUG] snarkJS: processing: tauG2: 0/4096
[DEBUG] snarkJS: processing: alphaTauG1: 0/4096
[DEBUG] snarkJS: processing: betaTauG1: 0/4096
[DEBUG] snarkJS: processing: betaTauG2: 0/1
[INFO]  snarkJS: Contribution Response Hash imported:
60736f5b 7484eb59 1e4e57b4 22a6d71f
bdac9cf9 9d8c3583 e4b15191 2094cb2a
b5c51d30 8bc9deee e6df74f9 7e7ccf1d
89ce3c5a 06893553 16c96731 419f3fc7
[INFO]  snarkJS: Next Challenge Hash:
75422bee 499a44f2 bdf6d0f5 6b32d5fa
7f8b092b 1c92a093 da1ee4da b64fc2bf
982892a1 7d23a4c3 96006c4f 971c10ee
6d2ae5dd 4a327727 94cedefd 05fdbd12

这将创建一个名为pot12_0000.ptau的文件。

第二阶段

接下来我们将在下一阶段应用我们的电路:

\> snarkjs powersoftau prepare phase2 pot12_0001.ptau pot12_final.ptau -v

然后将创建一个证明和验证密钥(这是在zkey文件中创建的):

\> snarkjs groth16 setup multiplier2.r1cs pot12_final.ptau multiplier2_0000.zkey

然后设置下一个阶段:

> snarkjs powersoftau prepare phase2 pot12_0001.ptau pot12_final.ptau -v[DEBUG] snarkJS: Starting section: tauG1
[DEBUG] snarkJS: tauG1: fft 0 mix start: 0/1
[DEBUG] snarkJS: tauG1: fft 0 mix end: 0/1
[DEBUG] snarkJS: tauG1: fft 1 mix start: 0/1
[DEBUG] snarkJS: tauG1: fft 1 mix end: 0/1
[DEBUG] snarkJS: tauG1: fft 2 mix start: 0/1
[DEBUG] snarkJS: tauG1: fft 2 mix end: 0/1
[DEBUG] snarkJS: tauG1: fft 3 mix start: 0/1
[DEBUG] snarkJS: tauG1: fft 3 mix end: 0/1
 .... details missed out
[DEBUG] snarkJS: betaTauG1: fft 11 mix end: 1/2
[DEBUG] snarkJS: betaTauG1: fft  11  join: 11/11
[DEBUG] snarkJS: betaTauG1: fft 11 join  11/11  1/1 0/1
[DEBUG] snarkJS: betaTauG1: fft 12 mix start: 0/2
[DEBUG] snarkJS: betaTauG1: fft 12 mix start: 1/2
[DEBUG] snarkJS: betaTauG1: fft 12 mix end: 0/2
[DEBUG] snarkJS: betaTauG1: fft 12 mix end: 1/2
[DEBUG] snarkJS: betaTauG1: fft  12  join: 12/12
[DEBUG] snarkJS: betaTauG1: fft 12 join  12/12  1/1 0/1
接

下来我们创建密钥:

> snarkjs groth16 setup mult.r1cs pot12_final.ptau mult_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:
ac024737 f6a5a4ce 860483b8 515e6915
6205c88a 2e6b7055 f4a03fdb e78c3e4b
c9a7986e 9e8a2cd0 4e28fe88 1cd6c96a
9e569461 1f01666b 6a7ed94a 3504e134

然后为Ceremony作出贡献:

snarkjs zkey contribute mult_0000.zkey mult_0001.zkey --name="Test Name" -vEnter a random text. (Entropy): 
Applying key: L Section: 0/2
Applying key: H Section: 0/4
Circuit Hash: 
    948f8091 7fa93ed2 c1459ef5 0ce43732
    d86879cd 267c0625 8ea5c5da d35c6fdc
    a61310cf 095f7d39 dc4d4bf9 641c7d4c
    df2aae27 fa9d59dd 925d156c 8ecf506b
Contribution Hash: 
    6bcba108 6554a7c6 aa2bb90d 7c901871
    2f0d9bc8 d6f2290b b3850a59 c0c0bdd9
    8e61897b eefb0691 5863b31a 2ea8033e
    2f880c29 9621d0a7 6ff6e071 007fcd4f

最后,我们可以导出验证密钥:

\> snarkjs zkey export verificationkey mult_0001.zkey verification_key.json

我们现在可以查看验证密钥文件:

{
 "protocol": "groth16",
 "curve": "bn128",
 "nPublic": 1,
 "vk_alpha_1": [
  "4930972919657545726860728636203202889989795230486834516884623257662010190968",
  "17784464477734652112678078638948832338689828495400343595590810154267715615773",
  "1"
 ],
 "vk_beta_2": [
  [
   "18389735958499306728010265966534631076957479993331219391194646786717212290454",
   "9377762495436441301891640165839693718450498177510036079594436038367782263806"
  ],
  [
   "12918025179235334873924565184099963869927560708469813538777622359611980563600",
   "9540299846849550800883433886871516082732747826796133848225752385718676233704"
  ],
  [
   "1",
   "0"
  ]
 ],
 "vk_gamma_2": [
  [
   "10857046999023057135944570762232829481370756359578518086990519993285655852781",
   "11559732032986387107991004021392285783925812861821192530917403151452391805634"
  ],
  [
   "8495653923123431417604973247489272438418190587263600148770280649306958101930",
   "4082367875863433681332203403145435568316851327593401208105741076214120093531"
  ],
  [
   "1",
   "0"
  ]
 ],
 "vk_delta_2": [
  [
   "6678561741832709084950120792594057740372012012476808764391217711675983692110",
   "19148562476715307366333124452364601954136306739968359421280546942781306687117"
  ],
  [
   "5563686774264337713632059638379062839883993286221464997715904103056019482412",
   "21833682533925220432016594073010435262143992710094235623186050651622850207784"
  ],
  [
   "1",
   "0"
  ]
 ],
 "vk_alphabeta_12": [
  [
   [
    "21035614430046395676452458856349037799926906859868468846877507191464853481937",
    "7367376076358797456371954886520136044173614048593332592178094606599134546984"
   ],
   [
    "5808825009653597050362562643979192678810121406759169545733784434854763413918",
    "15128225491901928330780610339864969395330419807108978760255288410444914516625"
   ],
   [
    "14978815026753531164200162544695939844698822789400754850228256443689058138231",
    "16113300741635819930196783951232141998238231281531753181323378044203883884342"
   ]
  ],
  [
   [
    "8442579491476795281405460092751645692381846639953353246612942751519012569788",
    "11827292701507789496064142034155273588916516375204067786052314521160910352971"
   ],
   [
    "20072517047914614006053365712147494445532735080074807478164761993842384472110",
    "13665874946665444505746003584809490872324268348019328507331521810995839980467"
   ],
   [
    "10225689113248454267459923513638914637857045930066471172993596968519514548462",
    "6383370432527878416577498240685833420691833124835369534381884954863421906203"
   ]
  ]
 ],
 "IC": [
  [
   "18715829740044647887122344913298058336630317728738304325862477358219862297827",
   "16221092531741964322070455355625510828324417870530275245397592617997280882899",
   "1"
  ],
  [
   "673958305085585829783514648122080086902081959530482708587291142529753209278",
   "6811756694984425962860666144580149688381174003774696142976434024786320245650",
   "1"
  ]
 ]
}

生成一个证明

现在我们有了可以根据witness文件创建证明的文件:

\> snarkjs groth16 prove mult_0001.zkey witness.wtns proof.json public.json

输出将是proof.json,它包含了我们的知识证明:

{
 "pi_a": [
  "18179065977147657779359641627266856730189560012430348972168729148195594119398",
  "4325130652974965851962487796548080753812713465953132240508427612753615137668",
  "1"
 ],
 "pi_b": [
  [
   "18395390851775000847122561780630950260849796100997778613417368640548299239475",
   "17639909396142653244025863699056463248483166788147768144883360518935838049735"
],
  [
   "9408131275963864266616099995774753746213060751552818483760857814043622474916",
   "8981404227605788652195858905745591103367179864186050631891035451705025332378"
],
  [
   "1",
   "0"
]
 ],
 "pi_c": [
  "1737020500140345915930097080595151095303222939533212987558942021306795966145",
  "145473143193388753772867796175071880043993095936447841945077555539388439000",
  "1"
 ],
 "protocol": "groth16",
 "curve": "bn128"
}
和public.json:
[
 "20"
]

我们也可以检查验证密钥,看看它对证明是否有效:

> snarkjs zkey verify mult.r1cs pot12_final.ptau mult_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:
                c2d18bee ad37bdb0 ff2f6443 7ba50f8a
                a6ee3552 8356a79c e14ed342 58adecd3
                6c5068ac f7113bbb c68d2752 9abc0a6f
                9ec007a6 73401931 67d58666 5fa6b5d5
[INFO]  snarkJS: Circuit Hash:
                c2d18bee ad37bdb0 ff2f6443 7ba50f8a
                a6ee3552 8356a79c e14ed342 58adecd3
                6c5068ac f7113bbb c68d2752 9abc0a6f
                9ec007a6 73401931 67d58666 5fa6b5d5
[INFO]  snarkJS: -------------------------
[INFO]  snarkJS: ZKey Ok!

验证证明

最后,我们可以取proof、public value、verification,证明这个proof是有效的:

> snarkjs groth16 verify verification_key.json public.json proof.jsonsnarkJS: OK!

利用Golang进行验证

现在让我们在Golang中创建一个程序,它将读取验证密钥、公共值和证明:

package main

import (
  "fmt"
  "io/ioutil"
  "github.com/iden3/go-circom-prover-verifier/parsers"
  "github.com/iden3/go-circom-prover-verifier/verifier"
)

func main() {

  fmt.Println("zkSNARK Groth16 verify")

  proofJson, _ := ioutil.ReadFile( "proof.json")

  vkJson, _ := ioutil.ReadFile("verification_key.json")

  publicJson,_ := ioutil.ReadFile("public.json")

  public, _ := parsers.ParsePublicSignals(publicJson)
  proof, _ := parsers.ParseProof(proofJson)
  vk, _ := parsers.ParseVk(vkJson)

  v := verifier.Verify(vk, proof, public)
  fmt.Printf("%v",v)  

}

示例运行:

go-circom-prover-verifier
zkSNARK Groth16 prover
true

已经完成了。

结论

zkSnark是目前计算机科学和网络安全领域最热门的话题之一,它可以被用来证明知识——比如你有一个私钥或密码——但却不用真正泄露它。如果可以加入智能合约的力量,我们就能够创造一个全新的信任世界。

下面是完整的教程:

https://asecuritysite.com/zero/zksnark03

Source:https://medium.com/asecuritysite-when-bob-met-alice/the-magic-of-zksnarks-from-equation-to-verification-1d8c87553ff

关于

ChinaDeFi - ChinaDeFi.com 是一个研究驱动的DeFi创新组织,同时我们也是区块链开发团队。每天从全球超过500个优质信息源的近900篇内容中,寻找思考更具深度、梳理更为系统的内容,以最快的速度同步到中国市场提供决策辅助材料。

本文首发于:https://mp.weixin.qq.com/s/OD1jbTGwHVzobGyrGqfKJQ

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
ChinaDeFi 去中心化金融社区
ChinaDeFi 去中心化金融社区
ChinaDeFi.com 是一个研究驱动的DeFi创新组织,同时我们也是区块链开发团队。每天从全球超过500个优质信息源的近900篇内容中,寻找思考更具深度、梳理更为系统的内容,以最快的速度同步到中国市场提供决策辅助材料。