Stoffel-Labs/stoffel

GitHub: Stoffel-Labs/stoffel

Stoffel 是一个基于寄存器的虚拟机与工具链,用于在本地和分布式多方安全计算(MPC)场景中执行隐私保护程序。

Stars: 36 | Forks: 4

# stoffel [![GitHub License](https://img.shields.io/github/license/Stoffel-Labs/stoffel)](LICENSE) [![Reddit](https://img.shields.io/reddit/subreddit-subscribers/StoffelMPC?style=social&label=r%2FStoffelMPC)](https://www.reddit.com/r/StoffelMPC/) 此仓库包含 Stoffel Virtual Machine 的核心 crate,这是一个为本地执行和网络化多方安全计算 (MPC) 构建的基于寄存器的虚拟机。 ## Stoffel VM 背景! 就目前的形式而言,Stoffel 旨在处理简单和复杂的程序。该 VM 支持整数、布尔值、字符串和浮点数等基本值,以及对象、数组、闭包、外部对象和秘密份额等更复杂的运行时类型。该 VM 被设计为寄存器机,以使执行具有可预测性,并能清晰地映射到优化的运行时和底层 MPC 后端。 其指令集涵盖了内存操作、算术运算、位运算、控制流和函数调用。Stoffel 还具有真正的词法作用域闭包系统,函数可以从其周围环境中捕获值作为 upvalue,并在原始作用域退出后继续使用它们。 Stoffel 原生支持 Rust <> Stoffel FFI。这允许你使用原生的 Rust 函数和对象扩展运行时,同时保持 VM 的执行模型不变。运行时还公开了一个可配置的钩子系统,可以拦截指令执行、寄存器访问、栈事件、对象和数组访问、闭包创建等,以便进行调试或检测。 该工作区目前包括: - `crates/stoffel-cli`:类似 Cargo 的 `stoffel` 项目 CLI - `crates/stoffel-lang`:Stoffel-Lang 编译器 - `crates/stoffel-rust-sdk`:CLI 和应用程序使用的 Rust SDK - `crates/stoffel-vm`:运行时、网络层、MPC 集成、CLI 二进制文件和 C FFI - `crates/stoffel-vm-types`:共享的 VM 类型、指令定义和已编译的字节码格式 - `include/`:公共 C 头文件和 FFI 说明 ## 功能 Stoffel VM 目前支持以下指令: ### 内存操作 - `LD(dest_reg, stack_offset)`:将当前活动记录中的值加载到寄存器中 - `LDI(dest_reg, value)`:将立即数加载到寄存器中 - `MOV(dest_reg, src_reg)`:将值从一个寄存器移动到另一个寄存器 - `PUSHARG(reg)`:将寄存器值作为函数参数压栈 ### 算术运算 - `ADD(dest_reg, src1_reg, src2_reg)`:将两个寄存器相加 - `SUB(dest_reg, src1_reg, src2_reg)`:将两个寄存器相减 - `MUL(dest_reg, src1_reg, src2_reg)`:将两个寄存器相乘 - `DIV(dest_reg, src1_reg, src2_reg)`:将两个寄存器相除 - `MOD(dest_reg, src1_reg, src2_reg)`:取模运算 ### 位运算 - `AND(dest_reg, src1_reg, src2_reg)`:按位与 - `OR(dest_reg, src1_reg, src2_reg)`:按位或 - `XOR(dest_reg, src1_reg, src2_reg)`:按位异或 - `NOT(dest_reg, src_reg)`:按位非 - `SHL(dest_reg, src_reg, amount_reg)`:左移 - `SHR(dest_reg, src_reg, amount_reg)`:右移 ### 控制流 - `JMP(label)`:无条件跳转 - `JMPEQ(label)`:相等则跳转 - `JMPNEQ(label)`:不相等则跳转 - `JMPLT(label)`:小于则跳转 - `JMPGT(label)`:大于则跳转 - `CMP(reg1, reg2)`:比较两个寄存器 - `CALL(function_name)`:调用函数 - `RET(reg)`:使用寄存器中的值从当前函数返回 ### 值 Stoffel VM 目前公开了以下运行时值变体: - `Value::I64(i64)`:64 位有符号整数 - `Value::I32(i32)`:32 位有符号整数 - `Value::I16(i16)`:16 位有符号整数 - `Value::I8(i8)`:8 位有符号整数 - `Value::U8(u8)`:8 位无符号整数 - `Value::U16(u16)`:16 位无符号整数 - `Value::U32(u32)`:32 位无符号整数 - `Value::U64(u64)`:64 位无符号整数 - `Value::Float(F64)`:64 位浮点数 - `Value::Bool(bool)`:布尔值 - `Value::String(String)`:字符串值 - `Value::Object(ObjectRef)`:对象表引用 - `Value::Array(ArrayRef)`:数组表引用 - `Value::Foreign(ForeignObjectRef)`:外部对象引用 - `Value::Closure(Arc)`:带有捕获环境的函数闭包 - `Value::Unit`:Unit/void/nil 值 - `Value::Share(ShareType, ShareData)`:用于 MPC 的秘密共享值 ### 标准库内置功能! Stoffel VM 默认会注册以下常规的运行时内置功能: - `print`:将值打印到控制台 - `type`:以字符串形式获取值的类型 - `create_object`:创建新对象 - `create_array`:创建新数组 - `get_field`:从对象或数组中获取字段 - `set_field`:在对象或数组中设置字段 - `array_length`:获取数组的长度 - `array_push`:将一个或多个值追加到数组中 - `create_closure`:创建闭包 - `call_closure`:调用闭包 - `get_upvalue`:从闭包中读取捕获的 upvalue - `set_upvalue`:更新闭包中捕获的 upvalue - `ClientStore.get_number_clients`:获取已知的本地客户端槽位数量 - `ClientStore.get_number_input_clients`:获取包含输入材料的客户端数量 - `ClientStore.get_number_output_clients`:获取具备输出能力的客户端数量 - `ClientStore.take_share`:将客户端份额加载到 VM 中 - `ClientStore.take_share_fixed`:将客户端定点份额加载到 VM 中 - `MpcOutput.send_to_client`:将份额结果发送给客户端 ### MPC 内置功能 该 VM 还注册了专注于 MPC 的模块化内置功能: - `Share.*`:明文到份额的转换、份额上的算术运算、开盒、随机份额生成、客户端输出、本地插值以及承诺检查 - `Mpc.*`:运行时 MPC 元数据,如节点 ID、阈值、实例 ID、就绪状态和随机性辅助工具 - `Rbc.*`:可靠广播辅助工具 - `Crypto.*`:哈希和曲线/域转换辅助工具 - `Bytes.*`:字节数组辅助工具 - `Avss.*`:特定于 AVSS 的辅助函数 ## 我该如何使用它!? 目前,使用该运行时最直接的方法是将其嵌入到 Rust 程序中并注册 `VMFunction` 值。`VirtualMachine::new()` 会自动注册标准库和 MPC 内置功能。 ``` use std::collections::HashMap; use stoffel_vm::core_types::Value; use stoffel_vm::core_vm::VirtualMachine; use stoffel_vm::functions::VMFunction; use stoffel_vm::instructions::Instruction; fn main() -> Result<(), String> { let mut vm = VirtualMachine::new(); let hello_world = VMFunction::new( "hello_world".to_string(), vec![], vec![], None, 2, vec![ Instruction::LDI(0, Value::String("Hello, World!".to_string())), Instruction::PUSHARG(0), Instruction::CALL("print".to_string()), Instruction::LDI(1, Value::Unit), Instruction::RET(1), ], HashMap::new(), ); vm.try_register_function(hello_world)?; let result = vm.execute("hello_world")?; println!("Program returned: {:?}", result); Ok(()) } ``` 既然你已经熟悉了 Stoffel VM 的基础知识,接下来可以探索的好地方有: 1. `crates/stoffel-vm-types/examples/generate_client_mul_program.rs` 查看字节码生成示例 2. `crates/stoffel-vm/src/tests/vm_mpc_integration.rs` 查看 VM + MPC 执行流程 3. `tests/p2p_integration.rs` 查看 QUIC 网络覆盖范围 ## 了解更多 要了解更多关于你可以用 Stoffel 构建什么的信息,请访问 [stoffelmpc.com](https://stoffelmpc.com?utm_source=github&utm_medium=readme&utm_campaign=stoffel-repo&utm_term=mpc) ## 已编译的字节码 StoffelVM 还通过 `stoffel-vm-types::compiled_binary::CompiledBinary` 提供了一种可移植的编译二进制格式。该格式使用魔数 `STFL`,并且可以在 `VMFunction` 定义和序列化二进制文件之间进行往返转换。 你可以像这样从 Rust 定义的函数生成已编译的二进制文件: ``` use stoffel_vm_types::compiled_binary::{utils::save_to_file, CompiledBinary}; // Assume `functions: Vec` already exists. let binary = CompiledBinary::from_vm_functions(&functions); save_to_file(&binary, "program.stflb").unwrap(); ``` ## 构建和测试 构建所有内容: ``` cargo build ``` 运行测试套件: ``` cargo test cargo test -- --ignored ``` 以 release 模式构建运行时和 CLI: ``` cargo build --release -p stoffel-vm ``` HoneyBadger 和 AVSS 后端代码默认进行构建。分布式节点运行会从已编译的 `.stflb` 程序清单中选择后端。 ## Stoffel CLI `stoffel` 二进制文件是一个构建在 `crates/stoffel-rust-sdk` 之上的、类似 Cargo 的项目 CLI。 创建并运行一个项目: ``` cargo install --path crates/stoffel-cli stoffel init hello-mpc cd hello-mpc stoffel run --input a=40 --input b=2 ``` 项目模板: ``` stoffel init my-lib --lib stoffel init rust-app --template rust stoffel init py-app --template python stoffel init contract-app --template solidity-foundry stoffel init hardhat-app --template solidity-hardhat ``` 编译项目字节码、验证源码或检查字节码: ``` stoffel build stoffel check stoffel compile src/main.stfl -O2 --output target/debug/hello-mpc.stflb stoffel compile --disassemble target/debug/hello-mpc.stflb ``` `build` 和 `compile` 在未提供源路径时,默认处理所有的 `src/**/*.stfl` 文件。编译单个文件时请使用 `--output`。 当 `stoffel-run` 可用时,运行本地 MPC 开发模式: ``` cargo build -p stoffel-vm --bin stoffel-run stoffel dev --runner /path/to/stoffel/target/debug/stoffel-run --parties 5 --threshold 1 --input a=40 --input b=2 ``` `stoffel dev` 运行一次,会监听 `Stoffel.toml` 和已配置的源代码树,然后在 `.stfl` 文件或项目配置发生更改时重新构建并重新运行。使用 `stoffel dev --once` 可以获得以前那种适合脚本的一次性运行行为,或者使用 `--poll-ms ` 来调整重新加载延迟。 运行编译后的字节码或项目测试: ``` stoffel run target/debug/hello-mpc.stflb --entry main --input a=40 --input b=2 stoffel run --input a=40 --input b=2 stoffel run program.stfl --local --client-input 0=42 --parties 5 --threshold 1 stoffel run program.stfl --local --expected-output-clients 2 stoffel run target/debug/program.stflb --network --config offchain-client.toml --input x=42 stoffel run target/debug/program.stflb --network --config party-network.toml --connect-timeout-ms 1000 stoffel test stoffel test --test selected --verbose ``` `run` 接受 `.stfl` 源文件或 `.stflb` 字节码。默认情况下,它通过本地 MPC 协调器运行;`--local` 被接受作为显式的本地模式选择器。使用 `--client-input SLOT=VALUE` 提供 `ClientStore` 输入。使用 `--expected-output-clients N` 为动态输出循环或仅输出运行声明具备输出能力的本地客户端槽位 `0..N-1`;这不会合成客户端输入。 `--network --config` 使用 SDK 网络配置:链下客户端配置通过协调器/节点 RPC 路径执行,而网络配置会验证并连接到真实的节点地址。 项目管理实用程序: ``` stoffel status --verbose stoffel clean stoffel clean --all stoffel update --check stoffel update ``` `status` 验证项目配置,检查检测到的依赖管理器,编译已配置的源代码,并报告本地 MPC 网络配置。`clean` 移除项目的 `target/` 目录和 Stoffel 构建缓存;`--all` 还会移除已知的生态系统缓存,如 `node_modules`、Foundry 缓存/输出和 Python 测试缓存。`update` 从源码重新安装本地 CLI 并运行检测到的项目依赖更新命令;使用 `--check` 可以在不更改文件的情况下进行检查。 CLI 读取 `Stoffel.toml`,默认入口为 `src/main.stfl`,并将字节码写入 `target/debug/.stflb` 或 `target/release/.stflb`。 ## VM Runner CLI 包含一个 CLI,用于在本地或作为分布式 MPC 会话的一部分运行已编译的 Stoffel 字节码文件。 构建 CLI: ``` cargo build --release -p stoffel-vm ``` 显示可用的标志: ``` cargo run -p stoffel-vm --bin stoffel-run -- --help ``` 在本地运行已编译的程序(默认入口函数为 `main`): ``` ./target/release/stoffel-run path/to/program.stflb ./target/release/stoffel-run path/to/program.stflb main --trace-instr ``` 作为 5 方 MPC 会话的 leader 节点运行: ``` STOFFEL_AUTH_TOKEN=replace-with-random-secret \ ./target/release/stoffel-run path/to/program.stflb main \ --leader \ --bind 127.0.0.1:9000 \ --n-parties 5 \ --threshold 1 ``` 作为另一方加入: ``` STOFFEL_AUTH_TOKEN=replace-with-random-secret \ ./target/release/stoffel-run path/to/program.stflb main \ --party-id 1 \ --bootstrap 127.0.0.1:9000 \ --bind 127.0.0.1:9002 \ --n-parties 5 \ --threshold 1 ``` 在客户端模式下运行以向参与方服务器提交输入: ``` ./target/release/stoffel-run --client \ --inputs 10,20 \ --servers 127.0.0.1:10000,127.0.0.1:9002,127.0.0.1:9003,127.0.0.1:9004,127.0.0.1:9005 \ --n-parties 5 ``` AVSS 输出客户端模式可以重建私有域输出: ``` ./target/release/stoffel-run --client \ --mpc-backend avss \ --mpc-curve secp256k1 \ --inputs 0x \ --outputs 2 \ --servers 127.0.0.1:9000,127.0.0.1:9001,127.0.0.1:9002,127.0.0.1:9003,127.0.0.1:9004 \ --n-parties 5 ``` 注意: - 在 bootnode、leader 和 party 流程中进行经过身份验证的发现时,需要使用 `STOFFEL_AUTH_TOKEN` - CLI 接受任何文件路径;本仓库按惯例将编译后的固件存储为 `.stflb` - 对于客户端模式和旧版二进制文件,`--mpc-backend` 支持 `honeybadger` 和 `avss`;v3+ 的 `.stflb` 节点运行使用清单中指定的后端,并会拒绝冲突的 CLI 覆盖参数 - 对于 AVSS,`--mpc-curve` 支持 `bls12-381`、`bn254`、`curve25519`、`ed25519`、`secp256k1` 和 `p-256` (`secp256r1`) ## Docker 流程 API/协调器拓扑结构可使用 reserve-index compose 栈运行: ``` STOFFEL_AUTH_TOKEN=replace-with-random-secret \ docker compose -f docker-compose.coordinator.reserve-index.yml up --build ``` 该协调器路径目前通过 HoneyBadger/BLS12-381 VM 路径运行。AVSS compose 栈是独立的,是 AVSS 曲线和本地份额存储的持久性测试平台: ``` STOFFEL_AUTH_TOKEN=replace-with-random-secret \ docker compose -f docker-compose.avss.yml up --build ``` `docker-compose.avss.yml` 为每个参与方挂载了本地数据卷,并将 `STOFFEL_LOCAL_STORE` 转发给 `stoffel-run。 AVSS 门限 ECDSA 示例镜像了现有的门限签名固件: ``` STOFFEL_AUTH_TOKEN=replace-with-random-secret \ STOFFEL_PROGRAM=/app/programs/threshold_ecdsa_secp256k1.stflb \ STOFFEL_MPC_CURVE=secp256k1 \ docker compose -f docker-compose.avss.yml up --build STOFFEL_AUTH_TOKEN=replace-with-random-secret \ STOFFEL_PROGRAM=/app/programs/threshold_ecdsa_p256.stflb \ STOFFEL_MPC_CURVE=p-256 \ docker compose -f docker-compose.avss.yml up --build ``` 这些程序的 Stoffel 源码位于 `crates/stoffel-lang/examples/threshold_signatures/threshold_ecdsa_secp256k1/main.stfl` 和 `crates/stoffel-lang/examples/threshold_signatures/threshold_ecdsa_p256/main.stfl`。VM 仅提供用于域求逆、将开盒曲线点转换为 `x mod q` 以及格式化最终 ECDSA 输出的基础辅助工具。门限 ECDSA 协议本身是在 Stoffel 程序中表达的。返回的布局是固定宽度的Big-Endian 格式 `r(32) || s(32) || sec1_compressed_pk(33)`,因此调用者可以直接对 `(r, s)` 进行 DER 编码。 对于 AVSS 证书签名路径,请运行 `/app/programs/avss_certificate_keygen.stflb` 并使用 `STOFFEL_MPC_CURVE=secp256k1` 或 `STOFFEL_MPC_CURVE=p-256` 来持久化存储每个参与方的 CA 签名份额。密钥生成是幂等的:如果存储键已存在,它会加载现有份额,并且仅在首次使用时生成。然后使用 `STOFFEL_WAIT_FOR_CLIENTS=1` 运行 `/app/programs/avss_certificate_sign.stflb`;客户端提交真实的 SHA-256 TBS 摘要,并使用 `--outputs 2` 重建固定宽度的门限 ECDSA `r || s` 材料。相应的 Stoffel 源码位于 `crates/stoffel-lang/examples/avss_certificate/keygen/main.stfl` 和 `crates/stoffel-lang/examples/avss_certificate/sign/main.stfl`。 ## C Foreign Function Interface `stoffel-vm` 同时构建为 `rlib` 和 `cdylib`,因此该运行时也可以从兼容 C 的环境中嵌入。 相关文件: - `include/stoffel_vm.h` - `include/README.md` 特定于平台的库名称: - Linux: `libstoffel_vm.so` - macOS: `libstoffel_vm.dylib` - Windows: `stoffel_vm.dll`
标签:Rust, 可视化界面, 安全多方计算, 寄存器机, 密码学, 手动系统调用, 文档结构分析, 生成式AI安全, 编译器, 网络流量审计, 虚拟机, 通知系统