#system #circuit #computing #start #zkvc

zkvc

A Rust crate for building zero-knowledge proof-based volunteer computing systems

1 unstable release

new 0.1.0 May 13, 2025

#1059 in HTTP server

MIT license

24KB
420 lines

zkvc - Zero Knowledge Volunteer Computing

A Rust library for building zero-knowledge proof-based volunteer computing systems. This library provides a framework for creating distributed computing applications where clients can prove they performed computations correctly without revealing their private inputs.

Quick Start

Add the following to your Cargo.toml:

[dependencies]
zkvc = "0.1.0"
ark-bls12-381 = "0.3"
ark-r1cs-std = { version = "0.3", features = ["std"] }
ark-relations = "0.3"

Basic Usage

1. Define Your Circuit

First, define your computation as a circuit by implementing the ConstraintGenerator trait:

use ark_bls12_381::Fr;
use ark_relations::r1cs::SynthesisError;
use zkvc::circuit::{ConstraintGenerator, ZkCircuitContext};

pub struct MyCircuit {
    // Your circuit's private and public inputs
    private_input: u64,
    public_input: u64,
}

impl ConstraintGenerator<Fr> for MyCircuit {
    fn generate_constraints(
        &self,
        context: &mut ZkCircuitContext<Fr>,
    ) -> Result<(), SynthesisError> {
        // Create private witness
        let private_var = context.new_witness(|| Ok(Fr::from(self.private_input)))?;
        
        // Create public input
        let public_var = context.new_public_input(|| Ok(Fr::from(self.public_input)))?;
        
        // Define your constraints
        private_var.enforce_equal(&public_var)?;
        
        Ok(())
    }
}

2. Setup Phase

Generate proving and verification keys for your circuit:

use std::path::PathBuf;
use zkvc::setup;

let circuit = MyCircuit {
    private_input: 0,
    public_input: 0,
};

setup::generate_keys_to_files(
    Box::new(circuit),
    &PathBuf::from("pk.bin"),
    &PathBuf::from("vk.bin"),
)?;

3. Server Implementation

Create a server that verifies proofs from clients:

use zkvc::server::{ServerApp, ServerConfig};

let config = ServerConfig {
    listen_address: "127.0.0.1:65432".to_string(),
    verification_key_path: PathBuf::from("vk.bin"),
};

let server = ServerApp::new(config)?
    .with_valid_proof_handler(|client_id, public_inputs| {
        println!("Client {} provided valid proof with inputs: {:?}", client_id, public_inputs);
        Ok(())
    })
    .with_invalid_proof_handler(|client_id, reason| {
        println!("Client {} provided invalid proof: {}", client_id, reason);
        Ok(())
    })
    .with_error_handler(|client_id, error| {
        println!("Client {} encountered an error: {}", client_id, error);
        Ok(())
    });

server.run().await?;

4. Client Implementation

Create a client that generates and sends proofs:

use zkvc::client::{ClientApp, ClientConfig};
use url::Url;

let config = ClientConfig {
    server_url: Url::parse("http://127.0.0.1:65432")?,
    proving_key_path: PathBuf::from("pk.bin"),
    proof_path: Some(PathBuf::from("proof.json")),
    client_id: "client-1".to_string(),
};

let client = ClientApp::new(config)?;

let circuit = MyCircuit {
    private_input: 42,
    public_input: 42,
};

let response = client.generate_and_send_proof(Box::new(circuit)).await?;

Arkworks Gadgets

The library supports Arkworks gadgets for complex operations. Here's an example of using MiMC hash:

use ark_r1cs_std::ToBytesGadget;
use arkworks_mimc::{
    constraints::{MiMCNonFeistelCRHGadget, MiMCVar},
    params::mimc_7_91_bls12_381::{MIMC_7_91_BLS12_381_PARAMS, MIMC_7_91_BLS12_381_ROUND_KEYS},
};

// Inside your circuit implementation:
let public_zero = context.new_witness(|| Ok(Fr::from(0u64)))?;
let public_round_keys = MIMC_7_91_BLS12_381_ROUND_KEYS
    .iter()
    .map(|x| context.new_witness(|| Ok(*x)))
    .collect::<Result<Vec<_>, _>>()?;

let mimc_var = MiMCVar::<Fr, MIMC_7_91_BLS12_381_PARAMS>::new(
    1,
    public_zero,
    public_round_keys
);

let value = context.new_witness(|| Ok(Fr::from(42)))?;
let hash = MiMCNonFeistelCRHGadget::<Fr, MIMC_7_91_BLS12_381_PARAMS>::evaluate(
    &mimc_var,
    &FpVar::<Fr>::Constant(Fr::from(0u64)).to_bytes()?,
    &value.to_bytes()?,
)?;

Dependencies

~20–33MB
~571K SLoC