使用 SnarkJS 和 Circom 进行零知识证明
2024-02-1722:56
登链社区
2024-02-17 22:56
登链社区
2024-02-17 22:56
收藏文章
订阅专栏

 

  • 原文链接:https://betterprogramming.pub/zero-knowledge-proofs-using-snarkjs-and-circom-fac6c4d63202
  • 译文出自:登链翻译计划[1]
  • 译者:张小风[2] ,校对:Tiny 熊[3]
  • 本文永久链接:learnblockchain.cn/article…[4]

摘要:本文介绍了如何使用 SnarkJS 和 Circom 在 JavaScript 项目中进行零知识证明。零知识证明技术的重要性在于可以证明拥有信息而无需透露,适用于匿名投票等场景。文章介绍了如何使用 Circom 编写电路,生成证明和验证密钥。此外,还讨论了 Circomlib 的使用以及在 JavaScript 中计算 poseidon hash 的方法。

img

Unsplash[5] 上的 Maria Cappelli[6] 拍摄的照片

简介

零知识证明[7] 技术,尤其是 zk-SNARK[8] ,是加密领域中最令人兴奋的技术之一,原因如下:

  • 你可以证明自己拥有信息,而无需透露它(例如,你可以用它进行匿名投票)。
  • 证明很小,易于在区块链上验证,因此可以用于 Rollup。

Rollup[9] 是一种区块链扩展解决方案,其中计算是在链下完成的,并且在一定数量的交易之后,状态会同步回区块链。这种解决方案为你提供了区块链的安全性(在同步之后),但证明所需的空间(和 gas)远小于原始交易。因此,zk-rollup 是区块链的理想扩展解决方案。

我之前有一篇文章[10] ,在其中展示了零知识证明是如何通过 Tornado Cash 代币混合器的源代码工作的。如果你对这项技术不熟悉,强烈建议在阅读本文之前阅读该文章。

在本文中,我将向你展示如何在 JavaScript 项目中使用 zk-SNARK。

Circom

如果你已经阅读了我的之前的文章[11] ,你就会知道,你需要一个电路来生成零知识证明。电路是系统用来计算输出和证明的巨大数学表达式。零知识证明本身就是证明你已成功进行了计算。

电路可能非常复杂,但幸运的是,有电路编程语言和库,可以轻松编写自己的电路。我们将使用 Circom[12]。Circom 是用 Rust 编写的。要安装它,你必须使用以下命令安装 Rust 环境:

curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh

Rust 安装完成后,克隆 Circom 存储库并构建编译器:

git clone https://github.com/iden3/circom.git
cd circom
cargo build --release
cargo install --path circom

如果一切顺利,现在你已经安装了 Circom 编译器。

我们需要的另一样东西是 circomlib[13]。Circomlib 是一个带有许多有用的预定义电路的编程库。因此,创建一个空项目,并使用以下代码安装 circomlib:

npm init
npm i circomlib

现在,一切都准备好创建我们的电路了。以下是它的样子:

pragma circom 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();

这个简单的电路有一个私有输入和输出信号[14] 。我们使用 circomlib 中的 poseidon hasher 生成输入 hash。使用这个电路,我们可以证明我们知道给定 hash 的原始数据,而无需透露它。

首先,我们通过 circom 编译器编译电路,它将生成一个 wasm 文件和一个 r1cs 文件。

circom poseidon_hasher.circom --wasm --r1cs -o ./build

生成的 wasm 和 r1cs 文件可在 build 文件夹中找到。要生成证明,我们需要一个 proving key 文件,要生成此文件,我们需要一个 ptau 文件。可以使用 snarkjs[15] 生成此 ptau 文件,或者你可以下载一个预生成的文件(你可以在 snarkjs 存储库中找到链接)。对于测试,生成的文件对我们来说就足够了,但在你的生产应用中,建议进行仪式并生成自己的 ptau 文件(你可以在我的之前的文章[16]中了解更多)。

wget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_12.ptau

现在,我们可以使用电路和 ptau 文件生成 proving key(zkey 文件):

npx snarkjs groth16 setup build/poseidon_hasher.r1cs powersOfTau28_hez_final_12.ptau circuit_0000.zkey

不建议在生产中使用此 zkey 文件,但对于测试,对我们来说就足够了(有关更多信息,请查看 snarkjs 文档[17])。

snarkjs

现在,一切都准备好生成证明了。我们将使用 snarkjs,因此使用以下命令安装它:

npm i snarkjs

生成证明的过程如下:

const { proof, publicSignals } = await snarkjs.groth16.fullProve(
  { in10 }, 
  "build/poseidon_hasher_js/poseidon_hasher.wasm"
  "circuit_0000.zkey");
console.log(publicSignals);
console.log(proof);

输入信号作为 fullProve 函数的第一个参数传递。第二个参数是编译后的电路,最后一个参数是生成的 proving key。该函数返回电路的输出和证明。

我们需要一个验证密钥,可以从 proving key 生成以验证证明。以下是如何获取它:

npx snarkjs zkey export 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;

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。只有在给定的 hash 是给定数据的 poseidon hash 时,电路才会成功运行。但是我们如何在 JS 中计算 poseidon hash 呢?

Circomlib 有一个 JS 实现[18] ,可以用于此目的。让我们安装它:

npm i circomlibjs

现在,我们可以使用以下代码计算 hash

 const poseidon = await circomlibjs.buildPoseidon();
 const hash = poseidon.F.toString(poseidon([10]));
 console.log(hash);

poseidon 函数的结果是一个 Buffer,我们必须将其转换为数字。在 zk-SNARK 中,每个计算都是在有限域[19]中进行的,因此我们必须使用 poseidon.F.toString 进行转换。

Circomlibjs 和 snarkjs 在 Node.js 和浏览器中都能很好地工作,因此你可以在客户端生成或验证证明。还可以生成用于验证的智能合约,你可以将其用于 Solidity 代码中验证证明(有关更多信息,请查看 snarkjs 文档[20])。

Circomlibjs 还具有智能合约生成器。例如,如果你想在链上生成 poseidon hash,可以通过生成的代码实现。

这是我关于在 JavaScript 中使用 zk-SNARK 的非常简短的教程。这不是一个完整的课程,你可能有很多问题,但我希望我能帮助你开始你的旅程。Circom[21]snarkjs[22] 都有很好的文档,你还可以从像 Tornado Cash[23] 这样的现有项目中学到很多。

这个教程的源代码可以在这个 GitHub 仓库[24]中找到。


本翻译由 DeCert.me[25] 协助支持, 在 DeCert 构建可信履历,为自己码一个未来。


登链社区是区块链开发者的家园,在这里不仅可以阅读文章、学习课程、参与问答与讨论,还可以发布活动、进行人才招募。我们帮助开发者更好的进入 web3 。


学习系统的技术内容 / 发布活动、招聘

https://learnblockchain.cn/


开发者的链上技能认证平台

https://decert.me/


给开发者的开源、免费工具箱

https://chaintool.tech/


关注社区 Twitter

@UpchainDAO


加入社区 Discord

https://discord.gg/pZxy3CU8mh


加入微信群

参考资料

[1]

登链翻译计划: https://github.com/lbc-team/Pioneer

[2]

张小风: https://learnblockchain.cn/people/74

[3]

Tiny 熊: https://learnblockchain.cn/people/15

[4]

learnblockchain.cn/article…: https://learnblockchain.cn/article/7403

[5]

Unsplash: https://unsplash.com/?utm_source=medium&utm_medium=referral

[6]

Maria Cappelli: https://unsplash.com/@rikku72?utm_source=medium&utm_medium=referral

[7]

零知识证明: https://learnblockchain.cn/tags/%E9%9B%B6%E7%9F%A5%E8%AF%86%E8%AF%81%E6%98%8E

[8]

zk-SNARK: https://en.wikipedia.org/wiki/Non-interactive_zero-knowledge_proof

[9]

Rollup: https://learnblockchain.cn/article/1977

[10]

文章: https://learnblockchain.cn/article/7402

[11]

之前的文章: https://learnblockchain.cn/article/7402

[12]

Circom: https://iden3.io/circom

[13]

circomlib: https://github.com/iden3/circomlib

[14]

信号: https://docs.circom.io/circom-language/signals/

[15]

snarkjs: https://github.com/iden3/snarkjs

[16]

之前的文章: https://learnblockchain.cn/article/7402

[17]

snarkjs 文档: https://github.com/iden3/snarkjs

[18]

JS 实现: https://github.com/iden3/circomlibjs

[19]

有限域: https://en.wikipedia.org/wiki/Finite_field

[20]

snarkjs 文档: https://github.com/iden3/snarkjs

[21]

Circom: https://docs.circom.io/

[22]

snarkjs: https://github.com/iden3/snarkjs/blob/master/README.md

[23]

Tornado Cash: https://github.com/tornadocash/tornado-core

[24]

这个 GitHub 仓库: https://github.com/TheBojda/zksnark-tutorial

[25]

DeCert.me: https://decert.me/

【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。

专栏文章
查看更多
数据请求中

推荐专栏

数据请求中

一起「遇见」未来

DOWNLOAD FORESIGHT NEWS APP

Download QR Code