本文是介绍零知识证明的系列文章中的第二篇,主要探讨它们在Solana上的应用,特别是ZK压缩技术。这项技术通过验证状态转换来降低链上状态存储成本,并解决Solana的状态增长问题。同时文章详细解析了零知识证明的原理、zk-SNARKs和zk-STARKs的区别、ZK压缩的工作机制,以及未来在Solana上的发展潜力。
特别感谢 Matt、Porter、Nick、Swen 和 bl0ckpain 审阅了本系列文章。
这是零知识证明入门系列的第二篇文章。在阅读本文之前,强烈建议先阅读《零知识证明:基础知识介绍》,因为它提供了本文分析所需的底层理论、数学和密码学的必要背景。本文假定读者已经具备这些知识,因此,如果你对零知识证明不熟悉,强烈建议之后再阅读这篇文章。本文的目标是让读者具备参与 Solana 上零知识证明讨论的基本知识,甚至走上开发新的、创新性的零知识原语的道路。
有了这些新知识后,我们终于可以问:什么是零知识证明?它们在 Solana 上是如何使用的?
现在我们终于掌握了必要的理论、数学和密码学知识,是时候问一个合适的问题:到底什么是零知识证明?
零知识证明是一种加密过程,其中一个参与者能够向另一个参与者证明某个陈述是真实的,而无需透露任何额外信息,除了该陈述确实为真之外。这些证明必须在统计上是合理、完整且防止信息泄露的。
有两种类型的陈述需要以零知识证明。在高层次上:
第一个陈述最终涉及宇宙的一些内在属性——即基本为真的事物,如 1 + 1 = 2。第二个陈述被称为知识证明。也就是说,它不仅超越了某些事情为真的证明,而且依赖于证明者所知道的内容。
如前所述,为了证明这些陈述,我们的证明可以是交互式的或非交互式的。在交互式零知识证明中,证明者和验证者进行一系列轮次,直到验证者确信无疑。Zcash 使用非交互式零知识证明来允许用户进行匿名交易。
相比之下,在非交互式零知识证明中,证明是在没有证明者和验证者之间任何直接通信的情况下离线提供的。在这里,证明者生成一个包含所有必要信息的证明,验证者可以独立验证该证明而无需进一步互动。Filecoin 使用非交互式零知识证明来证明用户已存储数据而无需揭示数据本身。
zk-SNARK 是一种简洁的、非交互的、知识论证。这些零知识证明特别高效且紧凑,或者说简洁。如果证明的大小和验证所需的时间比要验证的计算增长得慢,则认为证明是简洁的。因此,如果我们想要一个简洁的证明,就不能让验证者在每一轮哈希操作中做些工作,否则验证时间将与计算成比例。简洁证明之所以可能,要归功于多项式和 Fiat-Shamir 启发法。
无论要证明的陈述多么复杂,zk-SNARK 都能保持证明的大小较小且相对快速验证。这使得 zk-SNARK 对汇总来说非常有吸引力;在这里,我们有一种方法来证明给定 L2 的所有交易都是有效的,并且证明足够小可以在 L1 上验证。像 Mina 这样的协议更进一步,使用递归证明,从而可以用恒定大小的证明验证整个链的历史记录。Pickles 是 Mina 的新证明系统及相关工具包,这是第一个部署的能够无信任设置递归组合的 zk-SNARK。请注意,通过递归组合,我们指的是电路。
电路描述你想要证明的计算。它是一系列的数学运算,将一些输入转换为输出。在零知识证明中,电路用于表示正确执行的计算,而不揭示计算的输入。一般工作流程如下:
某些类型的 zk-SNARK,如 Groth16,每个电路都需要一个可信设置。这可能会阻碍你,因为你需要为每个新程序运行一个新的仪式。其他 zk-SNARK,如 PlonK,只需要一个通用的可信设置即可简化整个过程。还有其他类型的零知识证明,如 zk-STARKs,完全消除了对可信设置的需求。
zk-STARK 是一种可扩展的、透明的、知识论证。zk-STARKs 由 StarkWare 发明并首次在 2018 年的这篇论文中提出,作为 zk-SNARKs 的替代方案。本质上,它们允许区块链将计算转移到单个链下的 STARK 证明器,并使用链上的 STARK 验证器来验证这些计算的完整性。
zk-STARKs 被认为是零知识的,因为链下证明器使用的输入不会暴露给区块链,从而保护了用户的隐私。zk-STARKs 具有可扩展性,因为将计算移至链下显著降低了 L1 验证成本。其证明也呈线性扩展,而 zk-SNARKs 只能准线性扩展。此外,zk-STARKs 不依赖复杂的可信设置仪式,他们认为这些仪式容易受到“有毒废料”——如果仪式未正确进行,验证者可能接受无效证明——的影响。相反,zk-STARKs 使用公开可验证的随机性来设置证明者和验证者之间的交互。而且,这些证明只能由实际执行计算的链下证明器生成,并附带计算所需的辅助输入。
zk-STARKs 通过成为可扩展的、透明的知识论证解决了 zk-SNARKs 的局限性。它们还带有更为简单的加密假设,完全避免了诸如椭圆曲线等元素的使用。相反,它们纯粹依赖哈希和信息论,使它们抗量子。然而,证明的大小在几百千字节范围内,这可能会限制它们在带宽或存储有限的环境(如区块链)中的可行性。
请注意,一些更复杂的证明设置和 zkVM 将在最终验证步骤中递归地使用 zk-STARKs 到 zk-SNARKs 的组合。
Solana 最紧迫的问题之一是状态增长问题。为了解决这个问题,Solana 的状态存储在账户数据库中,该数据库位于全节点的磁盘上。这是一个键值存储,数据库中的每个条目被称为账户。账户地址为 32 字节,账户可以存储的数据量在 0 到 10 MB 之间变化。目前,存储 10 MB 数据大约需要花费 70 SOL,无论是存放在一个 10 MB 的账户还是分散在一万个 10 KB 的账户中,成本都是相同的。每天大约有一百万个新账户被添加到链上,根据 Toly 在状态增长问题一文中所述,总状态已经超过五亿个账户。随着 Solana 的持续增长,这将带来几个挑战,即无限的快照大小、PCI 带宽限制、账户索引以及昂贵的内存和磁盘管理。
当前完整的快照大小约为 70 GB,这对于当前硬件而言是可以管理的。然而,持续的增长将不可避免地导致状态管理效率低下和潜在瓶颈。随着快照大小的增加,硬件故障后冷启动新系统所需的时间会显著变长,这对网络重启情况可能是有害的。
外设组件互连 (PCI) 带宽是指 CPU 和外围设备(如显卡、网卡和存储设备)之间的数据传输速率。PCI Express (PCIe) 是一种高速接口标准,旨在取代旧的 PCI 标准并提供更高的数据传输速率。最新的 PCI 带宽速度可达 1 TB,或 128 GB/s。尽管这听起来很多,但在 Solana 的背景下并非如此。如果一笔交易读取或写入 128 MB 的数据,那么 128 GB/s 的 PCI 带宽会将 Solana 的交易处理能力限制在每秒 1000 笔交易 (TPS)。然而,大多数交易访问的是已经加载并缓存在验证者 RAM 中的近期内存。尽管如此,高效的内存管理对于确保 Solana 扩展时维持高吞吐量至关重要,否则这一带宽可能很快成为一个限制因素。
每个验证者需要维护所有现有账户的索引。这是因为创建新账户需要证明该账户尚不存在。超过五亿个账户的总状态中,即使是最小索引(即每个条目一个 32 字节的键和一个 32 字节的数据哈希),也需要大约 32 GB 的 RAM。这种状态存储费用昂贵,必须谨慎管理以防止性能下降。随着 Solana 状态的不断增长,使用快速但昂贵的内存(如 RAM)和缓慢但便宜的内存(如硬盘)来进行某些操作的区别变得至关重要。
每次 Solana 交易都需要指定其读取和写入的所有账户。目前,交易的上限为 1232 字节,并且必须包含以下内容:
当交易被执行时,会发生以下情况:
随着状态的不断增长,这一生命周期带来了几个挑战。具体来说,链上状态很昂贵,更多的账户存储在磁盘上会导致更大的快照和索引。此外,并不是所有账户都被频繁访问,因此对它们产生持续的资源消耗是低效的。
与其将所有账户存储在磁盘上并在需要时读取,不如让交易将账户数据作为交易负载的一部分传递。我们可以使用 Merkle 树确保提交交易的用户提供正确的状态。Merkle 证明是一种承诺某些数据的方式。这样,可以通过与承诺对比验证这些证明,以确认正确状态已被传递并且用户没有关于所提供状态撒谎。
虽然安全,但这些证明可能会相当大。例如,如果树中有 100k 个账户,证明大小将为 544 字节。为多个账户提供证明可能会迅速超过 1232 字节的交易大小限制。幸运的是,我们可以通过使用更有效的证明系统来绕过这一问题。使用常量证明大小的承诺,如 KZG 或 Pedersen 承诺,会减少证明大小,使其更容易包含在交易大小限制内。
ZK 压缩只是解决 Merkle 证明大小问题的一种机制——这是一种通过利用 Solana 的账本 来证明某些计算已正确完成,而不涉及链上存储相关成本的方法。
ZK 压缩是一种新原语,允许开发者压缩链上状态,将状态成本降低几个数量级,同时保留安全性、性能和可组合性。例如,创建 100 个代币账户目前的成本约为 0.2 SOL,而使用 ZK 压缩,成本降至原来的 1/5000,约为 0.00004。
ZK 压缩利用零知识证明来验证状态转换,而无需暴露底层数据。它通过将多个账户分组到一个单一的、可验证的 Merkle 根中存储在链上,而底层数据则存储在账本上来实现这一点。有效性证明是简洁的零知识证明,用于证明 n 个账户作为叶子存在于 m 个状态树中,同时保持恒定的 128 字节证明大小。这些证明在链下生成并在链上验证,减少了 Solana 上的整体计算负担。ZK 压缩使用 Groth16,一种著名的基于配对的 zk-SNARK,作为其证明系统。
然而,这些账户并不是普通的 Solana 账户。相反,它们是压缩账户。
ZK 压缩状态存储在压缩账户中。这些账户与普通 Solana 账户相似,但在效率和可扩展性方面有几个关键区别:
压缩的程序派生地址 (PDAs) 可以通过其独特且持久的地址标识。它们遵循类似于常规 PDA 账户的布局,包含数据、Lamports、拥有者和地址字段。然而,与常规 PDA 不同,数据字段体现了 AccountData 结构,其中包含判别符、数据和数据哈希字段。
不同类型的节点在支持 ZK 压缩方面扮演着关键角色。任何人都可以运行 Photon RPC 节点、Prover 节点或 Light Forester 节点以连接到 Devnet 和 Mainnet-Beta。对于本地开发,ZK Compression CLI test-validator
命令启动一个包含所有相关节点(即 Photon RPC 和 Prover)、系统程序、账户和运行时功能的单节点 Solana 集群。
Photon RPC 节点 索引压缩程序。这使得客户端可以读取和构建与压缩状态交互的交易。规范的压缩索引器名为 Photon,由 Helius 提供。这种类型的节点可以在本地运行,只需最少的设置,并且需要指向现有的 RPC。
Prover 节点 用于生成状态包含的有效性证明。ZK Compression RPC API 规范 的 getValidityProof 端点可用于获取证明。Prover 节点可以作为独立节点运行,也可以与其他 RPC 捆绑在一起。注意规范的 Photon RPC 实现包含一个 Prover 节点。
Light Forester 节点 管理共享和程序拥有的状态树的创建、滚动更新和更新。这适用于希望自己的程序拥有的状态树由一组 Light Forester 节点服务的开发者。
任何人可以运行上述节点之一以及存储生成证明和提交交易所需的原始数据。这引入了一种影响压缩状态活性的信任假设。也就是说,如果数据丢失或延迟,除非个人存储数据,否则无法提交交易。由于只需要一个诚实节点提供数据,并且证明是自验证的,问题在于其活性和潜在审查,而不是安全性。
此外,验证压缩账户的程序当前可升级的事实引入了另一个信任假设。这样做是为了使程序能够修改以修复任何问题或适应新需求。然而,一旦达到稳定和安全状态,未来可以使其不可变或冻结。
另一个活性信任假设是 Forester 节点的使用。这些节点通过清空队列并异步推进状态根来维护状态根的前进和管理 nullifier 队列。在这里,账户哈希被替换为零以将其置空。这种前进和置空的分离确保了压缩状态转换的即时最终性,同时将交易保持在 Solana 的大小限制内。由于 nullifier 队列有固定大小,Forester 节点对于协议的活性至关重要。一个满队列将导致关联状态树的活性故障。幸运的是,Forester 节点通过清空队列来防止这种情况。然而,人们仍然需要运行这些节点以帮助协议的完整性和活性。如果没有这些节点,ZK 压缩只能支持大约两千个账户/地址。
即使不需要隐藏什么,零知识证明也将需要多个计算步骤的问题转化为只需验证单个证明就能知道计算是否正确的问题。这些计算不必是某特定叶属于给定树的判断——它们可以是任何任意的计算。然而,这需要付出代价。
在使用 ZK 压缩之前,请考虑以下几点:
如果出现以下情况,可能更倾向于使用普通账户:
ZK 压缩是一种可扩展、安全、高效且灵活的原语,直接解决了 Solana 的状态增长问题,并支持广泛的应用和用例。可以说,其最显著的优势是状态成本的降低。ZK 压缩允许应用程序通过在较便宜的账本空间上安全存储状态,同时保持最小的链上存储和状态指纹识别,轻松扩展到数百万用户。例如,假设 SOL 价格为 130 美元,铸造 10,000 个代币账户大约需要花费 2,600 美元。而使用 ZK 压缩,这一成本降低到不到五十美分。
ZK 压缩也非常契合当前的 Solana 规范。例如,压缩账户的结构几乎与普通 Solana 账户相同。它还支持 Solana 特有的创新,如并行性。也就是说,同一状态树(即承诺)下访问不同压缩账户的任何两笔交易都可以并行执行。此外,ZK 压缩加强了同步原子可组合性。例如,列出 n 个压缩账户和 m 个普通账户的交易是一个完全有效的配置。引用压缩账户的指令可以调用引用普通账户的另一指令或程序。即使账户在不同的状态树下压缩也是如此。如果一条指令失败,则整个交易将回滚,更改从一个指令可见到下一个。这与 ZK Rollup不同,除非它们加锁,否则汇总不能彼此同步或原子调用。自然地,这引发了一个 ZK 压缩与汇总之间的比较。
ZK 压缩不是汇总。尽管两者依赖相同的技术,但它们的实现有所不同。有两种类型的汇总:
零知识汇总的整个状态在基础层(即以太坊)上表示为单个根。这导致了许多声称 ZK 压缩实际上是汇总的观点。然而,有一些关键差异。
考虑涉及 ZK Rollup上 500 笔交易的情景。在这种情况下,整个汇总被视为一个单一电路。所有 500 笔交易一起验证,结果是一个证明,确认状态根从 A 改变为 B。在此证明验证后,管理 L1 和 L2 之间交互的智能合约相应地更新状态根。相比之下,在 ZK 压缩中,500 笔交易中的每一笔都生成自己的证明,以验证账户数据的正确性。这些交易由 SVM 自身执行,并且在每个证明验证后,账户被视为“普通”账户。
如果我们把 ZK 压缩归类为汇总,这意味着 Solana 上存储的任何 Merkle 根都可以被视为基于有效性的汇总。如果我们查看 Solana 上当前所有的压缩 cNFT 根,那么大约有 4-5 千个基于有效性的汇总,取决于我们是否计入具有零铸币的 Merkle 树。
因此,显然 ZK 压缩是针对 Solana 架构定制的独特解决方案。它是一种新原语,不同于 ZK Rollup,能够在不涉及汇总的复杂性和分离的情况下增强可扩展性和效率。
我在 Helius 的第一个写作任务是涵盖 Solana 的 v1.16 更新。我对更好的零知识证明运行时支持感到非常兴奋,并在文章中进行了报道。然而,这些改进被推迟了。我在v1.17 更新文章中再次详细报道了这些改进,结果它们又被推迟了。我没有在v1.18 更新文章中提及它们。自然地,我感到失望,其他人也表达了挫败感。
尽管如此,Solana 上有一个萌芽的,虽然很小的 ZK 开发者社区。最初,Light Protocol 专注于私人程序执行的形式 PSP(Private Solana Programs),之后他们把重点精炼到 ZK 压缩。Dark protocol 也是建立在 Solana 上的一个futarchic隐私协议。它没有核心团队,贡献通过提案完成。Arcium,以前称为Elusiv,正在使用多方计算执行环境 (MXEs) 来驱动其自身的并行化、保密计算网络。Bonsol 是一个零知识“协处理器”,允许开发者运行任何risc0 图像并在 Solana 上验证它(即,可验证的链下计算)。教程 和零知识证明相关链接列表也已经流传开来。
最值得注意的是,ZK Token Proof Program 验证了几种专门设计用于与Pedersen 承诺 和 Twisted ElGamal Encryption结合使用的零知识证明,后者基于curve25519。它支持保密转移,后者使用零知识证明加密 SPL 代币的余额和交易金额。目标是保密而非匿名。同态加密允许在加密数据上进行计算而无需解密。为此,保密转移使用 Twisted ElGamal 加密对密文进行隐藏数学运算,并使用Sigma 协议验证这些转账而不泄露敏感信息。只有拥有解密密钥的账户持有人才能查看其加密余额。然而,全球审计系统允许通过单独的解密密钥选择性地读取以进行合规和审计。
ZK Token Proof Program 目前是一项受阻的功能,原因是SIMD-0153: ZK ElGamal Proof Program 的通过。这个新的 SIMD 旨在弃用专门为 SPL Token 程序设计的现有 ZK Token Proof 程序,并用一个更通用的独立于任何特定应用的零知识证明程序代替它。该 SIMD 已经合并,得到了Anza和Firedancer 团队的支持。
然而,形势开始转变。随着这些改进终于进入 Devnet 和 Mainnet-Beta,Solana 正在成为一个 ZK 巨人。 现在 Solana 上已经有三个 ZK syscalls 生效。
Poseidon 是专为零知识证明设计的一族哈希函数,用于 Zcash、Mina 和 Light Protocol 等项目。Poseidon 比传统的、广义的哈希函数(如 SHA-256)在零知识证明中更具计算效率。
Poseidon 哈希函数对零知识友好是因为它们:
以前在一个交易中计算 Poseidon 哈希太贵了。然而,这随着 epoch 644 和 Poseidon syscall(即一个系统调用,输入二维字节片并计算相应的 Poseidon 哈希作为输出)的激活而改变。这令人兴奋,因为 ZK 压缩依赖 Poseidon 哈希来进行其状态树。
Poseidon syscall 使用 BN254 曲线 计算哈希,参数如下:
其输出将是编码为 32 字节的 Posiedon 哈希结果,采用指定的端序。
注意这里用于 syscall 的具体变体是 Poseidon,带有 x _5_S-box 和为 BN254 曲线定制的参数。light-poseidon
crate 将促进这些哈希的计算。该 crate 本身经过审核并与Circom兼容。
alt_bn128 指的是 Barreto-Naehrig (BN-128) 椭圆曲线的实现,这是一条对配对友好的曲线,能够实现高效的 zk-SNARKs 证明和计算。这条曲线对于各种零知识证明系统至关重要,包括 Groth16,ZK Compression 依靠它来验证状态转换。此 syscall 显著减少了每份证明所需的空间,为高效的链上证明提供了重要的空间和时间优化。
sol_alt_bn128_group_op syscalls 在 alt_bn128 曲线上进行操作,包括 G1(我们简单地指某一椭圆曲线上的一组点)中的点加法、G1 中的标量乘法和配对:
sol_alt_bn128_compression syscalls 在 alt_bn128 曲线的 G1 或 G2 组中压缩或解压缩点,并以标准的大端格式返回点。
这些 syscalls 当前在测试网上生效,一旦解决加载程序重新编译阶段中的错误,它们似乎将在 Devnet 上可用,根据 SIMD-0075: Secp256r1 Precompile 提案。该提案旨在简化 alt_bn128 syscalls 以及 Poseidon syscall 的错误代码,确保一致性并减少因验证者返回的不同错误代码而导致共识失败的风险。
alt_bn128 syscalls 可用于常量证明大小的常规向量承诺,例如 KZG 承诺。因此,它们将与任何配对友好的曲线兼容,并且不需要 ZK-prover 电路。
Solana 是一条 ZK 链。它是一个高性能的 Layer 1 区块链,具有低费用和椭圆曲线操作的运行时支持。零知识证明相关 syscalls 的实施和支持促进了创新,允许新颖的原语和应用程序(如 ZK 压缩)在 Solana 上构建。
alt_bn128 syscalls 的引入缩小了 Solana 和依赖预编译合约进行EIP-196、EIP-197 和 EIP-198 指定的椭圆曲线操作的 Solidity 合约之间的可组合性差距。这些操作有助于在以太坊的 gas 限制内进行 zk-SNARK 证明验证。因此,依赖这些椭圆曲线操作的 Solidity 合约现在可能更容易过渡到,甚至是与 Solana 互操作。SIMD-0075 对于互操作性解决方案至关重要。一旦完全实施,该 SIMD 将使项目(例如即将推出的 blobsream-solana(将 DA 从 Celestia 流式传输到 Solana))能够使用链下证明生成和链上验证来存储 Merkle 承诺。没有这些系统调用,就无法在 Solana 上验证 Groth16 证明。此外,这些系统调用增强了信任最小化的桥接和互操作性,允许其他区块链无缝且安全地与 Solana 交互。
Toly 是对的——随着所有这些对 Solana 运行时的增强,Solana 成为了一个以太坊 L2。很快,将没有任何东西可以阻止你将 Solana 的所有区块提交到以太坊上的某个数据验证桥合约中。反之,也将没有任何东西能阻止你将以太坊的所有区块提交到 Solana 上的某个数据验证桥程序中。双向互操作性由零知识证明加速推动,而非过时的桥接方案,这是 Solana 光明且充满希望的未来。
零知识证明无疑是密码学家开发的最强大原语之一,如果不是最强大的话。通过在第一篇文章中考察这一概念背后的理论、数学和密码学,从基本原理出发,这一点显而易见。潜在的应用是无穷无尽的,从链上游戏的真实战争迷雾到证明 L2 上的一组交易导致了特定的状态转换。
这个两部分系列文章本可以再写五十多页,涵盖同态加密的复杂性、在 Circom 中编写电路以及分析不同的承诺方案。然而,这些文章的目标是教育读者了解零知识证明的基础知识,以便他们可以掌握这一新知识,并将其应用于 Solana。
Solana 正在成为一个 ZK 巨头。从 ZK 压缩的发布到不久的将来各种系统调用的上线,其重要性不言而喻。虽然像 ZK 压缩这样的原语为普通开发者抽象掉了零知识证明的所有复杂性,但对基础知识的理解对于推动 Solana 上的讨论及其发展来说是无价的。
如果你已经读到这里,谢谢你,匿名者!请务必在下方输入你的电子邮件地址,这样你就不会错过有关 Solana 最新动态的任何更新。准备好深入研究了吗?探索 Helius 博客 上的最新文章,并立即继续你的 Solana 之旅。
- 原文链接: helius.dev/blog/zero-kno...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!