理解 Plonk(五):多项式承诺

什么是多项式承诺

所谓承诺,是对消息「锁定」,得到一个锁定值。这个值被称为对象的「承诺」。

这个值和原对象存在两个关系,即 Hiding 与 Binding。

Hiding: 不暴露任何关于 的信息;

Binding:难以找到一个 ,使得

最简单的承诺操作就是 Hash 运算。请注意这里的 Hash 运算需要具备密码学安全强度,比如 SHA256, Keccak 等。除了 Hash 算法之外,还有 Pedersen 承诺等。

顾名思义,多项式承诺可以理解为「多项式」的「承诺」。如果我们把一个多项式表达成如下的公式,

那么我们可以用所有系数构成的向量来唯一标识多项式

如何对一个多项式进行承诺?很容易能想到,我们可以把「系数向量」进行 Hash 运算,得到一个数值,就能建立与这个多项式之间唯一的绑定关系。

或者,我们也可以使用 Petersen 承诺,通过一组随机选择的基,来计算一个 ECC 点:

如果在 Prover 承诺多项式之后,Verifier 可以根据这个承诺,对被锁定的多项式进行求值,并希望 Prover 可以证明求值的正确性。假设 ,Verifier 可以向提供承诺的 Prover 询问多项式在 处的取值。Prover 除了回复一个计算结果之外(如 ) ,还能提供一个证明 ,证明 所对应的多项式 处的取值 的正确性。

多项式承诺的这个「携带证明的求值」特性非常有用,它可以被看成是一种轻量级的「可验证计算」。即 Verifier 需要把多项式 的运算代理给一个远程的机器(Prover),然后验证计算(计算量要小于直接计算 )结果 的正确性;多项式承诺还能用来证明秘密数据(来自Prover)的性质,比如满足某个多项式,Prover 可以在不泄漏隐私的情况下向 Verifier 证明这个性质。

虽然这种可验证计算只是局限在多项式运算上,而非通用计算。但通用计算可以通过各种方式转换成多项式计算,从而依托多项式承诺来最终实现通用的可验证计算。

按上面 的方式对多项式的系数进行 Pedersen 承诺,我们仍然可以利用 Bulletproof-IPA 协议来实现求值证明,进而实现另一种多项式承诺方案。此外,还有 KZG10 方案,FRI,Dark,Dory 等等其它方案。

KZG10 构造

与 Pedersen 承诺中用的随机基向量相比,KZG10 多项式承诺需要用一组具有内部代数结构的基向量来代替。

请注意,这里的 是一个可信第三方提供的随机数,也被称为 Trapdoor,需要在第三方完成 Setup 后被彻底删除。它既不能让 Verifier 知道,也不能让 Prover 知道。当 设置好之后, 被埋入了基向量中。这样一来,从外部看,这组基向量与随机基向量难以被区分。其中 ,而 ,并且存在双线性映射

对于一个多项式 进行 KZG10 承诺,也是对其系数向量进行承诺:

这样承诺 巧好等于

对于双线性群,我们下面使用 Groth 发明的符号 表示两个群上的生成元,这样 KZG10 的系统参数(也被称为 SRS, Structured Reference String)可以表示如下:

下面构造一个 的 Open 证明。根据多项式余数定理,我们可以得到下面的等式:

这个等式可以解释为,任何一个多项式都可以除以另一个多项式,得到一个商多项式加上一个余数多项式。由于多项式在 处的取值为 ,那么我们可以确定:余数多项式一定为 ,因为等式右边的第一项在 处取值为零。所以,如果 ,我们可以断定: 处等零,所以 的根,于是 一定可以被 这个不可约多项式整除,即一定存在一个商多项式 ,满足上述等式。

而 Prover 则可以提供 多项式的承诺,记为 ,作为 的证明,Verifier 可以检查 是否满足整除性来验证证明。因为如果 ,那么 则无法被 整除,即使 Prover 提供的承诺将无法通过整除性检查:

承诺 是群 上的一个元素,通过承诺的加法同态映射关系,以及双线性映射关系 ,Verifier 可以在 上验证整除性关系:

有时为了减少 Verifier 在 上的昂贵操作,上面的验证等式可以变形为:

同点 Open 的证明聚合

在一个更大的安全协议中,假如同时使用多个多项式承诺,那么他们的 Open 操作可以合并在一起完成。即把多个多项式先合并成一个更大的多项式,然后仅通过 Open 一点,来完成对原始多项式的批量验证。

假设我们有多个多项式, ,Prover 要同时向 Verifier 证明 ,那么有

通过一个随机数 ,Prover 可以把两个多项式 折叠在一起,得到一个临时的多项式

进而我们可以根据多项式余数定理,推导验证下面的等式:

我们把等号右边的第二项看作为「商多项式」,记为

假如 处的求值证明为 ,而 处的求值证明为 ,那么根据群加法的同态性,Prover 可以得到商多项式 的承诺:

因此,只要 Verifier 发给 Prover 一个额外的随机数 ,双方就可以把两个(甚至多个)多项式承诺折叠成一个多项式承诺

并用这个折叠后的 来验证多个多项式在一个点处的运算取值:

从而把多个求值证明相应地折叠成一个,Verifier 可以一次验证完毕:

由于引入了随机数 ,因此多项式的合并不会影响承诺的绑定关系(Schwartz-Zippel 定理)。

协议:

公共输入:

私有输入:

证明目标:

第一轮:Verifier 提出挑战数

第二轮:Prover 计算 ,并发送

第三轮:Verifier 计算

多项式约束与线性化

假设 分别是 的 KZG10 承诺,如果 Verifier 要验证下面的多项式约束:

那么 Verifier 只需要把前两者的承诺相加,然后判断是否等于 即可

如果 Verifier 需要验证的多项式关系涉及到乘法,比如:

最直接的方法是利用双线性群的特性,在 上检查乘法关系,即验证下面的等式:

但是如果 Verifier 只有 上的承诺 ,而非是在 上的承诺 ,那么Verifer 就无法利用双线性配对操作来完成乘法检验。

另一个直接的方案是把三个多项式在同一个挑战点 上打开,然后验证打开值之间的关系是否满足乘法约束:

同时 Prover 还要提供三个多项式求值的证明 供 Verifier 验证。

这个方案的优势在于多项式的约束关系可以更加复杂和灵活,比如验证下面的稍微复杂些的多项式约束:

假设 Verifier 已拥有这些多项式的 KZG10 承诺, 。最直接粗暴的方案是让 Prover 在挑战点 处打开这 6 个承诺,发送 6 个 Open 值和对应的求值证明:

Verifier 验证 个求值证明,并且验证多项式约束:

我们可以进一步优化,比如考虑对于 这样一个简单的多项式约束,Prover 可以减少 Open 的数量。比如 Prover 先 Open ,发送求值证明 然后引入一个辅助多项式 ,再 Open 处的取值。

显然对于一个诚实的 Prover, 求值应该等于零。对于 Verifier,它在收到 之后,就可以利用承诺的加法同态性,直接构造 的承诺:

这样一来,Verifier 就不需要单独让 Prover 发送 的 Opening,也不需要发送新多项式 的承诺。Verifier 然后就可以验证 这个多项式约束关系:

这个优化过后的方案,Prover 只需要 Open 两次。第一个 Opening 为 ,第二个 Opening 为 。而后者是个常数,不需要发送给 Verifier。Prover 只需要发送两个求值证明,不过我们仍然可以用上一节提供的聚合证明的方法,通过一个挑战数 ,Prover 可以聚合两个多项式承诺,然后仅需要发送一个求值证明。

我们下面尝试优化下 个多项式的约束关系的协议:

协议:

公共输入:

私有输入:

证明目标:

第一轮:Verifier 发送

第二轮:Prover 计算并发送三个Opening,

第三轮:Verifier 发送 随机数

第四轮:Prover 计算 ,利用 折叠 这四个承诺,并计算商多项式 ,发送其承诺 作为折叠后的多项式在 处的求值证明

第五轮:Verifier 计算辅助多项式 的承诺

计算折叠后的多项式的承诺:

计算折叠后的多项式在 处的求值:

检查下面的验证等式:

这个优化后的协议,Prover 仅需要发送三个 Opening,一个求值证明;相比原始方案的 6 个 Opening和 6 个求值证明,大大减小了通信量(即证明大小)。

Reference