PoRv2:一种快速、透明的基于 ZK 的储备证明

  • osecio
  • 发布于 1天前
  • 阅读 53

本文介绍了PoRv2,一个基于零知识证明(ZKP)的快速、透明的储备证明系统,它结合了zk-proofs和Merkle树,允许用户在不需要外部审计的情况下验证交易所的负债。该系统使用plonky2 ZK算法,提高了效率和透明度,并提供了一个验证服务器以方便用户验证,旨在提高加密货币交易所的透明度和用户信任。

PoRv2:一种快速、透明的基于 ZK 的储备证明

在此,我们将探讨 zk-proofs、Merkle 树以及我们的新开源实现 PoRv2。我们的储备证明使用户无需依赖外部审计师即可验证交易所的负债,从而为信任树立了新标准。

PoRv2 标题图片:一种快速、透明的基于 ZK 的储备证明

什么是储备证明?

储备证明 (PoR) 的核心是一个至关重要的系统,旨在表明加密货币平台确实持有其欠用户的资金。 交易所和托管人可以通过它使用强大的密码学方法来证明他们有足够的资产来支付所有客户的存款。

这样理解:PoR 是关于实现透明度的。它是一种让平台提供清晰、可验证的财务健康状况证明的方式。 对于用户而言,这意味着更有信心他们的资金在他们使用的平台上是安全的。

从历史上看,传统的储备证明方式通常存在缺陷。 它们可能会泄露太多关于平台的敏感信息,并且在没有直接用户验证方法的情况下,过度依赖外部审计师。

我们 OtterSec 与 Backpack 合作,刚刚开发了一个储备证明系统,可用于证明 CEX 的偿付能力。 我们的 零知识储备证明 (PoRv2) 基于 OKX 储备证明算法,因为它是迄今为止已知最快、最高效的算法。 我们还使用 recursive plonky2 作为零知识证明的算法,但我们对电路进行了一些改进,以提高用户端的透明度和可验证信息,从而消除了对审计公司的信任需求。

此外,我们还创建并开源了一个 PoR 验证器服务器,该服务器接收并验证证明。

为什么我们对 PoR 使用 ZK?

证明储备金至关重要,但对于任何持有用户资金的平台来说,这都提出了一个独特的挑战:如何在公开证明偿付能力的同时,又不暴露敏感的用户余额信息或泄露专有的财务细节? 这就是 零知识证明 (ZKP) 成为游戏规则改变者的地方。

简而言之,零知识证明允许一方在不泄露除声明本身有效性之外的任何信息的情况下,向另一方证明某个声明为真。 想象一下,在不实际告诉任何人密码的情况下,证明你知道一个秘密密码。 你确认你拥有该知识,但秘密仍然属于你。

在储备证明的背景下,ZKP 非常适合解决隐私悖论。 它们使平台能够通过密码学方式证明两件重要的事情:

  1. 总和证明:交易所的负债等于所有用户余额的总和。 (例如:btc_liability = user1_btc + user2_btc + user3_btc + ...)。
  2. 非负性:所有用户都有正数净余额。 这确保了总和证明不会被具有负净余额的用户篡改。 用户可以拥有负资产余额(例如,借入 BTC),但前提是用其他资产抵押。

值得注意的是,我们无法保证所有用户都包含在 ZK 分析中。 因此,如果我们仅使用 ZKP 来证明这两个声明,交易所可能会通过将用户排除在 PoR 之外来篡改总和证明。 这就是为什么我们还使用 Merkle 树来证明包含的原因。

什么是 Merkle 树?它如何在 PoR 中发挥作用?

Merkle 树是一种树数据结构,其中每个叶节点都是单个数据(如用户的余额)的密码哈希,而每个非叶节点都是其子节点的密码哈希。 这种结构允许整个数据集由顶部的单个唯一哈希(称为 Merkle 根)进行概括。

image

在 PoR 中,我们可以使用 Merkle 树来验证每个用户是否包含在储备证明中。 它的工作原理如下:

  1. Merkle 树是使用叶节点生成的,叶节点是用户信息哈希(例如,sha256({id: 1, balances: {"BTC": 0.1, "ETH": 0.2, ...}}));
  2. Merkle 树公开;
  3. 每个用户都可以下载 Merkle 树,并通过哈希其帐户信息并检查哈希是否为叶子之一来检查其帐户是否包含在内;

换句话说,这样使用 Merkle 树可以让用户轻松验证他们的个人余额是否包含在总体总额中。

OtterSec PoRv2

我们刚刚开源了我们的储备证明代码 (PoRv2),它使用 plonky2 ZK 算法 来创建一个 Merkle 树和一个最终的 ZK 证明,该证明以递归方式验证较小的总和与非负性证明。

我们将其命名为 PoRv2,因为我们已经有一个基于 Vitalik 的偿付能力证明 的版本,该版本并非最佳版本。

非负性证明

在我们的非负性证明中,电路接收每个用户的资产余额和每种资产的价格。 通过这些输入,它会计算帐户的美元余额并检查其是否大于 0。

我们还检查求和期间的溢出,以防止篡改最终结果。

总和证明

总和证明验证了一个公共电路输入,该输入是通过对每种资产的所有用户余额求和来计算的。 (例如,BTC final: user1_btc + user2_btc ...)。 请注意,每种资产的最终总和不是基于美元的; 我们使用资产余额本身来计算最终余额。

OtterSec PoRv2 的主要特点是什么?

  1. 透明度:交易所可以安全地披露整个 Merkle 树,因此用户可以验证它,而无需外部审计公司。 此外,该代码允许资产价格承诺和验证。
  2. 时间效率:通过使用 Mac M3 Pro 在 8 分钟内为 750,000 个用户生成证明,我们将证明时间从之前的版本缩短了 100 倍以上。查看我们的基准
  3. 内存效率:我们还能够减少证明数百万用户负债所需的 RAM 量。 现在,我们能够使用具有 16GB 内存的机器。
  4. 小型证明:我们能够将最终证明减少到小于 500KB,将每个包含证明减少到 ~52KB。 我们需要存储的唯一大文件是 Merkle 树,如果 PoR 参数得到微调,它消耗的内存不超过 200MB。 此外,我们没有将每个包含证明存储在静态文件中,而是提供了一种按需生成包含证明的有效方法,从而消除了交易所存储数百万个文件并节省磁盘空间和资源的需求。
  5. 隐私:我们使用多种加密机制来确保用户余额和其他私人信息保持安全和私密。

ZK 电路

我们使用两种不同的 ZK 电路来生成最终证明:

  1. 批量电路
  2. 递归电路

通过这两个电路,我们可以生成证明递归树:

image

注意:我们使用 512 作为 BATCH_SIZE,8 作为 RECURSIVE_SIZE,这表明每个电路有多少个子电路。 这可以在代码中轻松调整,最佳配置将取决于 PoR 中要证明的帐户数量。

注意 2:我们将空证明作为填充添加到没有正确长度的块中。

此树中的每个非叶节点都是 ZK 证明,它是使用相关电路生成的; 每个电路还生成每个节点的 Merkle 树哈希,该哈希包含在 Merkle 树中。

叶节点

叶节点是帐户信息的哈希。 它的计算方式如下:

h=Poseidon(asset_balances0​ ∣∣ asset_balances1​ ... ∣∣ SHA256(user_id) ∣∣ user_nonce)

换句话说,所有余额都与哈希的用户 ID(可以是 uuid、用户名或增量 ID)和一个 nonce 连接在一起。 nonce 是一个随机数,用作针对攻击者的安全措施,他们可能会暴力破解哈希以找出其他用户的余额。 由于 Merkle 树是一个公共证明,因此我们需要小心防范此类数据泄露。

批量电路

批量电路是 PoR 算法中第一个经过验证的电路。 它接收帐户信息(分组为 512),并使用以下约束生成 ZK 证明:

公共输入

  • 美元计价的实际资产价格
  • Merkle 树哈希
  • 汇总资产余额

私有输入

  • 用户余额
  • Merkle 树叶哈希

约束

  • account_equityi​==Σ account_asset_balancesi​[asset_num]∗asset_prices[asset_num]
  • account_equityi​>=0 (非负性)
  • total_asset_balance[asset_num]==Σ account_asset_balancesi​[asset_num] (总和证明)
  • merkle_tree_hash==Poseidon(hash0​,hash1​, ...,hash511​) (merkle 树哈希)
  • account_asset_balancesi​[asset_num]<MAX_SAFE_INT/512 (溢出检查) --> 溢出检查是以这种方式进行的,以提高性能(请注意,512 实际上是 BATCH_SIZE

这是批量电路输入的可视化方案 + 如何生成用户哈希:

image

递归电路

递归电路将八个子证明作为输入,验证所有资产价格是否相同,并计算汇总余额和 Merkle 哈希。 以下是约束。

公共输入

  • 汇总的资产余额
  • 资产价格
  • Merkle 树哈希

私有输入

  • 8 个子证明

约束

  • total_asset_balance[asset_num]==Σ subproofi​.public_input.asset_balances[asset_num] (总和证明)
  • asset_price[asset_num]==subproofi​.public_input.asset_prices[0]
  • asset_price[asset_num]==subproofi​.public_input.asset_prices[asset_num] (验证所有资产价格是否相同)
  • merkle_tree_hash==Poseidon(hash0​,hash1​,...,hash31​) (merkle 树哈希)
  • 通过检查两个正数的总和是否导致负数来检查每个总和是否溢出 (溢出检查)

这是递归电路输入的可视化方案。 请注意,此树只有三个级别(L1、L2、L3)。 根据用户数量,它可能具有更多递归级别:

image

全局证明和包含证明

证明

在证明所有批量电路和所有递归电路之后,我们得到了最终证明(这是递归树根的 ZK 证明)、整个 Merkle 树和用户 nonce。 在我们的代码中,它被序列化为 merkle_tree.jsonfinal_proof.jsonprivate_nonces.json 文件。

使用 ZK 证明和 Merkle 树,我们已经可以证明资产余额的总和及其非负性; 我们将其称为 “全局证明”。

对于用户包含证明,我们获取 Merkle 树、用户资产余额、标识哈希和 nonce,以将其捆绑到一个证明文件中 ( inclusion_proof_<id>.json)。 我们将 Merkle 树的一部分捆绑到包含证明文件中,以使证明更小

验证

全局证明

为了验证全局证明,代码会反序列化 merkle_tree.jsonfinal_proof.json 文件,并执行以下检查:

  1. 验证最终证明是否是通过有效且受信任的电路生成的。
  2. 验证 ZK 最终证明。
  3. 验证资产价格是否有效。 (它不验证它是否与实际价格匹配;你需要手动执行此操作。 它仅验证小数是否有效。)
  4. 验证 Merkle 树根哈希是否与最终证明 merkle_tree_hash 公共输入相同。 这确保了 merkle_tree.jsonfinal_proof.json 已链接(它们属于同一全局证明)。
  5. 通过再次哈希所有节点来验证整个 Merkle 树,从批量电路开始,因为验证者没有必要的信息再次哈希叶子(为了隐私)。 这确保了树没有被篡改。

包含证明

为了验证包含证明,代码会反序列化 inclusion_proof_<id>.json 文件以及 final_proof.json。 之后,它执行以下检查:

  1. 验证 ZK 最终证明。
  2. 验证 Merkle 树根是否与最终证明中的 Merkle 树根相同。
  3. 重新计算用户相关的节点叶哈希。
  4. 使用重新计算的哈希验证部分 Merkle 树(它不包含所有叶子)。

PoR 验证器服务器

为了自动化验证过程,我们创建了一个 验证器服务器,交易所可以将证明提交到该服务器。 提交后,将验证证明并将其添加到数据库。

添加证明后,任何用户都可以进入网站并查看其信息(请参阅 backpack 的示例):

image

以下分解了各个字段的含义以及为什么需要它们:

  • 状态 --> 验证证明是否有效,确保信息未被篡改。
  • 证明时间戳 --> 交易所生成证明的时间。
  • 验证时间戳 --> PoR 服务器验证证明的时间。
  • 证明文件 URL --> 从中下载证明的 URL。 用户可以下载它以自行验证证明的有效性。
  • 证明者版本 --> 使用的 PoRv2 版本。 对证明/验证使用不同的版本可能会由于 ZK 电路差异而导致错误。 因此,如果你要自行验证证明的有效性,请确保下载并使用与证明相同的证明者版本。
  • 文件哈希 (SHA256) --> 由于我们仅存储证明的 URL,因此在我们的验证后可能会恶意更改它。 SHA256 可用于证明文件在验证后是否被修改。 如果你要自行验证证明,请检查下载的 zip 文件是否与网站上显示的哈希匹配。

此外,你还可以在网站上查看交易所的负债:

image

这些是交易所应在其储备中拥有的资产数量,以便在每种资产上都具有偿付能力。 你可以通过检查他们在区块链上的储备钱包来匹配他们是否拥有。 你可以在 https://backpack.exchange/reserves 中查看 backpack 的钱包,并在 https://backpack-por.osec.io/ 中查看我们用于 backpack 的验证器服务器。

自我验证

作为用户,你可以自行验证这两个证明,包含证明用于验证你是否包含在 PoR 总负债总和中,全局证明用于验证交易所提供的承诺是否有效。

如何验证我是否包含在内?

如果你是用户并且想要进行包含的自我验证,则需要按照以下步骤操作:

  1. 从我们的 github 下载 PoRv2 可执行文件
  2. 从交易所下载包含文件和最终证明文件 ( inclusion_proof_<id>.jsonfinal_proof.json),并将文件放在与 PoRv2 应用程序相同的目录中。
  3. 打开终端并执行此操作:./plonky2_por verify-inclusion

这将验证证明是否有效并显示你的资产余额。 你需要手动验证余额是否正确。 请记住,证明不是实时计算的; 你必须验证余额在证明生成日期是否正确。 这是经过验证的有效证明的示例:

[!] 用于生成证明的信息如下,请手动验证它们是否正确:
[!] 注意:这不是实时信息,请验证该信息相对于证明生成时间是否正确
[!] 注意 2:某些资产余额已四舍五入到某些小数位,请验证它们是否足够接近原始余额
======================
证明生成日期:2025-02-22 19:59:59 UTC
证明生成时间戳(毫秒):1740254399944
已计入资产数量:100

-----资产余额-----
ETH:0
BTC:1.2
USDC:0
...
======================
[!] 正在验证全局证明(信任文件内部的电路数据)...
[+] 全局证明有效!
[!] 正在验证包含证明...
[+] 包含证明根哈希有效! 用户包含在 merkle 树中!
[+] 成功验证文件包含证明:inclusion_proof_00476816e43cf2efffdabdda7f55c5203bc9e28382c551f83931de02fd364a25.json

[+] 所有包含证明均有效!
[+] 在 13.731875 毫秒内完成!

如何验证全局证明?

如果你要验证全局证明是否有效,只需按照以下步骤操作:

  1. 从我们的 github 下载 PoRv2 可执行文件
  2. 下载 merkle_tree.jsonfinal_proof.json 文件,并将它们放在与 PoRv2 应用程序相同的目录中。 你可以从我们的 PoR 验证器服务器下载这些文件(下载 zip 文件并解压缩)。
  3. 打开终端并执行 ./plonky2_por verify-global。 这可能需要一段时间才能验证,因为它需要反序列化一个大文件并验证最终证明电路(这涉及重建它)。

这将验证全局证明并打印资产价格以进行手动验证。 请注意,显示的资产价格不是实时的; 你必须将它们与证明生成日期和时间的价格进行匹配。

[!] 正在验证储备证明...
[!] 用于生成证明的信息如下,请手动验证它们是否正确:
[!] 注意:这不是实时信息,请验证该信息相对于证明生成时间是否正确
[!] 注意 2:资产价格已四舍五入到某些小数位,请验证它们是否足够接近原始价格
======================
证明生成日期:2025-02-22 19:59:59 UTC
证明生成时间戳(毫秒):1740254399944
已计入资产数量:100

-----资产价格-----
BTC:95000 美元
ETH:2402.48 美元
...
======================

验证完成后,并且所有证明都有效,系统将打印每种资产的汇总余额。 这些是交易所的负债,你可以使用它们来检查他们是否有储备金来支付。

[!] 正在重建根电路... 这可能需要几分钟...
[+] 根电路重建成功!
[!] 正在验证最终证明...
[+] 证明有效!
[!] 正在验证资产价格...
[+] 资产价格有效!
[!] 正在验证资产小数...
[+] 资产小数有效!
[!] 正在验证 merkle 树根哈希...
[+] Merkle 树根哈希有效!
[!] 正在验证 merkle 树...
[+] Merkle 树有效!

[!] 以下信息是最终所需的资产储备金,已通过零知识证明验证
[!] 注意:这不是实时信息,该信息与证明的生成时间相关
[!] 注意 2:我们无法保证所有用户都包含在证明中,但你可以通过验证包含证明来检查你是否包含在内
======================
证明生成日期:2025-02-22 19:59:59 UTC
证明生成时间戳(毫秒):1740254399944
已计入资产数量:100

-----资产储备金-----
BTC:1.2
ETH:5.4
...
======================

[+] 所有证明均有效!
[+] 在 4.455745214 秒内完成!

结论

总之,储备证明是加密货币平台的重要机制,使它们能够以透明的方式展示偿付能力并获得用户信任。 通过采用零知识证明,平台可以在不暴露敏感用户数据的情况下实现这种透明度,从而有效地证明总负债并确保非负性,同时保护隐私。 我们的系统进一步改进了此过程,提高了效率并消除了手动验证的需要。

我们目前正在与 Backpack 合作,在生产环境中实施此算法,以每 24 小时生成和验证证明。 这标志着朝着建立实时储备证明系统迈出了重要一步,特别是考虑到它提供了更高的透明度,这是减少对外部审计公司需求的一个进步,因为用户将能够自行验证所有内容。

有关 Backpack Exchange 如何在实践中实施储备证明的更多信息,你可以阅读他们的详细文章:Backpack Exchange 的储备证明:真正的透明度,ZK 验证

  • 原文链接: osec.io/blog/2025-08-27-...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
osecio
osecio
Audits that protect blockchain ideas.