use std::path::PathBuf;
use std::process;
use std::time::Instant;
use clap::Args;
use joy_rs::Warrior;
use super::{check_target, load_bundle, make_input};
#[derive(Args)]
pub struct ProveArgs {
pub input: PathBuf,
#[arg(long)]
pub target: Option<String>,
#[arg(long, default_value = "debug")]
pub profile: String,
#[arg(long, value_delimiter = ',')]
pub input_values: Option<Vec<u64>>,
#[arg(long, value_delimiter = ',')]
pub secret: Option<Vec<u64>>,
#[arg(long)]
pub zk: bool,
#[arg(long, default_value_t = joy_rs::DEFAULT_BUDGET)]
pub budget: u64,
#[arg(long)]
pub output: Option<PathBuf>,
#[arg(long)]
pub state: Option<String>,
}
fn artifact_path(input: &PathBuf) -> PathBuf {
let stem = input
.file_stem()
.and_then(|s| s.to_str())
.unwrap_or("program");
input.with_file_name(format!("{}.zheng", stem))
}
pub fn cmd_prove(args: ProveArgs) {
if let Err(e) = check_target(args.target.as_deref().unwrap_or("nox")) {
eprintln!("error: {}", e);
process::exit(1);
}
let bundle = match load_bundle(&args.input, &args.profile, args.target.as_deref()) {
Ok(b) => b,
Err(e) => {
eprintln!("error: {}", e);
process::exit(1);
}
};
let pi = make_input(&args.input_values, &args.secret);
let warrior = Warrior::with_budget(args.budget);
let t0 = Instant::now();
let path = args.output.unwrap_or_else(|| artifact_path(&args.input));
let zk = args.zk || !pi.secret.is_empty();
let result = if let Some(state_path) = &args.state {
joy_rs::state_execution::load_certificate(std::path::Path::new(state_path)).and_then(
|certificate| {
if zk {
warrior
.prove_zk_state_certificate(&bundle, &pi, &certificate, args.budget)
.and_then(|(artifact, result)| {
artifact.save(&path).map(|bytes| (result, bytes))
})
} else {
warrior
.prove_state_certificate(&bundle, &pi, &certificate, args.budget)
.and_then(|(artifact, result)| {
artifact.save(&path).map(|bytes| (result, bytes))
})
}
},
)
} else if zk {
warrior
.prove_zk_execution(&bundle, &pi, args.budget)
.and_then(|(artifact, result)| artifact.save(&path).map(|bytes| (result, bytes)))
} else {
warrior
.prove_execution(&bundle, &pi, args.budget)
.and_then(|(artifact, result)| artifact.save(&path).map(|bytes| (result, bytes)))
};
let (result, bytes) = match result {
Ok(value) => value,
Err(error) => {
eprintln!("error: {error}");
process::exit(1);
}
};
let mode = if args.state.is_some() && zk {
"private authenticated state execution (Triton ZK)"
} else if args.state.is_some() {
"authenticated public state execution"
} else if zk {
"private execution (Triton ZK)"
} else {
"public execution"
};
eprintln!(
"Proved {mode} in {} ms: {} reductions, {} bytes",
t0.elapsed().as_millis(),
result.cycle_count,
bytes
);
eprintln!("Output: {:?}", result.output);
println!("{}", path.display());
}