Rust零知识证明库bellman的使用,bellman提供高效zk-SNARKs证明系统实现与密码学工具

Rust零知识证明库bellman的使用,bellman提供高效zk-SNARKs证明系统实现与密码学工具

bellman 是一个用于构建zk-SNARK电路的Rust库。它提供了电路特性和基本结构,以及布尔值和数字抽象等基本gadget实现。

bellman 使用 ffgroup crate来在标量字段类型上通用地构建电路,该标量字段类型用作电路的"字"。模标量字段质数的算术运算是高效的,而其他操作(如布尔逻辑)则使用这些字来实现。

当前状态

目前 bellman 捆绑了Groth16证明系统的实现。未来这将被移到一个单独的crate中,而 bellman 将包含任何使实现证明系统更容易的工具。

许可证

根据以下任一许可证授权:

  • Apache License, Version 2.0
  • MIT license

示例代码

以下是一个使用bellman创建简单zk-SNARK电路的完整示例:

use bellman::{
    gadgets::{
        boolean::{AllocatedBit, Boolean},
        multipack,
        sha256::sha256,
    },
    groth16, Circuit, ConstraintSystem, SynthesisError,
};
use bls12_381::{Bls12, Scalar};
use ff::PrimeField;
use rand::rngs::OsRng;
use sha2::{Digest, Sha256};

// 定义一个简单的电路用于SHA256哈希计算
struct MyCircuit {
    // 电路输入,None表示不知道输入值
    input: Option<Vec<u8>>,
}

// 为电路实现Circuit trait
impl<Scalar: PrimeField> Circuit<Scalar> for MyCircuit {
    fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
        // 将输入转换为布尔值位
        let bit_values = if let Some(input) = self.input {
            input
                .into_iter()
                .flat_map(|byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8))
                .collect::<Vec<bool>>()
        } else {
            vec![false; 256]
        };

        // 为每个位分配电路变量
        let preimage_bits = bit_values
            .into_iter()
            .enumerate()
            .map(|(i, b)| {
                AllocatedBit::alloc(cs.namespace(|| format!("preimage bit {}", i)), Some(b))
            })
            .collect::<Result<Vec<_>, _>>()?
            .into_iter()
            .map(Boolean::from)
            .collect::<Vec<_>>();

        // 计算SHA256哈希
        let hash = sha256(cs.namespace(|| "sha256"), &preimage_bits)?;

        // 将哈希位打包到标量中
        multipack::pack_into_inputs(cs.namespace(|| "pack hash"), &hash)
    }
}

fn main() {
    // 创建随机参数
    let rng = &mut OsRng;
    
    // 生成CRS (Common Reference String)
    let params = {
        let c = MyCircuit { input: None };
        groth16::generate_random_parameters::<Bls12, _, _>(c, rng).unwrap()
    };

    // 准备验证密钥
    let pvk = groth16::prepare_verifying_key(&params.vk);

    // 创建证明
    let input = b"hello world";
    let c = MyCircuit {
        input: Some(input.to_vec()),
    };
    let proof = groth16::create_random_proof(c, &params, rng).unwrap();

    // 计算预期哈希
    let hash = Sha256::digest(input);
    let mut hash_bits = Vec::new();
    for byte in hash.iter() {
        for i in 0..8 {
            hash_bits.push((byte >> i) & 1u8 == 1u8);
        }
    }
    let inputs = multipack::bytes_to_b bits(&hash);
    let inputs = multipack::compute_multipacking::<Scalar>(&inputs);

    // 验证证明
    assert!(groth16::verify_proof(&pvk, &proof, &inputs).is_ok());
    println!("Proof verified successfully!");
}

这个示例演示了如何使用bellman:

  1. 定义了一个简单的电路来计算SHA256哈希
  2. 生成证明参数
  3. 创建证明
  4. 验证证明

电路将输入位转换为布尔值,计算SHA256哈希,并将结果打包为标量值用于验证。


1 回复

以下是基于您提供的内容整理的完整示例demo,首先展示内容中的示例,然后提供完整实现:

内容中的示例代码

1. 定义电路示例

use bellman::{
    Circuit,
    ConstraintSystem,
    SynthesisError,
};
use pairing::{Engine, Field};

struct MyCircuit<E: Engine> {
    a: Option<E::Fr>,
    b: Option<E::Fr>,
}

impl<E: Engine> Circuit<E> for MyCircuit<E> {
    fn synthesize<CS: ConstraintSystem<E>>(
        self,
        cs: &mut CS
    ) -> Result<(), SynthesisError> {
        let a_var = cs.alloc(|| "a", || {
            self.a.ok_or(SynthesisError::AssignmentMissing)
        })?;
        
        let b_var = cs.alloc(|| "b", || {
            self.b.ok_or(SynthesisError::AssignmentMissing)
        })?;
        
        let ab_var = cs.alloc(|| "a*b", || {
            let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?;
            let b = self.b.ok_or(SynthesisError::AssignmentMissing)?;
            a.mul_assign(&b);
            Ok(a)
        })?;
        
        cs.enforce(
            || "a*b = ab",
            |lc| lc + a_var,
            |lc| lc + b_var,
            |lc| lc + ab_var
        );
        
        Ok(())
    }
}

2. 生成和验证证明示例

use bellman::groth16::{
    generate_random_parameters,
    create_random_proof,
    prepare_verifying_key,
    verify_proof,
};
use pairing::bls12_381::{Bls12, Fr};
use rand::thread_rng;

fn main() {
    let rng = &mut thread_rng();
    let circuit = MyCircuit::<Bls12> {
        a: Some(Fr::from_str("3").unwrap()),
        b: Some(Fr::from_str("5").unwrap()),
    };
    
    let params = generate_random_parameters::<Bls12, _, _>(
        circuit.clone(), 
        rng
    ).unwrap();
    
    let pvk = prepare_verifying_key(&params.vk);
    let proof = create_random_proof(circuit, &params, rng).unwrap();
    
    let result = verify_proof(&pvk, &proof, &[]).unwrap();
    assert!(result);
    println!("Proof verified successfully!");
}

完整示例demo

use bellman::{
    Circuit,
    ConstraintSystem,
    SynthesisError,
    groth16::{
        generate_random_parameters,
        create_random_proof,
        prepare_verifying_key,
        verify_proof,
    }
};
use pairing::{
    Engine,
    bls12_381::{Bls12, Fr},
    Field
};
use rand::thread_rng;
use std::str::FromStr;

// 定义电路结构
struct MultiplicationCircuit<E: Engine> {
    // 输入值a
    a: Option<E::Fr>,
    // 输入值b
    b: Option<E::Fr>,
}

// 为电路实现Circuit trait
impl<E: Engine> Circuit<E> for MultiplicationCircuit<E> {
    fn synthesize<CS: ConstraintSystem<E>>(
        self,
        cs: &mut CS
    ) -> Result<(), SynthesisError> {
        // 分配输入a
        let a_var = cs.alloc(|| "a", || {
            self.a.ok_or(SynthesisError::AssignmentMissing)
        })?;
        
        // 分配输入b
        let b_var = cs.alloc(|| "b", || {
            self.b.ok_or(SynthesisError::AssignmentMissing)
        })?;
        
        // 计算a*b并分配结果
        let ab_var = cs.alloc(|| "a*b", || {
            let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?;
            let b = self.b.ok_or(SynthesisError::AssignmentMissing)?;
            a.mul_assign(&b);
            Ok(a)
        })?;
        
        // 添加约束:a * b = ab
        cs.enforce(
            || "a*b = ab constraint",
            |lc| lc + a_var,
            |lc| lc + b_var,
            |lc| lc + ab_var
        );
        
        Ok(())
    }
}

fn main() {
    // 初始化随机数生成器
    let rng = &mut thread_rng();
    
    // 创建电路实例
    let circuit = MultiplicationCircuit::<Bls12> {
        a: Some(Fr::from_str("3").unwrap()),
        b: Some(Fr::from_str("5").unwrap()),
    };
    
    // 1. 生成CRS (公共参考字符串)
    println!("Generating parameters...");
    let params = generate_random_parameters::<Bls12, _, _>(circuit.clone(), rng)
        .expect("Failed to generate parameters");
    
    // 2. 准备验证密钥
    let pvk = prepare_verifying_key(&params.vk);
    
    // 3. 创建证明
    println!("Creating proof...");
    let proof = create_random_proof(circuit, &params, rng)
        .expect("Failed to create proof");
    
    // 4. 验证证明
    println!("Verifying proof...");
    let result = verify_proof(&pvk, &proof, &[])
        .expect("Failed to verify proof");
    
    assert!(result, "Proof verification failed");
    println!("Proof verified successfully!");
    
    // 5. 测试错误案例
    println!("Testing with invalid inputs...");
    let invalid_circuit = MultiplicationCircuit::<Bls12> {
        a: Some(Fr::from_str("4").unwrap()),  // 错误的a值
        b: Some(Fr::from_str("5").unwrap()),
    };
    
    let invalid_proof = create_random_proof(invalid_circuit, &params, rng)
        .expect("Failed to create invalid proof");
    
    let invalid_result = verify_proof(&pvk, &invalid_proof, &[])
        .expect("Failed to verify invalid proof");
    
    assert!(!invalid_result, "Invalid proof should not verify");
    println!("Invalid proof correctly rejected");
}

这个完整示例演示了:

  1. 定义一个简单的乘法电路
  2. 生成zk-SNARK参数
  3. 创建和验证证明
  4. 包含错误案例测试

使用步骤:

  1. 将代码保存为main.rs
  2. 在Cargo.toml中添加bellman和pairing依赖
  3. 运行程序将输出证明生成和验证过程

注意:实际使用时需要根据具体需求设计更复杂的电路和约束条件。

回到顶部