|
| 1 | +use std::{fs, path::PathBuf}; |
| 2 | + |
| 3 | +use anyhow::{Context, Result}; |
| 4 | +use binius_core::constraint_system::{ConstraintSystem, Proof, ValueVec, ValuesData}; |
| 5 | +use binius_examples::setup; |
| 6 | +use binius_utils::serialization::{DeserializeBytes, SerializeBytes}; |
| 7 | +use binius_verifier::{config::StdChallenger, transcript::ProverTranscript}; |
| 8 | +use clap::Parser; |
| 9 | + |
| 10 | +/// Prover CLI: generate a proof from a serialized constraint system and witnesses. |
| 11 | +#[derive(Debug, Parser)] |
| 12 | +#[command( |
| 13 | + name = "prover", |
| 14 | + about = "Generate and save a proof from CS and witnesses" |
| 15 | +)] |
| 16 | +struct Args { |
| 17 | + /// Path to the constraint system binary |
| 18 | + #[arg(long = "cs-path")] |
| 19 | + cs_path: PathBuf, |
| 20 | + |
| 21 | + /// Path to the public values (ValuesData) binary |
| 22 | + #[arg(long = "pub-witness-path")] |
| 23 | + pub_witness_path: PathBuf, |
| 24 | + |
| 25 | + /// Path to the non-public values (ValuesData) binary |
| 26 | + #[arg(long = "non-pub-data-path")] |
| 27 | + non_pub_data_path: PathBuf, |
| 28 | + |
| 29 | + /// Path to write the proof binary |
| 30 | + #[arg(long = "proof-path")] |
| 31 | + proof_path: PathBuf, |
| 32 | + |
| 33 | + /// Log of the inverse rate for the proof system |
| 34 | + #[arg(short = 'l', long = "log-inv-rate", default_value_t = 1, value_parser = clap::value_parser!(u32).range(1..))] |
| 35 | + log_inv_rate: u32, |
| 36 | +} |
| 37 | + |
| 38 | +fn main() -> Result<()> { |
| 39 | + let _tracing_guard = tracing_profile::init_tracing().ok(); |
| 40 | + let args = Args::parse(); |
| 41 | + |
| 42 | + // Read and deserialize constraint system |
| 43 | + let cs_bytes = fs::read(&args.cs_path).with_context(|| { |
| 44 | + format!("Failed to read constraint system from {}", args.cs_path.display()) |
| 45 | + })?; |
| 46 | + let cs = ConstraintSystem::deserialize(&mut cs_bytes.as_slice()) |
| 47 | + .context("Failed to deserialize ConstraintSystem")?; |
| 48 | + |
| 49 | + // Read and deserialize public values |
| 50 | + let pub_bytes = fs::read(&args.pub_witness_path).with_context(|| { |
| 51 | + format!("Failed to read public values from {}", args.pub_witness_path.display()) |
| 52 | + })?; |
| 53 | + let public = ValuesData::deserialize(&mut pub_bytes.as_slice()) |
| 54 | + .context("Failed to deserialize public ValuesData")?; |
| 55 | + |
| 56 | + // Read and deserialize non-public values |
| 57 | + let non_pub_bytes = fs::read(&args.non_pub_data_path).with_context(|| { |
| 58 | + format!("Failed to read non-public values from {}", args.non_pub_data_path.display()) |
| 59 | + })?; |
| 60 | + let non_public = ValuesData::deserialize(&mut non_pub_bytes.as_slice()) |
| 61 | + .context("Failed to deserialize non-public ValuesData")?; |
| 62 | + |
| 63 | + // Reconstruct the full ValueVec |
| 64 | + // Take ownership of the underlying vectors without extra copies |
| 65 | + let public: Vec<_> = public.into(); |
| 66 | + let non_public: Vec<_> = non_public.into(); |
| 67 | + let witness = ValueVec::new_from_data(cs.value_vec_layout.clone(), public, non_public) |
| 68 | + .context("Failed to reconstruct ValueVec from provided values")?; |
| 69 | + |
| 70 | + // Setup prover (verifier is not used here) |
| 71 | + let (_verifier, prover) = setup(cs, args.log_inv_rate as usize)?; |
| 72 | + |
| 73 | + // Prove |
| 74 | + let mut prover_transcript = ProverTranscript::new(StdChallenger::default()); |
| 75 | + prover |
| 76 | + .prove(witness, &mut prover_transcript) |
| 77 | + .context("Proving failed")?; |
| 78 | + let transcript = prover_transcript.finalize(); |
| 79 | + |
| 80 | + // Wrap into serializable Proof with a stable challenger type identifier. |
| 81 | + // NOTE: Avoid std::any::type_name for cross-platform stability; use a constant instead. |
| 82 | + let proof = Proof::owned(transcript, "HasherChallenger<Sha256>".to_string()); |
| 83 | + |
| 84 | + // Serialize and save the proof |
| 85 | + if let Some(parent) = args.proof_path.parent() |
| 86 | + && !parent.as_os_str().is_empty() |
| 87 | + { |
| 88 | + fs::create_dir_all(parent) |
| 89 | + .with_context(|| format!("Failed to create parent directory {}", parent.display()))?; |
| 90 | + } |
| 91 | + let mut buf = Vec::new(); |
| 92 | + proof |
| 93 | + .serialize(&mut buf) |
| 94 | + .context("Failed to serialize proof")?; |
| 95 | + fs::write(&args.proof_path, &buf) |
| 96 | + .with_context(|| format!("Failed to write proof to {}", args.proof_path.display()))?; |
| 97 | + |
| 98 | + eprintln!("Saved proof to {} ({} bytes)", args.proof_path.display(), buf.len()); |
| 99 | + Ok(()) |
| 100 | +} |
0 commit comments