Skip to content

Commit 75a71f2

Browse files
author
Dmytro Gordon
committed
Add prover binary
1 parent 0c61270 commit 75a71f2

File tree

4 files changed

+139
-0
lines changed

4 files changed

+139
-0
lines changed

crates/core/src/constraint_system.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,12 @@ impl<'a> std::ops::Deref for ValuesData<'a> {
654654
}
655655
}
656656

657+
impl<'a> From<ValuesData<'a>> for Vec<Word> {
658+
fn from(value: ValuesData<'a>) -> Self {
659+
value.into_owned()
660+
}
661+
}
662+
657663
/// A zero-knowledge proof that can be serialized for cross-host verification.
658664
///
659665
/// This structure contains the complete proof transcript generated by the prover,

crates/examples/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,7 @@ sha2.workspace = true
3030
default = ["rayon"]
3131
perfetto = ["tracing-profile/perfetto"]
3232
rayon = ["binius-prover/rayon"]
33+
34+
[[example]]
35+
name = "prover"
36+
path = "examples/prover.rs"

crates/examples/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,35 @@ Look at these examples for reference:
332332
- `sha256.rs` - Shows parameter/instance separation, random data generation
333333
- `zklogin.rs` - Shows complex witness population with external data generation
334334

335+
## Prover binary
336+
337+
The `prover` example binary reads a constraint system and witnesses from disk and produces a serialized proof. This is useful for cross-host proof generation pipelines.
338+
339+
Arguments:
340+
- `--cs-path PATH`: path to the constraint system binary
341+
- `--pub-witness-path PATH`: path to the public values binary (ValuesData)
342+
- `--non-pub-data-path PATH`: path to the non-public values binary (ValuesData)
343+
- `--proof-path PATH`: path to write the proof binary
344+
- `-l, --log-inv-rate N`: log of the inverse rate (default: 1)
345+
346+
Usage:
347+
348+
```bash
349+
# 1) Generate artifacts from an example circuit (e.g., sha256)
350+
cargo run --release --example sha256 -- save \
351+
--cs-path out/sha256/cs.bin \
352+
--pub-witness-path out/sha256/public.bin \
353+
--non-pub-data-path out/sha256/non_public.bin
354+
355+
# 2) Produce a proof from those files
356+
cargo run --release --example prover -- \
357+
--cs-path out/sha256/cs.bin \
358+
--pub-witness-path out/sha256/public.bin \
359+
--non-pub-data-path out/sha256/non_public.bin \
360+
--proof-path out/sha256/proof.bin \
361+
--log-inv-rate 1
362+
```
363+
335364
## Tips
336365

337366
1. **Keep it simple**: The main function should just create the CLI and run it

crates/examples/examples/prover.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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

Comments
 (0)