深入探讨 ZK-Rollup ——如何应用零知识证明降低链上成本?

IP归属:广东

作者:Fluidex

编译:阿瓜

很少有人会深入研究这样的问题:ZK-Rollup究竟如何提升性能?或者,一个完整的ZK-Rollup系统是什么样子的?或者,在ZK-Rollup系统中是否有一些重要但通常被忽视的细节?

Fluidex,作为极少数独立开发ZK-Rollup系统的团队之一,在这里想要分享一些从ZK-Rollup系统开发中获得的经验。我们将谈论一些重要但很少被提及的话题,如ZK-Rollup系统的性能瓶颈在哪里,经济成本在哪里等等。

目前,对区块链技术的主要期望是进一步扩大使用规模,提高性能和降低成本。在这篇文章中,我们将深入研究ZK-Rollup,它是以太坊第二层的扩展解决方案之一。它巧妙地应用了零知识证明技术(被称为ZK-SNARK),以减少链上成本,因此,能够大大改善以太坊的TPS(约10倍-100倍)。ZK-Rollup被许多人认为是长期内最重要的以太坊第二层扩展解决方案,包括以太坊的创始人Vitalik。

总的来说,我自己的观点是,在短期内,optimistic rollups可能在通用的EVM计算中胜出,而ZK-rollups可能在简单的支付、交易和其他特定应用案例中胜出,但从中长期来看,随着 ZK-rollups技术的改进, ZK-rollups将在所有案例中胜出。——V神

ZK-SNARK和ZK-Rollup概述

同样,我们不会专注于ZK-SNARK证明的密码学细节,因为如前所述,有足够多的高质量资源来解释它。在本章中,我们将简要地回答以下问题。ZK-SNARK能做什么?为什么它能成为ZK-Rollup的核心,并与 “rollup ”一起帮助提升以太坊的性能?“rollup” 到底是什么意思?

ZK-SNARK的特性

一般来说,在区块链生态系统中,每个节点会对区块中的每笔交易执行相同的计算,然后验证他们的结果与其他节点的结果是否相同。换句话说,对于每笔交易的上链,它将被每个节点执行。这就是区块链的性能相对较低的一个主要原因。

然而,“再次计算”是验证交易的唯一方法吗?换句话说:验证的成本是否有必要和计算的成本一样高?

答案是否定的。验证的成本可能比计算的成本更低。让我们以数独为例。解决一个数独问题的复杂性与验证一个数独解决方案的复杂性是完全不同的。"再次计算 "是效率最低的验证方法。如果你碰巧有计算机科学背景,只需考虑计算复杂性理论中的P与NP问题。

因此,在区块链中,即使增加计算成本,也值得有一个可以降低验证成本的技术方案。原因是,对于每笔交易,计算只会发生一次,而验证会在每个节点上发生。ZK-SNARK本质上就是这样一种技术,可以大大降低验证成本。一般来说,ZK-SNARK可以使验证成本比计算成本低几个数量级。准确地说,将验证复杂性从线性降低到常数(或对数),这就是 "简洁",即 "SNARK "中的 “S”,所代表的含义。

让我们看看ZK-SNARK是如何工作的。

对于一个特定的程序,它首先会被预处理。在一次性预处理之后,对于每个输入,验证者需要计算与输入相对应的结果,以及生成一个成本相对较大的“证明”(通常以大整数的形式)。任何验证者都可以使用这个 "证明 "和输入来快速验证结果的正确性,而无需实际运行程序。

用模拟代码进行更详细的描述:

Rollup系统的现实世界设计

在一个正常的Rollup系统中,我们将维护一个全局默克尔树。Rollup系统中的所有状态(包括账户中每个代币的余额,账户的随机数等)将成为树上的一个叶子节点。

ZK-SNARK将在数学上保证对默克尔树的每一次更新都满足一些 "预定的规则"。这些规则是由ZK-Rollup开发者的设置决定的。例如,对于ZK-Rollup转账系统,开发者可以要求:

转账金额小于发件人账户的余额。

发送人账户的签名是有效的,并且随机数是正确的。

发送方账户中减少的金额等于接收方账户中增加的金额。

此外,默克尔树根的哈希值将从新的叶子中计算出来。

为了保证最坏情况下的安全性(也就是说,即使Rollup系统的开发者跑了,用户仍然可以完整地提取他们的资产),系统应该确保用户能够从头开始重建树(称为 "数据可用性"),并且能够通过默克尔树证明做出类似“Alice实际上有3个ETH ”的断言。为了实现这一点,系统应该将每笔交易的数据公开,并存储在链上。

对于一批成百上千的交易,在我们按照特定的顺序执行并更新默克尔树后,我们将使用ZK-SNARK来证明结果的正确性(即默克尔树的新根)。请注意,这里的交易数量是由一个预定义的配置决定的,这个配置在运行时是固定的。这批交易将被一起证明和验证,被称为“L2块”。

同样,让我们用模拟代码来演示真实世界的ZK-Rollup系统中的数据流:

自己的专门业务模块。例如,Fluidex有一个订单匹配引擎,它从用户的订单中生成匹配的交易,然后将其发送到状态管理器中。

ZK-Rollup的TPS限制

ZK-Rollup系统的TPS的主要制约因素是什么?

证明的速度

证明是ZK-Rollup系统中最耗费资源的部分。那些刚接触ZK-Rollup的人通常错误地认为证明速度是对TPS的主要限制。实际上,由于每个L2块的证明可以完全并行完成,使用数百人规模的证明者集群是一种常见的做法。因此,尽管ZK-SNARK证明确实需要很长时间,但它主要会导致从L2撤回到L1的延迟更长,以及运营商的服务器成本更高,但不会对TPS造成限制。

链上存储数据和ETH GAS的限制

这是对TPS的一个真正的限制。让我们回顾一下ZK-Rollup的整体设计。为了确保安全/数据的可用性,每个交易都应该存储在链上。这部分数据将作为CALLDATA存储在ETH交易历史中,平均成本为16gas/byte。对于一个正常的交易/匹配订单,每笔交易估计为40字节。

让我们尝试通过GAS限制来估计TPS的限制。

每个ETH区块的开采需要大约13s,最大GAS量为1250万。假设一个ZK-SNARK验证需要花费30-50万GAS,那么每个ETH区块最多可以包含12,000,000 / (40*16) = 20,000个交易。所以这样一来,ZK-Rollup的TPS上限将是1500-2000。这也是许多Rollup系统在白皮书中声称的性能上限值。

默克尔树上的全局状态更新

这是一个很少讨论但很关键的观点。一个现实世界的ZK-Rollup系统的TPS实际上更多的是受到这个模块的限制,而不是上面讨论的证明速度或GAS限制。

为了支持大量的用户和资产,我们需要默克尔树有一定的深度。假设我们使用的是二进制密集梅克尔树,我们打算支持100万用户和1000种资产,那么默克尔树的深度就需要达到30。假设每个事务会引起5-10个叶子节点的更新,那么总共会有大约200次哈希计算。

出于性能考虑,我们不会在ZK-Rollup的默克尔树中使用像SHA3这样的普通哈希值。相反,我们将使用与ZK-SNARK更兼容的,如poseidon或save。根据Fluidex的测试结果,每个poseidon的哈希值大约需要30us(每个测试的树深度是20,因此,每个哈希值将是57ms / 100 / 20 = 30us)。因此,从默克尔树的角度估计,ZK-Rollup系统的极限是1 / 0.00003 / 200 = 160 TPS。

因此,默克尔树的并行更新对于突破100-300TPS的水平至关重要。与计算ZK-SNARK证明不同的是,ZK-SNARK证明可以完全并行化,而要并行化默克尔树的更新则需要更多的斟酌,并且很难在其上应用分布式计算。这也是一个技术挑战。

上面计算的100-300TPS接近许多现实世界中ZK-Rollup系统的实际性能上限值。

杂项开发经验

为什么ZK-SNARK的逻辑描述被称为 "电路"?

对于有软件工程师经验的人来说,在下面的代码中,if-分支和else-分支中只有一个会被执行,而不是两个都执行,只选择一个。

这种 "只有一个条件分支会被执行 "的概念对于软件开发来说似乎很自然,但对于硬件芯片电路的设计来说却不是这样的。在硬件顺序逻辑电路的开发中,所有 "分支"(如果仍然称为 "分支")的逻辑都将在序列被触发时执行。开发者需要从不同的 "分支 "中选择并保持正确的全局状态。

ZK证明的代码最终将被转换为一些巨大的多项式(可能有数亿项),这样,程序的证明将被转换为多项式的证明。然后,这些多项式将以门电路的形式被约束。这也是为什么我们把ZK证明程序称为电路的原因之一。因此,代码具有与硬件电路相同的属性:所有分支的代码将被一起执行。这就是为什么ZK证明代码被称为 "电路"。此外,与硬件电路类似,ZK证明电路中没有递归和复杂的循环,循环的数量只能是恒定的。

因此,在开发ZK证明电路时,开发者需要重新考虑他们软件开发的习惯。例如,在优化软件时,我们可以把重点放在最常执行的分支上。但是在ZK证明电路中,由于所有的分支都会被执行,所以不经常执行的分支也需要被考虑。

关于DSL的意见

ZK证明电路的开发有几种选择,比如低级计算库,如ethsnarks / bellman,或者DSL,如ZoKrates / Circom / Zinc。

我们选择了Circom,它提供了一个恰到好处的抽象水平。一方面,它提高了读/写代码的效率,另一方面,它不会歪曲底层电路的细节。

相比之下,用ethsnarks和bellman开发的效率就比较低。另外,当代码被审查时,不管是内部还是外部,太多的 "语法噪音 "使审查者不能专注于核心逻辑。此外,ZoKrates和Zinc过于抽象。例如,ZoKrates中python风格的控制流语法掩盖了底层电路,不利于低级别的优化(如C/Rust的内联汇编)。

打个比方,ethsnarks / bellman就像传统开发中的汇编语言,而cirom就像C,而ZoKrates就像Python。然而,ZoKrates的工具链并不像Python解释器那样成熟。这就是为什么我们宁愿使用“C”(这里是cirom)作为我们的开发语言,而不是同时维护“Python”(这里是ZoKrates)代码和 “CPython解释器”(这里是ZoKrates解释器)代码。

然而,Circom本质上仍然是一个R1CS DSL。Fluidex实际上使用PLONK证明系统。我们可能会在Circom上做重大改变,以更好地利用PLONK,包括支持自定义门、plookup、聚合与递归等。

本文来源:陀螺科技 文章作者:陀螺财经
收藏
举报
陀螺财经
累计发布内容366篇 累计总热度10万+

陀螺科技现已开放专栏入驻,详情请见入驻指南: https://www.tuoluo.cn/article/detail-27547.html

陀螺财经专栏: https://www.tuoluo.cn/columns/author1286673/

本文网址: https://www.tuoluo.cn/article/detail-10051111.html

免责声明:
1、本文版权归原作者所有,仅代表作者本人观点,不代表陀螺科技观点或立场。
2、如发现文章、图片等侵权行为,侵权责任将由作者本人承担。

相关文章