zk-prover 0.0.2

Rust wrapper around Nargo and Barretenberg to generate and verify zero-knowledge proofs using Noir circuits
Documentation
use anyhow::{Context, Result, anyhow};
use serde::{Deserialize, Serialize};
use std::fs::{self};
use std::path::Path;
use std::process::Command;

#[derive(Debug, Serialize, Deserialize)]
pub struct Inputs {
    pub price_start: String,
    pub price_end: String,
    pub timestamp_start: String,
    pub timestamp_end: String,
    pub expected_apy: String,
}

#[derive(Debug)]
pub struct ProofResult {
    pub proof: Vec<u8>,
    pub public_inputs: Vec<String>,
}

pub fn generate_proof_from_file(
    inputs: &Inputs,
    circuit_dir: &str,
    profile_name: &str,
    circuit_name: &str,
) -> Result<ProofResult> {
    let profile_path = Path::new(circuit_dir).join(profile_name);
    let compiled_dir = Path::new(circuit_dir).join("target");
    let json_path = compiled_dir.join(format!("{circuit_name}.json"));
    let witness_path = compiled_dir.join(format!("{circuit_name}.gz"));
    let proof_path = compiled_dir.join("proof");
    let vk_dir = compiled_dir.join("vk");
    let vk_path = vk_dir.join("vk");
    let verifier_path = compiled_dir.join("Verifier.sol");

    if vk_dir.exists() && vk_dir.is_dir() {
        fs::remove_dir_all(&vk_dir).context("Failed to remove vk directory")?;
    }
    fs::create_dir_all(&vk_dir).context("Failed to create vk directory")?;

    println!("🔧 Writing inputs to profile: {}", profile_path.display());
    let toml_str = toml::to_string(inputs).context("Failed to serialize inputs to TOML")?;
    fs::write(&profile_path, toml_str).context("Failed to write TOML input file")?;

    println!("⚙️ Running nargo execute...");
    let output = Command::new("nargo")
        .args(["execute", "-p", profile_name])
        .current_dir(circuit_dir)
        .output()
        .context("Failed to run nargo execute")?;
    if !output.status.success() {
        return Err(anyhow!(
            "nargo execute failed: {}",
            String::from_utf8_lossy(&output.stderr)
        ));
    }

    println!("📦 Running bb prove...");
    let output = Command::new("bb")
        .args([
            "prove",
            "-b",
            &json_path.to_string_lossy(),
            "-w",
            &witness_path.to_string_lossy(),
            "-o",
            &compiled_dir.to_string_lossy(),
        ])
        .current_dir(circuit_dir)
        .output()
        .context("Failed to run bb prove")?;
    if !output.status.success() {
        return Err(anyhow!(
            "bb prove failed: {}",
            String::from_utf8_lossy(&output.stderr)
        ));
    }

    println!("📄 Reading generated proof...");
    let proof = fs::read(&proof_path).context("Failed to read proof file")?;

    println!("🔐 Generating verification key...");
    let output = Command::new("bb")
        .args([
            "write_vk",
            "-b",
            &json_path.to_string_lossy(),
            "-o",
            &vk_dir.to_string_lossy(),
        ])
        .current_dir(circuit_dir)
        .output()
        .context("Failed to run bb write_vk")?;
    if !output.status.success() {
        return Err(anyhow!(
            "bb write_vk failed: {}",
            String::from_utf8_lossy(&output.stderr)
        ));
    }

    println!("✅ Verifying proof...");
    let output = Command::new("bb")
        .args([
            "verify",
            "-k",
            &vk_path.to_string_lossy(),
            "-p",
            &proof_path.to_string_lossy(),
        ])
        .current_dir(circuit_dir)
        .output()
        .context("Failed to run bb verify")?;
    if !output.status.success() {
        return Err(anyhow!(
            "bb verify failed: {}",
            String::from_utf8_lossy(&output.stderr)
        ));
    }

    println!("📝 Generating Solidity verifier...");
    let output = Command::new("bb")
        .args([
            "write_solidity_verifier",
            "-k",
            &vk_path.to_string_lossy(),
            "-o",
            &verifier_path.to_string_lossy(),
        ])
        .current_dir(circuit_dir)
        .output()
        .context("Failed to run bb write_solidity_verifier")?;
    if !output.status.success() {
        return Err(anyhow!(
            "bb write_solidity_verifier failed: {}",
            String::from_utf8_lossy(&output.stderr)
        ));
    }

    println!("✅ ZK proof generation complete.");
    Ok(ProofResult {
        proof,
        public_inputs: vec![],
    })
}