如何进行ZK:Noir与Circom比较

本文对Circom和Noir进行了高层次比较,探讨了它们的生态系统、工具集、性能以及最佳用例。Circom作为一个低级领域特定语言,关注于电路约束的细粒度控制,而Noir则是一种更高层次的语言,旨在简化开发者体验,使其无需手动管理约束,进而提升工具的灵活性和可用性。

这篇文章提供了 Circom 和 Noir 的高层次比较,探讨了它们的生态系统、工具、性能和最佳用例。

零知识证明电路是现代隐私保护去中心化系统中的基础构建块。在过去的几年里,ZKP 语言领域发生了显著变化,许多不同的解决方案被提出。早期的先锋如 Circom 以强调控制电路约束的低级、高度优化的语言奠定了基础。相比之下,Noir 代表了一代新型 ZKP 语言,致力于提升开发者体验,消除了手动管理约束的需求。

概述

Circom 是由 Iden3 开发的 DSL,用于定义算术电路,这些电路又被编译成各自的 R1CS(秩-1 约束系统)表示。该编译器用 Rust 编写,输出约束以及见证生成(wasm 或 C)和约束调试(sym)所需的文件。虽然 Circom 主要在 R1CS 中运行,本质上涉及二次约束,但它也允许线性约束。然而,复杂表达式仍需手动重构以避免非二次约束(任何不是常量、线性或二次的算术表达式),这迫使开发者在解决复杂任务时更多地扮演密码学家的角色,而非普通开发者的角色。

另一方面,Noir 被创建为一种 DSL,采用了更高层次的方法,语法简单且熟悉,深受 Rust 启发。Noir 的关键特性是将电路编译为一种中间表示语言,称为 ACIR。ACIR 作为一种额外的层,可以进一步编译成适用于不同平台和证明系统的算术电路,通过任何兼容 ACIR 的后端。它不仅可以作为单独的工具,用于编写可以被不同后端证明和验证的电路,还可以作为在 Aztec 网络中编写智能合约的语言。

后端与证明系统

生成和验证证明的工具对任何 ZKP 语言来说至关重要。

Circom 电路首先被编译为算术约束系统(R1CS),然后可以通过各种后端工具进行处理。最常见的工具是 snarkjs。它提供了广泛的证明系统和处理编译电路的功能。然而,对于大型电路存在一些性能问题,因此提出了更高效的替代方案:

Circom 证明后端

Noir 是后端无关的,因此语言本身并不受任何后端解决方案的影响。电路主要编译为 ACIR(抽象电路中间表示)。Noir 后端只是一个将 ACIR 转换为你的基于 PLONK 的后端能够理解的东西的模块。默认的证明后端是 Aztec 的 Barretenberg。有关 Noir 后端及其功能的完整列表,请参见下表:

Noir 证明后端

生态系统与工具

Circom 和 Noir 都拥有强大的生态系统,提供开发、证明以及与不同环境的集成的工具。作为更成熟的解决方案,Circom 在生产中被广泛使用,而 Noir 正在快速发展,似乎在多样性上已经超越了 Circom 工具。

Noir 是 Aztec 网络生态系统的重要组成部分,因为它被用于智能合约。此外,自动生成能够验证 Noir 证明的 Solidity 验证器合约为 Aztec Layer-2 区块链或任何需要验证的自定义链上逻辑提供了动力。与此同时,Noir 以类似 Circom 的方式被使用——作为全栈开发的一个元素,支持网页、移动应用、游戏等中的证明。

在此部分,我们将对标准工具进行比较,并突出一些特定语言的特定功能。

两个语言都提供了包含关键数据结构、密码学和基本操作的标准库:Circom 的 circomlib 和 Noir 的内置库。

Circom 的附加库扩展了标准库的功能,提供了更复杂的逻辑和数据结构。Noir 通过无缝支持创建和导入类似 Rust 的库继续保持步伐,因此与 Circom 相比,你已经可以找到更多不同的库,从常用工具和字符串操作到加密安全的伪随机数生成器,甚至机器学习库。

多语言集成

这两种语言都有 JS 和 Rust 包用于与电路交互。此外,就多语言集成而言,Circom 支持 Go,而 Noir 提供 Python、Swift 和 Kotlin。

开发体验

在 Circom 和 Noir 中开发可以形容为驾驶手动挡和自动挡汽车。在手动挡汽车(Circom)的情况下,你对换挡(约束)有完全控制。这可以显著提升性能,但需要技能和仔细管理。在驾驶自动挡汽车(Noir)的情况下,大多数复杂性都为你处理。它提供了更顺畅和更用户友好的体验,让你无需了解底层齿轮(ZK)系统的工作原理。

一个简单的例子来说明二者的区别将是来自 circomlib 库的一个简单的 isZero 检查。电路看起来是这样的:

pragma circom 2.0.0;

template IsZero() {
    signal input in;
    signal output out;

    signal inv;

    inv <-- in != 0 ? 1 / in : 0;

    out <== -in * inv + 1;
    in * out === 0;
}

component main = IsZero();

如你所见,逻辑条件像 x == 0 不能直接表达。我们必须手动管理约束,考虑到 Circom 不允许非二次约束。因此,我们通过计算 out 使用一个辅助变量 inv 来强制约束 in * out == 0,以处理 in 非零的情况。

即使像检查值是否为零这样简单的操作,也需要开发者以加密学的方式思考,并找到适合 R1CS 约束系统的解决方案。

Noir 为你处理这一切,代码看起来相当简单:

fn isZero(x : Field) -> bool {
    x == 0
}

##[test]
fn test_is_zero() {
    assert(isZero(0));
    assert(!isZero(5));
}

Noir 让你专注于逻辑,而 Circom 则让你与约束搏斗。

调试

除了在两种语言中都提供的常见日志记录功能(log 和 plintln)外,还有更复杂的电路调试工具。开发者首要看到的是语法高亮,缺少这一点将使编码耗时一倍。幸运的是,Noir 和 Circom 都具有 VSCode 高亮插件。此外,Noir 在 Neovim、Emacs 和 Zed 中也有类似插件,而 Circom 还支持 Vim 的语法高亮(如果你是个真正的硬核开发者)。

下一个调试步骤是更先进的工具。对于 Circom,有 Shield —— 一个提供库、插件、测试以及我们这里最感兴趣的调试工具的开发框架。它的调试功能允许你显示 Circom 电路日志、输入/输出信号日志以及通过/失败约束和信号计算。

Noir 提供了两种不同的调试方式:通过另一个 VSCode 扩展( vscode-noir)在界面中提供清晰的视觉步骤,或者使用与 Nargo(Noir CLI 工具)一起提供的 REPL 调试器。

测试

就测试而言,Noir 具有内置的 #[test] 装饰器,可以用于函数在 nargo test 命令上编译和运行。你还可以为负面测试指定失败原因。

当内置功能不够时,开发者框架发挥作用。我们已经提到 Circom 的 Shield,还有 Typescript 测试和开发环境,如 hardhat-zkitcircomkit。类似地,Noir 工具也包含 hardhat-noir 插件,但它向前推进了一步,提供在 Foundry 中进行测试的方式,使用 foundry-noir-helper

安全测试

零知识电路中的安全性至关重要,因为漏洞可能导致无效证明或篡改验证。

Circom 工具提供了一套静态分析器( Circomspec, CIVER, EcnePICUS)来检查电路代码潜在错误和漏洞,而无需实际运行。

Noir 程序可以通过形式验证工具( rocq-of-noirlampe)进行测试,利用一种技术,即使用数学证明来表明程序在所有可能输入下是正确的。

除了形式验证外,Noir 电路也支持突变测试。Hunter 是一个 Rust CLI 工具,通过以小方式修改程序的源代码(称为突变),并检查测试是否捕捉到它们,来衡量测试套件的质量。例如,用另一个操作符替换一个操作符。

远程编程环境

对于那些出于某种原因不想在本地机器上安装 ZKP 开发所需的所有依赖项的人,即使在你奶奶的手机上只要有浏览器的访问,也有选项可以运行电路。

Zkrepl 提供了一种简单的方法,可以在浏览器在线编程环境中编写和测试 Circom 电路。Noir 还没有这样的功能,但提供了一个有趣的替代方案——GitHub 开发者代码空间。该功能允许你通过使用 Noir 的 devcontainer(一个预装工具的 Docker 镜像)在远程机器上编码。

性能

零知识证明电路的性能取决于多个因素,如约束数量、证明系统和证明后端优化技术。我们的基准测试比较了 Noir 和 Circom 电路在一些标准库中基本密码哈希原语的性能,如 SHA-256、Pedersen 和 Poseidon。

作为参考,使用了 ZK Benchmark 仓库。然而,现有方法已被修改,以使比较尽可能准确。Circom 电路现在是使用 PlonK 证明系统进行证明,而不是 Groth16。决定选择这些由 Circom 和 Noir 都支持的证明系统,使得比较更多基于语言特性,而不仅仅是对证明系统及其相应后台的优化。因此,选择了以下组合:

  • Circom → SnarkJs → PlonK
  • Noir → Barretenberg → UltraHonk
使用 Circom 测试门:
        5 个约束
        设置在 605 毫秒内生成
        编译在 34 毫秒内完成
        见证在 132 毫秒内完成
        证明在 580 毫秒内完成

使用 Noir 测试门:
        21 个约束(5 个 ACIR 操作码)
        设置在 0 毫秒内生成
        编译在 134 毫秒内完成
        见证在 99 毫秒内完成
        证明在 48 毫秒内完成
使用 Circom 测试 sha256:
        31699 个约束
        设置在 13760 毫秒内生成
        编译在 1418 毫秒内完成
        见证在 278 毫秒内完成
        证明在 56146 毫秒内完成

使用 Noir 测试 sha256:
        7049 个约束(184 个 ACIR 操作码)
        设置在 0 毫秒内生成
        编译在 153 毫秒内完成
        见证在 121 毫秒内完成
        证明在 1651 毫秒内完成
使用 Circom 测试 pedersen:
        44 个约束
        设置在 607 毫秒内生成
        编译在 35 毫秒内完成
        见证在 129 毫秒内完成
        证明在 644 毫秒内完成

使用 Noir 测试 pedersen:
        2912 个约束(6 个 ACIR 操作码)
        设置在 0 毫秒内生成
        编译在 106 毫秒内完成
        见证在 104 毫秒内完成
        证明在 841 毫秒内完成

使用 Circom 测试 pedersen_30:
        1320 个约束
        设置在 1934 毫秒内生成
        编译在 56 毫秒内完成
        见证在 152 毫秒内完成
        证明在 3344 毫秒内完成

使用 Noir 测试 pedersen_30:
        7203 个约束(180 个 ACIR 操作码)
        设置在 0 毫秒内生成
        编译在 110 毫秒内完成
        见证在 116 毫秒内完成
        证明在 849 毫秒内完成
使用 Circom 测试 poseidon:
        517 个约束
        设置在 726 毫秒内生成
        编译在 483 毫秒内完成
        见证在 145 毫秒内完成
        证明在 1067 毫秒内完成

使用 Noir 测试 poseidon:
        944 个约束(318 个 ACIR 操作码)
        设置在 0 毫秒内生成
        编译在 135 毫秒内完成
        见证在 111 毫秒内完成
        证明在 105 毫秒内完成

使用 Circom 测试 poseidon_30:
        15510 个约束
        设置在 7830 毫秒内生成
        编译在 589 毫秒内完成
        见证在 245 毫秒内完成
        证明在 17194 毫秒内完成

使用 Noir 测试 poseidon_30:
        27856 个约束(9540 个 ACIR 操作码)
        设置在 0 毫秒内生成
        编译在 981 毫秒内完成
        见证在 985 毫秒内完成
        证明在 963 毫秒内完成

基准测试的关键观察:

  • 约束数量:Noir 电路往往有更多的约束但更少的 ACIR 操作码。这种约束数量的差异是由于 Noir 与 Circom 的不同,Noir 开箱即用地支持许多操作符和控制流语句,因此在需要的地方自动引入新约束。这可能有助于防止无约束计算错误,但缺点是性能较低。然而,除了自动处理的约束外,Noir 仍允许你创建 无约束oracle 函数,使计算更有效。
  • 设置时间:由于所使用的证明系统具有 Plonk 特性,Circom 和 Noir 都利用通用设置,意味着不需要每个电路的设置。但 Barretenberg 后端完全不需要这一步骤,使得设置几乎是瞬时的。
  • 编译时间:对于像 SHA-256 这样的复杂大型电路,Noir 一般编译得更快,而对于小型和中型电路,Circom 编译得更快。这可能表明 Circom 的直接约束管理对于小型电路是高效的,但在提升复杂性时 Noir 从 ACIR 优化中受益。
  • 见证生成时间:对于大多数电路,Noir 见证生成稍快,但没有显著差异。这两个语言都对这一过程进行了优化,但 ACIR 优化可能在某些情况下导致小的优势。
  • 证明生成时间:在证明生成方面,Noir 毫无疑问是赢家。Noir 的 UltraHonk 尤其在大型电路如 SHA-256 上表现优越,生成证明速度比 Circom 的 PlonK 快超过 30 倍。

结论

Circom 的生态系统经过实战考验,已经准备就绪,成为现有 ZKP 解决方案的明显选择。你可以在诸多核心项目中找到使用它的严肃活跃项目,如 Tornado Cash、Semaphore、Rarimo 等。然而,Noir 的快速发展、较低的开发者进入门槛以及更先进的工具生态使它成为一个非常有竞争力的解决方案,尤其是对于寻求灵活性、类似 Rust 的模块化和跨平台支持的开发者。

尝试这两种语言以寻找最适合你项目的语言绝对值得,因为虽然 Noir 抽象掉了许多密码学话题,但 Circom 仍被认为是开始 ZKP 旅程的最佳语言之一。它的抽象程度并不低到让开发者始终感觉自己是密码学家,但也不高到迫使他们通过约束管理去学习零知识核心的基本知识。

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

0 条评论

请先 登录 后评论
mariiazhvanko
mariiazhvanko
江湖只有他的大名,没有他的介绍。