原文链接: Inner Product Arguments

翻译:Star.LI @ Trapdoor Tech

介绍

你也许听说过“BulletProofs”:它是一种零知识证明算法,不要求可信设置。比如,门罗币(Monero)就用了这个算法。这种证明系统的核心是内积证明1,一个能让证明者向验证者证明“内积“正确性的小技巧。内积,即是计算两个向量中每个分量的乘积和:

其中 ,

一个比较有趣的例子就是当我们设置向量 为某个 的幂,即 ,那么它的内积就变成了多项式

点的取值。

内积证明采用Pedersen承诺。我之前写过一篇文章介绍KZG承诺,Pedersen承诺与其类似,承诺值也是在椭圆曲线上的,不同的是它不需要可信设置。下面比较这两个多项式承诺方案(PCS),KZG承诺方案 和 Pedersen承诺与内积证明相结合的方案:

  Pedersen+IPA KZG
安全假设 离散对数 双线性群
可信设置
承诺大小 1个群元素 1个群元素
证明大小 2 log n个 群元素 1个群元素
验证 O(n) 群运算 1个配对

说到底,和KZG承诺相比,我们这个承诺方案的效率要低一些。证明大小更大(),不过对数本身还是挺小的,所以不至于太糟。但可惜的是验证者需要做的计算是线性的, 这失去了简洁性。这些局限使得 Pedersen 承诺对于某些应用来说不太现实,但在一些情况下这些缺点可以被规避。

  • 其中一个例子我在之前的文章多重打开中曾经提到过。这里的诀窍是你可以将多个打开聚合成一个。
  • Halo2 2, 其中多个打开的线性成本可以被聚合。

在以上这两个例子中,特点就是多个打开的成本被分摊了。如果你只想打开一个多项式,那就比较困难了,你需要承担整个打开的运算成本。

但是,Pedersen 承诺与内积证明结合的方案,很大的好处是较少的安全假设。也就是,不需要配对,并且不需要可信设置。

Pedersen 承诺

在我们讨论内积证明之前,我们要先看一下依赖的结构:Pedersen承诺。为了使用Pedersen承诺,我们需要一个椭圆曲线 。让我们首先回顾一下我们使用椭圆曲线可以做到哪些事情(在这里我会使用加法符号表示,看起来更自然一些):

  1. 你可以将两个椭圆曲线点 相加:
  2. 你可以将元素与一个标量相乘,其中椭圆曲线的阶 (即元素数量):

无法计算两个曲线元素的“乘积”:“”运算是未定义的,所以你没办法计算“”;与此相反,与标量相乘是很容易计算的,比如

另一个重要的性质就是不存在有效的计算“离散对数”的算法,这意味着对于满足的给定的,如果你不知道是不可计算的,我们称对于的离散对数。

Pedersen承诺则利用该不可计算性来构造承诺方案。假设有两个点,它们的离散对数(比如存在使得)并不可知,那么我们可以向两个数提交承诺:

为椭圆曲线的一个元素。

为打开一个承诺,证明者给验证者,然后验证者计算,如果相等的话就被接受。

承诺方案的中心性质在于它是不是绑定(binding)。给定,一个试图作弊的证明者是否能够生成并使验证者接受它们,即同时满足

如果有人能做到上述行为的话,那么它们也可以找出离散对数。为什么呢?我们知道,整理后可得

所以不可同时为0。假说不为零,我们得到:

对于。这样我们就找到了的值。我们知道该问题是难题,所以在现实中没有攻击者能够做到。

这意味着对于攻击者来说找到另外的来打开承诺在计算性上是不可能的。(它们的确存在,只是无法通过计算获得 – 就像哈希碰撞)。

我们可以扩展一个向量的承诺,比如说一个标量列表。我们只是需要一个“基”,即一个相等数量的互相未知离散对数的群元素,然后我们就可以计算承诺了:

这给了我们一个向量承诺,尽管这个承诺相对复杂:为了打开任意元素,必须打开所有的元素。但这里有一个重要的性质:这个承诺方案是加同态的,这意味着如果我们有另外一个承诺,那么我们可能可以通过添加两个承诺得到两个向量的和:

因为有了加同态的性质,这个向量承诺就变得有用了。

内积证明

内积证明的基本策略是“分治法”:将一个问题规约成多个同类型的子问题,而不是试图一步完全解决它。当子问题规约到一定程度的时候,就可以简单解决。

在这当中每一步,问题的大小都会减半。这保证了步后,问题大小会减少到1,可以通过简单证明解决。

假设我们需要证明的承诺 具有以下形式:

其中 ,且 是我们的“基”,即:它们是群 中的元素,并且它们之间对于任意一方的离散对数都未知。同时介绍一种新的表示方法:,一个由标量组成的向量()和另一个由群元素组成的向量()的乘积,我们将其定义为

也就是说,我们要证明 是以下元素的承诺

  • 基为 的向量
  • 基为 的向量
  • 基为 的内积

单看本身似乎并不是很有用 – 在大多数应用中我们想让验证者知道 ,而不是仅仅将这个结果藏在一个承诺里。这可以通过我后面要讲到的一个小技巧来解决。

证明

我们想让证明者向验证者证明 的确具有形式 。就像之前提到的,不是直接证明,而是要把这个问题规约成,如果这一性质对于另一个承诺 成立,则 也满足该性质。

接下来证明者就要和验证者玩一个小游戏了。证明者提交一些信息,然后验证者发起一个挑战,从而引出下一个承诺 。将它称作一个游戏不代表这个证明必须是交互的:Fiat-Shamir算法允许我们通过将挑战换成一个承诺的抗碰撞哈希值,从而将交互式的证明转化成非交互式的。

证明描述

承诺 符合 的形式,并且以为基。我们将符合这样形式的 称为拥有“内积性质”。

规约步骤

假设 , 证明者计算

这里我们定义 为向量 的“左半部”, 为“右半部”,向量 类似。

然后证明者计算如下的承诺:

并发送给验证者。然后验证者发送挑战 (通过使用Fiat-Shamir将它变成非交互式的,这意味着 的哈希)。证明者以此来计算更新的向量:

长度为原向量的一半。

现在,验证者计算新的承诺:

还有更新的基:

现在,如果新的承诺 符合了 的形式 - 那么承诺就遵从最初的假设,拥有“内积性质”。

所有的向量大小都减半 – 这让我们离成功又近一步。在这里我们替换 , 并重复以上步骤。

接下来我解释这个方法可行的数学原理,同时推荐你们去看看 Vitalik 所做的一个漂亮的可视化展示 以得到一些直观的感受。

最终步骤

当我们一直重复以上步骤,n每次降低一半。最终我们会到达,然后就可以停下了。这时证明者发送两个向量,事实上就是两个标量,然后验证者就可以非常直观地计算:

如果等于 就接受,反之则拒绝。

正确性(correctness) 及合理性(soundness)

在之前我假设 为我们所需要的形式,然后以此证明 也成立。现在我要证明为什么该逻辑成立。我们需要验证以下两点:

  • 正确性 – 即当证明者遵从相应操作的时候,它们可以达到说服验证者该结论为正确的目的;
  • 合理性 – 即试图作弊的证明者不能使用错误的证明通过验证者验证,或者成功率低至可忽略不计。

让我们从正确性证起,假设证明者依照操作进行每一个步骤。既然如此,我们知道给定 为基,,同时

验证者计算

为了使承诺具有内积属性,我们需要验证 。这个等式成立,因为

这样正确性就证明了。为证明合理性,我们需要证明,证明者的初始承诺 不具有内积属性,那么通过规约步骤,是无法产生一个具有内积属性的承诺

假设证明者提交了 ,其中 。如果我们走一遍如上的规约步骤,我们会得到

所以现在我们假设证明者成功作弊,那么 就满足了内积属性,则有:

展开左侧可得

注意证明者可以自由选择 ,所以我们不能直接假设它们会遵从以上定义。

同时乘以 并移到同一边,我们得到 的二次方程式:

除非所有项都为零,该等式至多会有两个解 ,但是验证者是在证明者已经承诺了他们的 , 值后选择 值,证明者能够成功作弊的概率非常小;我们通常选择域 大小约为 。因此,当证明者不按照协议选择正确值时,验证者选择到一个让等式能够成立的 值的概率微乎其微。

这就完成了我们的合理性证明。

仅在最后计算基变化

验证者在每一轮都需要做两件事:计算挑战 ,并计算更新的基 。但是在每一轮都更新 效率很低,验证者可以简单地保存他们在 轮中遇到的挑战值

假设轮后,这些基为 。元素是标量(或者长度为1的向量),因为长度到达1的时候我们会终止协议。通过计算,是一个长度为n的椭圆曲线上的多标量点乘(MSM)。的标量因子是下面多项式的系数

的标量因子由以下多项式给定

使用内积证明来验证多项式值

针对我们的主要应用 – 验证 处的取值 – 我们需要对协议做一些小的扩充。

  • 最重要的一点是,我们想要验证 的结果,而不仅是承诺 拥有“内积属性”。
  • 对于验证者来说是已知的。因此我们可以把这部分从承诺中移除来简化协议。

如何构造承诺

如果我们想要验证多项式,我们通常需要从承诺开始进行构造。证明者可以将的计算发送给验证者。

那么貌似验证者可以计算最初的承诺,因为他们已知,然后开始证明流程。

但稍等一下。大多数情况下,是证明者生成的承诺,一个恶意的证明者可以在这里作弊,比如说提交一个。在这种情况下,因为证明者生成的承诺有一个偏移,他们能够证明

为了避免这种情况,我们需要在证明流程中进行一点改变。 收到承诺和计算结果后,验证者生成一个向量并且重新选择基,之后证明继续。因为证明者不能预判的取值,它们就无法成功操控除了之外的结果(或者说概率极小)。

注意如果想要得到一个通用的内积,我们还要防止证明者操控向量 – 但在多项式取值的应用中,的部分可以完全去掉不用考虑,因此这里略过细节。

如何去掉第二个向量

注意,如果我们想要进行多项式计算,验证者已知向量。给定挑战,他们可以通过在“仅在最终计算基变化”一节中提到的技巧简单地得到

因此,我们可以从所有承诺中移除第二个向量并且只计算。这意味着验证者必须要能够从初始向量中计算最终的。因为的规约过程与基向量相同,线性组合也由之前定义的多项式的系数定义,也就是说

针对点值形式多项式的IPA

目前为止,我们用一个内积证明计算了使用它的系数提交的多项式,即一个由定义的多项式中的。然而,多数情况下我们想要一个在给定定义域计算值定义的多项式。因为任何阶低于的多项式都是由的计算结果定义的独一无二的多项式,所以这两者是完全相等的。但是这两者之间的转换在计算上非常费时,如果定义域适用快速傅立叶转换的话需要花费次计算,否则就是次。

为了避免这项开销,我们尝试避免使用多项式系数形式。这可以通过提交多项式值的承诺的而不是系数的承诺来实现:

这表示我们IPA的向量形式为

重心公式 使我们现在可以计算这个新的承诺多项式的取值,记作:

如果我们选择向量

我们可以得到,因此采用这种向量的IPA可以被用作证明点值多项式的取值。除了这一点差异之外,其他的证明过程是完全相同的。