从GB到KB,零知识证明如何打造简洁的区块链?

写在前面:本文作者为区块链开发者Ronald Mannak。他在文章中通过简单的描述说明了零知识证明对区块链可扩展性的意义。

很多人都写过关于零知识证明(ZKP)的技术文章。我最近也在文章中对比了新的通用zk-SNARKs。我发现科普ZKP应用的文章很少。ZKP的用途不仅仅是保护隐私,其功能多样,可以重新定义区块链的运作方式。

简洁的区块链,从GB到KB

区块链可以变得很大,随着区块数量的增加不断增长。区块链就是这样设计的,我们已经接受了这个事实。然而,Coda最近推出的测试网不同。首先,Coda的区块链是固定大小的,不会越来越大。其次,它的大小只有22KB,相当于80年代的经典家用电脑Commodore 64或ZX Spectrum的容量。Coda与传统区块链一样安全,甚至可以说比传统区块链更安全。越来越多的项目很快都将推出类似但更多功能的“简洁区块链”。这样的区块链是如何运作的?

曾经创建过区块链节点的人都了解这种痛苦:同步一个节点需要几个小时甚至几天的时间。很多区块链太大了,以至于磁盘空间和带宽需求超出了大多数人的家用电脑。这是导致中心化的部分原因。即使是像以太坊这样流行的区块链也只有大约10000个节点。其中大部分托管在AWS上,仅由少数实体拥有。区块链并不像很多人认为的那样去中心化。

为什么同步区块链需要这么长时间?有两个原因。第一个原因很明显:下载超过几百个G的数据需要一段时间。其次,区块链需要在下载后进行验证,因为恶意节点可能向你发送了错误的数据。

要验证区块链,必须从创世区块开始:执行第一笔交易并确认计算的状态等于下载的状态。再到下一笔交易,直到检查了区块链中的所有交易。这很浪费时间;成千上万的节点都经历了这个过程。

这是必要的,因为在传统计算中,验证计算是否正确的唯一方法是重新进行计算。这对于小范围的计算来说很好,但是对于一些要花费大量时间的计算来说就不太好了,比如区块链的例子。

ZKP提高效率和带宽

有一种方法可以在不重新做计算的情况下用更低的成本验证计算结果:即零知识证明(ZKP),其中zk-SNARKs可能是最知名的。

具体要怎么做呢?我们要讲区块链重放函数重写为zk-SNARK。zk-SNARK将输出两个东西:原始输出(就像原始的重放函数一样)和一个小的数学证明,证明结果是经过正确计算的。这个证明可以小到200字节(是的,小于1KB)。

不需要所有(甚至多个)计算机来执行重放函数。一台计算机可以创建证明,其他计算机可以在它们认为合适的任何时候进行验证。无论原始计算花费多长时间(甚至是小时、天或年,都没有关系),验证都只需几毫秒。证明可以通过U盘在网上发布,甚至可以印在T恤上。

如果恶意节点更改了余额,则证明将与结果不匹配,其他验证者都将拒绝该状态。如果恶意节点更改了zk-SNARK代码,那么结果也将被拒绝。(还有第三个参数,一个公开共享的字符串,它也将证明与zk-SNARK代码联系在一起。如果更改了代码,证明和共享字符串将不匹配,验证者将拒绝该结果。)

我们不再需要重做昂贵的计算,也不再需要下载区块链(因为我们已经有了区块链存在和有效的数学证明)。你只需要当前状态(例如最后一个区块)和一个简单的证明,即当前状态是有效的区块链的一部分,并花费几毫秒的时间来验证结果。

递归组合

验证一个证明很快,但是创建一个证明呢?时间并不固定,而且与传统计算相比,它在计算和内存方面的效率要低得多。事实上,虽然zk-SNARK版本的重放函数听起来不错,但在实践中它并不是一个很好的解决方案。它将耗费大量的内存,甚至比原来的非zk-SNARK重放函数更慢。

但还有另一个更好的解决方案。通过一些技巧,我们可以使用递归的zk-SNARK。使用递归,我们不必从头验证区块链,但是我们可以在之前的状态上构建,这要快得多。注意,递归的zk-SNARK不如非递归的zk-SNARK高效,但是最近的zk-SNARK构造已经取得了巨大的进步。

递归zk-SNARK程序使用之前的状态、属于之前状态的证明和新交易作为输入。它验证以前的状态(使用提供的证明)并检查新状态中的交易是否有效。如果答案是肯定的,它将输出新的状态和一个证明。

一旦新的状态和证明被分发到网络中,所有节点都可以丢弃之前的状态,而不会产生任何负面影响。新节点只需要下载最新的状态和证明。这就是为什么Coda能够有一个固定大小的区块链。

在我们的上一个例子中,只有一个节点会创建一个新的区块和证明。显然,同一个节点不一定需要产出每个区块。例如,可以从许多节点中随机选择一个节点(使用可验证的随机函数,节点甚至可以随机选择自己,而不会作弊)。我们可以做得更好。我们可以将区块产出逻辑划分为多个zk-SNARK。

最终的结果是,区块生产者不需要保留完整的区块链历史,它只需要之前的状态。所占容量到底有多小呢?一个普通的Coda节点只需要22 KB来存储证明、当前状态和Merkle路径。只要22 KB,节点可以验证整个区块链、查询余额和创建交易。但要生成区块,对节点的要求更多:它需要之前状态的完整余额Merkle树。Merkle树的大小取决于钱包的数量。如果Coda的钱包和以太坊一样多,那么Coda区块生产者大约需要1 GB。以太坊上最小的全节点容量是(截至2019年12月)230 GB。一个巨大的差异。

通过这种方式,网络有了更多的活跃节点,从而增强了去中心化,并为与区块链交互的程序打开了许多新的可能性,而不需要像Infura或Metamask这样的解决方案。考虑到99%的新用户在安装Metamask之前就失去耐心了,这可能会产生巨大的影响。