本文深入探讨了使用 Noir 构建零知识证明(ZKP)应用时常见的安全漏洞。文章详细分析了逻辑错误、有限域算术陷阱、意图与实现不符以及隐私泄露这四大类问题,并提供了具体的代码示例和审计关注点,旨在帮助开发者构建更安全可靠的 Noir 电路。
目录
介绍
在零知识证明(ZKP)的世界中,Noir 已经成为一种强大的、对开发者友好的语言,用于构建保护隐私的应用程序。Aztec 将 Noir 设计为一种基于 Rust 原则的特定领域语言(DSL),它简化了复杂算术电路的创建——这些电路定义了要证明的计算,而无需泄露敏感信息。Noir 的设计抽象了大部分密码学复杂性,但安全的电路仍然依赖于仔细的实现、全面的测试和独立的审查。
Noir 和零知识系统的核心原则
Noir 抽象了底层的密码学复杂性,使开发者能够专注于逻辑而不是电路优化。与早期的框架(如 Circom 或 ZoKrates)不同,Noir 利用类似 Rust 的语法和工具来减少样板代码和人为错误。然而,这种抽象并不能完全消除风险:Noir 编译器自动将 Noir 电路转换为抽象电路中间表示(ACIR),然后由 Barretenberg、Groth16 和 PLONK 等证明系统处理,以生成和验证证明。这种抽象消除了处理复杂数学细节的负担。但是,开发者仍然有责任确保电路逻辑本身的正确性。
这些电路的安全性取决于三个基本属性:
电路中的一个单一的缺陷可能会破坏这些支柱中的一个或多个,导致不安全或不正确的证明。
Noir 电路中常见的安全漏洞
下面,我们探讨一些威胁基于 Noir 的系统的可靠性、完备性或零知识属性的漏洞:
逻辑错误直接危及可靠性。例如,一个旨在证明“知道一个大于 100 的秘密值”的电路可能会忽略一个强制执行此不等式的约束。攻击者可以提交像 50 这样的值,并“证明”合规性,从而欺骗验证者。这种差距通常源于需求到电路逻辑的不完整转换。
审计重点:
例子:
考虑以下电路,我们希望将用户的年龄限制为至少 18 岁:
由于 Noir 感觉像是编写“正常”的 Rust 风格的高级代码,因此 `if is_adult` 条件在证明期间被评估,但不受约束。为了强制执行 `user.age >= 18`,电路实现者必须明确声明它。正确的实现是:
2. 有限域中的算术陷阱
Noir 在有限域上运行,其中对原生 Field 类型的算术运算以素数为模进行包装。这为系统的可靠性引入了微妙的风险:
审计重点:
例子:
考虑以下示例,其中两个私有 `Field` 输入 $x,y$ 的总和被约束为等于一个公共 `Field` 输入 $z$: 如果目的是执行以字段的素数 $p$ 为模的检查:$x + y = z \mod p$,则上述实现是正确的。但是,如果目的是检查总和 $x+y$ 而不减少 $\mod p$(将隐式执行),则上述可能会导致错误的结果。例如,对于 $p=7$ 和 $x=5,y=4$,我们可能想要检查 $5+4=9$ 而不是 $5+4=2\mod 7$。为了避免这种歧义,需要确保该字段足够大。
作为旁注,关于约束值在预期范围内,我们注意到 Noir 为固定大小的输入(如 `Field` 和数组)添加了隐式的 `assert`。因此,显式的 `assert` 仅对于动态对象(如向量、切片等)是必需的。
3. 意图与实现不匹配
即使是文档完善的电路也可能存在开发者意图与代码之间的差异。例如,一个旨在强制执行“用户 X 拥有 NFT Y”的电路可能会无意中验证证明,即使 X 已经出售了 Y。这些不匹配通常源于模糊的规范或对密码学原语的误解。
审计重点:
例子:
考虑一个授权场景,其中用户根据对秘密的了解被授予对某些资源的访问权限。例如,这可以是一个更大的基于 ZK 的登录系统的一部分,在该系统中,授权是在不泄露用户凭据的情况下授予的。
一个有些简单但具有说明性的漏洞,可能源于不够详细的规范或对密码学假设的误解,是通过以下实现引入的:虽然电路通过约束 `poseidon([sk]) == auth_hash` 来证明对秘密的了解,但它未能强制执行用户 ID 和秘密之间的任何绑定。因此,任何知道秘密的人都可以为任何用户 ID 生成有效的证明。一种修复方法是使用一些域分离常量从秘密派生用户 ID,如下所示:
请注意,所示的漏洞本身不是 Noir 特有的,并且可能适用于其他电路 DSL,例如 Circom。然而,Noir 的高级 Rust 风格语法(这也是其无可争议的优势之一)可能会使类似的错误更难发现。
4. 隐私泄露
隐私失败会危及零知识属性,并通过以下两个主要途径暴露敏感数据:
隐式泄露:公共输出可能与私有输入相关联。
审计重点:
例子:
一个完全泄露本应是私有输入(年龄)的简单例子如下:一种修复方法是不返回私有输入(年龄):
另请注意,当电路公开来自小域的秘密输入的公共哈希时,攻击者可以暴力破解该值。例如,考虑上面的例子,其中电路还返回年龄的公共哈希。尽管哈希在隔离状态下是密码学安全的,但可能的年龄范围有限(只有大约 82 = 100-18 个潜在值,假设最大年龄为 100),允许攻击者快速迭代每个候选值,计算其哈希,并将其与公共哈希匹配。通过这样做,攻击者可以轻松恢复实际年龄,从而危及输入的隐私。
结论
零知识电路的成功或失败取决于严格的约束设计。通过将每个业务规则转换为显式断言,防止有限域算术的意外情况,并将每个公共接口视为潜在的侧信道,团队可以同时保持可靠性和隐私性。随着 Noir 生态系统的成熟,持续的同行评审和周到的审计(无论是内部还是外部)仍然是通往值得信赖的 ZK 应用程序的最可靠途径。
如果你对审计 Noir 电路有任何疑问,请联系我们的 ZK 团队。
- 原文链接: blog.openzeppelin.com/de...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!