Rust零知识证明虚拟机库sp1-zkvm的使用,sp1-zkvm提供高效ZK-SNARKs验证和zkVM开发支持

SP1

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]);
    }
}

1 回复

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!("高级配置示例完成");
}

性能优化建议

  1. 使用批量证明处理多个证明
  2. 合理配置证明系统参数
  3. 优化电路设计减少约束数量
  4. 使用预计算和缓存机制

注意事项

  • 确保私有输入数据的机密性
  • 合理设置证明大小和验证时间的平衡
  • 定期更新库版本以获得性能改进和安全修复

这个库为Rust开发者提供了强大的零知识证明能力,特别适合构建需要隐私保护的分布式应用和区块链解决方案。

回到顶部