保姆級教程:如何在JavaScript 項目中使用zk-SNARK

在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 查看更多精彩資訊

Total
0
Shares
Related Posts