Back to Blog

Zcash Orchard 健全性漏洞分析 | BlockSec 周报

Code Auditing
June 10, 2026
11 min read
Key Insights

在过去一周(2026/06/01 - 2026/06/07),区块链生态系统中观察到多起攻击事件。本周报告重点关注 Zcash Orchard 隐私池中一个严重健全性漏洞的公开披露,该漏洞可能允许对 ZEC 进行不可检测的伪造。目前尚未确认有链上利用行为,但此次披露触发了紧急网络升级,ZEC 价值损失超过 40%。

日期 事件 类型 预计损失
2026/06/04 Zcash Orchard ZK 健全性漏洞 未确认有利用行为

Web3 最佳安全审计机构

在上线前验证设计、代码和业务逻辑

本周重点:Zcash Orchard 健全性漏洞

本事件被选为本周重点,因为它是在生产环境中发现的最严重的 ZK 漏洞之一。一个缺失的电路约束在经过多次审计后仍未被发现,持续超过四年,最终通过 AI 辅助安全审查被发现。该漏洞类别(ZK 电路中欠约束的关系)可能存在于任何基于 ZK 电路构建的协议中。

2026 年 6 月 4 日,Zcash 公开披露了其 Orchard 隐私池电路中的一个严重健全性漏洞 [1]。零知识证明电路中一个缺失的约束破坏了防止双重花费的密码学绑定,可能允许同一隐私票据在不被察觉的情况下被多次花费。该漏洞自 2022 年 5 月 Orchard 激活以来便已存在,并于 2026 年 5 月 29 日由安全研究员 Taylor Hornby 通过 AI 辅助审计发现。紧急网络升级(NU6.2)于 2026 年 6 月 3 日修补了该电路,并恢复了 Orchard 功能。目前未发现任何漏洞被利用的证据。

背景

Zcash 是一个注重隐私的一层区块链,其原生代币为 ZEC。与比特币所有交易细节均公开可见不同,Zcash 通过零知识证明支持隐私交易,隐藏发送方地址、接收方地址和交易金额。Zcash 拥有多个隐私池,每个池对应其隐私协议的不同版本。Orchard 是最新一代,于 2022 年 5 月随 NU5 网络升级激活,并使用 halo2 零知识证明系统 [2] 来验证交易。当用户进行隐私交易时,他们充当证明者:使用 Orchard 电路构造零知识证明,证明交易有效——他们拥有该票据、无效符被正确派生、金额平衡——而无需透露任何私密细节。网络节点充当验证者,在不查看底层数据的情况下验证证明。Orchard 电路定义了每个有效证明必须满足的约束。该漏洞存在于此电路实现中,涉及 Zcash 中的四个核心概念:密钥、地址、票据和无效符。

密钥。 Zcash 的密钥层级比大多数区块链更为复杂。单个花费密钥(钱包秘密)派生出若干子密钥:ask(花费授权密钥)、nk(无效符派生密钥)和 rivk(一个随机化器)。由此,系统计算出 ak(授权公钥)和 ivk(传入查看密钥,通过 ivk = Commit(ak, nk, rivk) 计算)。密钥 ivk 用于识别和接收传入资金。

地址。 要创建 Orchard 地址,用户选取一个分散化参数 d(一个 11 字节的值),它确定一个分散化基点 g_d = DiversifyHash(d)。地址是配对 (d, pk_d),其中分散化传输密钥 pk_d 通过椭圆曲线标量乘法计算:pk_d = [ivk] g_d。这意味着地址与用户的查看密钥通过密码学方式绑定。

票据。 票据是代表已收资金的资产记录。出于隐私原因,链上存储的不是票据本身,而是票据承诺 cm(对票据内容的密码学承诺,包括 pk_d、价值和其他数据)。票据被锁定到接收者的地址。

无效符。 花费票据时,花费者揭示一个无效符 nf,由票据数据和无效符密钥 nk 计算得出:nf = Extract_P([(F_nk(ρ) + ψ) mod p]G + cm)。关键的安全属性是每个票据必须恰好产生一个无效符。一旦无效符出现在链上,相应的票据即被视为永久花费。如果同一票据能产生不同的无效符,它就可以被多次花费而不被任何人察觉。

绑定链。 这些概念通过密码学绑定链相互连接:

红色高亮节点(pk_dnk)是漏洞破坏绑定链的位置:电路必须强制执行 pk_d = [ivk] g_d,将花费者绑定到正确的 ivk,进而绑定到该票据正确的 nk。如果此绑定被破坏,花费者可以伪造一个假的 ivk,从而每次花费时使用不同的 nk。不同的 nk 值对同一票据产生不同的无效符,从而实现双重花费。

电路如何强制执行此绑定。 关系 pk_d = [ivk] g_d 是一个椭圆曲线标量乘法(Q = [k]P),使用倍加法实现。在零知识电路中,验证者不直接执行算法;相反,电路约束每个中间步骤。正确的标量乘法电路必须强制执行,除其他事项外,内部循环基点等于预期输入基点P_loop = P_input)。没有此约束,电路可能证明执行了有效的标量乘法,但使用了错误的基点,使整个绑定链毫无意义。

漏洞分析

存在漏洞的 ECC 小工具用于强制执行 pk_d = [ivk] g_d 的标量乘法关系中,其中 Q = pk_dk = ivkP = g_d。存在漏洞的代码位于 halo2 仓库的变量基标量乘法实现中(incomplete.rs L309-L310):

// incomplete.rs(完整源码链接见上方)
298  for (row, k) in bits.iter().enumerate() {
299      // z_{i} = 2 * z_{i+1} + k_i
         ...
305      z = region.assign_advice(|| "z", self.z, row + offset, || z_val)?;
306      zs.push(Z(z.clone()));
307
308      // 赋值 `x_p`、`y_p`
309      region.assign_advice(|| "x_p", self.double_and_add.x_p, row + offset, || x_p)?;  // 漏洞
310      region.assign_advice(|| "y_p", self.y_p, row + offset, || y_p)?;                  // 漏洞
311
312      // 如果该位被设置,使用 `y`;如果未被设置,使用 `-y`
313      let y_p = y_p
314          .zip(k.as_ref())
315          .map(|(y_p, k)| if !k { -y_p } else { y_p });
316
317      // 计算并赋值 lambda1
318      let lambda1 = y_a.zip(y_p).zip(x_a.value()).zip(x_p)
             .map(|(((y_a, y_p), x_a), x_p)| (y_a - y_p) * (x_a - x_p).invert());
         ...
     }

在零知识电路中,证明者填写每个单元格值;电路本身无法在单元格之间复制或传递值——它只能定义验证者检查的约束。标记为 漏洞 的两行使用 assign_advice() 将基点坐标 x_py_p(称为见证值的私有电路输入)写入电路的建议列(证明者的私有输入区域)。此函数填写一个值而不创建将其与外部基点绑定的约束。一个单独的约束确实确保基值在所有循环迭代中相等——证明者不能在每次迭代中使用不同的基点。然而,证明者可以在所有迭代中替换一个任意基点,电路不会拒绝它,因为没有约束将循环的基值锚定到从外部传入的实际 g_d

正确的函数是 copy_advice(),它填写值添加一个等式约束(复制约束),强制其与实际基点 g_d 匹配。由于 g_d 因地址而异(由每个地址的分散化参数派生),电路无法将其硬编码——它必须将循环的基点约束为与上游计算的 g_d 相匹配。

因此,电路实际上并未强制执行 pk_d = [ivk] g_d。恶意证明者可以在循环内提供任意基点(而非正确的 g_d),电路仍会接受证明:内部计算在代数上保持自洽,但不再锚定到协议指定的分散化基点。这个额外的自由度允许证明者每次选择不同的 nk,计算相应的 ivk = Commit(ak, nk, rivk),并使用无约束的标量乘法使伪造的 ivk 通过验证。由于无效符依赖于 nk,每次花费产生不同的无效符:

同一票据 N + nk_1 → nf_1
同一票据 N + nk_2 → nf_2
其中:nf_1 ≠ nf_2

共识仅检查无效符是否已出现在链上。由于每次花费产生唯一的、看似合法的无效符,双重花费对网络不可见。

修复方案 [3] 在循环的第一次迭代(row == 0)中添加了一个 copy_advice() 调用,创建一个复制约束,将循环的基点锚定到从外部传入的实际 base。其余迭代继续使用 assign_advice(),但现有的迭代间一致性约束将该锚点传播到所有迭代。

影响与响应

利用场景。 恶意证明者可利用该漏洞多次花费同一 Orchard 票据,每次生成不同的无效符。由于零知识证明隐藏了私有电路输入,欺诈性无效符与合法无效符无法区分。该攻击不留下确定性的密码学链上证据,使得无法确定性地判断漏洞是否曾被利用。

该漏洞自 2022 年 5 月 Orchard 激活(NU5 升级)以来便已存在,总暴露窗口超过四年。Zcash 的转门账务限制了可从 Orchard 池流入透明或 Sapling 池的伪造价值数量,从而限制了对更广泛供应量的实际影响。然而,伪造票据可能在隐私池内不被察觉地存在,其隐私属性使得在密码学上无法证明漏洞是否曾被利用。

注意:转门仅在一个池的总流出量超过总流入量时触发。攻击者可能随时间小额提取伪造价值而不触及此限制。只有当合法用户集体尝试提取超过池实际持有量时,差异才会显现。

发现与响应。 该漏洞于 2026 年 5 月 29 日由安全研究员 Taylor Hornby(受 Shielded Labs 委托)使用基于 Anthropic 前一天发布的 Opus 4.8 模型的 AI 辅助审计框架发现。此前使用旧模型对同一电路进行的审计未发现该漏洞。Hornby 当天将问题报告给 ZODL。2026 年 6 月 2 日(UTC)的紧急软分叉暂时禁用了 Orchard 交易,2026 年 6 月 3 日(UTC,区块 3,364,600)的 NU6.2 网络升级引入了修正电路,恢复了 Orchard 功能 [1]。6 月 4 日公开披露后,ZEC 价值损失超过 40%,清算金额超过 1 亿美元 [4]

结论

Zcash Orchard 漏洞由标量乘法电路中缺失的等式约束引起,允许证明者绕过基点绑定并伪造无效符以实现双重花费。与通常可通过代码审查或测试发现的传统智能合约漏洞不同,ZK 电路中的健全性漏洞需要理解电路实际证明的内容与应该证明的内容之间的差距——这一微妙之处在专业密码学家超过四年的专业审计中都未被发现。

halo2 库在整个 ZKP 生态系统中被广泛使用,类似的欠约束关系可能存在于基于这些密码学构建块构建的其他项目中。使用零知识证明的协议应实施余额完整性检查(例如转门账务)以限制未发现的健全性漏洞的潜在影响:如果没有 Zcash 的转门机制,在隐私池内创建的伪造价值可能已自由流入更广泛的供应量中。Shielded Labs 已宣布计划对 Orchard 电路进行数学形式化验证。

这一发现是人机协作工作流程的典型案例:一位经验丰富的安全研究员构建了审计框架并主导了调查,而 AI 则负责对各个电路约束进行广泛检查。单独任何一个组件都不足以完成任务:之前仅使用旧模型的 AI 运行未发现该漏洞,多年的专家人工审查同样未能发现。Hornby 本人是 Zcash 安全专家——需要领域专业知识来为 AI 设计正确的审计范围。正如 BlockSec 最近发布的研究 [5] 也表明的那样,AI 模型在安全分析方面正在取得快速进展,但仍需要专家指导来将 AI 引导至正确的目标并验证其发现。专家与 AI 之间的交互协作——而非单独依赖 AI——是最有效的工作模式。

参考文献

  1. Orchard 伪造漏洞及后续步骤,Zcash 社区论坛,2026 年 6 月 4 日。链接
  2. halo2:一个零知识证明系统,GitHub。链接
  3. 修复:通过复制约束锚定标量乘法基点,halo2 GitHub。链接
  4. 为何 Zcash 修补隐私池漏洞后 ZEC 仍下跌 40%,CoinTelegraph,2026 年 6 月 5 日。链接
  5. 重新评估 EVMBench:AI 智能体是否已准备好应对智能合约安全?,arXiv,2026 年。链接

开始使用 Phalcon Security

检测每一个威胁,发出重要警报,并阻止攻击。

立即免费试用

关于 BlockSec

BlockSec 是一家全栈区块链安全与加密合规提供商。我们构建产品和服务,帮助客户在协议和平台的完整生命周期中进行代码审计(包括智能合约、区块链和钱包)、实时拦截攻击、分析事件、追踪非法资金,并满足 AML/CFT 合规义务。

BlockSec 在知名会议上发表了多篇区块链安全论文,报告了多起 DeFi 应用的零日攻击,阻止了多次黑客攻击并挽救了超过 2000 万美元,并保障了数十亿美元加密货币的安全。

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit