use sha2::{Digest, Sha256};
use std::{env, time::Instant};
include!("src/bins_consts.rs");
include!("src/bins_fs.rs");
fn poseidon_hex(data: &[u8]) -> String {
let hash = qp_poseidon_core::hash_bytes(data);
hex::encode(&hash[..16]) }
fn print_bin_hash(dir: &Path, filename: &str) {
let path = dir.join(filename);
if let Ok(data) = std::fs::read(&path) {
println!(
"cargo:warning= {}: {} bytes, hash: {}",
filename,
data.len(),
poseidon_hex(&data)
);
}
}
fn file_sha256_hex(dir: &Path, filename: &str) -> String {
let data =
std::fs::read(dir.join(filename)).expect("Failed to read generated artifact for manifest");
let mut hasher = Sha256::new();
hasher.update(&data);
hex::encode(hasher.finalize())
}
fn json_escape(s: &str) -> String {
s.replace('\\', "\\\\").replace('"', "\\\"")
}
fn write_manifest(
dir: &Path,
pkg_version: &str,
num_leaf_proofs: usize,
num_private_batch_proofs: usize,
) {
let mut content = String::new();
content.push_str("{\n");
content.push_str(" \"manifest_version\": 1,\n");
content.push_str(&format!(" \"package_version\": \"{}\",\n", json_escape(pkg_version)));
content.push_str(&format!(" \"num_leaf_proofs\": {},\n", num_leaf_proofs));
content.push_str(&format!(" \"num_private_batch_proofs\": {},\n", num_private_batch_proofs));
content.push_str(" \"files\": {\n");
for (idx, filename) in MANIFESTED_FILES.iter().enumerate() {
let comma = if idx + 1 == MANIFESTED_FILES.len() { "" } else { "," };
content.push_str(&format!(
" \"{}\": \"{}\"{}\n",
json_escape(filename),
file_sha256_hex(dir, filename),
comma
));
}
content.push_str(" }\n}\n");
std::fs::write(dir.join(MANIFEST_FILE), content).expect("Failed to write artifact manifest");
}
fn main() {
if env::var("SKIP_CIRCUIT_BUILD").is_ok() {
println!(
"cargo:warning=[quantus-cli] Skipping circuit generation (SKIP_CIRCUIT_BUILD is set)"
);
return;
}
let out_dir = env::var("OUT_DIR").expect("OUT_DIR not set");
let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
let build_output_dir = Path::new(&out_dir).join("generated-bins");
let num_leaf_proofs: usize = env::var("QP_NUM_LEAF_PROOFS")
.map(|v| v.parse().expect("QP_NUM_LEAF_PROOFS must be a valid usize"))
.unwrap_or(DEFAULT_NUM_LEAF_PROOFS);
let num_private_batch_proofs: usize = env::var("QP_NUM_PRIVATE_BATCH_PROOFS")
.map(|v| v.parse().expect("QP_NUM_PRIVATE_BATCH_PROOFS must be a valid usize"))
.unwrap_or(DEFAULT_NUM_PRIVATE_BATCH_PROOFS);
println!("cargo:rerun-if-env-changed=QP_NUM_LEAF_PROOFS");
println!("cargo:rerun-if-env-changed=QP_NUM_PRIVATE_BATCH_PROOFS");
println!(
"cargo:warning=[quantus-cli] Generating ZK circuit binaries (num_leaf_proofs={}, num_private_batch_proofs={})...",
num_leaf_proofs, num_private_batch_proofs
);
let start = Instant::now();
std::fs::create_dir_all(&build_output_dir)
.expect("Failed to create generated-bins directory in OUT_DIR");
qp_wormhole_circuit_builder::generate_all_circuit_binaries(
&build_output_dir,
true,
num_leaf_proofs,
Some(num_private_batch_proofs),
)
.expect("Failed to generate circuit binaries");
let pkg_version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION not set");
std::fs::write(build_output_dir.join(VERSION_MARKER), &pkg_version)
.expect("Failed to write version marker");
write_manifest(&build_output_dir, &pkg_version, num_leaf_proofs, num_private_batch_proofs);
let elapsed = start.elapsed();
println!(
"cargo:warning=[quantus-cli] ZK circuit binaries generated in {:.2}s",
elapsed.as_secs_f64()
);
print_bin_hash(&build_output_dir, "common.bin");
print_bin_hash(&build_output_dir, "verifier.bin");
print_bin_hash(&build_output_dir, "dummy_proof.bin");
print_bin_hash(&build_output_dir, "private_batch_common.bin");
print_bin_hash(&build_output_dir, "private_batch_verifier.bin");
print_bin_hash(&build_output_dir, "dummy_private_batch_proof.bin");
print_bin_hash(&build_output_dir, "public_batch_common.bin");
print_bin_hash(&build_output_dir, "public_batch_verifier.bin");
let project_bins = Path::new(&manifest_dir).join("generated-bins");
let is_source_build =
!manifest_dir.contains("target/package/") && !manifest_dir.contains(".cargo/registry/src");
if is_source_build {
publish_dir_atomically(&build_output_dir, &project_bins)
.unwrap_or_else(|e| panic!("Failed to publish generated-bins: {e}"));
}
}