将代数电路转换为R1CS(一阶约束系统)

文章详细介绍了如何将一组算术约束转换为Rank One Constraint System (R1CS),涵盖了转换中的优化和Circom库的实现方法。

这篇文章解释了如何将一组算术约束转化为 Rank One Constraint System (R1CS)。

本资源的重点是实现:我们讨论了这种转换的更多边界情况,讨论了优化,并解释了 Circom 库如何实现它。

先决条件

  • 我们假设读者了解如何使用 算术电路 (zk circuits) 来表示计算的有效性。
  • 读者熟悉 模算术。这里的所有操作都发生在一个有限域中,因此 -5 实际上是指 5 的模 p 加法逆元,而 2/3 表示 3 的模 p 乘法逆元乘以 2。

Rank 1 Constraint System 概述

Rank 1 Constraint System (R1CS) 是一个算术电路,其要求是每个等式约束有一个乘法(对加法的数量没有限制)。

这使得算术电路的表示与双线性配对的使用兼容。配对的输出 G1∙G2→GT 不能再次进行配对,因为在 GT 中的元素不能作为其他配对的输入。因此,我们每个约束只允许一个乘法。

见证向量

在一个算术电路中,见证是一个对所有信号的赋值,使其满足方程的约束。

在 Rank 1 Constraint System 中,见证向量是一个 1×n 向量,包含所有输入变量、输出变量和中间值的值。它表明你已经从头到尾执行了电路,知道输入、输出以及所有中间值。

通过约定,第一个元素总是 1,以便使一些计算更简单,我们稍后将演示。

例如,如果我们有约束

z=x²y

我们宣称知道解,那么这必须意味着我们知道 x、y 和 z。因为 Rank One Constraint Systems 每个约束恰好要求一个乘法,上述多项式约束必须写作

₁₁v₁=xxz=v₁y

一个见证意味着我们不仅知道 x、y 和 z,我们必须知道这种展开形式中的每个中间变量。具体而言,我们的见证是一个向量:

₁[1,z,x,y,v₁]

其中每个项都有一个满足上述约束的值。

例如,

[1,18,3,2,9]

是一个有效的见证,因为当我们将值代入时,₁[constant=1,z=18,x=3,y=2,v₁=9] 它满足约束

v₁=x∗x→9=3⋅3

z=v₁∗y→18=9⋅2

额外的 1 项在这个例子中没有使用,它只是一个方便,我们会稍后解释。

示例 1:将 z=x⋅y 转换为 Rank 1 Constraint System

在我们的例子中,我们将说我们在证明 41×103=4223。

因此,我们的见证向量是 [1,4223,41,103],作为对 [1,z,x,y] 的赋值。

在我们能够创建 R1CS 之前,我们的约束需要是以下形式

result = left_hand_side × right_hand_side

幸运的是,它已经是 z⏟result=x⏟左侧×y⏟右侧

这显然是一个简单的例子,但简单的例子通常是一个很好的起点。

要创建一个有效的 R1CS,你需要一个包含恰好一个乘法的公式列表。

稍后我们将讨论如何处理不只有一个乘法的情况,例如 ³z=x³ 或 ³z=x³+y。

我们的目标是创建一个形式为:

Oa=La∘Ra

的方程组,其中 O、L 和 R 是大小为 n x m 的矩阵(n 行和 m 列)。

矩阵 L 编码乘法左侧的变量,R 编码乘法右侧的变量。O 编码结果变量。向量 a 是见证向量。

具体而言,L、R 和 O 是列数与见证向量 a 相同的矩阵,每列表示索引使用的相同变量。

因此,对于我们的例子,见证有 4 个元素 (1,z,x,y),所以每个矩阵会有 4 列,所以 m=4。

行数将对应于电路中的约束数量。在我们的例子中,我们只有一个约束:z=x∗y,因此我们将只有一行,所以 n=1。

让我们直接跳入答案并解释我们是如何获得的。

Oa=La∘Ra [0100]⏟Oa=[0010]⏟La∘[0001]⏟Ra

[0100][1422341103]=[0010][1422341103]∘[0001][1422341103]

在这个例子中,矩阵中的每个项目都作为一个指示变量,用于表示与该列对应的变量是否存在。(从技术上讲,它是变量的系数,但我们稍后会讨论到)。

对于左侧条款,x 是出现在乘法左侧的唯一变量,因此如果这些列代表 [1,z,x,y],那么…

L 是 [0,0,1,0],因为 x 出现了,而其他变量没有。

R 是 [0,0,0,1] 因为乘法右侧的唯一变量是 y,并且

O 是 [0,1,0,0],因为我们在乘法的“输出”中只有 z 变量。

我们没有任何常数,因此 1 列在任何地方都为零(稍后我们将讨论它何时非零)。

此方程是正确的,我们可以在 Python 中验证这一点

import numpy as np

## 定义矩阵
O = np.matrix([[0,1,0,0]])
L = np.matrix([[0,0,1,0]])
R = np.matrix([[0,0,0,1]])

## 见证向量
a = np.array([1, 4223, 41, 103])

## 乘法 `*` 是逐元素的,而不是矩阵乘法。
## Result 包含一个布尔值,指示该元素的逐元素指示该等式对该元素为真。
result = np.matmul(O, a) == np.matmul(L, a) * np.matmul(R, a) 

## 检查每个逐元素的等式是否为真
assert result.all(), "result contains an inequality"

你可能会想知道这有什么意义,我们是不是只是在用一种更不简洁的方式说 41×103=4223?

你是对的。

R1CS 可以相当冗长,但它们与 二次算术程序 (QAPs) 完美对应,可以简化。不过我们在这里不关心 QAP。

但这是 R1CS 的一个重要点。R1CS 传达的信息与原始算术约束完全相同,但每个等式约束仅包含一个乘法。在这个例子中,我们只有一个约束,但在下一个例子中我们将添加更多。

示例 2:将 r = x y z * u 转换

在这个稍微复杂一点的例子中,我们现在需要处理中间变量。我们每行的计算只能有一个乘法,因此我们必须按照以下方式分解方程:

v₁=xy v₂=zur r=v₁v₂

没有规则要求我们必须这样分解,下面的分解也是有效的:

v₁=xy v₂=v₁zr v₂u

我们将使用第一个变换作为这个例子的处理。

L、R 和 O 的大小

因为我们正在处理 7 个变量 (r,x,y,z,u,v₁,v₂),所以我们的见证向量将有八个元素(第一个是常数 1),我们的矩阵将有八列。

因为我们有三个约束,所以矩阵将有三行。

左侧项和右侧项

这个例子将强烈强调“左侧项”和“右侧项”的概念。具体而言,x、z 和 v₁ 是左侧项,而 y、u 和 v₂ 是右侧项。

v₁v₂r⏟ 输出项 === xzv₁⏟ 左侧项 ××× yuv₂⏟ 右侧项

基于左侧项构造矩阵 L

让我们构造矩阵 A。我们知道它将有三行(因为有三个约束)和八列(因为有八个变量)。

[l₁,2 l₁,3 l₁,4 l₁,5 l₁,6 l₁,7 l₁,8 l₂,2 l₂,3 l₂,4 l₂,5 l₂,6 l₂,7 l₂,8 l₃,2 l₃,3 l₃,4 l₃,5 l₃,6 l₃,7 l₃,8]

我们的见证向量将与这个相乘,所以让我们定义我们的见证向量布局为:

[1 r x y u v₁ v₂]

这告诉我们 L 的列代表的是什么:

L=[l₁,1 l₁,r l₁,x l₁,y l₁,z l₁,u l₁,v₁ l₁,v₂ l₂,1 l₂,r l₂,x l₂,y l₂,z l₂,u l₂,v₁ l₂,v₂ l₃,1 l₃,r l₃,x l₃,y l₃,z l₃,u l₃,v₁ l₃,v₂]

L 的第一行

在第一行,对于第一个左侧变量,我们有 ( v₁=xy ):

v₁ v₂ r === xz v₁ L ××× y u v₂

这意味着就左侧而言,变量 x 是存在的,其他变量则不存在。因此,我们将第一行转化如下:

L=[00100000 l₂,1 l₂,r l₂,x l₂,y l₂,z l₂,u l₂,v₁ l₂,v₂ l₃,1 l₃,r l₃,x l₃,y l₃,z l₃,u l₃,v₁ l₃,v₂]

请记住,L 的列标记如下:

[1 r x y u v₁ v₂]

我们看到 1 在 x 列中。

L 的第二行

继续向下,我们看到只有 z 是出现在我们方程组的左侧。

v₁ v₂ r === xz v₁ L ××× y u v₂

因此,在该行中,我们将所有归零,除了代表 z 的列。

L=[0010000000001000 l₃,1 l₃,r l₃,x l₃,y l₃,z l₃,u l₃,v₁ l₃,v₂]

L 的第三行

最后,我们在第三行中唯一出现在左侧运算符的变量是 ( v₁ )

v₁ v₂ r === xz v₁ L ××× y u v₂

这完成了矩阵 L。

L=[001000000000100000000010]

下图应使映射更清晰:

v₁ v₂ r === xz v₁ L ××× y u v₂ 1 r x y u v₁ v₂ [001000000000100000000010]

L 的替代变换

我们可以通过展开左侧值来完成相同的操作

v₁ v₂ r === xz v₁ ××× yu v₂

v₁=(0⋅1+0⋅r+1⋅x+0⋅y+0⋅z+0⋅u+0⋅v₁+0⋅v₂)× y v₂=(0⋅1+0⋅r+0⋅x+0⋅y+1⋅z+0⋅u+0⋅v₁+0⋅v₂)× u r=(0⋅1+0⋅r+0⋅x+0⋅y+0⋅z+0⋅u+1⋅v₁+0⋅v₂)× v₂

我们可以这样做是因为添加零项并不会更改值。我们只需小心展开零变量,使其具有与我们定义的见证向量相同的“列数”。

然后,如果我们将上面展开中的系数(以框表示)拿出来,

v₁=(0⋅1+0⋅r+1⋅x+0⋅y+0⋅z+0⋅u+0⋅v₁+0⋅v₂)× y v₂=(0⋅1+0⋅r+0⋅x+0⋅y+1⋅z+0⋅u+0⋅v₁+0⋅v₂)× u r=(0⋅1+0⋅r+0⋅x+0⋅y+0⋅z+0⋅u+1⋅v₁+0⋅v₂)× v₂

我们获得的 L 矩阵与刚才生成的相同。

L=[001000000000100000000010]

从右侧项构造矩阵 R

R=[r₁,1 r₁,r r₁,x r₁,y r₁,z r₁,u r₁,v₁ r₁,v₂ r₂,1 r₂,r r₂,x r₂,y r₂,z r₂,u r₂,v₁ r₂,v₂ r₃,1 r₃,r r₃,x r₃,y r₃,z r₃,u r₃,v₁ r₃,v₂]

矩阵 R 代表我们方程的右侧项:

v₁ v₂ r === xz v₁ ××× yu v₂ R

矩阵 R 必须有 1 代表 y、u 和 v₂。矩阵中的行对应于算术约束的行,即我们可以将约束(行)编号如下:

(1)(2)(3) v₁ v₂ r === xz v₁ ××× y u v₂ R

因此第一行在 y 列中有 1,第二行在 u 列中有 1,第三行在 v₂ 列中有 1。其他都是零。

这导致矩阵 R 得到如下结果:

1 r x y u v₁ v₂ [000100000000010000000001]

下图说明了变换。

v₁ v₂ r === xz v₁ ××× y u v₂ R 1 r x y u v₁ v₂ [000100000000010000000001]

构造矩阵 O

是一项练习,读者确定矩阵 O 为

O=[000000100000000101000000]

使用与早先矩阵一致的列标签。

提醒一下,C 是通过乘法结果得出的

v₁ v₂ r C=== xz v₁ ××× y u v₂

列标签如下

1 r x y u v₁ v₂ [000000100000000101000000]

检测我们的反馈 r=x⋅y⋅z⋅u

import numpy as np

## 输入 A B 和 C
L = np.matrix([[0,0,1,0,0,0,0,0],
              [0,0,0,0,1,0,0,0],
              [0,0,0,0,0,0,1,0]])

R = np.matrix([[0,0,0,1,0,0,0,0],
              [0,0,0,0,0,1,0,0],
              [0,0,0,0,0,0,0,1]])

O = np.matrix([[0,0,0,0,0,0,1,0],
              [0,0,0,0,0,0,0,1],
              [0,1,0,0,0,0,0,0]])

## 为 x、y、z 和 u 选择随机值
import random
x = random.randint(1,1000)
y = random.randint(1,1000)
z = random.randint(1,1000)
u = random.randint(1,1000)

## 计算代数电路
r = x * y * z * u
v₁ = x * y
v₂ = z * u

## 创建见证向量
a = np.array([1, r, x, y, z, u, v₁, v₂])

## 逐元素乘法,而不是矩阵乘法
result = np.matmul(O, a) == np.multiply(np.matmul(L, a), np.matmul(R, a))

assert result.all(), "system contains an inequality"

示例 3:与常数相加

如果我们想为以下构建一个 Rank One Constraint System 呢?

z=x∗y+2

这就是那一列 1 变得有用的地方。

加法是免费

你可能在 ZK-SNARKs 的上下文中听过“加法是免费的”这句话。这意味着当我们有一个加法操作时,不需要创建额外的约束。

我们可以把上面的公式写作

v₁=xy v₂=v₁+2

但这会使我们的 R1CS 比需要的要大。

相反,我们可以将其写为

−2+z=xy

然后变量 z 和常数 −2 在我们用见证向量乘以 O 时自动“结合”在一起。

我们的见证向量的形式是 [1, z, x, y],所以我们的矩阵 L、R 和 O 如下:

L=[0010]

R=[0001]

O=[−2100]

每当有加法常量时,我们简单地将其放置在 1 列中,按照约定这是第一列。

再次,我们来对我们的数学做一些单元测试:

import numpy as np
import random

## 定义矩阵
L = np.matrix([[0,0,1,0]])
R = np.matrix([[0,0,0,1]])
O = np.matrix([[-2,1,0,0]])

## 选择随机值来测试方程
x = random.randint(1,1000)
y = random.randint(1,1000)
z = x * y + 2 # 见证向量
a = np.array([1, z, x, y])

## 检查等式
result = O.dot(a) == np.multiply(np.matmul(L, a), R.dot(a))
assert result.all(), "result contains an inequality"

示例 4:与常数相乘

在上述所有示例中,我们从未使用常数乘以变量。这就是为什么 R1CS 中的条目始终是 1 的原因。正如你从上面的例子中可能猜到的,矩阵中的条目是变量乘以常数的相同值,以下示例将显示。

让我们解决以下的表达式

z=2x²+y

请注意,当我们说“每个约束一个乘法”时,我们指的是两个变量的乘法。与常数相乘不是“真实”的乘法,因为它实际上是对同一变量的重复加法。

以下解是有效的,但生成了不必要的行:

v₁=xx z=2v₁

更优化的解决方案如下:

−y+z=2xx

使用更优的解决方案,我们的见证向量将呈现为 [1, out, x, y]

矩阵将定义为:

L=[0020] R=[0010] O=[010−1]

[1, z, x, y] 在 r1cs 形式中进行符号乘法,给回我们的原始方程:

[010−1][1 zy x y] = [0020][1 zy x y]∘[0010][1 zy x y]

z–y=2xx z=2x²+y

所以我们知道我们正确设置了 L、R 和 O。

在这里我们有一行(约束)和一个“真实”的乘法。一般规则是:

Rank One Constraint system 中的约束数量应等于非恒定乘法的数量。

示例 5:一个大约束

让我们做一些实施以下的内容,结合我们学到的所有知识。

假设我们有以下约束:

z=3x²y+5xy–x–2y+3

我们将按如下方式分解:

v₁=3xx v₂=v₁y–v₂+x+2y–3+z=5xy

请注意,所有加法项已移至左侧(这就是我们在加法示例中做的,但在这里更为明显)。

将右侧保留为 5xy 的第三行是任意的。我们可以将两边都除以 5,而最终约束为

−v₂+x5+2y5−35+z5=xy

然而这并不会改变见证,因此两者都是有效的。因为所有操作都是在有限域中进行的,这个操作是在左右两侧乘以 5 的乘法逆元。

我们的见证向量将是

[1,z,x,y,v₁,v₂]

我们的矩阵将有三行,因为我们有三个约束:

v₁=3xx v₂=v₁y−v₂+x+2y−3+z=5xy

我们将标记输出 O 为红色,左侧 L 为绿色,右侧 R 为紫色。这产生以下矩阵:

L=[003000000010005000]

R=[001000000100000100]

O=[000010000001−31120−1]

列标签为

[1 out x y v₁ v₂]

让我们照常检查我们的工作。

import numpy as np
import random

## 定义矩阵
L = np.array([[0,0,3,0,0,0],
               [0,0,0,0,1,0],
               [0,0,5,0,0,0]])

R = np.array([[0,0,1,0,0,0],
               [0,0,0,1,0,0],
               [0,0,0,1,0,0]])

O = np.array([[0,0,0,0,1,0],
               [0,0,0,0,0,1],
               [-3,1,1,2,0,-1]])

## 为 x 和 y 选择随机值
x = random.randint(1,1000)
y = random.randint(1,1000)

## 这是我们的原始公式
out = 3 * x * x * y + 5 * x * y - x - 2 * y + 3 # 包含中间变量的见证向量
v₁ = 3 * x * x
v₂ = v₁ * y
w = np.array([1, out, x, y, v₁, v₂])

result = O.dot(w) == np.multiply(L.dot(w),R.dot(w))
assert result.all(), "result contains an inequality"

Rank One Constraint Systems 不需要从单一多项式开始

为了简化问题,我们一直在使用如下形式的例子 z=xy+... 但大多数实际的算术约束将是一组算术约束,而不是单个约束。

例如,假设我们证明数组 ₁₂₃₄[x₁,x₂,x₃,x₄] 是二进制且 v 小于 16。约束集将是

₁²₁₂²₂₃²₃₄²₄₄₃₂₁x₁²=x₁x₂²=x₂x₃²=x₃x₄²=x₄v=8x₄+4x₃+2x₂+x₁

为了将这个转化为 Rank One Constraint System,我们注意到最后一行没有任何乘法,所以我们可以在第一个约束中替代 x₁:

₁²₄₃₂₂²₂₃²₃₄²₄x₁²=v–8x₄–4x₃–2x₂x₂²=x₂x₃²=x₃x₄²=x₄

假设我们的见证向量是 [1,v,x₁,x₂,x₃,x₄],我们可以创建 R1CS 如下:

L=[001000000100000010000001] R=[001000000100000010000001] O=[010−2−4−8000100000010000001]

进行替换并不是严格必要的,但它节省了 R1CS 中的一行。在后面的部分中,我们将展示一个有效的 R1CS,其中我们未进行替换。

所有操作都是在模质数下进行的

在上述示例中,为了简化呈现,我们使用了传统算术,但现实世界的实现则使用模算术。

原因很简单:编码像 2/3 这样的数字会导致表现不佳的浮动数,这计算密集且容易出错。

如果我们在某个质数下进行所有数学计算,例如 23,那么编码 2/3 会变得简单。这和 2⋅3−1 是一样的,在模算术中乘以二和提升到负一的幂都是直观的。

Circom 实现

在 Circom 中,一个构建 Rank 1 Constraint Systems 的语言,有限域 använder 的质数为 21888242871839275222246405745257275088548364400416034343698204186575808495617(这等于我们在 有限域上的椭圆曲线 中讨论的 BN128 曲线的阶)。

这意味着在该表示中的 −1 是

p = 21888242871839275222246405745257275088548364400416034343698204186575808495617

## 1 - 2 = -1
(1 - 2) % p

## 21888242871839275222246405745257275088548364400416034343698204186575808495616

Circom 中的 out = x * y

如果我们在 Circom 中写 out = x * y,它将看起来如下:

pragma circom 2.0.0;

template Multiply2() {
    signal input x;
    signal input y;
    signal output out;

    out <== x * y;
 }

component main = Multiply2();

让我们将其转换为 R1CS 文件并打印出 R1CS 文件。

circom multiply2.circom --r1cs --sym
snarkjs r1cs print multiply2.r1cs

我们得到以下输出:

console result of Circom compilation

这看起来与我们的 R1CS 解决方案有所不同,但实际上它编码的是相同的信息。

Circom 实现中的差异如下:

  • 值为零的列不打印。
  • Circom 写作 Oa=La∘Ra 以 La∘Ra–Oa=0 的形式出现。

那么 21888242871839275222246405745257275088548364400416034343698204186575808495616,实际上是 −1 呢?

Circom 的解决方案是

A=[00−10] B=[0001] C=[0−100]

尽管负一可能是意外的,但对于见证向量 [1 out x y],这实际上与 La∘Ra–Oa=0 的形式是一致的。(我们将看到 Circom 确实使用了此列分配)。

你可以为 x、y 和 out 插入值,看看 La∘Ra–Oa=0 这个等式是否成立。

让我们看看 Circom 的变量到列的分配。让我们使用 wasm 求解器重新编译我们的电路:

circom multiply2.circom --r1cs --wasm --sym

cd multiply2_js/

我们创建 input.json 文件

echo '{"x": "11", "y": "9"}' > input.json

并计算见证

node generate_witness.js multiply2.wasm input.json witness.wtns

snarkjs wtns export json witness.wtns witness.json

cat witness.json

我们得到以下结果:

terminal output after computing the witness

显然 Circom 使用的是与我们使用的相同的列布局:[1, out, x, y],因为在我们的 input.json 中将 x 设置为 11,y 设置为 9。

如果我们使用 Circom 生成的见证(将巨大数字替换为 −1 以便易读),那么我们看到 Circom 的 R1CS 是正确的。

a=[199119] L=[00−10] → La=−11 R=[0001] → Ra=9 O=[0−100] → Oa=−99

Aw⋅Bw–Cw=0(−11)(9)–(−99)=0−99+99=0

L 在 x 中有一个 −1 的系数,R 在 y 中有一个 +1 的系数,而 O 中有 −1 的系数。在模形式中,这与终端输出的内容完全相同:

terminal output of the R1CS

检查我们工作的其余部分

回顾一下,我们探讨的公式是

z=x∗y z=x∗y∗z∗u z=x∗y+2 z=3x²y+5xy–x–2y+3

我们刚刚在上面的部分讨论了第(1),在这一部分我们将说明非恒定乘法的数量是约束的数量。

约束的(2)的电路为:

pragma circom 2.0.8;

template Multiply4() {
    signal input x;
    signal input y;
    signal input z;
    signal input u;

    signal v1;
    signal v2;

    signal out;

    v1 <== x * y;
    v2 <== z * u;

    out <== v1 * v2;
}

template main = Multiply4();

考虑到我们迄今为止讨论的所有内容,Circom 输出及其注释应自解释。

annotation of constraint generation for Multiply4()

考虑到这一点,其他公式的约束应如下:

z=x∗y 1 个约束z=x∗y∗z∗u 3 个约束z=x∗y+2 1 个约束z=3x²y+5xy–x–2y+3 3 个约束

这个是读者的练习,编写 Circom 电路并验证上述内容。

你并不需要见证来计算 R1CS

需要注意的是,在 Circom 代码中,我们在计算 R1CS 之前从未提供见证。我们之前提供见证只是为了使示例不那么抽象,并使其易于检查我们的工作,但这并不是必要的。这一点很重要,因为如果验证者需要见证来构建 R1CS,那么证明者将不得不放弃隐藏的解决方案!

当我们说“见证”时,我们指的是一个填充值的向量。验证者知道“见证”的“结构”,即变量到列的分配,但不知道值。

R1CS 在未优化的情况下也是有效的

从多项式到 R1CS 的有效转换并不是唯一的。你可以使用更多的约束编码同一问题,而这效率较低。这里是一个例子。

在一些 R1CS 教程中,像

²z=x²+y

这样的公式的约束被转换为

₁₁v₁=xxz=v₁+y

正如我们所注意到的,这不是有效的。然而,你只需使用本文中的方法即可为此创建有效的 R1CS。我们只需添加一个虚拟乘法如下所示:

₁₁v₁=xxz=(v₁+y)∗1

我们的见证向量是形式为 [1,z,x,y,v₁],L、R 和 O 定义如下:

L=[0010000011]

R=[0010010000]

O=[0000101000]

L 的第二行实现了加法,而通过使用第二行的第一个元素来完成乘以一。

这是完全有效的,但解决方案比所需的多了一行多了一列。

如果没有乘法呢?

如果我们想编码以下电路会如何呢?

z=x+y

这在实践中是非常无用的,但为了完整性,可以通过使用虚拟乘法将其解决。

out=(x+y)∗1

对于我们的典型见证向量布局 [1,z,x,y],我们有以下矩阵:

L=[0011] R=[1000] O=[0100]

Rank One Constraint Systems 只是出于方便

原始关于 Groth16 的 论文 并没有提到 Rank One Constraint System 这个术语。 R1CS 从实现角度来看很方便,但从纯数学角度来看,它只是显式标记和分组不同变量的系数。因此,当你阅读关于该主题的学术论文时,通常会缺少因为它是更抽象概念的实现细节。

有用的资源

通过 RareSkills 深入学习

这篇博客来自我们 零知识课程 的学习资料。

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

0 条评论

请先 登录 后评论
RareSkills
RareSkills
https://www.rareskills.io/