Rust零知识证明虚拟机库sp1-zkvm的使用,sp1-zkvm提供高效ZK-SNARKs验证和zkVM开发支持
SP1是最快、功能最完整的零知识虚拟机(zkVM),可以证明任意Rust(或任何LLVM编译语言)程序的执行。SP1通过让开发者能够轻松地用普通Rust代码编写ZKP程序,使ZK对任何开发者都变得可访问。
今天,开发者可以编写程序,包括复杂的、大型的程序,如ZK Tendermint轻客户端或使用Reth的type-1 zkEVM,使用Rust(支持std),生成证明并验证它们。大多数Rust crate应该被支持,并且可以被你的程序无缝使用。示例程序可以在示例文件夹中找到。
要开始使用,请确保你已经安装了Rust。然后按照SP1书中的安装指南操作,并阅读入门部分。
SP1已经通过了Veridise、Cantina和KALOS的审计,并推荐用于生产环境。审计报告可在此处获取。
当前的MSRV(最低支持的Rust版本)是1.79。
开源是SP1精神的核心部分,也是其优势的关键。我们希望培养一个充满活力的开源贡献者社区,涵盖个人、团队和地区。如果你想贡献,或跟随贡献者讨论,你可以使用我们的主要Telegram与我们聊天。我们的贡献者指南可以在CONTRIBUTING.md中找到。开发技巧的快速概述可以在DEVELOPMENT.md中找到。
我们一直在寻找对大大小小任务感兴趣的贡献者,包括跨代码库的次要杂务、优化性能、为常用加密操作添加预编译、添加文档、创建新的示例程序等等。如果有兴趣,请在Telegram聊天中联系我们!
我们想感谢以下项目,它们之前的工作对使这个项目成为现实起到了重要作用。
- Plonky3:SP1的证明器由Plonky3工具包提供动力。
- Valida:SP1的交叉表查找、证明器、借用宏和芯片设计,包括约束,都受到了Valida的启发。
- RISC0:SP1的Rust工具链、安装/构建脚本和我们的RISCV运行时借用了RISC0的代码。
- Cairo:Cairo引入了"内置"的概念,允许zkVM加速某些操作。然而,"内置"的复杂性嵌入在CPU中,限制了它们的复杂性。SP1通过执行一个易于扩展的"预编译"愿景扩展了这个想法,这些预编译可以作为额外的表与CPU一起添加。
// 示例:使用sp1-zkvm进行简单的零知识证明
// 引入必要的库
use sp1_zkvm::prelude::*;
// 定义一个简单的程序,计算斐波那契数列的第n项
#[sp1_zkvm::program]
fn fibonacci() {
// 读取输入,即斐波那契数列的项数
let n = sp1_zkvm::io::read::<u32>();
// 初始化斐波那契数列的前两项
let mut a = 0;
let mut b = 1;
// 计算斐波那契数列的第n项
for _ in 0..n {
let c = a + b;
a = b;
b = c;
}
// 输出结果
sp1_zkvm::io::write(&a);
}
// 主函数,用于执行证明生成和验证
fn main() {
// 设置证明生成器
let mut proof_builder = sp1_zkvm::ProofBuilder::new();
// 提供输入数据
proof_builder.write(&5u32); // 计算斐波那契数列的第5项
// 生成证明
let proof = proof_builder.prove(fibonacci);
// 验证证明
let is_valid = proof.verify();
// 输出验证结果
println!("Proof is valid: {}", is_valid);
// 读取输出结果
let result: u32 = proof.read();
println!("Fibonacci result: {}", result);
}
完整示例代码:
// Cargo.toml依赖配置
// [dependencies]
// sp1-zkvm = "5.2.1"
use sp1_zkvm::prelude::*;
// 使用sp1_zkvm属性标记程序
#[sp1_zkvm::program]
fn fibonacci_sequence() {
// 从虚拟机读取输入
let n: u32 = sp1_zkvm::io::read();
// 初始化斐波那契数列
let mut fib = vec![0u32; n as usize];
if n > 0 {
fib[0] = 0;
}
if n > 1 {
fib[1] = 1;
}
// 计算斐波那契数列
for i in 2..(n as usize) {
fib[i] = fib[i-1] + fib[i-2];
}
// 将结果写回虚拟机
sp1_zkvm::io::write(&fib);
}
fn main() {
println!("Starting SP1 zkVM Fibonacci example...");
// 创建证明构建器
let mut builder = sp1_zkvm::ProofBuilder::new();
// 设置输入参数(计算前10个斐波那契数)
builder.write(&10u32);
// 生成证明
println!("Generating proof...");
let proof = builder.prove(fibonacci_sequence);
// 验证证明
println!("Verifying proof...");
let is_valid = proof.verify();
if is_valid {
println!("✓ Proof verified successfully!");
// 读取计算结果
let result: Vec<u32> = proof.read();
println!("Fibonacci sequence: {:?}", result);
} else {
println!("✗ Proof verification failed!");
}
}
// 测试用例
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fibonacci() {
let mut builder = sp1_zkvm::ProofBuilder::new();
builder.write(&5u32);
let proof = builder.prove(fibonacci_sequence);
assert!(proof.verify());
let result: Vec<u32> = proof.read();
assert_eq!(result, vec![0, 1, 1, 2, 3]);
}
}
Rust零知识证明虚拟机库sp1-zkvm使用指南
简介
sp1-zkvm是一个基于Rust的高性能零知识证明虚拟机库,专门为ZK-SNARKs验证和zkVM开发提供支持。该库通过优化的证明系统和虚拟机架构,实现了高效的零知识证明生成和验证,特别适用于需要隐私保护的区块链应用和可信计算场景。
核心特性
- 高效的ZK-SNARKs证明生成和验证
- 完整的zkVM开发环境支持
- Rust原生集成,提供类型安全的API
- 可配置的证明系统和电路优化
- 支持多种零知识证明后端
安装方法
在Cargo.toml中添加依赖:
[dependencies]
sp1-zkvm = "0.8.0"
基本使用方法
1. 创建简单的零知识证明
use sp1_zkvm::{Prover, Verifier, ZkProof};
fn main() {
// 初始化证明器
let mut prover = Prover::new();
// 添加私有输入数据
let secret_data = vec![1u32, 2, 3, 4, 5];
prover.add_private_input(&secret_data);
// 添加公共输入数据
let public_data = vec![10u32];
prover.add_public_input(&public_data);
// 生成证明
let proof = prover.prove().expect("Failed to generate proof");
// 验证证明
let mut verifier = Verifier::new(proof);
verifier.add_public_input(&public_data);
let is_valid = verifier.verify().expect("Verification failed");
println!("Proof is valid: {}", is_valid);
}
2. 自定义zkVM程序
use sp1_zkvm::{ZkProgram, ZkProof};
#[derive(Clone)]
struct MyZkProgram;
impl ZkProgram for MyZkProgram {
fn execute(&self, inputs: &[u32]) -> Vec<u32> {
// 在zkVM中执行的计算逻辑
inputs.iter().map(|x| x * 2).collect()
}
}
fn main() {
let program = MyZkProgram;
let inputs = vec![1, 2, 3, 4, 5];
// 生成证明
let proof = program.prove(&inputs).expect("Proof generation failed");
// 验证证明
let result = program.verify(&proof, &inputs).expect("Verification failed");
println!("Verification result: {:?}", result);
}
3. 高级配置示例
use sp1_zkvm::{ProverConfig, VerifierConfig, ProofSystem};
fn advanced_usage() {
// 配置证明器
let prover_config = ProverConfig {
proof_system: ProofSystem::Groth16,
optimization_level: 3,
..Default::default()
};
let mut prover = Prover::with_config(prover_config);
// 复杂计算示例
prover.add_private_input(&[123u64]);
prover.add_public_input(&[456u64]);
// 执行zkVM计算
let result = prover.compute(|env| {
let private: u64 = env.private_input(0);
let public: u64 = env.public_input(0);
private + public
});
let proof = prover.prove().unwrap();
println!("Computation result: {}", result);
}
完整示例demo
// 完整示例:使用sp1-zkvm进行隐私保护的投票系统
use sp1_zkvm::{Prover, Verifier, ZkProgram, ZkProof};
use serde::{Serialize, Deserialize};
// 投票数据结构
#[derive(Serialize, Deserialize, Clone)]
struct Vote {
voter_id: u64, // 投票者ID(私有)
candidate_id: u32, // 候选人ID(公共)
timestamp: u64, // 时间戳(私有)
}
// 自定义zkVM投票程序
#[derive(Clone)]
struct VotingZkProgram;
impl ZkProgram for VotingZkProgram {
fn execute(&self, inputs: &[u8]) -> Vec<u8> {
// 反序列化输入数据
let vote: Vote = bincode::deserialize(inputs).unwrap();
// 在zkVM中执行的投票验证逻辑
// 验证投票时间戳在有效范围内(示例逻辑)
let is_valid = vote.timestamp > 1672531200 && vote.timestamp < 1704067200;
// 返回验证结果和候选人ID
let result = (is_valid, vote.candidate_id);
bincode::serialize(&result).unwrap()
}
}
fn main() {
println!("SP1-ZKVM 投票系统示例");
// 示例1:基本证明生成和验证
basic_proof_example();
// 示例2:自定义投票程序
voting_program_example();
// 示例3:高级配置使用
advanced_config_example();
}
fn basic_proof_example() {
println!("\n=== 基本证明示例 ===");
let mut prover = Prover::new();
// 添加私有输入(投票数据)
let private_vote_data = vec![123u64, 4567890123u64]; // [voter_id, timestamp]
prover.add_private_input(&private_vote_data);
// 添加公共输入(候选人ID)
let public_candidate_id = vec![1u32]; // 候选人1
prover.add_public_input(&public_candidate_id);
// 生成证明
let proof = prover.prove().expect("证明生成失败");
println!("基本证明生成成功");
// 验证证明
let mut verifier = Verifier::new(proof);
verifier.add_public_input(&public_candidate_id);
let is_valid = verifier.verify().expect("验证失败");
println!("基本证明验证结果: {}", is_valid);
}
fn voting_program_example() {
println!("\n=== 自定义投票程序示例 ===");
let voting_program = VotingZkProgram;
// 创建投票数据
let vote = Vote {
voter_id: 123456,
candidate_id: 2,
timestamp: 1698765432,
};
// 序列化输入数据
let inputs = bincode::serialize(&vote).unwrap();
// 生成投票证明
let proof = voting_program.prove(&inputs).expect("投票证明生成失败");
println!("投票证明生成成功");
// 验证证明
let verification_result = voting_program.verify(&proof, &inputs).expect("投票验证失败");
let result: (bool, u32) = bincode::deserialize(&verification_result).unwrap();
println!("投票验证结果 - 有效: {}, 候选人ID: {}", result.0, result.1);
}
fn advanced_config_example() {
println!("\n=== 高级配置示例 ===");
use sp1_zkvm::{ProverConfig, ProofSystem};
// 配置高性能证明器
let prover_config = ProverConfig {
proof_system: ProofSystem::Groth16, // 使用Groth16证明系统
optimization_level: 3, // 最高优化级别
max_batch_size: 100, // 最大批量处理大小
..Default::default()
};
let mut prover = Prover::with_config(prover_config);
// 批量处理多个投票
let batch_votes: Vec<Vec<u64>> = vec![
vec![111u64, 1698765000u64], // 投票1: [voter_id, timestamp]
vec![222u64, 1698765100u64], // 投票2
vec![333u64, 1698765200u64], // 投票3
];
for vote_data in &batch_votes {
prover.add_private_input(vote_data);
}
// 公共输入(所有投票都投给同一个候选人)
prover.add_public_input(&[3u32]); // 候选人3
// 执行批量计算
let results = prover.compute_batch(|env, index| {
let voter_id: u64 = env.private_input(index * 2);
let timestamp: u64 = env.private_input(index * 2 + 1);
let candidate: u32 = env.public_input(0);
// 验证逻辑:时间戳有效且投票给指定候选人
let is_valid = timestamp > 1698760000 && candidate == 3;
(voter_id, is_valid)
});
// 生成批量证明
let proof = prover.prove().unwrap();
println!("批量证明生成成功,处理了 {} 个投票", batch_votes.len());
// 输出每个投票的验证结果
for (i, (voter_id, is_valid)) in results.iter().enumerate() {
println!("投票 {} - 投票者ID: {}, 有效: {}", i + 1, voter_id, is_valid);
}
println!("高级配置示例完成");
}
性能优化建议
- 使用批量证明处理多个证明
- 合理配置证明系统参数
- 优化电路设计减少约束数量
- 使用预计算和缓存机制
注意事项
- 确保私有输入数据的机密性
- 合理设置证明大小和验证时间的平衡
- 定期更新库版本以获得性能改进和安全修复
这个库为Rust开发者提供了强大的零知识证明能力,特别适合构建需要隐私保护的分布式应用和区块链解决方案。