在JavaScript 中使用zk-SNARK 的簡易教程請拿好。
原文標題:《Zero-Knowledge Proofs Using SnarkJS and Circom》
撰文:Laszlo Fazekas
編譯:ChinaDeFi
零知識證明技術,尤其是zk-SNARK 技術是加密領域最令人興奮的技術之一,因為:
- 我們可以在不洩漏具體信息的同時證明該信息。
- 證明很小,很容易在區塊鏈上進行驗證,所以可以Rollup。
Rollup 是一種區塊鏈擴展解決方案,其計算是在鏈下完成的,在給定數量的交易後,狀態將同步回區塊鏈,這種解決方案可以為我們提供區塊鏈的安全性和更低的gas 費,所以我們說zk-Rollup 是區塊鏈的理想擴展解決方案。
在本文中,作者會向我們展示如何在JavaScript 項目中使用zk-SNARK。
眾所周知,我們需要一個電路來生成零知識證明。電路是系統用來計算輸出和證明的數學表達式。零知識證明本身就是我們已經成功完成計算的證明。
電路可能會非常複雜,但好在有電路編程語言和庫可以讓我們比較輕鬆的編寫自己的電路。在本文中我們會使用Circom。 Circom 是用Rust 編寫的。可以使用以下命令來安裝Rust 環境。
curl –proto ‘=https’ –tlsv1.2 https://sh.rustup.rs -sSf | sh’=https’ –tlsv1.2 https://sh.rustup.rs -sSf | sh
安裝完Rust 後,克隆Circom 存儲庫並構建編譯器:
git clone https://github.com/iden3/circom.gitclone https://github.com/iden3/circom.gitcd circomcargo build –releasecargo install –path circom
如果這過程中沒有差池,那麼我們已經安裝好了Circom 編譯器。
現在還需要解決Circomlib,Circomlib 是一個包含許多有用的預定義電路的編程庫。因此,創建一個空項目,並使用以下代碼安裝Circomlib:
npm initinitnpm i circomlib
現在,我們已經為創建電路做好了準備,下面是它應該看起來的樣子:
pragma circom 2.0.0;2.0.0;include “node_modules/circomlib/circuits/poseidon.circom”;template PoseidonHasher() {signal input in;signal output out;component poseidon = Poseidon(1);poseidon.inputs[0] <== in;out <== poseidon.out;}component main = PoseidonHasher();
這個簡單的電路,有一個專用輸入和一個輸出信號。我們正在使用Circomlib 中的poseidon 哈希計算器來生成輸入hash。使用此電路,可以證明我們已經知道給定的原始數據hash,但不需要透露它。
在第一步中,可以通過Circom 編譯器來編譯電路,該編譯器將生成一個wasm 和rlcs 文件。
circom poseidon_hasher.circom –wasm –r1cs -o ./build
生成的wasm 和rlcs 文件在構建文件夾中可用。要生成證明,我們需要一個證明密鑰文件,而要生成這個文件,我們就需要一個ptau 文件。該ptau 文件可以由snarkjs 生成。或者也可以下載一個預生成的文件(可以在snarkjs 存儲庫中找到鏈接)。關於測試,生成的文件對我們有些好處,但在我們生產應用程序中,建議生成自己的ptau。
wget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_12.ptau
現在可以使用電路和ptau 文件生成證明密鑰(zkey 文件):
npx snarkjs groth16 setup build/poseidon_hasher.r1cs powersOfTau28_hez_final_12.ptau circuit_0000.zkey
不建議將此zkey 文件用於生產,但對於測試,它對我們有幫助。
現在,我們已經準備好生成證明了。這其中會用到snarkjs,所以用下面的命令進行安裝:
npm i snarkjs
證明生成如下所示:
const { proof, publicSignals } = await snarkjs.groth16.fullProve({ in: 10 },”build/poseidon_hasher_js/poseidon_hasher.wasm”,”circuit_0000.zkey”);console.log(publicSignals);console.log(proof);
輸入信號在函數的第一個參數中傳遞fullProve。第二個參數是編譯電路,最後一個參數是生成的證明密鑰。該函數反饋電路的輸出和證明。
現在我們需要一個可以從證明密鑰生成的驗證密鑰來驗證證明。獲取方法如下:
npx snarkjs zkey export verificationkey circuit_0000.zkey verification_key.jsonexport verificationkey circuit_0000.zkey verification_key.json 驗證碼如下:const vKey = JSON.parse(fs.readFileSync(“verification_key.json”));const res = await snarkjs.groth16.verify(vKey, publicSignals, proof);if (res === true) {console.log(“Verification OK”);} else {console.log(“Invalid proof”);}
驗證密鑰是verify 函數的第一個參數,輸出和證明是第二和第三個參數。該函數的結果是一個簡單的布爾值。
在此例子中,我們使用電路來計算hash,但這並不總是可行的,因為hash 可以使部分結果,或者我們的電路看起來像如下所示:
pragma circom 2.0.0;2.0.0;include “node_modules/circomlib/circuits/poseidon.circom”;template PoseidonHasher() {signal input in;signal input hash;component poseidon = Poseidon(1);poseidon.inputs[0] <== in;hash === poseidon.out;}component main {public [hash]} = PoseidonHasher();
這個電路沒有輸出,只有兩個輸入。第一個輸入是數據,第二個輸入是數據的哈希。在模板的最後一行,我們檢查hash。只有給定的hash 是給定數據的poseidon hash,電路才會成功運行。但是要如何在JS 中計算poseidon hash 呢?
Circomlib 有一個可以用於此的JS 實現。需要我們安裝它:
npm i circomlibjs
現在我們可以用下面的代碼來進行計算:
const poseidon = await circomlibjs.buildPoseidon();const poseidon = await circomlibjs.buildPoseidon();const hash = poseidon.F.toString(poseidon([10]));console.log(hash);
該poseidon 函數結果是Buffer,我們需要將其轉換為數字。在zk-SNARK 中,每次計算都是在有限域中完成的,所以我們必須使用poseidon.F.toString 進行轉換。
Circomlibjs 和snarkjs 在Node.js 和瀏覽器中運行良好,所以我們可以在客戶端生成或驗證證明,還可以生成用於驗證的智能合約。這樣我們就可以在Solidity 代碼中使用它來驗證證明。
Circomlibjs 也有智能合約生成器。
這是在JavaScript 中使用zk-SNARK 的簡短教程,它不是一個完整教程,大家可能還存有很多問題,我們可以藉助Circom 和snarkjs,他們都有很好的文檔記錄,我們也可以從Tornado Cash 等現有項目中學到很多東西。
展開全文打開碳鏈價值APP 查看更多精彩資訊