原文:https://rot256.dev/post/fri/
作者:Mathias Hall-Andersen
译者:Kurt Pan
在本文中,我们将研究Fast Reed-Solomon IOP (FRI) (FRI) 邻近性测试,该测试可以使不受信任的证明者说服验证者,一个承诺的向量是接近于一个 Reed-Solomon 码字的,且通信量仅为编码维度的多项式对数。这可以很容易地用于仅从密码学哈希函数(更确切地说,随机预言)来构建实际高效的 zkSNARK,且无需可信设置。
假设读者了解群论和有限域的基础知识;没有这些,FRI 看起来就会像是一系列毫无动机的魔法方程。还会假设读者熟悉交互式预言证明 (IOP) 的基础知识和邻近性测试的总体目标 / 想法。我们不会花时间讨论 IOP 的基础知识,但尽管如此,本文所用的模型将始终会是 IOP :即证明者可以向验证者发送(长的)预言 / 消息,验证者可以在任何时间对任意索引读取预言 / 消息。
FRI 原始论文只用了相对较少的时间来给出构造的动机,而用了大量的时间来进行可靠性分析,当然这也是可以理解的。此外,尽管 FRI 相对简单(正如我们将看到的),实际上对可靠性的形式化证明会极为复杂,尤其是超出唯一解码半径时。
本文的重点有所不同:我们将重点关注构造背后的直觉,“折叠过程”是如何想出的,给出一些例子,以及关注为什么直观上可以期望该构造是能够发挥作用的。换句话说,关注要如何想出 FRI 的构造?以及如何对其泛化推广?
Fast Reed-Solomon IOP (FRI) 是一种对 Reed-Solomon 码的邻近性测试,即始终会接受的字符串“yes”语言就是 Reed-Solomon 码:
简单来说:即是一个维度为 的向量 ,次数小于 的多项式的求值。
FRI 的目标是去区分开对应于诚实行为的 和所有中远离所有 Reed-Solomon 码字的向量,即相对汉明距离大于某个
直观上这很有用, 因为如果 小于 Reed-Solomon 码的唯一解码半径, 则每当验证者接受时(),我们就可以唯一地去讨论编码在 中的"消息"了 。构造 SNARK 时,这会使得知识抽取器可以恢复出唯一的低次( )多项式 。
承诺问题(Promise Problems):注意我们并不关心以下情况: ,即当 接近一个 Reed-Solomon 码字,但也不是码字本身时会发生什么。可能会有某种方式可以通过对 的测试,但也不是协议中的诚实行为。在复杂性理论中,这种对判定问题的泛化被称为承诺问题 , 被称为 * 承诺(promise)*。
FRI 通过不断分别归约 到更小的语言 来达成这个目标。
我们稍后会花相当多的时间在这个归约上,因为这是 FRI 的核心,现在先令 为一个确定"压缩因子"的常数, ,以及 将为大小的求值域 :
FRI 的核心目标就是概率性地把
换句话说:如果你从一个码字开始,你最终得到的也会是一个码字;如果你从一个远离码字的东西开始,你最终也会得到一个远离码字的东西;除去一个很小 / 可忽略的概率。
重复此过程后 rounds
注定失败集合:集合
,或多或少直接显式出现在 对 FRI 的逐轮可靠性证明中,它与脚本的“注定失败集合”这一一般概念密切相关。形式化的可靠性分析在于给出证明者一开始在但可以离开这个注定失败集合的概率上界。
那么我们要如何得到这样的一个归约呢?
这就是本文的重点, 所以让我们开始深入探讨。
要实例化 FRI,我们需要以下成分:
首先注意到,对于有限域, 任意映射
要看到这一点, 考虑一个非平凡的同态(即
具体来说, 对于商同态
这很好,因为即使我们最终是对多项式感兴趣,这也让我们能够更抽象地思考域中的群同态。因为同态的核是一个子群,且每个子群
这比一开始就给出同态或找到"好"多项式要容易得多,所以:
这种思考框架可以使我们更好地理解 FRI 的底层结构,了解为什么比如说平方映射是对某些域的自然选择,同时也使我们能够将 FRI 推广到其他设置。
为群论欢呼!
如上所述, 最简单的构造
对于那些喜欢 SageMath 的人, 以下代码段做的就是这件事, 即对于一个给定的生成元 op
,计算多项式
''' 给定:
- g : ker(q(x)) 的生成元
- op : 群操作
- X : 未定元
返回对\lt g>的多项式 q(X)
'''
def phi(g, op, X):
# 计算 H = \lt g>
e = g
H = []
while 1:
H.append(e)
e = op(e, g)
if e == g: break
# 找到群单位元
one = H[-1]
assert all([op(one, e) == e for e in H])
# 插值同态多项式
return prod([(X - e) for e in H]) + one
有限域自然地提供了两种群结构供我们探索:
这两种都可以工作,有时一种会比另一种更好, 具体取决于域。
那么让我们依次来看看......
回顾一下,任意有限域
对于任意循环群
可能有点抽象, 我们看几个例子:
考虑素域
分解群的阶, 我们会得到
我们接着选择
为了得到一个子群
注意在这种情况下, 单位元是
下面的 SageMath 代码可以用来生成这个例子:
# 选择单位根
F = GF(17)
w = F.multiplicative_generator()
print(w)
# 选择 2 阶子群的生成元
m = w.multiplicative_order()
assert m % 2 == 0
g = w^(m / 2)
print(g)
# 计算同态:
# 群操作是乘法
P.\lt X> = PolynomialRing(F)
q = phi(g, lambda a,b: a*b, X)
print(q)
如上所示, 在选择阶
让我们看另一个例子:
考虑素域
如果我们分解群的阶, 我们会得到
我们选择
为了得到一个子群
多项式
惊不惊喜:这是一个“立方”映射,因为
以下 SageMath 代码用于生成这个例子:
# 选择单位根
F = GF(31)
w = F.multiplicative_generator()
print(w)
# 选择 3 阶子群的生成元
m = w.multiplicative_order()
assert m % 3 == 0
g = w^(m / 3)
print(g)
# 计算同态:
# 群操作是乘法
P.\lt X> = PolynomialRing(F)
q = phi(g, lambda a,b: a*b, X)
print(q)
因为 FRI 会需要一系列的小子群, 上述方法非常适合
然而, 在比如说二进制域
对于域
考虑扩域:
将
因此我们可以通过选择任何元素
商映射
以下 SageMath 代码用于生成这个例子:
# 域定义
F = GF(2)
R.\lt z> = PolynomialRing(F)
F2 = F.extension(z^4 + z + 1, 'z')
# 任意选择一个生成元
g = F2(z^3 + z + 1)
# 计算同态:
# 群操作是加法
P.\lt X> = PolynomialRing(F2)
q = phi(g, lambda a,b: a + b, X)
print(q)
# 检验
e1 = F2.random_element()
e2 = F2.random_element()
assert q(e1 + e2) == q(e1) + q(e2)
除了是
因此
上面的矩阵是使用以下 SageMath 代码计算的:
# 在标准基上求值 q
B = [F2(1), F2(z), F2(z^2), F2(z^3)]
E = [q(e) for e in B]
print(E)
# 构造 GF(2) 矩阵
M = Matrix([vector(e) for e in E])
print(M)
# 检验
e3 = F2.random_element()
assert vector(e3) * M == vector(q(e3))
很明显
当我们对于线性子空间计算
练习:证明上述断言。
提示:使用
当且仅当 。 提示:使用对于任何
- 线性映射 。
一般来说,我们不想对整个域
此外 FRI 的可靠性分析实际上需要
考虑扩域:
注意
为获得
注意
因此, 当满足以下任一条件时, 就可以满足 FRI 的先决条件:
完成所有这些预备工作后,接下来就让我们来构造 FRI 协议吧。
在继续之前,让我们简要回顾一下 FRI 的成分。
FRI 通过以下参数确定:
而且不用担心, 文末会有很多例子。
令
在实践中是用 FFT 在
对现在定义为
这可以通过重复多项式除法来计算, 但并不需要显式计算此分解: 我们只需要其作为说明性的教学工具。
用未定元
在继续之前, 先进行一些快速观察:
到目前为止还没有魔法, 双方都还没有做任何事情。
事实上,关于部分求值
回想一下
因此, 如果我们考虑一个求值表
表中每一行的点都位于一个
这里有一个关键的观察:表的每一列都包含来自
结果是, 次数为
有了这些观察结果, FRI 协议实际上非常简单:
列一致性检查是可能的,因为来自
停下来思考一下:如果
的点在选定的列和选定的行相交,验证者要做什么?比如在上图中,验证者如果查询 列,他要做些什么?
答: 验证者不应该做任何特别的事情:
验证者在每个
打开 。插值唯一的 次与 在 上一致的单变量多项式 。然后打开 并检查 。
注:通常从中选取
的域 要比求值域 大得多,比如说是安全参数的指数。所以上述事件在实际中发生的可能性很小。
选择随机行:验证者选择随机行,诚实的证明者承诺该行。通过查询随机列来测试邻近性。
因为行
因此,随机测试几列的策略是合理的。如果许多位置(比如一个常数分数)不正确,则证明者会以很高的概率被抓住。因此,相反地,如果检查以高概率通过,那么
新多项式
为了进一步降低
递归地对
注意:要继续递归一个新的子群
需要定义一个新的商映射 。因此,要递归多次,我们需要原始的 拥有许多小子群:这样我们就可以在每一层递归上用一个新的子群进行求商。
注意:为了提高 FRI 的轮复杂度和可靠性,一致性检查仅在折叠结束时执行,即没有中间的一致性检查,仅在递归结束时进行,同时检查各层的一致性。这是因为折叠具有非常小的可靠性错误(对于指数大小的域可忽略),而无论域的大小如何,一致性检查都具有常数的可靠性错误。
因为理解事物通过例子总是更容易,因此该页面实际上已经在浏览器中实现了 FRI 协议,以可视化正在发生的情况。我在这上面花了很多时间,所以请享受它。让我们看一些例子:
(译者注:简单起见,以下截图仅选取最简单的选项,更多交互式内容请读者跳转至原始网页查看。)
一开始要选取一个域
求值域和域:
得到下列商映射
x | 1 | 13 | 16 | 4 |
---|---|---|---|---|
q(x) | 1 | 16 | 1 | 16 |
考虑下面的(随机生成的)多项式:
x | 1 | 13 | 16 | 4 |
---|---|---|---|---|
f(x) | 14 | 0 | 5 | 2 |
证明者发送
用一个未定元
考虑
注意:对于较大的域,表的行已被截断以提高可读性。
这个时候,除了在承诺
验证者现在选择一个随机挑战
其定义了表中的一行(标注为蓝色):
此行对应于多项式
要求证明者承诺这一行。当然,他也可能不会这样做……
验证者逐列运行一致性检查,尝试检测此类错误:
验证者选择
这些点位于 1 次列多项式上:
验证者在
为了增强可靠性,验证者会重复这个“安全参数”次。如果检测到错误,它就知道证明者已损坏并中止。经过此测试后,验证者确信承诺的行
对于 FRI 的下一轮,我们将新的多项式(现在为
其次数为原
并选取子群
注意:码字
是证明者已经发送的蓝色行。
Kurt Pan 翻译后记: 在目前诸多 FRI 相关文献之中,我视此篇为质量最上乘。此篇没有用 fancy 的相关技术内容吸引眼球,也没有陷入可靠性分析从而深入代数编码理论的论文窠臼,而是重视 FRI 构造的 motivation & intuition,通过例子以及 SageMath 代码说明了 FRI 协议中最核心的一轮归约函数的本质:一个具有非平凡小核的商群同态映射的多项式,以及通过求值表的观察说明了 FRI 协议的“选择随机行,检查随机列”的模块化邻近性测试的本质。同等内容可迁移至对 FFT/NTT,以及 Additive FFT/ECFFT/FRI-Binius/ Circle FRI 等前沿技术的理解。Learn math the hard way. The hard way is the easy way.
【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。