|
12 | 12 |
|
13 | 13 | use { |
14 | 14 | ark_std::rand::distributions::{Distribution, Standard}, |
15 | | - provekit_common::{ |
16 | | - Base, Ext, FieldHash, HashConfig, PublicInputs, PublicInputsHash, WhirR1CSProof, |
17 | | - WhirR1CSScheme, R1CS, |
| 15 | + provekit_common::{Base, Ext, FieldHash, PublicInputs}, |
| 16 | + provekit_fixtures::{ |
| 17 | + builders::squaring_chain, |
| 18 | + harness::{prove_setup, time_prove_core}, |
18 | 19 | }, |
19 | | - provekit_fixtures::builders::squaring_chain, |
20 | | - provekit_prover::WhirR1CSProver, |
21 | 20 | provekit_verifier::WhirR1CSVerifier, |
22 | 21 | std::{ |
23 | 22 | collections::HashMap, |
24 | 23 | path::PathBuf, |
25 | 24 | time::{Duration, Instant}, |
26 | 25 | }, |
27 | | - whir::transcript::ProverState, |
28 | 26 | }; |
29 | 27 |
|
30 | 28 | /// Log2 witness sizes to sweep. |
31 | 29 | const SIZES: [u32; 4] = [14, 16, 18, 20]; |
32 | 30 |
|
33 | | -/// Instance-binding hash for the probes (matches the harness default). |
34 | | -const HASH: HashConfig = HashConfig::Sha256; |
35 | | - |
36 | | -/// Inputs for a single-commit prove, built outside the timer so scheme |
37 | | -/// construction and the `commit`/`prove_noir` ownership copies aren't measured. |
38 | | -struct ProveInputs<P: FieldHash> { |
39 | | - scheme: WhirR1CSScheme<P>, |
40 | | - r1cs_owned: R1CS<Base<P>>, |
41 | | - witness_commit: Vec<Base<P>>, |
42 | | - witness_prove: Vec<Base<P>>, |
43 | | - num_witnesses: usize, |
44 | | - num_constraints: usize, |
45 | | -} |
46 | | - |
47 | | -/// Build the scheme + ownership copies (excluded from the timer and |
48 | | -/// flamegraph). |
49 | | -fn prove_setup<P>(r1cs: &R1CS<Base<P>>, witness: &[Base<P>]) -> ProveInputs<P> |
50 | | -where |
51 | | - P: FieldHash, |
52 | | - Standard: Distribution<Ext<P>> + Distribution<Base<P>>, |
53 | | -{ |
54 | | - let scheme = WhirR1CSScheme::<P>::new_for_r1cs(r1cs, witness.len(), 0, Vec::new(), true, HASH); |
55 | | - ProveInputs { |
56 | | - scheme, |
57 | | - r1cs_owned: r1cs.clone(), |
58 | | - witness_commit: witness.to_vec(), |
59 | | - witness_prove: witness.to_vec(), |
60 | | - num_witnesses: r1cs.num_witnesses(), |
61 | | - num_constraints: r1cs.num_constraints(), |
62 | | - } |
63 | | -} |
64 | | - |
65 | | -/// Time the proving core — `commit` + `prove_noir` — from pre-built inputs. |
66 | | -fn time_prove_core<P>( |
67 | | - inp: ProveInputs<P>, |
68 | | - public_inputs: &PublicInputs<Base<P>>, |
69 | | -) -> (Duration, WhirR1CSProof, WhirR1CSScheme<P>) |
70 | | -where |
71 | | - P: FieldHash, |
72 | | - Standard: Distribution<Ext<P>> + Distribution<Base<P>>, |
73 | | -{ |
74 | | - let ProveInputs { |
75 | | - scheme, |
76 | | - r1cs_owned, |
77 | | - witness_commit, |
78 | | - witness_prove, |
79 | | - num_witnesses, |
80 | | - num_constraints, |
81 | | - } = inp; |
82 | | - |
83 | | - // Transcript binding derives from the scheme; built before the timer starts. |
84 | | - let instance = public_inputs.hash_bytes::<P>(HASH); |
85 | | - let ds = scheme.create_domain_separator().instance(&instance); |
86 | | - |
87 | | - let start = Instant::now(); |
88 | | - let mut merlin = ProverState::new(&ds, P::transcript_sponge(HASH)); |
89 | | - let commitment = scheme |
90 | | - .commit( |
91 | | - &mut merlin, |
92 | | - num_witnesses, |
93 | | - num_constraints, |
94 | | - witness_commit, |
95 | | - true, |
96 | | - ) |
97 | | - .expect("commit"); |
98 | | - let proof = scheme |
99 | | - .prove_noir( |
100 | | - merlin, |
101 | | - r1cs_owned, |
102 | | - vec![commitment], |
103 | | - witness_prove, |
104 | | - public_inputs, |
105 | | - ) |
106 | | - .expect("prove_noir"); |
107 | | - (start.elapsed(), proof, scheme) |
108 | | -} |
109 | | - |
110 | 31 | /// Build a `2^log_size`-witness squaring chain, prove, verify, and return |
111 | 32 | /// `(prove, verify, narg_bytes, hints_bytes)`. |
112 | 33 | fn run_one<P>(log_size: u32) -> (Duration, Duration, usize, usize) |
|
120 | 41 |
|
121 | 42 | // Only commit + prove_noir are timed (setup excluded above). |
122 | 43 | let inp = prove_setup::<P>(&r1cs, &w); |
123 | | - let (prove_t, proof, scheme) = time_prove_core::<P>(inp, &public_inputs); |
| 44 | + let (prove_t, proof, scheme) = time_prove_core::<P>(inp, &public_inputs).expect("prove"); |
124 | 45 |
|
125 | 46 | let t = Instant::now(); |
126 | 47 | scheme |
@@ -187,13 +108,14 @@ fn size_sweep() { |
187 | 108 | println!(); |
188 | 109 | } |
189 | 110 |
|
190 | | -/// Repo `provekit/.claude/profile/` directory (created if absent). |
| 111 | +/// Workspace `target/profile/` directory (created if absent). Lives under the |
| 112 | +/// gitignored build dir so the artifacts are not committed and the probe is |
| 113 | +/// portable across machines. |
191 | 114 | fn profile_dir() -> PathBuf { |
192 | 115 | let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) |
193 | 116 | .join("..") |
194 | 117 | .join("..") |
195 | | - .join("provekit") |
196 | | - .join(".claude") |
| 118 | + .join("target") |
197 | 119 | .join("profile"); |
198 | 120 | std::fs::create_dir_all(&dir).expect("create profile dir"); |
199 | 121 | dir |
@@ -230,7 +152,8 @@ fn flamegraph_2pow20_bf() { |
230 | 152 |
|
231 | 153 | // Timed + captured: the true prove core only (setup/clones already done). |
232 | 154 | let (prove_t, proof, _scheme) = |
233 | | - time_prove_core::<provekit_backend_goldilocks::GoldilocksField>(inp, &public_inputs); |
| 155 | + time_prove_core::<provekit_backend_goldilocks::GoldilocksField>(inp, &public_inputs) |
| 156 | + .expect("prove"); |
234 | 157 | println!( |
235 | 158 | "\n[flamegraph] 2^20 goldilocks-BF prove={prove_t:.3?} narg={} hints={}", |
236 | 159 | proof.narg_string.len(), |
|
0 commit comments