本文介绍了 Circom 编程语言,它用于创建 Rank 1 Constraint Systems (R1CS) 并填充 R1CS 的 witness 向量,主要是为了简化约束系统的设计和自动化 witness 的生成。文章还解释了 Circom 存在的意义,以及它如何帮助开发者更轻松地进行零知识证明相关的开发,最后说明了学习 Circom 的理由,并概述了资源结构,包括语法和约束设计。
Circom 是一种用于创建 Rank 1 Constraint Systems (R1CS) 并填充 R1CS 的 witness 向量的编程语言。
R1CS 格式之所以引人关注,是因为该格式对于构建 SNARKs 非常有用,尤其是 Groth16。通过 SNARKs,我们可以实现可验证计算,从而能够证明计算的正确性。在验证时,感兴趣方花费较少的计算资源来确认正确性,而不是自己执行计算。也可以生成证明而不泄露底层数据,在这种情况下,我们将其称为 zkSNARKs。
我们 ZK 书的第一部分侧重于证明给定 R1CS 的 witness 的有效性。本资源侧重于如何以编程方式生成 R1CS,以及如何设计它们来模拟真实的算法,例如虚拟机或密码学哈希函数。
我们希望读者已经熟悉我们 ZK 书中的以下章节:
我们将假设读者了解什么是 R1CS 以及它代表什么。这在上面的四个章节中已得到充分解释。
没有必要完全理解 ZK 背后的数学原理才能使用 Circom,但是必须完全掌握一些原则,否则 Circom 将毫无意义。
尽管如此,如果读者想在 ZK 领域有所发展,那么学习 ZK 的基础知识必不可少。为此,我们强烈建议通读 ZK 书籍 的前两部分,并从头开始构建 Groth16 证明系统,以加强学习。
但是,如果读者的目标是快速了解 ZK 应用程序,那么我们建议阅读上面列出的四个章节,然后使用本资源。
创建 Circom 是为了解决为 SNARKs 开发约束系统中的两个主要问题。
因此,Circom 1) 简化了约束设计,并 2) 自动化了 witness 填充。
手动设计一组(正确的)约束,然后将其转换为 R1CS 的任务既繁琐又容易出错。创建 Circom 是为了通过以编程方式生成约束来使此任务更轻松且不那么繁琐。
例如,要说值 x
只能具有值 $\set{1,2,3}$,我们可以使用约束来表示:
$$ 0 === (x – 1) (x – 2) (x – 3) $$
但是,R1CS 每个约束只能有一个非恒定的乘法,因此我们必须将上述约束分解为两个约束:
$$ \begin{align} s &=== (x – 1)(x – 2) &&= x x – 3 * x + 2 \\
0 &=== s(x – 3) &&= x s – 3 s \end{align*} $$
对于小型系统,这种手动转换是可管理的。但是,如果我们需要为 100 甚至 1000 个变量创建此约束,则手动执行此操作将非常烦人。如果我们有数千个非常相似的约束,最好为约束创建一个“模板”并在 for 循环中生成约束。Circom 允许我们以编程方式创建这些约束。
例如,假设我们要约束 1,000 个变量具有值 $\set{0,1}$。Circom 可以通过循环生成这些值,如下所示:
template Constrain1000Example() {
signal input in[1000];
for (var i = 0; i < 1000; i++) {
0 === in[i] * (in[i] - 1);
}
}
component main = Constrain1000Example();
我们将在后面的章节中进一步解释语法,但核心思想是我们定义了一个约束 0 === in[i] * (in[i] - 1)
并重复了 1000 次。
ZK 上下文中的 witness 是对变量的赋值,该赋值满足算术电路中的所有约束。
正如我们在 算术电路 的文章中所看到的,证明一个数字小于另一个数字需要将两个数字都转换为二进制,因为“大于”在有限域中没有意义,因为数字会回绕。
以二进制形式表示数字 $x$,假设它适合四个位,则需要 $x$ 满足以下约束:
$$ \begin{align} x&===b_0+2b_1+4b_2+8b_3\\ 0&===b_0(b_0 – 1)\\ 0&===b_1(b_1 – 1)\\ 0&===b_2(b_2 – 1)\\ 0&===b_3(b_3 – 1) \end{align} $$
在这里,$b_0$ 是最低有效位,$b_3$ 是最高有效位。证明者必须提供 $b_0, b_1, b_2, b_3$,它们是 $x$ 的二进制位,以及 $x$ 本身。
在这种情况下,证明 $x$ 是一个四位数字变得更加繁琐,因为除了 $x$ 之外,我们还必须提供 $x$ 的二进制值,即使它们可以确定性且直接地导出。Circom 自动化了此过程,并允许我们编写代码以根据其他变量填充 witness 中的变量。例如,要填充二进制变量,我们可以编写以下 Circom 代码(...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!