使用 SnarkJS 和 Circom 的零知识证明

本文介绍了如何使用JavaScript中的zk-SNARK技术,特别是通过Circom和SnarkJS库来生成和验证零知识证明。首先解释了零知识证明的基本概念及其在区块链中的应用,接着介绍了如何安装Circom和SnarkJS,并详细说明了如何编写电路代码以生成证明,最后展示了验证证明的步骤。读者在完成后应该对如何在JavaScript项目中实现zk-SNARK有初步的理解和实践能力。

一份 JavaScript 教程

照片由 Maria Cappelli 供稿于 Unsplash

零知识证明 技术,特别是 zk-SNARK,是加密领域中最令人兴奋的技术之一,原因如下:

  • 你可以证明你拥有信息而不透露它(例如,你可以用于匿名投票)。
  • 证明体积小且易于在区块链上验证,因此可以用于 rollups。

Rollup 是一种区块链扩展解决方案,在该方案中,计算在链外完成,在一定数量的交易后,状态会同步回区块链。这一解决方案让你在同步后享有区块链的安全性,但证明所需的空间大大减少(而且所需的 gas 也更少),因此 zk-rollups 是区块链的理想扩展解决方案。

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

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

如果你读过我的 上一篇文章,你就知道你需要一个电路来生成零知识证明。电路是一个庞大的数学表达式,用于系统计算输出和证明。零知识证明本身证明了你成功地进行了计算。

电路可以非常复杂,但幸运的是,有电路编程语言和库,使其易于编写自己的电路。我们将使用 Circom。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。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();

这个简单的电路有一个私有输入和一个输出 signal。我们正在使用 circomlib 中的 poseidon 哈希函数来生成输入 hash。使用该电路,我们可以证明我们知道给定 hash 的原始数据而不泄露它。

在第一步中,我们通过 circom 编译器编译电路,将生成一个 wasm 和一个 r1cs 文件。

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

生成的 wasm 和 r1cs 文件在 build 文件夹中可用。要生成证明,我们需要一个证明密钥文件,并且生成此文件需要一个 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 文档)。

现在,一切准备就绪,可以生成证明。我们将使用 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.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 是给定数据的 poseidon hash 时,电路才会成功运行。但是,我们如何在 JS 中计算 poseidon hash

Circomlib 有一个 JS 实现 可以用来做这个。让我们安装它:

npm i circomlibjs

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

 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 代码中使用它来验证证明。(有关更多信息,请查看 snarkjs 文档。)

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

这就是我关于在 JavaScript 中使用 zk-SNARK 的简短教程。这不是一门完整的课程,你可能会有许多问题,但我希望我能帮助你开始你的旅程。Circomsnarkjs 文档很好,你也可以从现有项目中学到很多,例如 Tornado Cash

本教程的源代码可在 此 GitHub 仓库 中找到。

  • 原文链接: medium.com/better-progra...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,在这里修改,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
better-programming
better-programming
江湖只有他的大名,没有他的介绍。