1. 什么是零知识证明
所谓「零知识」证明(Zero Knowledge Proof),就是「什么也不知道」的证明。比如你想证明一件事,我来验证(挑战)你。如果你能在不把要证明的东西揭露给我的情况下,让我信服你确实拥有这个东西(比如问题的答案),就可以理解为零知识证明。关于零知识证明的科普网上有很多,比如数独问题(这里有中文翻译版),这里就不再赘述了。
第一次跟 zk 相关的论文是 GMR85 The Knowledge Complexity of Interactive Proof-Systems
第一篇非交互式证明的论文是 BFM88 Non-Interactive Zero-Knowledge and Its Applications
正式地说,满足以下特性的证明就是零知识证明:
- 完备性(compeleteness):若所要证明之事为真,则诚实的证明者能说服诚实的验证者
- 健全(soundness):如果命题为假,则作弊的证明者仅有非常小的概率可以欺骗诚实的验证者
- 零知识(Zero-Knowledge):若命题为真,则验证者除了被说服外,没会再获取任何其它信息。
这篇文章里,我们简单了解一下为什么零知识证明会引入多项式(如果你之前已经听说过零知识证明,相信大概率你会不停的听到过多项式这个词)。其它的知识,我们后面慢慢介绍。
2. 多项式:零知识证明的核心
2.1 如何证明一个数组
让我们暂时抛开零知识证明,从一个非常简单的例子说起。假设我有一个数组 b ,它的长度是 10 。我想向你证明这个数组的每一个元素都是 1 ,要怎么证明呢?
一个非常直观的做法是,你随机选择一个元素,我让你看一眼。如果真的是 1 ,那么你就有 $\frac{1}{10}$ 也就是 10% 的信心相信我说的是真的;并且每这样做一次,你对我的相信就增加 10% 。这就是一个非常朴素的证明方法。
使用这种证明方式时,根据严格程度不同,当你对我的信任度达到某个值(比如 50% 或 95% 时),你就可以选择相信我说的「数组的每一个元素都是 1 」这句话是真的。当然如果检查的过程中只要有一次是 1 ,你就可以完全认为我说的是假的。
这个方式很明显存在一些问题,无法实际应用:一方面,当要求非常严格时,你几乎要将所有元素都检查一遍才能相信我,这就不是「零知识」了;另一方面,即使不要求必须得「零知识」,在数组非常大的情况下(比如百万、千万个元素),需要非常多次的交互才能证明完成,这也很难实际应用。
那有没有别的方式,可以在有限的几次交互内,就可以达到非常可信的效果呢?
2.2 使用哈希可以吗
哈希也是一定常见的隐藏「知识」的方法,这是大家都熟知的:我不想让你知道具体的值,但又想让你验证我的值是否正确,那么我可以算一个哈希给你。常见的场景就是网站登录时的密码验证了。
但哈希是无法完全满足要求的。一方面,哈希的验证依赖于对比,这就需要以前用同样的数据产生过一次哈希,所以它每次只能「证明」同样的数据,数据产生变化是不行的;另一方面更重要的是,哈希只能验证数据,而在「零知识证明」中,我们最主要的是对「计算过程」进行验证。
什么是验证「计算过程」呢?大家可能听说过 zkevm 。所谓 zkevm ,就是用零知识证明的手段,证明 evm 虚拟机在执行过程中的正确性。这就是一种计算过程的验证。
2.3 非对称加密?
另一个常见的隐藏「知识」的方法是非对称加密,大家都很熟悉就不再赘述。但同样的,非对称加密也只能验证数据,而无法验证「计算过程」。
2.4 最合适的工具:多项式
聪明的数学家们早就为我们找到了解决这一问题的工具,那就是多项式。
没错,就是我们初中就学过的 $y = a_nx^n + a_{n-1}x^{n-1} + … + a_1x + a_0$
我们首先定义「验证者」为验证问题是真还是假的人;「证明者」则是要努力证明问题是真的人。假如说,我们能把前面「证明一个数组每个元素都是 1 」的问题等价转换成一个多项式,那么验证过程就变成了:
- 验证者和证明者使用同一方法将问题等价转换成一个多项式。验证者会很诚实的使用每个元素都是 1 的数据进行转换(不要纠结这里是否符合「零知识」,真正的零知识证明不完全是这样的);如果验证者也是,那么最终我们得到的多项式肯定是一样的;否则 ta 们得到的多项式肯定是不一样的。
- 验证者随机选一个数(假设为 $x$),发给证明者。
- 证明者使用 $x$ 值放入多项式进行计算,得到 $y$ 值返回给验证者。
- 验证者使用自己的多项式、同一个 $x$ 值进行计算,得到的值跟证明者提供的 $y$ 值进行比较,看是否相等。如果相等,我可以基本相信你的多项式和我的相同,从而也相信你的数组每个元素都是 1 ;如果不相等,我可以很确定的知道你在撒谎。
只要以上过程重复一次,我就可以很相信「你的数组每个元素都是 1 」了。当然这个过程也可以多重复几次,可以更加的确信。但总得来说,比一开始我们提出的方法高效多了。
你肯定会有疑问:为什么证明者随机选择一个值 $x$ ,让证明者给出 $y$ 值,如果相同就可以验证通过呢?主要有两个原因。一个原因是多项式的一个特性,即两个不同的多项式,最多有 $d$ 个点是重合的,其中 $d$ 是多项式的最高次幂的幂值(如 $y=3x^8 + 4x^5 + 2x + 1$ 这个多项式,$d$ 就是 8)。另一个原因,是多项式可取值的非常多,比如 0,1,…,$2^{32}$, … ,为了方便讨论,我们反这个集合中值的数据定义为 $R$ 。
基于这两个原因,如果证明者的多项式和验证者的不一样,那么当验证者从非常大的取值范围 $R$ 里随机取一个值 $x$ 时,两个多项式在 $x$ 点重合(即算出来的 $y$ 值一样)的概率为 $\frac{d}{R}$ ,这是一个非常小的概率,小到只要随机取一个值,验证者就可以完成验证了。(这里相关的知识来自于「Schwartz–Zippel 引理」,感兴趣的小伙伴可以自己搜索学习)。
现在我们知道了多项式可以用来在「隐藏知识」的情况下(你很难从多项式反推出是用哪些信息转换的),让验证者快速验证。但为什么说多项式就是最适合的工具呢?
2.5 用多项式验证计算过程
说多项式最适合,是因为多项式可以代表计算过程,所以对多项式进行验证,也等价于对多项式进行验证了。
其实理解「多项式可以验证计算过程」的关键,就是前面「把问题等价转换成多项式」这句话。多项式拥有这样的能力,能将计算过程等价转换成多项式(而非对称加密这些工具是不行的)。至于如果等价转换,我们以后会介绍到。
事实上,上面的例子其实也没计算过程……也就谈不上验证了。但是这肯定是可以做到的,区块链领域应用零知识证明最知名的 zkevm ,就是使用零知识证明(zk)的手段,让验证者不需将以太坊 evm 的 opcode 重新执行一遍,就可以相信别人执行的 opcode 的结果。执行 opcode ,这就是计算过程,而不是数据。这个计算过程,是无法用非对称加密的方式,让别人相信的。
3. 总结
零知识证明的核心就是多项式。这篇文章里我们大概了解了为什么使用多项式,最关键的核心是,多项式拥有两个特性:
- 可以隐藏知识
- 可以将计算过程等价转换成多项式
你现在一定特别想知道,如何将计算过程等价转换成多项式。别着急,这是很久以后的事情了,在这之前,我们需要知识关于零知识证明的更多细节。比如,前面的例子里验证者同样要知道整个多项式才能验证,虽然多项式隐藏了原始数据,但整个多项式被别人知道,这也不算是「零知识」。那怎么才能既隐藏了多项式,又能让别人验证呢?下一篇文章,我们就来解决这个问题。