跳转到主要内容

如何使用零知识证明在以太坊上构建隐私应用

零知识证明
隐私
菲利普·克劳斯
EF Builder Growth
2026年5月12日
12 分钟阅读

以太坊在设计上是极其公开的。任何拥有区块浏览器的人都可以看到每个地址、余额、交易、合约调用和事件。当你需要可验证性时,这种透明度是有用的。但当用户需要投票、申领、提款或证明成员身份,而不希望将每次操作都关联回同一个钱包时,这就成了一个问题。

匿名成员身份是一种可复用的模式,为以太坊上的大量隐私应用提供了动力。人们首先注册,然后证明他们属于该群体,而不透露他们具体是哪位成员。零知识证明是注册钱包和操作钱包之间的桥梁,这座桥梁不会透露是谁穿过了它。

周边的产品会发生变化,但隐私骨架保持不变。

通过匿名投票解释该模式

该模式包含三个部分。承诺用于注册每个成员。默克尔树将这些承诺汇聚成一个群体。证明和无效化器(nullifier)让一名成员可以操作一次,而不透露是哪位成员进行了操作。

第一步:注册

每个投票者在链下创建两个私有值:秘密值(secret)和无效化器(nullifier)。投票者将这些值哈希成一个公开的承诺,然后将该承诺注册到链上。

承诺是公开的注册记录。秘密值和无效化器是投票者稍后需要的私密票据(note)。如果丢失了该票据,投票者就无法证明其成员身份。如果泄露了它,其他人就可能代替该用户进行投票。

因为承诺是一个哈希,观察者无法恢复其中的私有值。承诺表明“有人注册了”,但不会透露稍后谁将使用该注册。

第二步:构建群体

随着越来越多投票者的注册,应用将他们的承诺收集到一棵默克尔树中。默克尔树将一长串值压缩成一个单一的哈希,称为根(root)。更改列表中的任何值,哈希就会改变,因此根充当了整个集合的防篡改摘要。

这棵树就是你的匿名集。如果树中有十个用户,观察者可以将随后的操作范围缩小到这十个人之一。如果树中有一万个用户,就很难将操作与某个人联系起来。一个匿名集很小的隐私应用通常不是非常私密,即使密码学是正确的。

第三步:匿名操作

当投票开始时,投票者不应使用注册承诺的同一个钱包进行投票。使用注册钱包投票会直接将投票与注册者联系起来,从而使隐私保护工作前功尽弃。相反,投票者会创建一个零知识证明。该声明被编码为一个电路,表示:“我知道能生成已注册承诺的私有值,并且我正在为这次投票揭示正确的无效化器哈希。”

该证明使验证者合约确信该声明是真实的。它不会透露秘密值、无效化器,也不会透露使用了哪个承诺。

无效化器是防止重复投票的机制。在提供证明的同时,投票者会发布一个无效化器哈希。投票合约在接受投票后会存储该哈希。如果同一私密票据再次用于同一次投票,它将生成相同的无效化器哈希,合约将拒绝第二次投票。结合证明,这使得合约只知道某个注册投票者操作了一次,而不知道具体是哪一个。

可复用的门控

同样的证明和无效化器组合不仅适用于投票。抛开投票的场景,你得到的是一个用于智能合约函数的隐私门控。

在函数运行之前,合约会检查默克尔根,验证证明,确认无效化器哈希未被使用,并将公共输入绑定到正确的应用、链、投票、申领或提款上。如果这些检查通过,它会将无效化器标记为已使用,并运行函数的其余部分。

将这个门控放在投票前面,你就得到了匿名投票。将它放在空投申领前面,你就得到了匿名申领。将它放在提款函数前面,你就得到了混币器式提款流程的核心。相同的承诺树,相同的无效化器理念,相同的证明模式。改变的只是函数体和周边的应用逻辑。

各部分在哪里运行

隐私工作通常在链下进行。用户存储票据,客户端应用构建见证数据并运行证明者来生成证明。索引器跟踪承诺和默克尔根。捆绑器将用户操作(UserOperation)传播到链上,并由 ERC-4337 代付合约赞助 Gas,因此一个全新的钱包不需要首先从用户已知的钱包中获取 ETH。

公开的执行发生在链上。验证者合约检查证明。应用合约检查有效的根和未使用的无效化器,存储无效化器哈希,并运行公开操作。

敏感的用户体验(UX)在于票据处理。应像对待密钥一样对待秘密值和无效化器。不要将它们放入分析、日志、URL、错误报告或常规的服务器端遥测中。一旦票据泄露,无论证明多么强大,隐私都将不复存在。

工具已经跟上

你不需要手动编写底层的密码学代码。一种常见的途径是使用高级零知识语言编写电路,生成一个 Solidity 验证者,然后从应用合约中调用该验证者。

合适的技术栈取决于具体任务。使用 snarkjs 的 Circom 是应用级电路的一条历史悠久的途径。使用 Barretenberg 的 Noir 是一条较新的、对开发者友好的途径。Halo2 和 gnark 是更底层的电路库。诸如 RISC Zero 或 SP1 之类的 zkVM 可以证明普通程序,但其证明成本可能比小型自定义电路更高。

对于匿名成员身份,在编写自己的电路之前,请先寻找现有的协议。Semaphore 将群组成员身份和基于无效化器的防双重使用机制打包到了合约和 JavaScript 库中。对于隐私投票和治理,MACI 是专门的途径,因为它增加了抗共谋的特性。成熟的协议通常比新电路更安全。

仅有证明是不够的

如果钱包流程泄露了关联,即使是完美的证明也会失效。从钱包 A 注册,随后又从钱包 A 操作,任何观察者都能将这些交易联系起来。在操作之前直接从钱包 A 向钱包 B 提供资金,这笔资金交易也会产生同样的问题。

这就是为什么捆绑器和代付合约如此重要。操作钱包应该是全新的,并且它不需要从用户试图与操作分离开的钱包中接收 ETH。

同样的问题也存在于链下。从同一个 IP 地址、RPC 提供商或会话提交注册和操作交易,可能会削弱电路提供的隐私保护。前端可能会通过分析、本地存储和支持日志发生泄露。零知识证明隐藏了证明内部的值。它并不能隐藏交易周围的一切。

公共输入是隐私应用失败的另一个地方。在电路中标记为公开的、作为事件发出的、包含在调用数据(calldata)中的,或由合约存储的任何内容都是可见的。审查公共输入应像审查 Solidity 合约上的访问控制一样仔细。

这为构建者带来了哪些改变

以太坊上的隐私是可交付的。构建者可以将各个部分组合成实际的应用。该技术栈包括用于私有声明的电路、用于证明检查的验证者、用于公共规则的应用合约、用于默克尔数据的索引器,以及用于无关联提交和 Gas 赞助的捆绑器加代付合约。

困难的部分在于产品设计、密钥管理、元数据卫生、审计以及扩大匿名集。如果其中任何一个环节出错,证明所提供的隐私就会荡然无存。

延伸阅读

  1. 零知识证明 (ethereum.org) (opens in a new tab)
  2. Semaphore 文档 (opens in a new tab)
  3. MACI 文档 (opens in a new tab)
  4. Circom 文档 (opens in a new tab)
  5. Noir 文档 (opens in a new tab)
  6. Halo2 手册 (opens in a new tab)
  7. gnark 文档 (opens in a new tab)
  8. RISC Zero 文档 (opens in a new tab)
  9. SP1 文档 (opens in a new tab)
  10. EIP-4337:通过 EntryPoint 合约实现账户抽象 (opens in a new tab)

页面最后更新: 2026年5月28日

这个页面对您有帮助吗?