使用 Arkworks 实现的开源 Aleo VM 和使用 Tendermint 实现的区块链的详细介绍

本文介绍了LambdaClass团队开发的Aleo区块链的替代实现,包括使用Tendermint共识层和使用arkworks框架实现的零知识虚拟机,目标是Aleo指令。文章还介绍了共识层、虚拟机以及VM与共识集成层,并指出了目前正在进行的工作,例如支持更多数据类型和指令、生成状态转换正确性的证明等。

介绍

在过去的 12 周里,我们在 LambdaClass 开发了 Aleo 区块链的另一种实现。我们要感谢 Aleo 的 Alex Pruden 和 Howard Wu 在整个过程中的支持。

从高层次上讲,该项目包括一个使用 Tendermint 的共识层和一个使用 arkworks 框架实现的、以 Aleo 指令为目标的零知识虚拟机。

你可以查看代码:

这个区块链的关键特性在于,它被设计成一个完全私有的平台,用户可以在上面开发应用程序,然后可以离线构建和执行这些应用程序,生成一个执行证明,然后将其发送到区块链节点进行验证和存储。


如果你需要一个在分布式系统、机器学习、编译器和密码学等领域合作了十年的工程师和研究人员团队,我们就是你要找的人。想更多地了解它吗?通过向我们发送电子邮件来预定与我们会面。


共识层

共识层负责验证执行状态更改的传入交易,并在任意数量的节点上复制这些交易(以及执行这些交易的顺序)。

为了实现这一点,我们决定利用 Tendermint Core,这是一个用 Go 编写的共识机制的实现。除了 Tendermint Core 二进制文件之外,你还需要运行你的 应用程序区块链接口(简称 ABCI)的实现。这个 ABCI 需要实现特定的Hook,Tendermint Core 在需要时通过套接字来调用这些Hook。例如,当接收到一个交易时,它会调用 CheckTx,这应该在将交易输入到 mempool 并将其转发到其他节点之前验证该交易。这种灵活的方法允许用任何语言编写 ABCI,只要它适当地响应调用即可。我们决定用 Rust 编写我们的实现。

你可以在这里查看此实现的的代码。该存储库还包含一个 CLI 应用程序,可以轻松地编译、部署和执行程序,并将这些交易发送到区块链。它还具有与帐户相关的其他几个功能,例如检索用户的余额或查看帐户拥有的 记录。我们将在本文的集成部分解释记录背后的动机,但它们本质上是在区块链中封装状态和所有权功能的一种方式。

设计考虑

考虑到 VM 的实现和区块链的要求,我们必须在共识层上做出一些设计决策。以下是 Tendermint Core 如何实现的一般概述:

  • Tendermint Core 和 ABCI 需要在同一节点中并排运行,并通过协议Hook定义的接口耦合在一起。
  • ABCI 上执行的所有代码都需要是确定性的,并且与外部服务隔离,因为我们希望确保所有交易在网络中的每个节点上执行确定性的状态更改。
  • ABCI 实现了两个数据库来维护区块链的当前状态:程序存储和记录存储。
    • 程序存储跟踪每个已部署程序的验证密钥和用途。该存储包含 credits 程序的密钥,作为内置默认值。该程序定义了信用记录。它本质上是一个原生的 Aleo 程序,具有用于管理信用记录的功能。
    • 记录存储封装了与验证传入交易中使用的记录是否已被花费相关的功能。
    • 隐私要求意味着我们不能披露哪些记录已被花费,哪些记录尚未花费。因此,区块链中的任何记录(即,它是程序执行的输出)都与已花费的记录分开存储,对于已花费的记录,我们只存储序列号。
  • 必须在启动时将创世块提供给 Tendermint,这通过 JSON 文件完成。我们编写了一个特定的二进制文件,为任意数量的节点生成它,并为每个节点提供固定数量的起始信用。
  • 为了简化测试,我们创建了多个 make 目标来初始化和启动多个验证器,这些验证器可以在本地或远程网络上运行。
  • CLI 和共识层都支持 Aleo 的 SnarkVM 和我们自己的 LambdaVM,并且目前可以通过编译器标志互换

权益质押

Tendermint 支持向网络添加新节点。通常,网络中的节点可以以两种不同的模式工作:

  • 非验证器:节点通过执行每个交易来赶上区块链,但没有投票权来验证和提交区块。
  • 验证器:节点是网络的一部分,可以投票和签名区块。

要添加一个非验证器,该节点需要具有相同的创世块并指向持久对等节点(充当网络中固定节点的 IP 地址)。要将一个节点转换为验证器,ABCI 需要实现更新 Tendermint 节点的投票权的功能。

为此,我们实现了一个 stake 命令,通过将信用交换为质押记录来“冻结”信用(并增加验证器的投票权),你可以在需要时“取消质押”(相应地减少投票权)。

当一个节点是一个验证器时,它会在它参与的每个区块提交中获得奖励。

虚拟机

从高层次上讲,我们的 VM 提供了一个 API 来获取一个看起来像这样的 Aleo 程序:

program main.aleo;

function add:
    input r0 as u16.public;
    input r1 as u16.private;
    add r0 r1 into r2;
    output r2 as u16.public;

并为其生成一对证明密钥和验证密钥(这通常被称为构建合成程序),允许任何人执行该程序并提供证明或验证所述证明。共识层使用它来部署程序(即,上传其验证密钥以及代码)、执行它们并验证它们。

在内部,此 VM 使用 Arkworks 作为后端。程序被转换为 Rank One Constraint System (R1CS),然后传递给 Marlin 证明者以供执行。当我们开始使用 Arkworks 时,我们注意到 API 的某些方面及其通用性正在成为开发人员的负担,因此我们围绕它创建了一个名为 Simpleworks 的薄包装器,以及一些基本文档

例子

给定以下 Aleo 程序

program foo.aleo;

function main:
    input r0 as u64.public;
    input r1 as u64.public;
    add r0 r1 into r2;
    output r2 as u64.public;

执行函数 main 将如下所示:

use lambdavm::jaleo::UserInputValueType::U16;

fn main() {
    use lambdavm::{build_program, execute_function};

    // Parse the program
    let program_string = std::fs::read_to_string("./programs/add/main.aleo").unwrap();
    let (program, build) = build_program(&program_string).unwrap();
    let function = String::from("main");
    // Declare the inputs (it is the same for public or private)
    let user_inputs = vec![U16(1), U16(1)];

    // Execute the function
    let (_execution_trace, proof) = execute_function(&program, &function, &user_inputs).unwrap();
    let (_proving_key, verifying_key) = build.get(&function).unwrap();

    assert!(lambdavm::verify_proof(verifying_key.clone(), &user_inputs, &proof).unwrap())
}

内部原理

我们的 VM 必须执行的最重要的任务是将程序转换为算术电路,因为其余的工作,即生成证明和验证它,使用 Arkworks API 非常简单。

在继续之前,你应该至少基本了解算术电路以及 Arkworks 如何让你使用它们。你可以在这里阅读有关它的信息。

要生成电路,我们执行以下步骤:

  • 获取程序的源代码并将其解析为 Program,其中包含有关它的所有相关信息(所有输入和输出指令的列表,它们是公开的还是私有的,所有常规指令(如 add 及其操作数)的列表等)。我们目前依赖 SnarkVM 的解析器,但计划编写我们自己的解析器。
  • 实例化一个 Arkworks ConstraintSystem,它将在最后保存我们所有的电路约束。
  • 对于每个输入指令,实例化其对应的 Gadget。你可以将gadget 视为算术电路中本机类型(如 u8)的等效项。如果输入是公开的,则 gadget 是公开的;否则,它会成为一个 witness,即私有的。在我们的示例中,第一个指令 input r0 as u16.public 变为对 UInt16Gadget.new_input(...) 的调用,第二个指令变为 UInt16Gadget.new_witness(...)
  • 对于每个常规指令,我们使用 gadget 的关联函数来执行操作并在我们的 ConstraintSystem 中生成其约束。在我们的示例中,当我们遇到 add r0 r1 into r2; 指令时,我们调用 UInt16Gadget.addmany(...)。这是一个 arkworks 提供的函数,它将采用一个 UInt16 列表,将它们相加,使用所有关联的约束隐式地改变 ConstraintSystem,然后返回总和的值。并非所有指令都实现了相应的 arkworks 函数,因此对于这些指令,我们不得不自己编写。
  • 对于每个输出指令,将计算出的值分配给寄存器。

因为一个程序可以有多个寄存器相互作用,为了做到以上,我们必须跟踪每个寄存器和它在执行过程中的值。为此,我们在整个执行过程中保留一个内部哈希表。

此外,我们还运行了一些基准测试,将我们的 VM 与 Aleo 的 SnarkVM 进行了比较,我们的结果表明我们比它快几倍;详细信息将在另一篇文章中发布。基准测试的代码在我们的 VM Repo中。

VM-共识集成层

上面,我们讨论了 VM 如何允许运行任意 Aleo 程序,这些程序可以部署、本地执行,然后在 Aleo 区块链上进行验证。每个 Aleo 交易要么是程序的部署,要么是程序执行的证明(这在技术上是不准确的,因为每个交易可以有多个这样的程序,但为简单起见,我们将忽略这一点)。在执行的情况下,节点使用程序的验证密钥来验证正确的执行,然后再将交易提交到区块。

在我们获得了一个基本的 VM 版本后,我们意识到获得一个功能齐全的 Aleo 区块链需要比上述更多的工作。如果事务证明某些计算已正确完成,那么它们的用处将非常小。为了有用,它们还需要 修改状态。在 Aleo 中,状态是通过 记录 来管理的,本质上是一个类似于比特币的 UTXO 模型。通常,当用户发送交易时,他们会花费他们拥有的一些记录来创建新的记录来代替它们。

因为 Aleo 是完全私有的,所以交易不能只发布它想要花费的记录以及签名;它必须在零知识中 证明 记录的所有权和存在,然后 加密 记录,以便只有它的所有者才能在线解密。

这意味着,为了与共识层集成并获得一个功能齐全的区块链,我们需要更多。VM 可以证明程序执行的正确性,但与交易相关的零知识证明还需要包括以下内容:

  • 零知识签名,证明提供的签名是正确的签名。记住,我们不能只显示发送交易的用户的地址。
  • 证明交易的调用者实际上 拥有 他们正在花费的记录。
  • 证明正在花费的记录是在链上的。这本质上是在零知识中验证 Merkle 路径。
  • 证明输入记录尚未被花费。这有点复杂,因为它需要在零知识中推导记录的 序列号(如果你了解 ZCash,可以将其视为 nullifier)。

我们还讨论了如何将记录加密存储在链上,以便只有拥有记录所有者查看密钥的人才能解密它们(在 Aleo 中,查看密钥 只是与允许记录解密的帐户关联的另一个密钥)。

但这里有一个问题。例如,当用户 A 想要向用户 B 发送资金时,他们必须创建一个由 B 拥有的记录并对其进行加密,以便只有 B 才能解密它。但 A 不一定拥有 B 的查看密钥,只有他们的地址。这意味着 Aleo 使用的加密方案不能是对称的,因为这要求用户 A 拥有 B 的查看密钥才能向他们发送资金,而不仅仅是他们的地址。

为了实现这一点,记录使用一种名为 ECIES(椭圆曲线综合加密方案)的方案进行加密。我们不会详细介绍它的工作原理,但它是 Diffie-Hellman 密钥交换与对称加密方案的组合。

我们在 VM 和共识层之间引入了一个中间层来解决上述所有问题。这个中间层处理与记录、它们的加密以及状态转换证明所需的 snark 相关的所有事情。

在原始的 SnarkVM 实现中,这个中间层实际上并不存在,因为它是 VM 本身的一部分,但我们发现将这两个关注点分开更有益。

进行中的工作

这个项目仍在积极开发中,并且正在进行一些工作。其中包括:

  • 支持 VM 上的一些数据类型和指令,包括 group 数据类型(椭圆曲线元素)和诸如 BHP 承诺之类的内容。你可以在 README 上查看完整列表。
  • 上面提到的一些电路证明了状态转换的正确性。
  • 生成输入记录在链上存在的证明。
  • 由于我们在区块链上存储记录信息的方式以及考虑到区块链的隐私要求,目前从 CLI 请求用户余额或未花费的记录并非易事:我们需要请求曾经存在的所有记录,以及所有已花费记录的序列号,并尝试在用户端解密它们。优化此过程的一些策略包括在本地跟踪记录,并且仅随着区块链的增长添加新创建的记录。

我们计划在未来四周内完成这些任务。虽然许多事情可以改进,但该项目已经可以投入生产。

我们有很多关于改进 SnarkVM 和 Aleo 的想法和评论,但我们会将其留到另一系列文章中。

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

0 条评论

请先 登录 后评论
lambdaclass
lambdaclass
LambdaClass是一家风险投资工作室,致力于解决与分布式系统、机器学习、编译器和密码学相关的难题。