Skip to content

Commit 53ad255

Browse files
authored
feat: Added support for generate vk and to use custom CRS files (#13)
1 parent ddeb0a2 commit 53ad255

File tree

11 files changed

+265
-37
lines changed

11 files changed

+265
-37
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ circuit_mersenne_field = {path="circuit_mersenne_field"}
3232
serde_json = { version = "*" }
3333
serde = { version = "1", default-features = false, features = ["derive", "alloc"]}
3434
clap = { version = "4.5.21", features = ["derive"] }
35+
sha3 = "*"
3536

3637
[dev-dependencies]
3738
rand = "0.8.4"

README.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,23 @@ It takes the zkos proof (in json format), and returns the boojum proof.
66
You can use it as a library, or as a cli tool:
77

88
```
9-
cargo run --release -- --input testing_data/risc_proof --output-dir tmp.json
10-
```
9+
cargo run --release -- prove --input testing_data/risc_proof --output-dir tmp.json
10+
```
11+
12+
## CRS file
13+
14+
For production - please make sure to use the real CRS file:
15+
16+
https://storage.googleapis.com/matterlabs-setup-keys-us/setup-keys/setup_2^24.key
17+
18+
The tool also offers to use the 'fake' file - that works for local testing, but must NEVER be used for production cases.
19+
20+
## Generating verification key
21+
22+
23+
```shell
24+
cargo run --release generate-vk --input-binary ../air_compiler/examples/hashed_fibonacci/app.bin --output-dir /tmp --trusted-setup-file crs/setup.key
25+
```
26+
27+
This will generate the verification key (and verification key hash) - that can be put into the solidity code.
28+
Or you can use era-boojum-verifier-cli tool to verify the proofs manually.

crs/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.key

crs/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# CRS key directory
2+
3+
You can put a real CRS file here, by downloading it from:
4+
5+
```shell
6+
curl https://storage.googleapis.com/matterlabs-setup-keys-us/setup-keys/setup_2\^24.key --output setup.key
7+
```
8+
9+
We don't include it in github, as it is around 1GB in size.

src/lib.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ use bellman::plonk::better_better_cs::cs::PlonkCsWidth4WithNextStepAndCustomGate
7474
use bellman::plonk::better_better_cs::cs::{ProvingAssembly, SetupAssembly};
7575
use bellman::plonk::better_better_cs::gates::selector_optimized_with_d_next::SelectorOptimizedWidth4MainGateWithDNext;
7676
use bellman::plonk::better_better_cs::verifier::verify as verify_snark;
77+
use boojum::ethereum_types::H256;
7778
use snark_wrapper::implementations::poseidon2::CircuitPoseidon2Sponge;
7879
use snark_wrapper::implementations::poseidon2::transcript::CircuitPoseidon2Transcript;
7980

@@ -392,3 +393,69 @@ pub fn prove_snark_wrapper(
392393
pub fn verify_snark_wrapper_proof(proof: &SnarkWrapperProof, vk: &SnarkWrapperVK) -> bool {
393394
verify_snark::<Bn256, SnarkWrapperCircuit, SnarkWrapperTranscript>(vk, proof, None).unwrap()
394395
}
396+
397+
// TODO: this should probably be moved somewhere into crypto.
398+
pub fn calculate_verification_key_hash(verification_key: SnarkWrapperVK) -> H256 {
399+
use bellman::compact_bn256::Fq;
400+
use bellman::{CurveAffine, PrimeField, PrimeFieldRepr};
401+
use sha3::{Digest, Keccak256};
402+
403+
let mut res = vec![];
404+
405+
// gate setup commitments
406+
assert_eq!(8, verification_key.gate_setup_commitments.len());
407+
408+
for gate_setup in verification_key.gate_setup_commitments {
409+
let (x, y) = gate_setup.as_xy();
410+
x.into_repr().write_be(&mut res).unwrap();
411+
y.into_repr().write_be(&mut res).unwrap();
412+
}
413+
414+
// gate selectors commitments
415+
assert_eq!(2, verification_key.gate_selectors_commitments.len());
416+
417+
for gate_selector in verification_key.gate_selectors_commitments {
418+
let (x, y) = gate_selector.as_xy();
419+
x.into_repr().write_be(&mut res).unwrap();
420+
y.into_repr().write_be(&mut res).unwrap();
421+
}
422+
423+
// permutation commitments
424+
assert_eq!(4, verification_key.permutation_commitments.len());
425+
426+
for permutation in verification_key.permutation_commitments {
427+
let (x, y) = permutation.as_xy();
428+
x.into_repr().write_be(&mut res).unwrap();
429+
y.into_repr().write_be(&mut res).unwrap();
430+
}
431+
432+
// lookup selector commitment
433+
let lookup_selector = verification_key.lookup_selector_commitment.unwrap();
434+
let (x, y) = lookup_selector.as_xy();
435+
x.into_repr().write_be(&mut res).unwrap();
436+
y.into_repr().write_be(&mut res).unwrap();
437+
438+
// lookup tables commitments
439+
assert_eq!(4, verification_key.lookup_tables_commitments.len());
440+
441+
for table_commit in verification_key.lookup_tables_commitments {
442+
let (x, y) = table_commit.as_xy();
443+
x.into_repr().write_be(&mut res).unwrap();
444+
y.into_repr().write_be(&mut res).unwrap();
445+
}
446+
447+
// table type commitment
448+
let lookup_table = verification_key.lookup_table_type_commitment.unwrap();
449+
let (x, y) = lookup_table.as_xy();
450+
x.into_repr().write_be(&mut res).unwrap();
451+
y.into_repr().write_be(&mut res).unwrap();
452+
453+
// flag for using recursive part
454+
Fq::default().into_repr().write_be(&mut res).unwrap();
455+
456+
let mut hasher = Keccak256::new();
457+
hasher.update(&res);
458+
let computed_vk_hash = hasher.finalize();
459+
460+
H256::from_slice(&computed_vk_hash)
461+
}

src/main.rs

Lines changed: 153 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::alloc::Global;
88
// - wrapping the proof into SNARK.
99
use std::path::Path;
1010

11-
use clap::Parser;
11+
use clap::{Parser, Subcommand};
1212

1313
use bellman::kate_commitment::{Crs, CrsForMonomialForm};
1414
use bellman::worker::Worker as BellmanWorker;
@@ -20,7 +20,7 @@ use execution_utils::{
2020
};
2121
use risc_verifier::prover::worker::Worker;
2222
use zkos_wrapper::circuits::BinaryCommitment;
23-
use zkos_wrapper::{Bn256, L1_VERIFIER_DOMAIN_SIZE_LOG};
23+
use zkos_wrapper::{Bn256, L1_VERIFIER_DOMAIN_SIZE_LOG, calculate_verification_key_hash};
2424
use zkos_wrapper::{
2525
circuits::RiscWrapperWitness, get_compression_setup, get_risc_wrapper_setup,
2626
get_snark_wrapper_setup, prove_compression, prove_risc_wrapper, prove_snark_wrapper,
@@ -30,16 +30,50 @@ use zkos_wrapper::{
3030
#[derive(Parser)]
3131
#[command(version, about, long_about = None)]
3232
struct Cli {
33-
#[arg(short, long)]
34-
input: String,
35-
36-
// Binary used to generate the proof.
37-
// If not specified, take the default binary (fibonacci hasher).
38-
#[arg(long)]
39-
input_binary: Option<String>,
33+
#[command(subcommand)]
34+
command: Commands,
35+
}
4036

41-
#[arg(short, long)]
42-
output_dir: String,
37+
#[derive(Subcommand)]
38+
enum Commands {
39+
/// Take the riscV final proof, and create a SNARK proof.
40+
Prove {
41+
#[arg(short, long)]
42+
input: String,
43+
44+
// Binary used to generate the proof.
45+
// If not specified, take the default binary (fibonacci hasher).
46+
#[arg(long)]
47+
input_binary: Option<String>,
48+
49+
#[arg(short, long)]
50+
output_dir: String,
51+
52+
/// File with the trusted setup.
53+
/// If missing - will use the 'fake' trusted setup.
54+
#[arg(long)]
55+
trusted_setup_file: Option<String>,
56+
},
57+
/// Generate verification key for the SNARK proof.
58+
GenerateVk {
59+
// Binary used to generate the proof.
60+
// If not specified, take the default binary (fibonacci hasher).
61+
#[arg(long)]
62+
input_binary: String,
63+
64+
#[arg(short, long)]
65+
output_dir: String,
66+
67+
/// File with the trusted setup.
68+
/// If missing - will use the 'fake' trusted setup.
69+
#[arg(long)]
70+
trusted_setup_file: String,
71+
72+
/// If true, then create VK for universal verifier program.
73+
/// If false then for the separate verifiers.
74+
#[arg(long)]
75+
universal_verifier: bool,
76+
},
4377
}
4478

4579
fn serialize_to_file<T: serde::ser::Serialize>(content: &T, filename: &Path) {
@@ -52,6 +86,14 @@ fn deserialize_from_file<T: serde::de::DeserializeOwned>(filename: &str) -> T {
5286
serde_json::from_reader(src).unwrap()
5387
}
5488

89+
/// Uploads trusted setup file to the RAM
90+
pub fn get_trusted_setup(crs_file_str: &String) -> Crs<Bn256, CrsForMonomialForm> {
91+
let crs_file_path = std::path::Path::new(crs_file_str);
92+
let crs_file = std::fs::File::open(&crs_file_path)
93+
.expect(format!("Trying to open CRS FILE: {:?}", crs_file_path).as_str());
94+
Crs::read(&crs_file).expect(format!("Trying to read CRS FILE: {:?}", crs_file_path).as_str())
95+
}
96+
5597
pub fn create_binary_commitment(
5698
binary_path: String,
5799
expected_end_params: &[u32; 8],
@@ -103,12 +145,106 @@ pub fn create_binary_commitment(
103145
fn main() -> Result<(), Box<dyn std::error::Error>> {
104146
let cli = Cli::parse();
105147

148+
match cli.command {
149+
Commands::Prove {
150+
input,
151+
input_binary,
152+
output_dir,
153+
trusted_setup_file,
154+
} => {
155+
println!("=== Phase 0: Proving");
156+
prove(input, input_binary, output_dir, trusted_setup_file)?;
157+
}
158+
Commands::GenerateVk {
159+
input_binary,
160+
output_dir,
161+
trusted_setup_file,
162+
universal_verifier,
163+
} => {
164+
println!("=== Phase 0: Generating the verification key");
165+
generate_vk(
166+
input_binary,
167+
output_dir,
168+
trusted_setup_file,
169+
universal_verifier,
170+
)?;
171+
}
172+
}
173+
Ok(())
174+
}
175+
176+
fn generate_vk(
177+
input_binary: String,
178+
output_dir: String,
179+
trusted_setup_file: String,
180+
universal_verifier: bool,
181+
) -> Result<(), Box<dyn std::error::Error>> {
182+
let worker = BellmanWorker::new_with_cpus(4);
183+
let boojum_worker = boojum::worker::Worker::new_with_num_threads(4);
184+
185+
let trusted_setup_file = Some(trusted_setup_file);
186+
187+
let crs_mons = match trusted_setup_file {
188+
Some(ref crs_file_str) => get_trusted_setup(crs_file_str),
189+
None => Crs::<Bn256, CrsForMonomialForm>::crs_42(
190+
1 << L1_VERIFIER_DOMAIN_SIZE_LOG,
191+
&BellmanWorker::new(),
192+
),
193+
};
194+
println!("=== Phase 1: Creating the Risc wrapper key");
195+
196+
let verifier_params = if universal_verifier {
197+
universal_circuit_no_delegation_verifier_vk().params
198+
} else {
199+
final_recursion_layer_verifier_vk().params
200+
};
201+
202+
let binary_commitment = create_binary_commitment(input_binary, &verifier_params);
203+
204+
let (_, _, _, risc_wrapper_vk, _, _, _) =
205+
get_risc_wrapper_setup(&boojum_worker, binary_commitment.clone());
206+
207+
println!("=== Phase 2: Creating the Compression key");
208+
let (_, _, _, compression_vk, _, _, _) =
209+
get_compression_setup(risc_wrapper_vk.clone(), &boojum_worker);
210+
211+
println!("=== Phase 3: Creating the SNARK key");
212+
213+
let (_, snark_wrapper_vk) = get_snark_wrapper_setup(compression_vk.clone(), &crs_mons, &worker);
214+
215+
serialize_to_file(
216+
&snark_wrapper_vk,
217+
&Path::new(&output_dir.clone()).join("snark_vk_expected.json"),
218+
);
219+
220+
println!(
221+
"VK key hash: {:?}",
222+
calculate_verification_key_hash(snark_wrapper_vk)
223+
);
224+
225+
Ok(())
226+
}
227+
228+
fn prove(
229+
input: String,
230+
input_binary: Option<String>,
231+
output_dir: String,
232+
trusted_setup_file: Option<String>,
233+
) -> Result<(), Box<dyn std::error::Error>> {
234+
let crs_mons = match trusted_setup_file {
235+
Some(ref crs_file_str) => get_trusted_setup(crs_file_str),
236+
None => Crs::<Bn256, CrsForMonomialForm>::crs_42(
237+
1 << L1_VERIFIER_DOMAIN_SIZE_LOG,
238+
&BellmanWorker::new(),
239+
),
240+
};
241+
106242
println!("=== Phase 1: Creating the Risc wrapper proof");
107243

108244
let worker = boojum::worker::Worker::new_with_num_threads(4);
109245

110-
let program_proof: zkos_wrapper::ProgramProof = deserialize_from_file(&cli.input);
111-
let binary_commitment = match cli.input_binary {
246+
let program_proof: zkos_wrapper::ProgramProof = deserialize_from_file(&input);
247+
let binary_commitment = match input_binary {
112248
Some(binary_path) => create_binary_commitment(binary_path, &program_proof.end_params),
113249
None => BinaryCommitment::from_default_binary(),
114250
};
@@ -143,7 +279,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
143279

144280
serialize_to_file(
145281
&risc_wrapper_proof,
146-
&Path::new(&cli.output_dir.clone()).join("risc_proof.json"),
282+
&Path::new(&output_dir.clone()).join("risc_proof.json"),
147283
);
148284

149285
println!("=== Phase 2: Creating compression proof");
@@ -175,17 +311,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
175311

176312
serialize_to_file(
177313
&compression_proof,
178-
&Path::new(&cli.output_dir.clone()).join("compression_proof.json"),
314+
&Path::new(&output_dir.clone()).join("compression_proof.json"),
179315
);
180316

181317
println!("=== Phase 3: Creating SNARK proof");
182318

183319
{
184320
let worker = BellmanWorker::new_with_cpus(4);
185321

186-
let crs_mons =
187-
Crs::<Bn256, CrsForMonomialForm>::crs_42(1 << L1_VERIFIER_DOMAIN_SIZE_LOG, &worker);
188-
189322
let (snark_setup, snark_wrapper_vk) =
190323
get_snark_wrapper_setup(compression_vk.clone(), &crs_mons, &worker);
191324

@@ -203,11 +336,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
203336

204337
serialize_to_file(
205338
&snark_wrapper_proof,
206-
&Path::new(&cli.output_dir.clone()).join("snark_proof.json"),
339+
&Path::new(&output_dir.clone()).join("snark_proof.json"),
207340
);
208341
serialize_to_file(
209342
&snark_wrapper_vk,
210-
&Path::new(&cli.output_dir.clone()).join("snark_vk.json"),
343+
&Path::new(&output_dir.clone()).join("snark_vk.json"),
211344
);
212345
}
213346

src/wrapper_inner_verifier/imports/circuit_layout.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ const COMPILED_WITNESS_LAYOUT: CompiledWitnessSubtree<Mersenne31Field> = Compile
378378
};
379379
const COMPILED_MEMORY_LAYOUT: CompiledMemorySubtree<'static> = CompiledMemorySubtree {
380380
shuffle_ram_inits_and_teardowns: Some(ShuffleRamInitAndTeardownLayout {
381-
lazy_init_addesses_columns: ColumnSet::<2usize> {
381+
lazy_init_addresses_columns: ColumnSet::<2usize> {
382382
start: 0usize,
383383
num_elements: 1usize,
384384
},

0 commit comments

Comments
 (0)