環(huán)境安裝
?環(huán)境:WIN10 x64
criom是基于Rust開(kāi)發(fā)的,因此主機(jī)需要配有Rust環(huán)境。
snarkjs需要node環(huán)境。
rust安裝及配置
安裝及配置參考 作者:荔枝味汽水 windows安裝rust詳細(xì)教程
windows安裝rust詳細(xì)教程 - 知乎 (zhihu.com)
注意:本人的cargo換國(guó)內(nèi)源選擇的 清華源
再進(jìn)行配置時(shí),最后一步在.cargo文件中新建的config文件中的配置為:
[source.crates-io]
replace-with = 'tuna'?[source.tuna]
registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"
否則在使用cargo build時(shí)會(huì)出現(xiàn)以下問(wèn)題:
node.js安裝及配置
安裝及環(huán)境配置參考 作者:WHF__ 的Node.js下載安裝及環(huán)境配置教程【超詳細(xì)】
Node.js下載安裝及環(huán)境配置教程【超詳細(xì)】_nodejs下載-CSDN博客
安裝cricom
在此我選擇將Cricom下載到 C盤(pán)
git clone https://github.com/iden3/circom.git
進(jìn)入criom目錄
cargo build --release
?等待編譯完成
?編譯完成后執(zhí)行安裝命令
cargo install --path circom
等待安裝完畢,使用 --help查看criom 版本
安裝snarkjs
npm install -g snarkjs@latest
構(gòu)建電路與證明
準(zhǔn)備工作?-電路部分
首先在circom目錄下創(chuàng)建一個(gè)電路文件,文件命名為:circuit.circom,具體內(nèi)容如下
pragma circom 2.1.4;
template Multiplier() {
signal input a;
signal input b;
signal output c;
c <== a*b;
}
component main = Multiplier();
?第一行表示指定編譯該電路用到的circom版本為2.1.4
電路包含三個(gè)變量,其中a,b為輸入,輸出為c,該電路可以證明Prover知道兩個(gè)數(shù)字a和b,其乘積為c 這里第5行的 <== 符號(hào)有兩個(gè)含義:將值與變量 c 相關(guān)聯(lián),然后是施加約束 a*b 之后是將該電路聲明為Multiplier模板,并用main組件將該模板實(shí)例化
circom在編譯電路時(shí)必須要有一個(gè)main組件
之后執(zhí)行下列命令編譯電路
circom circuit.circom --r1cs --wasm --sym
?編譯完成后結(jié)果:
這里的三個(gè)參數(shù):
- r1cs:生成基于R1CS約束系統(tǒng)的電路,得到一個(gè).r1cs的二進(jìn)制文件
- wasm:生成一個(gè)基于circuit_js的目錄(目錄明取決于電路名),目錄內(nèi)包含一個(gè)wasm文件和其他用于生成witness的相關(guān)文件
- sym:生成一個(gè).sym的符號(hào)文件,用于調(diào)試和打印約束系統(tǒng)
circom目錄中會(huì)多出倆個(gè)文件:分別是文件circuit.rics ,?文件circuit.sym 和文件夾circuit_js
如果還加了 --c 參數(shù),則還會(huì)生成一個(gè) _cpp 目錄,里面包含了相關(guān)的.cpp,.dat,MakeFile等等文件, 這些文件將用于編譯C代碼以生成witness文件
此外可以采用 -o 參數(shù)來(lái)指定生成的目錄名(如果不加這個(gè)參數(shù),則默認(rèn)目錄名為 circname_js ,這里 circname是你的.circom電路文件的名字
編譯電路后,可以用snarkjs的相關(guān)命令來(lái)查看電路,先看一下snarkjs的幫助文件
r1cs info Print statistiscs of a circuit
Usage: snarkjs ri [circuit.r1cs]
r1cs print Print the constraints of a circuit
Usage: snarkjs rp [circuit.r1cs] [circuit.sym]
?這里用ri參數(shù)可以查看電路信息(或者用r1cs info也可以)
snarkjs ri circuit.r1cs
?輸出表示電路采用的曲線為bn-128,包含4個(gè)導(dǎo)線,其中2個(gè)私有輸入,一個(gè)輸出,輸入輸出之間包含一 個(gè)約束關(guān)系
或者使用rp參數(shù)查看電路中的約束(或者用print r1cs也可以)
snarkjs rp circuit.r1cs
這里忽略掉前面的系數(shù),得到的約束就是 到此為止,電路就編譯好了,接下來(lái)需要給電路特定的輸入,也就是構(gòu)建witness,這里就需要用到前面 生成的wasm文件
snarkjs采用json文件的方式將witness輸入電路,需要準(zhǔn)備一個(gè) input.js?文件,如下
{"a": "3", "b": "11"}
- 注意這里的輸入均為字符串,因?yàn)镴S無(wú)法處理大于 的整數(shù),所以轉(zhuǎn)換為字符串形式處理
?將這個(gè)json文件放到剛剛生成的circuit_js下面,此時(shí)目錄里面應(yīng)該有四個(gè)文件,分別是:
然后在該目錄下執(zhí)行下列命令
node generate_witness.js circuit.wasm input.json witness.wtns
這樣就得到了 witness.wtns 的證據(jù)文件,之后將利用這個(gè)文件來(lái)生成對(duì)應(yīng)的snark證明
如果說(shuō)前面使用了 --c 參數(shù),則可以進(jìn)入到對(duì)應(yīng)的cpp目錄中,同時(shí)將對(duì)應(yīng)的input.json文件放到該目錄 下,在該cpp目錄下執(zhí)行make命令即可
準(zhǔn)備工作-可信設(shè)置部分
證明生成需要兩個(gè)文件,一個(gè)是前面構(gòu)造電路時(shí)生成的r1cs文件 circuit.r1cs ,另一個(gè)是證據(jù)文件 witness.wtns
接下來(lái)以Groth16為例來(lái)生成證明 Groth16需要為每個(gè)電路都執(zhí)行一次可信設(shè)置,因此在證明生成之前還需要針對(duì)電路完成一些準(zhǔn)備工 作,Plonk和FFlonk無(wú)需為每個(gè)電路都執(zhí)行可信設(shè)置,Plonk和FFlonk的生成過(guò)程可以看
Groth16的可信設(shè)置由兩部分組成
- 的冪次:這一部分與電路無(wú)關(guān)
- phase 2:這一部分取決于電路
首先來(lái)生成 的冪次,命令如下
snarkjs powersoftau new bn128 12 pot12_0000.ptau -v
利用 new 命令創(chuàng)建的冪次,這里有幾個(gè)參數(shù)說(shuō)明一下
- 第一個(gè)參數(shù)為指定需要的曲線,snarkjs支持bn128和bls12-381兩種曲線
- 第二個(gè)參數(shù)為約束參數(shù),表示可信設(shè)置所支持的最大約束的數(shù)量,這里的12表示可信設(shè)置最多支持 個(gè)約束,這個(gè)參數(shù)的最大值為28,也即snarkjs可以生成具有至多個(gè)約束的電路
生成之后會(huì)在目錄下得到一個(gè) pot12_0000.ptau 文件
接下來(lái)需要用 contribute 命令,使用新的貢獻(xiàn)來(lái)創(chuàng)建一個(gè)ptau文件
snarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau --name="First contribution" -v
這里會(huì)提示輸入一些隨機(jī)文本來(lái)為貢獻(xiàn)提供額外的熵源,這里隨便輸就行,比如輸入contribution" -v
contribute命令會(huì)將截止至現(xiàn)在的所有ptau文件作為輸入(截止至目前為止的ptau文件為上面新建的 pot12_0000.ptau ),同時(shí)輸出一個(gè)新的ptau文件 pot12_0001.ptau ,該文件中包含新貢獻(xiàn)者執(zhí)行的計(jì)算
contribute的過(guò)程還可以使用第三方軟件來(lái)更新,比如下面這樣(這里用的是這個(gè)庫(kù)的bn-256曲線構(gòu)建)
snarkjs powersoftau export challenge pot12_0001.ptau challenge_0003
snarkjs powersoftau challenge contribute bn128 challenge_0003 response_0003 - e="some random text"
snarkjs powersoftau import response pot12_0001.ptau response_0003 pot12_0002.ptau -n="Third contribution name"
- ?
更新完成之后,用 verify 命令驗(yàn)證截止至目前為止的ptau(只執(zhí)行了一次更新,所以驗(yàn)證0001這個(gè) ptau文件)
?snarkjs powersoftau verify pot12_0001.ptau
這里只是生成 的冪,還沒(méi)有執(zhí)行phase 2的命令,因此此時(shí)運(yùn)行后系統(tǒng)會(huì)輸出[WARN]提示
不過(guò)驗(yàn)證通過(guò)了,就沒(méi)什么問(wèn)題
這里注意一點(diǎn),每當(dāng)新的zk-snark需要執(zhí)行可信設(shè)置時(shí),只需要對(duì)最新的ptau文件執(zhí)行verify命令,即可 驗(yàn)證截止到目前為止的整個(gè)挑戰(zhàn)和相應(yīng)鏈
接下來(lái)是利用beacon命令創(chuàng)建一個(gè)ptau文件,這個(gè)ptau文件會(huì)以隨機(jī)beacon的形式對(duì)ptau文件完成貢 獻(xiàn),可信設(shè)置的第一階段需要對(duì)其應(yīng)用一個(gè)隨機(jī)beacon
引入beacon的命令如下
snarkjs powersoftau beacon pot12_0001.ptau pot12_beacon.ptau1cbf6603d6ff9ba4e1d15d0fd83be3a80bca470b6a43a7f9055204e860298f99 10 -n="Final Beacon"
這里利用了以太坊第16668892個(gè)區(qū)塊的Hash值作為beacon值,后面的參數(shù)10表示以該beacon值作為輸入,計(jì)算次Hash
接下來(lái)是可信設(shè)置的第二部分,也即phase 2
phase 2用到的命令為 prepare phase2 ,該命令會(huì)用到前面輸出的 pot12_beacon.ptau 文件,并基于 該文件計(jì)算基于 的拉氏插值多項(xiàng)式,命令如下
snarkjs powersoftau prepare phase2 pot12_beacon.ptau pot12_final.ptau -v
輸入命令之后,電腦會(huì)算一陣子,計(jì)算的時(shí)間取決于曲線、第一階段中允許的約束數(shù)量(約束數(shù)量越 大,計(jì)算時(shí)間越長(zhǎng))
生成完最終ptau文件后,別忘了用 verify 命令驗(yàn)證一下
snarkjs powersoftau verify pot12_final.ptau
密鑰生成
準(zhǔn)備完畢之后,接下來(lái)是根據(jù)電路構(gòu)建證明與驗(yàn)證密鑰
首先將circuit.r1cs文件復(fù)制到C:\circom\circuit_js目錄下
用電路和上面的最終ptau文件生成一個(gè)zkey文件,該文件是一個(gè)零知識(shí)密鑰文件,包含phase 2的所有貢獻(xiàn),以及用于證明和驗(yàn)證的密鑰,利用這個(gè)zkey文件可以驗(yàn)證其是否屬于特定的電路
snarkjs groth16 setup circuit.r1cs pot12_final.ptau circuit_0000.zkey
這里得到的 circuit_0000.zkey 文件不包含任何貢獻(xiàn),不能用于最終電路的證明,因此需要執(zhí)行前面 的貢獻(xiàn)更新步驟
接下來(lái)使用 zkey 命令來(lái)對(duì)zkey文件進(jìn)行貢獻(xiàn)更新(前面用的是 powersoftau 命令,基本流程是一樣 的)
snarkjs zkey contribute circuit_0000.zkey circuit_0001.zkey --name="First Contributor Name" -v #這里依然輸入之前輸入的值
snarkjs zkey contribute circuit_0001.zkey circuit_0002.zkey --name="Second contribution Name" -v -e="Another random entropy"
snarkjs zkey verify circuit.r1cs pot12_final.ptau circuit_0002.zkey # 更新完貢獻(xiàn)記得驗(yàn)證一下
然后引入隨機(jī)beacon值并驗(yàn)證
snarkjs zkey beacon circuit_0002.zkey circuit_final.zkey
1cbf6603d6ff9ba4e1d15d0fd83be3a80bca470b6a43a7f9055204e860298f99 10 -n="Final Beacon phase2"
snarkjs zkey verify circuit.r1cs pot12_final.ptau circuit_final.zkey #同樣引入beacon后驗(yàn)證一下
之后基于該zkey文件,導(dǎo)出一個(gè)驗(yàn)證密鑰,導(dǎo)出的密鑰為json格式
snarkjs zkey export verificationkey circuit_final.zkey verification_key.json
證明生成
接下來(lái)利用電路和證明密鑰來(lái)構(gòu)建證明
snarkjs groth16 prove circuit_final.zkey witness.wtns proof.json public.json
命令執(zhí)行完畢后,可以得到兩個(gè)json文件:
- 一個(gè)是 public.json?
- 另一個(gè)是 proof.json?
public.json文件中是33,我們前面給的witness分別是3和11,因此 正確
proof.josn里面包含用于驗(yàn)證的元素
上面三個(gè)就是Groth16中三個(gè)用于配對(duì)的元素
這里官方給了一個(gè)一步到位的方式,可以在一條命令里面同時(shí)構(gòu)建witness文件和證明,如下?
# Groth16
snarkjs groth16 fullprove input.json circuit.wasm circuit_final.zkey
proof.json public.json
# Plonk
snarkjs plonk fullprove witness.json circuit.wasm circuit_final.zkey
proof.json public.json
# FFlonk
snarkjs fflonk fullprove witness.json circuit.wasm circuit_final.zkey
proof.json public.json
驗(yàn)證
利用上述兩個(gè)json文件可以驗(yàn)證證明
snarkjs groth16 verify verification_key.json public.json proof.json
?如果輸出下列信息說(shuō)明驗(yàn)證通過(guò)了
現(xiàn)在把?把public.json里面的33改成32
再執(zhí)行一次驗(yàn)證命令,此時(shí)會(huì)輸出驗(yàn)證失敗?
?模擬執(zhí)行
最后是將驗(yàn)證密鑰導(dǎo)出為Solidity智能合約,就可以將這個(gè)合約發(fā)布到鏈上了
snarkjs zkey export solidityverifier circuit_final.zkey verifier.sol
snarkjs給了一個(gè)模擬驗(yàn)證執(zhí)行的命令,利用上面的兩個(gè)json文件可以模擬Verifier在remix中的驗(yàn)證過(guò)程
snarkjs zkey export soliditycalldata public.json proof.json
?輸出是三個(gè)群元素和公共輸入,均編碼為HEX形式
?
["0x1d0bde1fa11154e30fe2f4cf390f13e44ded5892b89704fc67286548b72a84b9", "0x24bdfd9600cd3305d33d22eb772f4a931e155b523a12a24d84454594e6006d43"],
[["0x2c48929cc2f3f143b445bcc9228423a7afb765007cf823892c259259e9b20567", "0x13f538fbcf2d881da5af31297e6085bbcd4bcf7f36b8761eeaa6c2feebcca626"],["0x1be7d0cd25b1cb6bd5b0c465b95581291289b547600b4a2e7bc404b24d0f4238", "0x2d960f51e9918d0479d5ef4fe3351ef654277af3c5a82d956a50542e0b4db0cf"]],
["0x2ed9cd3e86df53ded6d6f402f5a5cfa390d9d35292e3f3ffb3e34c5432a3d30d", "0x1f9f04d096b7638ec149a9ac8ceb06acc268716f60ab8f4b5c1f7881498fb3cd"],
["0x0000000000000000000000000000000000000000000000000000000000000020"]
這里Verifier會(huì)調(diào)用verifyProof函數(shù)來(lái)對(duì)上述這堆東西進(jìn)行驗(yàn)證,這里可以把上面的那個(gè)智能合約導(dǎo)入到 remix來(lái)模擬一下,這里給一個(gè)網(wǎng)址:http://remix.ethereum.org/
進(jìn)去之后,右上角切換中文
打開(kāi)本地文件->上傳verifier.sol文件(地址:C:\circom\circuit_js)
?進(jìn)入SOLIDITY模塊
編譯verifier.sol文件
之后點(diǎn)左側(cè)第四個(gè)部署并運(yùn)行智能合約,這里選擇Verifier的合約
然后下面有一個(gè)已部署的智能合約,把上面得到的那一串?dāng)?shù)字粘貼到verifyProof里面,點(diǎn)一下call
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-798648.html
右側(cè)主界面可以看到正在調(diào)用,如果驗(yàn)證通過(guò)的話decode output這里會(huì)輸出true文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-798648.html
到了這里,關(guān)于密碼協(xié)議形式化分析與可證明安全實(shí)驗(yàn)——Cricom實(shí)驗(yàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!