零知识证明之 SnarkJS 入门

本文深入介绍了零知识证明的概念,重点讲解了circom和snarkJS的使用,包括circom编译器的基础、零知识证明流程、snarkJS的安装与配置。通过实际操作演示了如何生成和验证零知识证明,包括设置生成、见证计算、证明生成与验证,以及在以太坊上部署Solidity验证器。文章还讨论了漏洞修复和零知识证明在zk rollup实现中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、SnarkJS相关基础

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

什么是SnarkJS

snarkjs是zkSARNK方案的 javascript 实现库,支持原始的8points协议和 Groth协议。利用snarkjs你可以进行可信设置、生成证据并验证证据。

snarkjs使用iden3自己的circom编译器对DSL定义的电路进行编译。
像iden3的SnarkJS这样的新工具首次启用了浏览器内高效的ZK验证和验证。

1. 什么是circom

circom下载地址:https://github.com/iden3/circom

circom是iden3设计的zk-snark电路描述DSL,circom npm包含了使用该DSL描述的电路的编译器。

2. 零知识证明的基本概念

【强烈推荐】zk-snark新手入门教程【circom/snarkjs】
参考URL: https://zhuanlan.zhihu.com/p/143519030

1、算术电路:零知识证明核心

零知识程序和其他程序的实现不太一样。首先,你要解决的问题需要先转化成多项式,再进一步转化成电路。

例如,多项式x³ + x +5 可以表示成如下的电路:

sym_1 = x * x // sym_1 = x² 
sym_2 = sym_1 * x // sym_2 = x³ 
y = sym_2 + x // y = x³ + x 
~out = y + 5

**Circom编译器将逻辑转换为电路。通常我们不需要自己设计基础电路。**如果你需要一个哈希函数或签名函数,可以在circomlib (https://github.com/iden3/circomlib) 找到。

2、证据的生成与验证:零知识证明的流程

在运行零知识证明程序之前,我们需要创建一个可信的设置,这需要 一个电路以及一些随机数。一旦设置完成就会生成一个证明密钥和一个验证密钥,分别用于生成证据和执行验证。

在这里插入图片描述
一旦创建了证明/验证密钥对,就可以生成证据了。

有两种类型的输入:公开输入和私有输入。例如,A向B转账但是不希望公开账户余额,那么A的账户余额就是私有输入,也被称为见证(Witness)。公开输入可以是A和B的地址或者转账金额,这完全取决于你的具体设计。

接下来证明人就可以利用证明密钥、公开输入和见证来生成证据:
在这里插入图片描述
最后一步是验证。验证方使用公开输入、证据和验证密钥来验证证据。
在这里插入图片描述
公开输入、见证(私有输入)、证明密钥、验证密钥、电路、证据这些基本概念以及相互之间的关系,就是我们继续下面的教程之前需要理解的零知识证明的基本概念。

3、Circom基本概念:算术电路语言

首先我们先了解下Circom的语法。Circom的语法类似javascript和C,提供一些基本的数据类型和操作,例如for、while、>>、array等。

让我们看一个具体的实例。

假设x、y是保密的(即witness),我们不想暴露x和y的具体值,但是希望证明 (x * y) + z == out,其中z,out是公开输入。我们假设out = 30, z = 10, 那么显然 (x*y) = 20,但是这不会暴露x和y的具体值。

circom提供了如下这些关键字用于描述算术电路:

  • signal:信号变量,要转换为电路的变量,可以是private或public
  • template:模板,用于函数定义,就像Solidity中的function或golang中的func
  • component:组件变量,可以把组件变量想象成对象,而信号变量是对象的公共成员

Circom也提供了一些操作符用于操作信号变量:

  • <==, ==>:这两个操作符用于连接信号变量,同时定义约束
  • ←, →:这些操作符为信号变量赋值,但不会生成约束条件
  • ===:这个操作符用来定义约束

二、如何使用snarkJS

https://github.com/iden3/snarkjs

1. 准备工作

安装 node v14

首先,请确保您已安装最新版本的Node.js。 尽管v12之后的任何版本都可以正常运行,但我们建议您安装v14或更高版本。

如果不确定安装的是哪个版本的Node,可以运行:

node -v

node 下载地址:https://nodejs.org/zh-cn/download/

安装snarkjs and circom

安装circom and snarkjs, 运行:

npm install -g circom@latest
npm install -g snarkjs@latest

snarkjs help命令

要查看所有snarkjs命令的列表以及它们的输入和输出说明,请运行:

snarkjs --help

您还可以在特定命令中使用–help选项:

snarkjs groth16 prove --help

您还可以在特定命令中使用–help选项:

snarkjs groth16 prove --help

大多数命令都有一个替代的较短别名(您可以使用–help来发​​现)。
例如,也可以使用以下命令调用前一个命令:

snarkjs g16p --help

2. 官方demo:用circom和snarkjs实现零知识证明应用的全流程

官方文档:https://docs.circom.io/1.-an-introduction/getting-started
官方参考:https://github.com/iden3/circom/blob/master/TUTORIAL.md
参考: https://cloud.tencent.com/developer/article/1638822

经过验证https://docs.circom.io/1.-an-introduction/getting-started 似乎比github 更新,所以推荐 参考 https://docs.circom.io/1.-an-introduction/getting-started

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

创建一个电路目录

创建一个 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 输入信号,名为 a 和 b ,还有一个输出 c.

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

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

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

编译电路

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

circom circuit.circom --r1cs --wasm --sym

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

  • r1cs选项将生成circuit.r1cs(电路的r1cs约束系统,采用二进制格式)。

  • wasm选项将生成circuit.wasm(用于生成见证的wasm代码)。

  • sym选项将生成circuit.sym(调试或如果要以注释模式打印约束系统所需的符号文件)。

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

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

查看电路有关的信息

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

root@VM-0-2-ubuntu:~/factor# snarkjs info -r circuit.r1cs
[INFO]  snarkJS: Curve: bn-128
[INFO]  snarkJS: # of Wires: 4
[INFO]  snarkJS: # of Constraints: 1
[INFO]  snarkJS: # of Private Inputs: 2
[INFO]  snarkJS: # of Public Inputs: 0
[INFO]  snarkJS: # of Labels: 4
[INFO]  snarkJS: # of Outputs: 1
root@VM-0-2-ubuntu:~/factor# 

打印约束(Print the constraints)

root@VM-0-2-ubuntu:~/factor# snarkjs r1cs print circuit.r1cs circuit.sym
[INFO]  snarkJS: [ 21888242871839275222246405745257275088548364400416034343698204186575808495616main.a ] * [ main.b ] - [ 21888242871839275222246405745257275088548364400416034343698204186575808495616main.c ] = 0

我的第一个零知识证明demo

Now that the circuit is compiled, we will use snarkJS to generate and validate zk-SNARK proofs. More specifically, we will prove that we are able to factor the number 33. That is, we will show that we know two integers a and b such that when we multiply them, it results in 33.

现在,电路已编译完毕,我们将使用snarkJS生成并验证zk-SNARK证明。 更具体地说,我们将证明我们能够分解数字33。也就是说,我们将证明我们知道两个整数a和b,以便将它们相乘时得出33。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西京刀客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值