use crate::{
error::{QuantusError, Result},
log_print, log_success,
};
use std::path::{Path, PathBuf};
include!("bins_consts.rs");
pub const BINS_DIR_ENV: &str = "QUANTUS_BINS_DIR";
const REQUIRED_FILES: &[&str] = &[
"prover.bin",
"verifier.bin",
"common.bin",
"aggregated_prover.bin",
"aggregated_verifier.bin",
"aggregated_common.bin",
"dummy_proof.bin",
"config.json",
];
pub fn resolve_bins_dir() -> PathBuf {
if let Ok(dir) = std::env::var(BINS_DIR_ENV) {
return PathBuf::from(dir);
}
let cwd_dir = PathBuf::from("generated-bins");
if cwd_dir.join("config.json").exists() {
return cwd_dir;
}
user_bins_dir()
}
fn user_bins_dir() -> PathBuf {
dirs::home_dir()
.expect("Could not determine home directory for ~/.quantus/generated-bins")
.join(".quantus")
.join("generated-bins")
}
pub fn ensure_bins_dir() -> Result<PathBuf> {
let dir = resolve_bins_dir();
if is_ready(&dir) {
return Ok(dir);
}
let num_leaf_proofs = env_num_leaf_proofs();
generate(&dir, num_leaf_proofs)?;
Ok(dir)
}
fn is_ready(dir: &Path) -> bool {
if !REQUIRED_FILES.iter().all(|f| dir.join(f).exists()) {
return false;
}
let version_ok = match std::fs::read_to_string(dir.join(VERSION_MARKER)) {
Ok(v) => v.trim() == env!("CARGO_PKG_VERSION"),
Err(_) => return false,
};
if !version_ok {
return false;
}
let config_path = dir.join("config.json");
match std::fs::read_to_string(&config_path) {
Ok(content) => {
#[derive(serde::Deserialize)]
struct ConfigCheck {
num_leaf_proofs: usize,
}
match serde_json::from_str::<ConfigCheck>(&content) {
Ok(config) => config.num_leaf_proofs == env_num_leaf_proofs(),
Err(_) => false,
}
},
Err(_) => false,
}
}
fn env_num_leaf_proofs() -> usize {
std::env::var("QP_NUM_LEAF_PROOFS")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(DEFAULT_NUM_LEAF_PROOFS)
}
fn generate(dir: &Path, num_leaf_proofs: usize) -> Result<()> {
std::fs::create_dir_all(dir).map_err(|e| {
QuantusError::Generic(format!("Failed to create bins directory {}: {}", dir.display(), e))
})?;
log_print!("");
log_print!("🛠️ Generating ZK circuit binaries (first-time setup, ~30s)...");
log_print!(" Target: {}", dir.display());
log_print!(" num_leaf_proofs: {}", num_leaf_proofs);
let start = std::time::Instant::now();
qp_wormhole_circuit_builder::generate_all_circuit_binaries(dir, true, num_leaf_proofs, None)
.map_err(|e| {
QuantusError::Generic(format!("Failed to generate circuit binaries: {}", e))
})?;
std::fs::write(dir.join(VERSION_MARKER), env!("CARGO_PKG_VERSION"))
.map_err(|e| QuantusError::Generic(format!("Failed to write version marker: {}", e)))?;
let elapsed = start.elapsed();
log_success!("Circuit binaries ready in {:.1}s", elapsed.as_secs_f64());
log_print!("");
Ok(())
}