use std::path::PathBuf;
use std::process;
use clap::Args;
use joy_rs::Warrior;
use super::{check_target, load_bundle, make_input};
#[derive(Args)]
pub struct VerifyArgs {
pub input: PathBuf,
#[arg(long, value_delimiter = ',')]
pub claim: Option<Vec<u64>>,
#[arg(long)]
pub proof: Option<PathBuf>,
#[arg(long)]
pub legacy_trace_statement: bool,
#[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, default_value_t = joy_rs::DEFAULT_BUDGET)]
pub budget: u64,
#[arg(long)]
pub state: Option<String>,
}
pub fn cmd_verify(args: VerifyArgs) {
if let Err(e) = check_target(args.target.as_deref().unwrap_or("nox")) {
eprintln!("error: {}", e);
process::exit(1);
}
let artifact = args.proof.as_ref().unwrap_or(&args.input);
match std::fs::symlink_metadata(artifact) {
Ok(metadata) if metadata.is_file() || (args.proof.is_none() && metadata.is_dir()) => {}
Ok(_) => {
eprintln!("error: verification input must be a regular file or source project");
process::exit(1);
}
Err(error) => {
eprintln!("error: cannot inspect verification input: {error}");
process::exit(1);
}
}
if let Some(result) = crate::state_verify::try_verify(&args) {
if let Err(error) = result {
eprintln!("Verification: FAIL ({error})");
process::exit(1);
}
return;
}
if let Some(result) = crate::execution_verify::try_verify(&args) {
if let Err(error) = result {
eprintln!("Verification: FAIL ({error})");
process::exit(1);
}
return;
}
if args.state.is_some() {
eprintln!("error: --state requires an authenticated state execution artifact");
process::exit(1);
}
if args.proof.is_none() {
if let Ok(artifact) = joy_rs::ProofArtifact::load(&args.input) {
require_legacy_mode(&args);
let warrior = Warrior::with_budget(args.budget);
match warrior.verify_artifact(&artifact) {
Ok(true) => {
if let Err(e) = joy_rs::proof::require_statement_only(args.claim.as_deref()) {
eprintln!("error: {}", e);
process::exit(1);
}
println!("Legacy statement check: PASS (execution and output unverified)");
println!(" program: {}", artifact.meta.program);
println!(" reported output (unverified): {:?}", artifact.meta.output);
println!(
" reported cycles (unverified): {}",
artifact.meta.cycle_count
);
}
Ok(false) => {
println!(
"Verification: FAIL (zheng proof rejected โ assembly or proof tampered)"
);
process::exit(1);
}
Err(e) => {
eprintln!("error: {}", e);
process::exit(1);
}
}
return;
}
}
let bundle = match load_bundle(&args.input, &args.profile, args.target.as_deref()) {
Ok(b) => b,
Err(e) => {
eprintln!("error: {}", e);
process::exit(1);
}
};
if args.proof.is_some() {
require_legacy_mode(&args);
}
if let Some(proof_path) = args.proof {
let artifact = match joy_rs::ProofArtifact::load(&proof_path) {
Ok(a) => a,
Err(e) => {
eprintln!("error: {}", e);
process::exit(1);
}
};
let warrior = Warrior::with_budget(args.budget);
match warrior.verify_zheng(&bundle, &artifact) {
Ok(true) => {
if let Err(e) = joy_rs::proof::require_statement_only(args.claim.as_deref()) {
eprintln!("error: {}", e);
process::exit(1);
}
println!("Legacy statement check: PASS (execution and output unverified)");
println!(" program: {}", artifact.meta.program);
println!(" reported output (unverified): {:?}", artifact.meta.output);
println!(
" reported cycles (unverified): {}",
artifact.meta.cycle_count
);
}
Ok(false) => {
println!("Verification: FAIL (zheng proof rejected for this bundle)");
process::exit(1);
}
Err(e) => {
eprintln!("error: {}", e);
process::exit(1);
}
}
return;
}
let claim = match args.claim {
Some(c) => c,
None => {
eprintln!("error: --claim <values> (re-execution) or --proof <artifact> is required");
process::exit(1);
}
};
let pi = make_input(&args.input_values, &args.secret);
let warrior = Warrior::with_budget(args.budget);
match warrior.verify_by_rerun(&bundle, &pi, &claim) {
Ok(true) => {
println!(
"Verification: PASS (re-execution; for a zheng proof use joy prove + --proof)"
);
}
Ok(false) => {
let executed = trident::runtime::Runner::run(&warrior, &bundle, &pi)
.map(|r| format!("{:?}", r.output))
.unwrap_or_else(|e| format!("<error: {}>", e));
println!("Verification: FAIL");
println!(" claimed: {:?}", claim);
println!(" executed: {}", executed);
process::exit(1);
}
Err(e) => {
eprintln!("error: {}", e);
process::exit(1);
}
}
}
fn require_legacy_mode(args: &VerifyArgs) {
if !args.legacy_trace_statement {
eprintln!("error: legacy trace statements do not prove execution; use a new public execution proof, or explicitly inspect with --legacy-trace-statement");
process::exit(1);
}
if args.claim.is_some()
|| args.input_values.is_some()
|| args.secret.is_some()
|| args.state.is_some()
{
eprintln!("error: legacy trace statements cannot verify requested input, output, secret or state constraints");
process::exit(1);
}
}