12

circom 及 snarkjs 入门教程[译]

 3 years ago
source link: https://learnblockchain.cn/article/1078
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

本教程是circom 和 snarkjs 最经典的入门文章

在本教程里将指导您创建第一个零知识zkSnark电路。 它将介绍各种编写电路的技术,并向您展示如何创建证明并在以太坊上进行链外和链上验证。

1. 安装工具

1.1 先决条件

需要在电脑中安装 Node.js ,Node.js 的最新的稳定版本(或8.12.0)可以正常工作。 不过,如果您安装了当前的最新版本的Node.js(10.12.0),将会看到显着的性能提升。 这是因为最新版本本身包含大数库(Big Integer Libraries)。 snarkjs 库会利用这些特性(如果可用的话),从而将性能提高10倍(!)。

1.2 安装 circom 和 snarkjs

运行:

npm install -g circom
npm install -g snarkjs

2. 使用 circuit

让我们创建一个电路,去 证明你能够因式分解一个数字

2.1 创建一个电路目录

  1. 创建一个 factor 目录,教程里的所有文件都将放在这个下面
mkdir factor
cd factor

​ 在真实的电路中,您可能需要创建一个 git 仓库,其中包含 circuits 目录和一个包含所有测试的 test 目录,以及用于构建所有电路的脚本。

  1. 使用下面的内容创建一个 circuit.circom 文件:
template Multiplier() {
   signal private input a;
   signal private input b;
   signal output c;
   c <== a*b;
}

component main = Multiplier();

这个电路有2个 private 输入信号,名为 ab ,还有一个输出 c .

电路做的事情是让强制信号 ca*b 的值。

在声明 Multiplier 模板之后, 我们使用名为 main 的组件实例化它。

注意:编译电路时,必须始终有一个名为 main 的组件。

2.2 编译电路

现在,我们准备编译电路。 运行以下命令:

circom circuit.circom -r circuit.r1cs

将电路编译为名为 circuit.rlcs 的文件

3. 将编译后的电路放入 snarkjs

现在电路已经编译好了,我们将继续使用 snarkjs

我们随时可以通过输入 snarkjs --help 来访问 snarkjs 的帮助

3.1 查看电路有关的信息

要显示电路的信息,可以运行:

> snarkjs info -r circuit.r1cs
# Wires: 4
# Constraints: 1
# Private Inputs: 2
# Public Inputs: 0
# Outputs: 1

还可以通过运行以下命令来打印电路的约束:

snarkjs printconstraints -r circuit.r1cs

3.2 用 snarkjs 启动配置

现在为电路运行启动配置:

snarkjs setup

默认 snarkjs 将寻找和使用 circuit.r1cs . 我们也可以用 -r <circuit r1csFile> 来指定一个电路文件。

setup 将输出2 个文件: proving_key.json and verification_key.json

3.3. 计算见证(witness)

在创建任何证明之前,我们需要计算与(所有)电路约束匹配的所有电路信号。

snarkjs 会帮我们计算这些。 我们需要提供一个包含输入的文件,它将执行电路并计算所有中间信号和输出。 这组信号就是“见证”。

零知识证明证明你知道一组与所有约束匹配的信号(见证),但不透露任何信号(公共输入和输出除外)。

例如,想像一下,你想证明自己能够因式分解33,这意味着你知道两个数 ab ,将它们相乘为 33。

因此,您想证明自己知道3和11。(当然,你可以始终使用1 和 数字本身作为 ab ,我们稍后将处理此问题。)

让我们创建一个 input.json 文件:

{"a": 3, "b": 11}

现在计算见证:

snarkjs calculatewitness

这时会生成包含所有信号的见证文件 witness.json , 可以打开看一看。

译者注,如果遇到提示 :Error: ENOENT: no such file or directory, open 'circuit.wasm' ERROR: Error: ENOENT: no such file or directory, open 'circuit.wasm'

就用 circom circuit.circom -w circuit.wasm 生成一个 circuit.wasm 在执行一次见证。

生成证明

现在我们已经生成了见证信息,我们可以创建证明了。

snarkjs proof

这个命令默认会使用 prooving_key.jsonwitness.json 文件去生成 proof.jsonpublic.json

proof.json 文件包好了实际的证明。而 public.json 文件将仅包含公开的输入和输出值。

验证证明

验证证明运行命令:

> snarkjs verify
OK

这个命令会使用 verification_key.json , proof.jsonpublic.json 来验证有效性。

这里我们证明我们知道一个见证,见证着公共输入和输出与 public.json 文件中的输入和输出匹配。

如果验证通过会输出 OK , 否则会显示 INVALID

生成 Solidity 验证者

snarkjs generateverifier

这个命令将使用到 verification_key.json 并生成一个 solidity 代码文件: verifier.sol

可以复制 verifier.sol 代码到 remix 进行部署。

verifier.sol 包含两个合约: Pairings 和 Verifier, 你只需要部署 Verifier 合约。

可以使用Rinkeby,Kovan或Ropsten等测试网,也可以使用 Javascript VM ,也许在某些浏览器中,验证会花很长时间,并且可能会挂起页面,请知晓。

链上验证证明

上面生成的 Verifier 合约有一个view 视图函数 verifyProof , 如果证明和输入正确,这个函数会返回 true .

The verifier contract deployed in the last step has a view function called verifyProof .

为了方便调用,可以使用snarkjs通过输入以下命令来生成调用的参数:

snarkjs generatecall

这命令的输出复制到 Remix 中的 verifyProof 方法的 parameters 字段中,调用 verifyProof

如果一切正常,方法应该返回 true

如果仅更改参数中的任何位,则可以检查结果返回 false 。

漏洞修复

签名提到了一个漏洞,现在来通过添加一些额外的约束修复电路。

我们约束不接受 1 作为任何一个值,这里使用 0 不可逆的特性,即 (a-1) 不可逆。

如果 a 是 1 则 (a-1)*inv = 1 是不可能成立的, 通过 1/(a-1) 来计算 inv 。

修改电路:

template Multiplier() {
   signal private input a;
   signal private input b;
   signal output c;
   signal inva;
   signal invb;

   inva <-- 1/(a-1);
   (a-1)*inva === 1;
   invb <-- 1/(b-1);
   (b-1)*invb === 1;

   c <== a*b;
}

component main = Multiplier();

circom 语言的一个好处是可以把 <== 分为两个动作 : <--===

<----> 操作符运算符只为信号分配一个值,而不创建任何约束。

=== 操作符添加约束而不分配值。

该电路还有另一个问题,那就是该运算可以在 Zr 中工作,因此我们还必须保证乘法不会溢出。 这可以通过二进制化输入并检查范围来修复,让我们留着在之后的教程里介绍。

探索更多

阅读我们的 代码库 了解更多 circom 的特性。

我们写好了一些基本的电路,如:binaritzations、comparators, eddsa, hashes, merkle trees 等等,可以在 circomlib 找到,还有更多电路在开发中。

小结

对于开发人员而言,没有什么比使用buggy 编译器更糟糕的了。现在依旧是编译器的早期阶段,因此存在许多错误,并且需要完成许多工作。

如有任何问题,请与我们联系。哪怕是一小段修复 bug 的代码。

最后,享受零知识证明!

原文链接:https://iden3.io/blog/circom-and-snarkjs-tutorial2.html

在本教程里将指导您创建第一个零知识zkSnark电路。 它将介绍各种编写电路的技术,并向您展示如何创建证明并在以太坊上进行链外和链上验证。

1. 安装工具

1.1 先决条件

需要在电脑中安装 Node.js ,Node.js 的最新的稳定版本(或8.12.0)可以正常工作。 不过,如果您安装了当前的最新版本的Node.js(10.12.0),将会看到显着的性能提升。 这是因为最新版本本身包含大数库(Big Integer Libraries)。 snarkjs 库会利用这些特性(如果可用的话),从而将性能提高10倍(!)。

1.2 安装 circom 和 snarkjs

运行:

npm install -g circom
npm install -g snarkjs

2. 使用 circuit

让我们创建一个电路,去 证明你能够因式分解一个数字

2.1 创建一个电路目录

  1. 创建一个 factor 目录,教程里的所有文件都将放在这个下面

    mkdir factor
    cd factor

​ 在真实的电路中,您可能需要创建一个 git 仓库,其中包含 circuits 目录和一个包含所有测试的 test 目录,以及用于构建所有电路的脚本。

  1. 使用下面的内容创建一个 circuit.circom 文件:
template Multiplier() {
   signal private input a;
   signal private input b;
   signal output c;
   c <== a*b;
}

component main = Multiplier();

这个电路有2个 private 输入信号,名为 ab ,还有一个输出 c .

电路做的事情是让强制信号 ca*b 的值。

在声明 Multiplier 模板之后, 我们使用名为 main 的组件实例化它。

注意:编译电路时,必须始终有一个名为 main 的组件。

2.2 编译电路

现在,我们准备编译电路。 运行以下命令:

circom circuit.circom -r circuit.r1cs

将电路编译为名为 circuit.rlcs 的文件

3. 将编译后的电路放入 snarkjs

现在电路已经编译好了,我们将继续使用 snarkjs

我们随时可以通过输入 snarkjs --help 来访问 snarkjs 的帮助

3.1 查看电路有关的信息

要显示电路的信息,可以运行:

> snarkjs info -r circuit.r1cs
# Wires: 4
# Constraints: 1
# Private Inputs: 2
# Public Inputs: 0
# Outputs: 1

还可以通过运行以下命令来打印电路的约束:

snarkjs printconstraints -r circuit.r1cs

3.2 用 snarkjs 启动配置

现在为电路运行启动配置:

snarkjs setup

默认 snarkjs 将寻找和使用 circuit.r1cs . 我们也可以用 -r <circuit r1csFile> 来指定一个电路文件。

setup 将输出2 个文件: proving_key.json and verification_key.json

3.3. 计算见证(witness)

在创建任何证明之前,我们需要计算与(所有)电路约束匹配的所有电路信号。

snarkjs 会帮我们计算这些。 我们需要提供一个包含输入的文件,它将执行电路并计算所有中间信号和输出。 这组信号就是“见证”。

零知识证明证明你知道一组与所有约束匹配的信号(见证),但不透露任何信号(公共输入和输出除外)。

例如,想像一下,你想证明自己能够因式分解33,这意味着你知道两个数 ab ,将它们相乘为 33。

因此,您想证明自己知道3和11。(当然,你可以始终使用1 和 数字本身作为 ab ,我们稍后将处理此问题。)

让我们创建一个 input.json 文件:

{"a": 3, "b": 11}

现在计算见证:

snarkjs calculatewitness

这时会生成包含所有信号的见证文件 witness.json , 可以打开看一看。

译者注,如果遇到提示 :Error: ENOENT: no such file or directory, open 'circuit.wasm' ERROR: Error: ENOENT: no such file or directory, open 'circuit.wasm'

就用 circom circuit.circom -w circuit.wasm 生成一个 circuit.wasm 在执行一次见证。

生成证明

现在我们已经生成了见证信息,我们可以创建证明了。

snarkjs proof

这个命令默认会使用 prooving_key.jsonwitness.json 文件去生成 proof.jsonpublic.json

proof.json 文件包好了实际的证明。而 public.json 文件将仅包含公开的输入和输出值。

验证证明

验证证明运行命令:

> snarkjs verify
OK

这个命令会使用 verification_key.json , proof.jsonpublic.json 来验证有效性。

这里我们证明我们知道一个见证,见证着公共输入和输出与 public.json 文件中的输入和输出匹配。

如果验证通过会输出 OK , 否则会显示 INVALID

生成 Solidity 验证者

snarkjs generateverifier

这个命令将使用到 verification_key.json 并生成一个 solidity 代码文件: verifier.sol

可以复制 verifier.sol 代码到 remix 进行部署。

verifier.sol 包含两个合约: Pairings 和 Verifier, 你只需要部署 Verifier 合约。

可以使用Rinkeby,Kovan或Ropsten等测试网,也可以使用 Javascript VM ,也许在某些浏览器中,验证会花很长时间,并且可能会挂起页面,请知晓。

链上验证证明

上面生成的 Verifier 合约有一个view 视图函数 verifyProof , 如果证明和输入正确,这个函数会返回 true .

The verifier contract deployed in the last step has a view function called verifyProof .

为了方便调用,可以使用snarkjs通过输入以下命令来生成调用的参数:

snarkjs generatecall

这命令的输出复制到 Remix 中的 verifyProof 方法的 parameters 字段中,调用 verifyProof

如果一切正常,方法应该返回 true

如果仅更改参数中的任何位,则可以检查结果返回 false 。

漏洞修复

签名提到了一个漏洞,现在来通过添加一些额外的约束修复电路。

我们约束不接受 1 作为任何一个值,这里使用 0 不可逆的特性,即 (a-1) 不可逆。

如果 a 是 1 则 (a-1)*inv = 1 是不可能成立的, 通过 1/(a-1) 来计算 inv 。

修改电路:

template Multiplier() {
   signal private input a;
   signal private input b;
   signal output c;
   signal inva;
   signal invb;

   inva <-- 1/(a-1);
   (a-1)*inva === 1;
   invb <-- 1/(b-1);
   (b-1)*invb === 1;

   c <== a*b;
}

component main = Multiplier();

circom 语言的一个好处是可以把 <== 分为两个动作 : <--===

<----> 操作符运算符只为信号分配一个值,而不创建任何约束。

=== 操作符添加约束而不分配值。

该电路还有另一个问题,那就是该运算可以在 Zr 中工作,因此我们还必须保证乘法不会溢出。 这可以通过二进制化输入并检查范围来修复,让我们留着在之后的教程里介绍。

探索更多

阅读我们的 代码库 了解更多 circom 的特性。

我们写好了一些基本的电路,如:binaritzations、comparators, eddsa, hashes, merkle trees 等等,可以在 circomlib 找到,还有更多电路在开发中。

小结

对于开发人员而言,没有什么比使用buggy 编译器更糟糕的了。现在依旧是编译器的早期阶段,因此存在许多错误,并且需要完成许多工作。

如有任何问题,请与我们联系。哪怕是一小段修复 bug 的代码。

最后,享受零知识证明!

原文链接: https://iden3.io/blog/circom-and-snarkjs-tutorial2.html

本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 5分钟前
  • 阅读 ( 7 )
  • 学分 ( 0 )
  • 分类:零知识证明

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK