zkREPL:一个zkSNARKs 在线开发环境

作者:Kevin Kwok
译者:Kurt Pan
原文链接:https://0xparc.org/blog/zkrepl

在计算的旧石器时代,计算机曾是机电的巨兽,每秒只可以执行几十次操作,但每年的成本却高达数百万美元。程序是通过细致的思考、在接线板中插入电线以及给卡片打孔来开发的。那个时候,bug就是是字面意义上的虫子,它们会啃咬电线,偶尔会导致短路,这可能会烧毁所有东西。

那时,对计算机进行编程是一项充满仪式感的艰苦的活动。但在 1950 年代后期,一种名为 LISP 的新编程系统被发明出来,它能够对其自己的实现进行推理——通过一个名为eval的结构,程序可以要求它们自己的制造者来产生新的程序。基于此,研究者提出了一个简单的程序,该程序将从键盘读取一些输入,将其发送到eval 结构,打印结果,然后循环回到起点以等待进一步的输入。

这个巧妙的技巧 ,REPL(译者注:读取﹣求值﹣输出循环), 引发了编程的民主化进程——把编程从一个仅由民族国家用来操控火箭的东西,变成了一个青少年用来制作游戏的东西。

零知识

近年来,我们见证了一个计算的新时代的兴起。我们有像以太坊和比特币这样的区块链,每秒处理几十个操作,每年gas要耗费数百万美元。我们经常看到"烧毁"整个协议的bug。

推动这个计算新时代的是能够推理自己的信任的新系统:来自可审计的中心化预言机、内容可寻址存储、拜占庭共识、多方计算,以及也许是最有趣的一个——零知识证明。

当前的零知识世界充满了“仪式“。巫师召集了成千上万的人们来努力进行驱魔——以可信的方式处理掉在可信设置中产生的有毒废物。

和这个婴儿期的技术一同到来的是一个与历史押韵的机会,并最终可使零知识民主化。

读取

在零知识民主化进程中,我们首先必须建立一种专家和业余爱好者都可以使用和理解的语言--一种通用语。为此,我们有幸能在Circom 2.0上进行构建,这是一种简单的语言,其语法对任何看过 JavaScript 的人都应该熟悉,同时也暴露出足够多的底层抽象,使得人们仍然可以理解正在构建的低层电路结构。

除了语言,我们还需要它的媒介。我们希望能够像单击 Web 浏览器中的链接一样轻松地进入零知识的世界,因此我们在Monaco之上构建了 zkREPL :Monaco是和Visual Studio Code 底层相同的文本编辑组件。但我们出于特定目的对其进行了扩展——自定义语法高亮,以及带有指向外部包含的工具提示。

将来,切换到CodeMirror 6可能会更好,因为 Monaco 在移动设备上运行得不是特别好,以及我们就可以利用 Joel Gustafson 的lezer-circom项目添加一个合适的增量语法解析器并启用各种新功能以用于探索、导航和可视化 Circom 代码。

在更深层次上,对于用户可以使他们自己相信那些声称在一个给定合约之下的代码确实是真正在运行的代码的能力,在构建一个可以显式推理自己的信任的系统的过程中,一个零知识系统仅能提供与其一样好的能力。为此,要提供一个使用户能够验证一个电路的源代码的系统,还有大量更多的工作可以去做。

求值

传统上,要在 Circom 中编写零知识程序,必须首先安装整个 Rust 工具链并从源代码编译编译器。构建 zkREPL 的第一步是将 Circom 编译器编译成 WebAssembly,以便它可以在浏览器中可移植地运行。

这涉及到一些障碍,其恼人程度各异。有一些相对简单的更改,例如将其调整为支持 WASM 等 32 位架构,以及禁用Rust WASM目前不支持的多线程功能。

然后出现了一些更讨厌的障碍:Circom 与名为WABT的外部 C++ 库静态链接,该库是 WebAssembly 二进制工具包,其工作是将基于文本的 WAT 格式转换为二进制 WASM 格式。Rust WASM 编译器后端不支持与不同语言编写的模块链接,但 WABT 项目已使用 Emscripten 单独编译为 WASM。为了解决这个问题,我们首先剥离了 Circom 调用 WABT 的所有代码并创建了一个包装脚本,当被要求将 Circom 编译为 WASM 时,它会请求启动一个无 WABT 的 Circom 并请求一个 WAT 文件并立即将其放入另一个 WABT 模块以生成最终的 WASM。

后来,Blaine Bublitz 发现了WAST库,这是 WASM 二进制格式的纯 Rust 实现,并向 Circom 提交了一组上游更改,以用这个纯 Rust 实现替换 WABT,让我们一劳永逸地摆脱了上述麻烦的魔改。

WebAssembly 是一个非常轻量级的规范,它本质上代表存粹的计算——它没有文件、时间甚至输出控制台的概念。这就是WASI的用武之地——它定义了一个标准环境,WASM 程序可以与之交互,以便读取文件、接受输入并打印到输出控制台。但是,WASM 是一项新技术,WASI 更是如此。

此时,我们的 Circom/WASM 实现表面上运行良好:它编译我们的代码并生成有效的 WASM 见证生成器。然而,当需要使用 SnarkJS 进行端到端测试时,我们发现所需的 R1CS 文件比我们预期的要大几个字节。经过一番调查,问题的根源确定了:在特定情况下,对一个文件的特定写入顺序,跳回先前位置并继续写入该文件时,会在 WASI 运行时的某些实现中出现bug,会把东西写到错误的地方。我们最终通过修补一个版本的 WASI 文件系统运行时解决了这个问题。

至此,我们已经将 Circom 2.0 的工作版本编译为可以在浏览器中运行的 WebAssembly。但除此之外,我们还将它打包为一个NodeJS 模块,因此任何人都可以通过在他们的计算机上运行npx circom2来使用 Circom 进行开发。此外,Blaine 还提供了一个编程 API,可以与hardhat-circom等构建工具集成。

在标准 Circom 语言之上,我们还涉及了一些超出核心语言的扩展。我们添加了直接从外部 URL 导入代码的功能,以及一种直接作为文件底部的注释为你的见证生成程序指定输入的方法。

将来,通过支持 PLONK 中的自定义门来进一步扩展语言将会很有趣。

输出

SNARKs是一种脆弱的生物;一根线没接上,你就可能引入了一个严重的错误,可能会将整个协议烧成灰烬。由于涉及的资产,环境不仅能打印输出,而且要以开发者能够真正理解代码的每一寸的方式和代码交织起来,这一点变得越来越重要。

在 zkREPL 中,将鼠标悬停在源代码中的signal上,就会看到一个工具提示,其中显示了从你的见证文件中提取的这些signal的值——这里不用你自己写print哦!

随着时间的推移,用于使人们了解正在运行的代码性质的工具会变得更加先进。例如,我们可能在某个时候能够集成诸如 Franklyn 的Ecne之类的工具的一些静态分析功能,以证明电路实现见证的唯一性。

未来,我们还可以添加新模式,以框图形式可视化和探索电路,能够放大单个块并查看底层线路,正如 Steven Hao 所建议的那样。

循环

就像比尔博·巴金斯在《霍比特人》中的旅程一样,REPL 的故事以“去而复返”开始和结束。通过回到起点,开发者可以迭代他们的实现、添加特性、改进算法和修复错误。自 1950 年代以来,计算机已经发展了很多,编程不再需要像以前那样孤独地冥想。随着互联网的出现,循环的过程不再是同步的,而是并行的。

在 Circom 中实现ECDSARSA等工作基本上是协同工作,因此 zkREPL 努力通过简化电路共享和协作的流程来支持这一点。因此,你可以简单地点击“Ctrl-S”并将你的电路副本保存为一页 Github Gist,然后从浏览器栏中复制 URL 以与朋友分享,或将其作为 iframe 嵌入到教程页面中。

将来,我们可以通过更好地与 Git 集成,或者通过实时多人查看和编辑代码的能力来进一步缩短循环。

结论

正如 0xPARC 是从 Xerox PARC(译者注:Palo Alto Research Center) 的丰富传奇中汲取的灵感,这个项目的命名是为了向那个聪明的小技巧致敬,它将编程从精英仪式转变为无处不在的民主仪式。

整个生态系统还处于起步阶段,像 zkREPL 这样的工具还很原始。如果有兴趣提供帮助,无论是通过实现上述的任何想法,还是通过贡献你自己的愿景,来看看我们的 Github吧。

这里试用 zkREPL !另请参阅Github,并查看npm 上的 circom2

Subscribe to Kurt Pan
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.