From 4f46c994c42f1cf11d4dd5a70befae49d54a8887 Mon Sep 17 00:00:00 2001 From: saitima Date: Thu, 15 Aug 2024 23:54:26 +0300 Subject: [PATCH 1/3] replace hardhat with foundry and fix CI tests --- .gitignore | 1 + Cargo.toml | 13 +- crates/codegen-bin/src/main.rs | 65 -- crates/codegen/Cargo.toml | 21 - crates/codegen/src/circuits.rs | 150 ---- crates/codegen/src/generate.rs | 253 ------ .../Cargo.toml | 8 +- crates/plonk-verifier-codegen-bin/src/main.rs | 65 ++ .../.gitignore | 0 crates/plonk-verifier-codegen/Cargo.toml | 18 + crates/plonk-verifier-codegen/src/circuits.rs | 351 ++++++++ crates/plonk-verifier-codegen/src/generate.rs | 792 ++++++++++++++++++ .../src/lib.rs | 59 +- .../src/serialize.rs | 10 +- .../src/tests.rs | 0 .../template/HardcodedValues.sol | 64 ++ .../template/PairingsBn254.sol | 0 .../Plonk4VerifierWithAccessToDNext.sol | 91 +- .../template/TranscriptLib.sol | 0 .../template/UncheckedMath.sol | 0 .../template/Verifier.sol | 0 crates/plonk-verifier-foundry/.gitignore | 3 + crates/plonk-verifier-foundry/LICENSE | 24 + crates/plonk-verifier-foundry/README.md | 39 + crates/plonk-verifier-foundry/bun.lockb | Bin 0 -> 28694 bytes crates/plonk-verifier-foundry/foundry.toml | 58 ++ crates/plonk-verifier-foundry/index.ts | 1 + crates/plonk-verifier-foundry/package.json | 38 + crates/plonk-verifier-foundry/remappings.txt | 2 + .../src/PairingsBn254.sol | 272 ++++++ .../src/Plonk4VerifierWithAccessToDNext.sol | 536 ++++++++++++ .../src/TranscriptLib.sol | 45 + .../src/UncheckedMath.sol | 15 + .../plonk-verifier-foundry/src/Verifier.sol | 168 ++++ .../test/HardcodedValues.sol | 147 ++++ .../plonk-verifier-foundry/test/Plonk.T.sol | 37 + crates/plonk-verifier-foundry/tsconfig.json | 27 + scripts/plonk-verifier/run-tests.sh | 41 + 38 files changed, 2840 insertions(+), 574 deletions(-) delete mode 100644 crates/codegen-bin/src/main.rs delete mode 100644 crates/codegen/Cargo.toml delete mode 100644 crates/codegen/src/circuits.rs delete mode 100644 crates/codegen/src/generate.rs rename crates/{codegen-bin => plonk-verifier-codegen-bin}/Cargo.toml (57%) create mode 100644 crates/plonk-verifier-codegen-bin/src/main.rs rename crates/{codegen => plonk-verifier-codegen}/.gitignore (100%) create mode 100644 crates/plonk-verifier-codegen/Cargo.toml create mode 100644 crates/plonk-verifier-codegen/src/circuits.rs create mode 100644 crates/plonk-verifier-codegen/src/generate.rs rename crates/{codegen => plonk-verifier-codegen}/src/lib.rs (77%) rename crates/{codegen => plonk-verifier-codegen}/src/serialize.rs (92%) rename crates/{codegen => plonk-verifier-codegen}/src/tests.rs (100%) create mode 100644 crates/plonk-verifier-codegen/template/HardcodedValues.sol rename crates/{codegen => plonk-verifier-codegen}/template/PairingsBn254.sol (100%) rename crates/{codegen => plonk-verifier-codegen}/template/Plonk4VerifierWithAccessToDNext.sol (94%) rename crates/{codegen => plonk-verifier-codegen}/template/TranscriptLib.sol (100%) rename crates/{codegen => plonk-verifier-codegen}/template/UncheckedMath.sol (100%) rename crates/{codegen => plonk-verifier-codegen}/template/Verifier.sol (100%) create mode 100644 crates/plonk-verifier-foundry/.gitignore create mode 100644 crates/plonk-verifier-foundry/LICENSE create mode 100644 crates/plonk-verifier-foundry/README.md create mode 100755 crates/plonk-verifier-foundry/bun.lockb create mode 100644 crates/plonk-verifier-foundry/foundry.toml create mode 100644 crates/plonk-verifier-foundry/index.ts create mode 100644 crates/plonk-verifier-foundry/package.json create mode 100644 crates/plonk-verifier-foundry/remappings.txt create mode 100644 crates/plonk-verifier-foundry/src/PairingsBn254.sol create mode 100644 crates/plonk-verifier-foundry/src/Plonk4VerifierWithAccessToDNext.sol create mode 100644 crates/plonk-verifier-foundry/src/TranscriptLib.sol create mode 100644 crates/plonk-verifier-foundry/src/UncheckedMath.sol create mode 100644 crates/plonk-verifier-foundry/src/Verifier.sol create mode 100644 crates/plonk-verifier-foundry/test/HardcodedValues.sol create mode 100644 crates/plonk-verifier-foundry/test/Plonk.T.sol create mode 100644 crates/plonk-verifier-foundry/tsconfig.json create mode 100755 scripts/plonk-verifier/run-tests.sh diff --git a/.gitignore b/.gitignore index dbf3d8e..ceafe9f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ target/ Cargo.lock .vscode *.log +data \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index ea9eb03..53fe8bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,18 @@ [workspace] members = [ - "crates/*" + "crates/bellman", + "crates/boojum", + "crates/cs_derive", + "crates/ff", + "crates/ff_derive", + "crates/franklin-crypto", + "crates/pairing", + "crates/plonk-verifier-codegen", + "crates/plonk-verifier-codegen-bin", + "crates/rescue-poseidon", + "crates/snark-wrapper", ] + resolver = "2" [profile.release] diff --git a/crates/codegen-bin/src/main.rs b/crates/codegen-bin/src/main.rs deleted file mode 100644 index 3e5ad4b..0000000 --- a/crates/codegen-bin/src/main.rs +++ /dev/null @@ -1,65 +0,0 @@ -use std::path::PathBuf; -use structopt::StructOpt; -use zksync_solidity_vk_codegen::{generate, Encoding}; - -const DEFAULT_OUTPUT_FILE: &str = "./hardhat/contracts"; - -const PAIRING_BN_254_FILE_PATH: &str = "PairingsBn254.sol"; -const TRANSCRIPT_LIB_FILE_PATH: &str = "TranscriptLib.sol"; -const UNCHECKED_MATH_FILE_PATH: &str = "UncheckedMath.sol"; -const PLONK_4_VERIFIER_FILE_PATH: &str = "Plonk4VerifierWithAccessToDNext.sol"; -const VEERIFIER_TEMPLATE_FILE_PATH: &str = "Verifier.sol"; - -#[derive(StructOpt, Debug)] -pub struct Opts { - /// Path to verification key (required) - #[structopt(long, parse(from_os_str))] - verification_key: PathBuf, - /// Path to the folder with templates (required) - /// Should point to the `codegen/template` directory - #[structopt(long, parse(from_os_str))] - templates_dir: PathBuf, - /// Output directory - #[structopt(long, parse(from_os_str), default_value = DEFAULT_OUTPUT_FILE)] - output: PathBuf, - - #[structopt(long)] - encoding: Option, -} - -fn main() { - let opts = Opts::from_args(); - println!("{:#?}", opts); - - let Opts { - verification_key, - output, - templates_dir, - encoding, - } = opts; - - let encoding = match encoding { - Some(encoding) => match encoding.as_str() { - "json" => Encoding::Json, - _ => Encoding::Default, - }, - None => Encoding::Default, - }; - - let template_path = |file_name: &str| templates_dir.join(file_name).to_string_lossy().into_owned(); - - generate( - verification_key, - output.clone(), - encoding, - vec![ - template_path(VEERIFIER_TEMPLATE_FILE_PATH).as_ref(), - template_path(PLONK_4_VERIFIER_FILE_PATH).as_ref(), - template_path(TRANSCRIPT_LIB_FILE_PATH).as_ref(), - template_path(PAIRING_BN_254_FILE_PATH).as_ref(), - template_path(UNCHECKED_MATH_FILE_PATH).as_ref(), - ], - ); - - eprintln!("Success!"); -} diff --git a/crates/codegen/Cargo.toml b/crates/codegen/Cargo.toml deleted file mode 100644 index 22ca732..0000000 --- a/crates/codegen/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "zksync_solidity_vk_codegen" -version = "0.1.0" -edition = "2018" -license = "MIT OR Apache-2.0" -description = "ZKsync solidity codegen for vks" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -franklin-crypto = { version = "=0.2.2", features = ["plonk"], path = "../franklin-crypto" } -rescue_poseidon = { version = "=0.5.2", path = "../rescue-poseidon" } - -handlebars = "3.5.5" -serde = "1" -serde_derive = "1" -serde_json = "1" - -hex = "0.4.3" -paste = "1.0" -ethereum-types = "=0.14.1" diff --git a/crates/codegen/src/circuits.rs b/crates/codegen/src/circuits.rs deleted file mode 100644 index b918228..0000000 --- a/crates/codegen/src/circuits.rs +++ /dev/null @@ -1,150 +0,0 @@ -use franklin_crypto::{ - bellman::{ - plonk::better_better_cs::{ - cs::{Circuit, ConstraintSystem, Gate, GateInternal, LookupTableApplication, PolyIdentifier, Width4MainGateWithDNext}, - gates::selector_optimized_with_d_next::SelectorOptimizedWidth4MainGateWithDNext, - }, - Engine, Field, PrimeField, SynthesisError, - }, - plonk::circuit::{ - allocated_num::{AllocatedNum, Num}, - boolean::Boolean, - custom_rescue_gate::Rescue5CustomGate, - }, -}; - -use rescue_poseidon::{circuit_generic_hash, CustomGate, HashParams, RescueParams}; - -use paste::paste; - -macro_rules! circuit_inner { - ($id:ident, $main_gate:ty, $declare_rescue:expr, $( $synth:tt ),*) => { - #[derive(Clone, Debug)] - pub struct $id; - - impl Circuit for $id { - type MainGate = $main_gate; - - fn synthesize>( - &self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { - inner_circuit_main_gate_part(cs)?; - $( - $synth(cs)?; - )* - - Ok(()) - } - - fn declare_used_gates() -> Result>>, SynthesisError> { - let has_rescue = $declare_rescue; - if has_rescue{ - Ok(vec![ - Self::MainGate::default().into_internal(), - Rescue5CustomGate::default().into_internal(), - ]) - }else{ - Ok(vec![ - Self::MainGate::default().into_internal(), - ]) - } - } - } - }; -} - -#[macro_export] -macro_rules! circuit { - ($id:ident, $main_gate:ty) => { - circuit_inner!($id, $main_gate, false, inner_circuit_main_gate_part); - paste! { - circuit_inner!([<$id WithLookup>], $main_gate, false, inner_circuit_lookup_part); - } - paste! { - circuit_inner!([<$id WithRescue>], $main_gate, true, inner_circuit_rescue_part); - } - paste! { - circuit_inner!([<$id WithLookupAndRescue>], $main_gate, true, inner_circuit_lookup_part, inner_circuit_rescue_part); - } - }; -} - -circuit!(DummyCircuit, Width4MainGateWithDNext); -circuit!(SelectorOptimizedDummyCircuit, SelectorOptimizedWidth4MainGateWithDNext); - -fn inner_circuit_main_gate_part>(cs: &mut CS) -> Result<(), SynthesisError> { - for _ in 0..32 { - let a = Num::alloc(cs, Some(E::Fr::one()))?; - let b = Num::alloc(cs, Some(E::Fr::zero()))?; - let flag = Boolean::alloc(cs, Some(true))?; - let c = Num::conditionally_select(cs, &flag, &a, &b)?; - let is_equal = Num::equals(cs, &a, &c)?; - - Boolean::enforce_equal(cs, &is_equal, &Boolean::Constant(true))?; - } - - Ok(()) -} - -fn inner_circuit_lookup_part>(cs: &mut CS) -> Result<(), SynthesisError> { - // add dummy lookup table queries - let dummy = CS::get_dummy_variable(); - dbg!("HAS LOOKUP"); - // need to create a table (any) - let columns = vec![PolyIdentifier::VariablesPolynomial(0), PolyIdentifier::VariablesPolynomial(1), PolyIdentifier::VariablesPolynomial(2)]; - let range_table = LookupTableApplication::new_range_table_of_width_3(2, columns.clone())?; - let _range_table_name = range_table.functional_name(); - - let xor_table = LookupTableApplication::new_xor_table(2, columns.clone())?; - let _xor_table_name = xor_table.functional_name(); - - let and_table = LookupTableApplication::new_and_table(2, columns)?; - let and_table_name = and_table.functional_name(); - - cs.add_table(range_table)?; - cs.add_table(xor_table)?; - cs.add_table(and_table)?; - - let binary_x_value = E::Fr::from_str("3").unwrap(); - let binary_y_value = E::Fr::from_str("1").unwrap(); - - let t = AllocatedNum::zero(cs); - let tt = AllocatedNum::one(cs); - let ttt = t.mul(cs, &tt)?; - ttt.inputize(cs)?; - - let binary_x = cs.alloc(|| Ok(binary_x_value))?; - - let binary_y = cs.alloc(|| Ok(binary_y_value))?; - - let table = cs.get_table(&and_table_name)?; - let num_keys_and_values = table.width(); - - let and_result_value = table.query(&[binary_x_value, binary_y_value])?[0]; - - let binary_z = cs.alloc(|| Ok(and_result_value))?; - - cs.begin_gates_batch_for_step()?; - - let vars = [binary_x, binary_y, binary_z, dummy]; - cs.allocate_variables_without_gate(&vars, &[])?; - - cs.apply_single_lookup_gate(&vars[..num_keys_and_values], table)?; - - cs.end_gates_batch_for_step()?; - - Ok(()) -} - -fn inner_circuit_rescue_part>(cs: &mut CS) -> Result<(), SynthesisError> { - dbg!("HAS RESCUE"); - // make single rescue hash to satisfy gate requirements of declaration - let mut params = RescueParams::default(); - params.use_custom_gate(CustomGate::QuinticWidth4); - - let elem = Num::alloc(cs, Some(E::Fr::from_str("42").unwrap()))?; - let _ = circuit_generic_hash::<_, _, _, 2, 3, 2>(cs, &[elem, elem], ¶ms, None)?; - - Ok(()) -} diff --git a/crates/codegen/src/generate.rs b/crates/codegen/src/generate.rs deleted file mode 100644 index 63fa902..0000000 --- a/crates/codegen/src/generate.rs +++ /dev/null @@ -1,253 +0,0 @@ -use franklin_crypto::bellman::plonk::better_better_cs::gates::selector_optimized_with_d_next::SelectorOptimizedWidth4MainGateWithDNext; -use franklin_crypto::bellman::{ - pairing::bn256::{Bn256, Fr}, - plonk::{ - better_better_cs::{cs::Width4MainGateWithDNext, setup::VerificationKey}, - domains::Domain, - }, - CurveAffine, Engine, -}; -use handlebars::*; -use serde_json::Map; -use std::io::Write; -use std::path::PathBuf; - -use serde::ser::Serialize; - -use crate::{ - circuits::DummyCircuit, - serialize::{FieldElement, G1Point, G2Point}, -}; - -pub enum MainGateType { - Standard, - SelectorOptimized, -} - -struct TemplateVars { - num_gates: usize, - has_rescue_custom_gate: bool, - has_lookup: bool, - is_selector_optimized_main_gate: bool, - num_main_gate_selectors: usize, - ab_coeff_idx: usize, - ac_coeff_idx: usize, - constant_coeff_idx: usize, - d_next_coeff_idx: usize, -} - -pub enum Encoding { - Json, - Default, -} - -pub fn generate(vk_path: PathBuf, output_dir: PathBuf, encoding_type: Encoding, template_files_path: Vec<&str>) { - let mut reader = std::fs::File::open(vk_path).expect("vk file"); - - let vk = match encoding_type { - Encoding::Json => serde_json::from_reader(reader).expect("read vk from json encoded data"), - Encoding::Default => VerificationKey::::read(&mut reader).expect("read vk from default encoded data"), - }; - // we know from the fact that vk belongs to a - // - standart main gate when there are 7 selectors - // - selector optimized main gate when there are 8 selectors - let num_selectors_of_main_gate = vk.gate_setup_commitments.len(); - let main_gate = if num_selectors_of_main_gate == 7 { - MainGateType::Standard - } else if num_selectors_of_main_gate == 8 { - MainGateType::SelectorOptimized - } else { - unimplemented!() - }; - - let num_gates = if vk.gate_selectors_commitments.len() == 0 { 1 } else { vk.gate_selectors_commitments.len() }; - - let has_rescue_custom_gate = if num_gates > 1 { true } else { false }; - - let has_lookup = if vk.total_lookup_entries_length > 0 { - assert!(vk.lookup_selector_commitment.is_some()); - assert!(vk.lookup_tables_commitments.len() > 0); - assert!(vk.lookup_table_type_commitment.is_some()); - true - } else { - assert!(vk.lookup_selector_commitment.is_none()); - assert!(vk.lookup_tables_commitments.len() == 0); - assert!(vk.lookup_table_type_commitment.is_none()); - false - }; - - let (num_main_gate_selectors, ab_coeff_idx, constant_coeff_idx, d_next_coeff_idx, ac_coeff_idx) = match main_gate { - MainGateType::Standard => ( - 7, - Width4MainGateWithDNext::AB_MULTIPLICATION_TERM_COEFF_INDEX, - Width4MainGateWithDNext::CONSTANT_TERM_COEFF_INDEX, - Width4MainGateWithDNext::D_NEXT_TERM_COEFF_INDEX, - None, - ), - MainGateType::SelectorOptimized => ( - 8, - SelectorOptimizedWidth4MainGateWithDNext::AB_MULTIPLICATION_TERM_COEFF_INDEX, - SelectorOptimizedWidth4MainGateWithDNext::CONSTANT_TERM_COEFF_INDEX, - SelectorOptimizedWidth4MainGateWithDNext::D_NEXT_TERM_COEFF_INDEX, - Some(SelectorOptimizedWidth4MainGateWithDNext::AC_MULTIPLICATION_TERM_COEFF_INDEX), - ), - }; - - let is_selector_optimized_main_gate = ac_coeff_idx.is_some(); - let ac_coeff_idx = if let Some(coeff) = ac_coeff_idx { coeff } else { 0 }; - - let vars = TemplateVars { - num_gates, - has_rescue_custom_gate, - has_lookup, - is_selector_optimized_main_gate, - num_main_gate_selectors, - ab_coeff_idx, - ac_coeff_idx, - constant_coeff_idx, - d_next_coeff_idx, - }; - - render(vars, vk, output_dir, template_files_path) -} - -fn render(vars: TemplateVars, vk: VerificationKey, output_dir: PathBuf, template_files_path: Vec<&str>) { - let mut map = MapWrapper::new(); - let mut handlebars = Handlebars::new(); - - map.insert("is_selector_optimized_main_gate", vars.is_selector_optimized_main_gate); - // main gate + custom rescue - map.insert("NUM_GATES", vars.num_gates); - map.insert("has_lookup", vars.has_lookup); - map.insert("has_rescue_custom_gate", vars.has_rescue_custom_gate); - map.insert("MAIN_GATE_AB_COEFF_IDX", vars.ab_coeff_idx); - map.insert("CONSTANT_TERM_COEFF_INDEX", vars.constant_coeff_idx); - map.insert("D_NEXT_TERM_COEFF_INDEX", vars.d_next_coeff_idx); - assert_eq!(vars.ab_coeff_idx, 4); - map.insert("MAIN_GATE_AC_COEFF_IDX", vars.ac_coeff_idx); - assert_eq!(vk.gate_setup_commitments.len(), vars.num_main_gate_selectors); - map.insert("NUM_MAIN_GATE_SELECTORS", vars.num_main_gate_selectors); - // a, b, c, d - println!("VK STATE WIDTH {}", vk.state_width); - map.insert("STATE_WIDTH", vk.state_width); - map.insert("DNEXT_INDEX", vk.state_width - 1); - map.insert("NUM_G2_ELS", vk.g2_elements.len()); - map.insert("NUM_LOOKUP_TABLES", vk.lookup_tables_commitments.len()); - map.insert("SERIALIZED_PROOF_LENGTH", 44); - let mut num_commitments_at_z = 2 + 4 + 3; - let mut num_commitments_at_z_omega = 1 + 2; - - let mut num_alpha_challenges = 1 + 2; - if vars.has_rescue_custom_gate { - num_commitments_at_z += 1; - num_alpha_challenges += 3; - } - if vars.has_lookup { - num_commitments_at_z += 3; - num_alpha_challenges += 3; - num_commitments_at_z_omega += 3; - } - - map.insert("rescue_alpha_idx", 1); - map.insert("num_commitments_at_z", num_commitments_at_z); - map.insert("num_commitments_at_z_omega", num_commitments_at_z_omega); - map.insert("NUM_ALPHA_CHALLENGES", num_alpha_challenges); - if vars.has_rescue_custom_gate { - map.insert("copy_permutation_alpha_idx", 4); - map.insert("lookup_alpha_idx", 6); - } else { - map.insert("copy_permutation_alpha_idx", 1); - map.insert("lookup_alpha_idx", 3); - } - - // domain - map.insert("num_inputs".into(), vk.num_inputs); - assert!(vk.num_inputs > 0); - let domain: Domain = Domain::new_for_size(vk.n as u64).expect("a domain"); - map.insert("domain_size".into(), domain.size); - map.insert("domain_generator".into(), FieldElement::from(domain.generator)); - - // G1Points - let mut gate_setup_commitments = vec![]; - for cmt in vk.gate_setup_commitments.iter() { - gate_setup_commitments.push(G1Point::from_affine_point(cmt.clone())) - } - map.insert("gate_setup_commitments", gate_setup_commitments); - - let mut gate_selectors_commitments = vec![]; - for cmt in vk.gate_selectors_commitments.iter() { - gate_selectors_commitments.push(G1Point::from_affine_point(cmt.clone())) - } - map.insert("gate_selectors_commitments", gate_selectors_commitments); - - let mut permutation_commitments = vec![]; - for cmt in vk.permutation_commitments.iter() { - permutation_commitments.push(G1Point::from_affine_point(cmt.clone())) - } - map.insert("permutation_commitments", permutation_commitments); - - if vk.total_lookup_entries_length > 0 { - assert!(vk.lookup_selector_commitment.is_some()); - assert!(vk.lookup_tables_commitments.len() > 0); - assert!(vk.lookup_table_type_commitment.is_some()); - - map.insert("has_lookup", true); - map.insert( - "lookup_selector_commitment", - G1Point::from_affine_point(vk.lookup_selector_commitment.unwrap_or(::G1Affine::zero())), - ); - if vk.total_lookup_entries_length > 0 { - assert!(vk.lookup_selector_commitment.is_some()); - } - let mut lookup_tables_commitments = vec![]; - for cmt in vk.lookup_tables_commitments.iter() { - lookup_tables_commitments.push(G1Point::from_affine_point(cmt.clone())) - } - map.insert("lookup_tables_commitments", lookup_tables_commitments); - map.insert( - "lookup_table_type_commitment", - G1Point::from_affine_point(vk.lookup_table_type_commitment.unwrap_or(::G1Affine::zero())), - ); - } - - // non residues - let mut non_residues = vec![]; - for el in vk.non_residues.iter() { - non_residues.push(FieldElement::from(el.clone())); - } - map.insert("non_residues", non_residues); - - // pairing g2 elements - let mut g2_elements = vec![]; - for point in vk.g2_elements.iter() { - g2_elements.push(G2Point::from_affine_point(point.clone())); - } - map.insert("g2_elements", g2_elements); - - for template_file_path in template_files_path { - let mut output_path = output_dir.clone(); - output_path.push(template_file_path.split('/').last().unwrap()); - let mut writer = std::fs::File::create(output_path).expect("output file"); - // register template from a file and assign a name to it - handlebars - .register_template_file("contract", template_file_path.clone()) - .expect(&format!("must read the template at path {}", template_file_path)); - - let rendered = handlebars.render("contract", &map.inner).unwrap(); - - writer.write(rendered.as_bytes()).expect("must write to file"); - } -} - -struct MapWrapper { - inner: Map, -} -impl MapWrapper { - fn new() -> Self { - Self { inner: Map::new() } - } - - fn insert(&mut self, key: &str, value: T) -> Option { - self.inner.insert(key.into(), to_json(value)) - } -} diff --git a/crates/codegen-bin/Cargo.toml b/crates/plonk-verifier-codegen-bin/Cargo.toml similarity index 57% rename from crates/codegen-bin/Cargo.toml rename to crates/plonk-verifier-codegen-bin/Cargo.toml index 9c4beaa..cae84ad 100644 --- a/crates/codegen-bin/Cargo.toml +++ b/crates/plonk-verifier-codegen-bin/Cargo.toml @@ -1,14 +1,16 @@ [package] -name = "codegen-bin" +name = "plonk-verifier-codegen-bin" version = "0.1.0" edition = "2018" license = "MIT OR Apache-2.0" -publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -zksync_solidity_vk_codegen = { path = "../codegen" } +codegen = {path = "../plonk-verifier-codegen", package = "plonk-verifier-codegen"} structopt = "0.3" dialoguer = "0.8" +[[bin]] +name = "generate" +path = "src/main.rs" diff --git a/crates/plonk-verifier-codegen-bin/src/main.rs b/crates/plonk-verifier-codegen-bin/src/main.rs new file mode 100644 index 0000000..eebdaae --- /dev/null +++ b/crates/plonk-verifier-codegen-bin/src/main.rs @@ -0,0 +1,65 @@ +use codegen::{generate, Encoding}; +use std::path::PathBuf; +use structopt::StructOpt; + +const DEFAULT_OUTPUT_FILE: &str = "./crates/plonk-verifier-foundry"; + +const PAIRING_BN_254_FILE_PATH: &str = "./crates/plonk-verifier-codegen/template/PairingsBn254.sol"; +const TRANSCRIPT_LIB_FILE_PATH: &str = "./crates/plonk-verifier-codegen/template/TranscriptLib.sol"; +const UNCHECKED_MATH_FILE_PATH: &str = "./crates/plonk-verifier-codegen/template/UncheckedMath.sol"; +const PLONK_4_VERIFIER_FILE_PATH: &str = "./crates/plonk-verifier-codegen/template/Plonk4VerifierWithAccessToDNext.sol"; +const VEERIFIER_TEMPLATE_FILE_PATH: &str = "./crates/plonk-verifier-codegen/template/Verifier.sol"; +const PROOF_TEST_TEMPLATE_FILE_PATH: &str = "./crates/plonk-verifier-codegen/template/HardcodedValues.sol"; + +#[derive(StructOpt, Debug)] +pub struct Opts { + /// Path to verification key(required) + #[structopt(long, parse(from_os_str))] + verification_key: PathBuf, + /// Path to proof key(optional) + #[structopt(long, parse(from_os_str))] + proof: Option, + /// Output directory + #[structopt(long, parse(from_os_str), default_value = DEFAULT_OUTPUT_FILE)] + output: PathBuf, + + #[structopt(long)] + encoding: Option, +} + +fn main() { + let opts = Opts::from_args(); + println!("{:#?}", opts); + + let Opts { + verification_key, + proof, + output, + encoding, + } = opts; + + let encoding = match encoding { + Some(encoding) => match encoding.as_str() { + "json" => Encoding::Json, + _ => Encoding::Default, + }, + None => Encoding::Default, + }; + + generate( + verification_key, + proof, + output.clone(), + encoding, + vec![ + VEERIFIER_TEMPLATE_FILE_PATH, + PLONK_4_VERIFIER_FILE_PATH, + TRANSCRIPT_LIB_FILE_PATH, + PAIRING_BN_254_FILE_PATH, + UNCHECKED_MATH_FILE_PATH, + PROOF_TEST_TEMPLATE_FILE_PATH, + ], + ); + + eprintln!("Success!"); +} diff --git a/crates/codegen/.gitignore b/crates/plonk-verifier-codegen/.gitignore similarity index 100% rename from crates/codegen/.gitignore rename to crates/plonk-verifier-codegen/.gitignore diff --git a/crates/plonk-verifier-codegen/Cargo.toml b/crates/plonk-verifier-codegen/Cargo.toml new file mode 100644 index 0000000..39e28dc --- /dev/null +++ b/crates/plonk-verifier-codegen/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "plonk-verifier-codegen" +version = "0.1.0" +edition = "2018" +license = "MIT OR Apache-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +handlebars = "*" +serde = "*" +serde_derive = "*" +serde_json = "*" +hex = "*" +paste = "1.0" +ethereum-types = "=0.14.1" +rescue_poseidon = {package = "rescue_poseidon", path = "../rescue-poseidon"} +# rescue-poseidon = {package = "rescue_poseidon", git = "https://github.com/matter-labs/rescue-poseidon"} diff --git a/crates/plonk-verifier-codegen/src/circuits.rs b/crates/plonk-verifier-codegen/src/circuits.rs new file mode 100644 index 0000000..2a90cc8 --- /dev/null +++ b/crates/plonk-verifier-codegen/src/circuits.rs @@ -0,0 +1,351 @@ +use rescue_poseidon::franklin_crypto::{ + bellman::{ + bn256::{Bn256, Fr}, + kate_commitment::{Crs, CrsForMonomialForm}, + plonk::{ + better_better_cs::{ + cs::{ + ArithmeticTerm, Circuit, ConstraintSystem, Gate, GateInternal, + LookupTableApplication, MainGate, MainGateTerm, PlonkConstraintSystemParams, + PlonkCsWidth4WithNextStepAndCustomGatesParams, PlonkCsWidth4WithNextStepParams, + PolyIdentifier, TrivialAssembly, VerificationKey, Width4MainGateWithDNext, + }, + gates::selector_optimized_with_d_next::SelectorOptimizedWidth4MainGateWithDNext, + proof::Proof, + }, + commitments::transcript::{keccak_transcript::RollingKeccakTranscript, Transcript}, + }, + worker::Worker, + Engine, Field, PrimeField, SynthesisError, + }, + plonk::circuit::{ + allocated_num::{AllocatedNum, Num}, + boolean::Boolean, + custom_rescue_gate::Rescue5CustomGate, + linear_combination::LinearCombination, + Width4WithCustomGates, + }, +}; + +use rescue_poseidon::{circuit_generic_hash, CustomGate, HashParams, RescueParams}; + +use paste::paste; + +macro_rules! circuit_inner { + ($id:ident, $main_gate:ty, $declare_rescue:expr, $( $synth:tt ),*) => { + #[derive(Clone, Debug)] + pub struct $id; + + impl Circuit for $id { + type MainGate = $main_gate; + + fn synthesize>( + &self, + cs: &mut CS, + ) -> Result<(), SynthesisError> { + inner_circuit_main_gate_part(cs)?; + $( + $synth(cs)?; + )* + + Ok(()) + } + + fn declare_used_gates() -> Result>>, SynthesisError> { + let has_rescue = $declare_rescue; + if has_rescue{ + Ok(vec![ + Self::MainGate::default().into_internal(), + Rescue5CustomGate::default().into_internal(), + ]) + }else{ + Ok(vec![ + Self::MainGate::default().into_internal(), + ]) + } + } + } + }; +} + +#[macro_export] +macro_rules! circuit { + ($id:ident, $main_gate:ty) => { + circuit_inner!($id, $main_gate, false, inner_circuit_main_gate_part); + paste!{ + circuit_inner!([<$id WithLookup>], $main_gate, false, inner_circuit_lookup_part); + } + paste!{ + circuit_inner!([<$id WithRescue>], $main_gate, true, inner_circuit_rescue_part); + } + paste!{ + circuit_inner!([<$id WithLookupAndRescue>], $main_gate, true, inner_circuit_lookup_part, inner_circuit_rescue_part); + } + } +} + +circuit!(MockCircuit, Width4MainGateWithDNext); +circuit!( + MockCircuitSelectorOptimized, + SelectorOptimizedWidth4MainGateWithDNext +); + +fn inner_circuit_main_gate_part>( + cs: &mut CS, +) -> Result<(), SynthesisError> { + for _ in 0..32 { + let a = Num::alloc(cs, Some(E::Fr::one()))?; + let b = Num::alloc(cs, Some(E::Fr::zero()))?; + let flag = Boolean::alloc(cs, Some(true))?; + let c = Num::conditionally_select(cs, &flag, &a, &b)?; + let is_equal = Num::equals(cs, &a, &c)?; + Boolean::enforce_equal(cs, &is_equal, &Boolean::Constant(true))?; + + let mut lc = LinearCombination::zero(); + for idx in 0..6 { + let el = E::Fr::from_str(&idx.to_string()).unwrap(); + let allocated = Num::alloc(cs, Some(el))?; + lc.add_assign_number_with_coeff(&allocated, E::Fr::one()); + } + let sum = Num::alloc(cs, Some(E::Fr::from_str(&20.to_string()).unwrap()))?; + let mut minus_one = E::Fr::one(); + minus_one.negate(); + lc.add_assign_number_with_coeff(&sum, minus_one); + } + let a = Num::alloc(cs, Some(E::Fr::one()))?; + let b = Num::alloc(cs, Some(E::Fr::one()))?; + let expected = cs.alloc_input(|| Ok(E::Fr::from_str(&2.to_string()).unwrap()))?; + let actual = a.add(cs, &b)?; + + let mut term = MainGateTerm::::new(); + term.add_assign(ArithmeticTerm::from_variable(expected)); + term.sub_assign(ArithmeticTerm::from_variable( + actual.get_variable().get_variable(), + )); + cs.allocate_main_gate(term)?; + + Ok(()) +} + +fn inner_circuit_lookup_part>( + cs: &mut CS, +) -> Result<(), SynthesisError> { + // add dummy lookup table queries + let dummy = CS::get_dummy_variable(); + // need to create a table (any) + let columns = vec![ + PolyIdentifier::VariablesPolynomial(0), + PolyIdentifier::VariablesPolynomial(1), + PolyIdentifier::VariablesPolynomial(2), + ]; + let range_table = LookupTableApplication::new_range_table_of_width_3(2, columns.clone())?; + let _range_table_name = range_table.functional_name(); + + let xor_table = LookupTableApplication::new_xor_table(2, columns.clone())?; + let _xor_table_name = xor_table.functional_name(); + + let and_table = LookupTableApplication::new_and_table(2, columns)?; + let and_table_name = and_table.functional_name(); + + cs.add_table(range_table)?; + cs.add_table(xor_table)?; + cs.add_table(and_table)?; + + let binary_x_value = E::Fr::from_str("3").unwrap(); + let binary_y_value = E::Fr::from_str("1").unwrap(); + + let t = AllocatedNum::zero(cs); + let tt = AllocatedNum::one(cs); + let ttt = t.mul(cs, &tt)?; + ttt.inputize(cs)?; + + let binary_x = cs.alloc(|| Ok(binary_x_value))?; + + let binary_y = cs.alloc(|| Ok(binary_y_value))?; + + let table = cs.get_table(&and_table_name)?; + let num_keys_and_values = table.width(); + + let and_result_value = table.query(&[binary_x_value, binary_y_value])?[0]; + + let binary_z = cs.alloc(|| Ok(and_result_value))?; + + cs.begin_gates_batch_for_step()?; + + let vars = [binary_x, binary_y, binary_z, dummy]; + cs.allocate_variables_without_gate(&vars, &[])?; + + cs.apply_single_lookup_gate(&vars[..num_keys_and_values], table)?; + + cs.end_gates_batch_for_step()?; + + Ok(()) +} + +fn inner_circuit_rescue_part>( + cs: &mut CS, +) -> Result<(), SynthesisError> { + // make single rescue hash to satisfy gate requirements of declaration + let mut params = RescueParams::default(); + params.use_custom_gate(CustomGate::QuinticWidth4); + + let elem = Num::alloc(cs, Some(E::Fr::from_str("42").unwrap()))?; + let _ = circuit_generic_hash::<_, _, _, 2, 3, 2>(cs, &[elem, elem], ¶ms, None)?; + + Ok(()) +} + +#[test] +fn test_create_proof_for_all_circuits() { + type T = RollingKeccakTranscript; + + let base_dir = std::env::var("PLONK_VERIFIER_DATA_DIR").expect("output dir for output files"); + let out_dir = format!( + "{}/std", + base_dir, + ); + println!("out dir {}", out_dir); + println!("Std main gate"); + create_proof_for_circuit::<_, PlonkCsWidth4WithNextStepParams, Width4MainGateWithDNext, T>( + MockCircuit {}, + &format!("{}/std", &out_dir), + ); + println!("Std main gate with lookup"); + create_proof_for_circuit::<_, PlonkCsWidth4WithNextStepParams, Width4MainGateWithDNext, T>( + MockCircuitWithLookup {}, + &format!("{}/std_with_lookup", &out_dir), + ); + println!("Std main gate with sbox custom gate"); + create_proof_for_circuit::< + _, + PlonkCsWidth4WithNextStepAndCustomGatesParams, + Width4MainGateWithDNext, + T, + >( + MockCircuitWithRescue {}, + &format!("{}/std_with_rescue", &out_dir), + ); + println!("Std main gate with lookup and sbox custom gate"); + create_proof_for_circuit::< + _, + PlonkCsWidth4WithNextStepAndCustomGatesParams, + Width4MainGateWithDNext, + T, + >( + MockCircuitWithLookupAndRescue {}, + &format!("{}/std_with_lookup_and_rescue", &out_dir), + ); + + let out_dir = format!( + "{}/optimized", + base_dir, + ); + println!("SelectorOptimized main gate"); + create_proof_for_circuit::< + _, + PlonkCsWidth4WithNextStepAndCustomGatesParams, + SelectorOptimizedWidth4MainGateWithDNext, + T, + >( + MockCircuitSelectorOptimized {}, + &format!("{}/optimized", &out_dir), + ); + println!("SelectorOptimized main gate with lookup"); + create_proof_for_circuit::< + _, + PlonkCsWidth4WithNextStepAndCustomGatesParams, + SelectorOptimizedWidth4MainGateWithDNext, + T, + >( + MockCircuitSelectorOptimizedWithLookup {}, + &format!("{}/optimized_with_lookup", &out_dir), + ); + println!("SelectorOptimized main gate with sbox custom gate"); + create_proof_for_circuit::< + _, + PlonkCsWidth4WithNextStepAndCustomGatesParams, + SelectorOptimizedWidth4MainGateWithDNext, + T, + >( + MockCircuitSelectorOptimizedWithRescue {}, + &format!("{}/optimized_with_rescue", &out_dir), + ); + println!("SelectorOptimized main gate with lookup and sbox custom gate"); + create_proof_for_circuit::< + _, + PlonkCsWidth4WithNextStepAndCustomGatesParams, + SelectorOptimizedWidth4MainGateWithDNext, + T, + >( + MockCircuitSelectorOptimizedWithLookupAndRescue {}, + &format!("{}/optimized_with_lookup_and_rescue", &out_dir), + ); +} + +fn init_crs(worker: &Worker, domain_size: usize) -> Crs { + let mon_crs = if let Ok(crs_file_path) = std::env::var("CRS_FILE") { + println!("using crs file at {crs_file_path}"); + let crs_file = + std::fs::File::open(&crs_file_path).expect(&format!("crs file at {}", crs_file_path)); + let mon_crs = Crs::::read(crs_file) + .expect(&format!("read crs file at {}", crs_file_path)); + assert!(domain_size <= mon_crs.g1_bases.len()); + + mon_crs + } else { + Crs::::crs_42(domain_size, &worker) + }; + + mon_crs +} + +fn create_proof_for_circuit< + C: Circuit, + P: PlonkConstraintSystemParams + 'static, + MG: MainGate, + T: Transcript, +>( + circuit: C, + out_dir: &str, +) -> (VerificationKey, Proof) { + let worker = Worker::new(); + println!("Synthesizing circuit"); + let mut assembly = TrivialAssembly::::new(); + circuit.synthesize(&mut assembly).unwrap(); + assert!(assembly.is_satisfied()); + assembly.finalize(); + + let domain_size = assembly.n() + 1; + assert!(domain_size.is_power_of_two()); + println!("Generating setup"); + let setup = assembly.create_setup::(&worker).unwrap(); + + let crs = init_crs(&worker, domain_size); + println!("Generating Vk"); + let vk = VerificationKey::from_setup(&setup, &worker, &crs).expect("vk from setup"); + + println!("Generating proof"); + let proof = assembly + .create_proof::(&worker, &setup, &crs, None) + .expect("proof"); + + save_proof_and_vk_into_file(&proof, &vk, &out_dir); + + (vk, proof) +} + +pub fn save_proof_and_vk_into_file>( + proof: &Proof, + vk: &VerificationKey, + output_path: &str, +) { + let proof_file_path = format!("{}_proof.json", output_path); + let proof_file = std::fs::File::create(&proof_file_path).unwrap(); + serde_json::to_writer(proof_file, &proof).unwrap(); + println!("proof saved at {proof_file_path}"); + + let vk_file_path = format!("{}_vk.json", output_path); + let vk_file = std::fs::File::create(&vk_file_path).unwrap(); + serde_json::to_writer(vk_file, &vk).unwrap(); + println!("vk saved at {vk_file_path}"); +} diff --git a/crates/plonk-verifier-codegen/src/generate.rs b/crates/plonk-verifier-codegen/src/generate.rs new file mode 100644 index 0000000..ef0ae85 --- /dev/null +++ b/crates/plonk-verifier-codegen/src/generate.rs @@ -0,0 +1,792 @@ +use rescue_poseidon::franklin_crypto::bellman::bn256::G1Affine; +use rescue_poseidon::franklin_crypto::bellman::plonk::better_better_cs::gates::selector_optimized_with_d_next::SelectorOptimizedWidth4MainGateWithDNext; +use rescue_poseidon::franklin_crypto::bellman::plonk::better_better_cs::proof::{self, Proof}; + +use handlebars::*; +use rescue_poseidon::franklin_crypto::bellman::plonk::commitments::transcript::keccak_transcript::RollingKeccakTranscript; +use rescue_poseidon::franklin_crypto::bellman::PrimeField; +use rescue_poseidon::franklin_crypto::bellman::{ + pairing::bn256::{Bn256, Fr}, + plonk::{ + better_better_cs::{cs::Width4MainGateWithDNext, setup::VerificationKey}, + domains::Domain, + }, + CurveAffine, Engine, +}; +use serde_json::Map; +use std::io::Write; +use std::path::PathBuf; + +use serde::ser::Serialize; + +use crate::circuits::{ + MockCircuitSelectorOptimized, MockCircuitSelectorOptimizedWithLookup, + MockCircuitSelectorOptimizedWithLookupAndRescue, MockCircuitSelectorOptimizedWithRescue, + MockCircuitWithLookup, MockCircuitWithLookupAndRescue, MockCircuitWithRescue, +}; +use crate::{ + circuits::MockCircuit, + serialize::{FieldElement, G1Point, G2Point}, +}; + +pub enum MainGateType { + Standard, + SelectorOptimized, +} + +struct TemplateVars { + has_rescue_custom_gate: bool, + has_lookup: bool, + is_selector_optimized_main_gate: bool, + num_main_gate_selectors: usize, + ab_coeff_idx: usize, + ac_coeff_idx: usize, + constant_coeff_idx: usize, + d_next_coeff_idx: usize, +} + +pub enum Encoding { + Json, + Default, +} + +// Generally it is okey to use MockCircuit in type definitions +// and then transmute it to the corresponding type of circuit +// by inspecting some values +pub fn generate( + vk_path: PathBuf, + proof_path: Option, + output_dir: PathBuf, + encoding_type: Encoding, + mut template_files_path: Vec<&str>, +) { + let mut reader = std::fs::File::open(vk_path).expect("vk file"); + + let vk = match encoding_type { + Encoding::Json => serde_json::from_reader(reader).expect("read vk from json encoded data"), + Encoding::Default => VerificationKey::::read(&mut reader) + .expect("read vk from default encoded data"), + }; + + // we know from the fact that vk belongs to a + // - standart main gate when there are 7 selectors + // - selector optimized main gate when there are 8 selectors + let num_selectors_of_main_gate = vk.gate_setup_commitments.len(); + let main_gate = if num_selectors_of_main_gate == 7 { + MainGateType::Standard + } else if num_selectors_of_main_gate == 8 { + MainGateType::SelectorOptimized + } else { + unimplemented!() + }; + + let has_rescue_custom_gate = if vk.gate_selectors_commitments.len() > 1 { + assert_eq!( + vk.gate_selectors_commitments.len(), + 2, + "only sbox custom gate is supported" + ); + true + } else { + assert!(vk.gate_selectors_commitments.is_empty()); + false + }; + + let has_lookup = if vk.total_lookup_entries_length > 0 { + assert!(vk.lookup_selector_commitment.is_some()); + assert!(vk.lookup_tables_commitments.len() > 0); + assert!(vk.lookup_table_type_commitment.is_some()); + true + } else { + assert!(vk.lookup_selector_commitment.is_none()); + assert!(vk.lookup_tables_commitments.len() == 0); + assert!(vk.lookup_table_type_commitment.is_none()); + false + }; + + let (num_main_gate_selectors, ab_coeff_idx, constant_coeff_idx, d_next_coeff_idx, ac_coeff_idx) = + match main_gate { + MainGateType::Standard => ( + 7, + Width4MainGateWithDNext::AB_MULTIPLICATION_TERM_COEFF_INDEX, + Width4MainGateWithDNext::CONSTANT_TERM_COEFF_INDEX, + Width4MainGateWithDNext::D_NEXT_TERM_COEFF_INDEX, + None, + ), + MainGateType::SelectorOptimized => ( + 8, + SelectorOptimizedWidth4MainGateWithDNext::AB_MULTIPLICATION_TERM_COEFF_INDEX, + SelectorOptimizedWidth4MainGateWithDNext::CONSTANT_TERM_COEFF_INDEX, + SelectorOptimizedWidth4MainGateWithDNext::D_NEXT_TERM_COEFF_INDEX, + Some(SelectorOptimizedWidth4MainGateWithDNext::AC_MULTIPLICATION_TERM_COEFF_INDEX), + ), + }; + + let is_selector_optimized_main_gate = ac_coeff_idx.is_some(); + let ac_coeff_idx = if let Some(coeff) = ac_coeff_idx { + coeff + } else { + 0 + }; + + let vars = TemplateVars { + has_rescue_custom_gate, + has_lookup, + is_selector_optimized_main_gate, + num_main_gate_selectors, + ab_coeff_idx, + ac_coeff_idx, + constant_coeff_idx, + d_next_coeff_idx, + }; + + let proof_template_dir = template_files_path.pop().unwrap(); + + render_verifier(vars, &vk, &output_dir, &template_files_path); + + if let Some(proof_path) = proof_path { + let mut reader = std::fs::File::open(proof_path).expect("proof file"); + let proof = match encoding_type { + Encoding::Json => { + serde_json::from_reader(reader).expect("read proof from json encoded data") + } + Encoding::Default => Proof::::read(&mut reader) + .expect("read proof from default encoded data"), + }; + unsafe { verify_proof(&vk, &proof, main_gate) }; + render_expected_proofs( + proof, + proof_template_dir, + &output_dir, + has_rescue_custom_gate, + has_lookup, + ); + } +} + +unsafe fn verify_proof( + vk: &VerificationKey, + proof: &Proof, + main_gate_type: MainGateType, +) { + use rescue_poseidon::franklin_crypto::bellman::plonk::better_better_cs::verifier::verify; + + assert_eq!(vk.n, proof.n); + assert_eq!(vk.num_inputs, proof.inputs.len()); + + let has_lookup = vk.total_lookup_entries_length > 0; + assert_eq!(has_lookup, proof.lookup_grand_product_commitment.is_some()); + assert_eq!(has_lookup, proof.lookup_s_poly_commitment.is_some()); + assert_eq!( + has_lookup, + proof.lookup_grand_product_opening_at_z_omega.is_some() + ); + assert_eq!(has_lookup, proof.lookup_s_poly_opening_at_z_omega.is_some()); + assert_eq!( + has_lookup, + proof.lookup_selector_poly_opening_at_z.is_some() + ); + assert_eq!(has_lookup, proof.lookup_t_poly_opening_at_z.is_some()); + assert_eq!(has_lookup, proof.lookup_t_poly_opening_at_z_omega.is_some()); + assert_eq!( + has_lookup, + proof.lookup_table_type_poly_opening_at_z.is_some() + ); + + let has_custom_gate = vk.gate_selectors_commitments.len() > 0; + + let is_valid = match main_gate_type { + MainGateType::Standard => { + if !has_lookup && !has_custom_gate { + verify::>( + std::mem::transmute(vk), + std::mem::transmute(proof), + None, + ) + .unwrap() + } else if has_lookup && !has_custom_gate { + verify::>( + std::mem::transmute(vk), + std::mem::transmute(proof), + None, + ) + .unwrap() + } else if has_custom_gate && !has_lookup { + verify::>( + std::mem::transmute(vk), + std::mem::transmute(proof), + None, + ) + .unwrap() + } else { + assert!(has_lookup); + assert!(has_custom_gate); + verify::>( + std::mem::transmute(vk), + std::mem::transmute(proof), + None, + ) + .unwrap() + } + } + MainGateType::SelectorOptimized => { + if !has_lookup && !has_custom_gate { + verify::>( + std::mem::transmute(vk), + std::mem::transmute(proof), + None, + ) + .unwrap() + } else if has_lookup && !has_custom_gate { + verify::< + Bn256, + MockCircuitSelectorOptimizedWithLookup, + RollingKeccakTranscript, + >(std::mem::transmute(vk), std::mem::transmute(proof), None) + .unwrap() + } else if has_custom_gate && !has_lookup { + verify::< + Bn256, + MockCircuitSelectorOptimizedWithRescue, + RollingKeccakTranscript, + >(std::mem::transmute(vk), std::mem::transmute(proof), None) + .unwrap() + } else { + assert!(has_lookup); + assert!(has_custom_gate); + verify::< + Bn256, + MockCircuitSelectorOptimizedWithLookupAndRescue, + RollingKeccakTranscript, + >(std::mem::transmute(vk), std::mem::transmute(proof), None) + .unwrap() + } + } + }; + + assert!(is_valid, "proof verification failed at codegen"); +} + +fn length_of_serialized_proof_from_vk( + vk: &VerificationKey, + has_custom_gate: bool, + has_lookup: bool, + has_dnext: bool, + quotient_degree: usize, +) -> usize { + assert_eq!(vk.state_width, quotient_degree); + + let mut num_commitments = vk.state_width; // trace + num_commitments += 1; // copy-perm z(x) + num_commitments += quotient_degree; + num_commitments += 2; // opening proofs + + if has_lookup { + num_commitments += 2; // lookup z(x) + lookup s(x) + } + + // openings + let mut num_openings = vk.state_width; // trace + if has_dnext { + num_openings += 1; + } + + if has_custom_gate { + num_openings += 1; // main gate selector + } + + num_openings += vk.state_width - 1; // sigmas + // copy-perm z(z) is part of linearizaton + num_openings += 1; // copy-perm z(z*w) + + if has_lookup { + // - s(z*w) + // - z(z*w) + // - t(z) + // - t(z*w) + // - selector(z) + // - type(z) + num_openings += 6; + } + + num_openings += 1; // quotient + num_openings += 1; // linearization + + 2 * num_commitments + num_openings +} + +fn compute_quotient_degree(state_width: usize, has_custom_gate: bool, has_lookup: bool) -> usize { + let mut main_gate_quotient_degree = 2; + if has_custom_gate { + main_gate_quotient_degree += 1; + } + + let copy_perm_quotient_degree = state_width; + + let lookup_quotient_degree = if has_lookup { 2 } else { 0 }; + + [ + main_gate_quotient_degree, + copy_perm_quotient_degree, + lookup_quotient_degree, + ] + .iter() + .cloned() + .max() + .unwrap() +} + +fn render_verifier( + vars: TemplateVars, + vk: &VerificationKey, + output_dir: &PathBuf, + template_files_path: &[&str], +) { + let mut map = MapWrapper::new(); + let mut handlebars = Handlebars::new(); + + map.insert( + "is_selector_optimized_main_gate", + vars.is_selector_optimized_main_gate, + ); + // main gate + custom rescue + map.insert("has_lookup", vars.has_lookup); + map.insert("has_rescue_custom_gate", vars.has_rescue_custom_gate); + map.insert("MAIN_GATE_AB_COEFF_IDX", vars.ab_coeff_idx); + map.insert("CONSTANT_TERM_COEFF_INDEX", vars.constant_coeff_idx); + map.insert("D_NEXT_TERM_COEFF_INDEX", vars.d_next_coeff_idx); + assert_eq!(vars.ab_coeff_idx, 4); + map.insert("MAIN_GATE_AC_COEFF_IDX", vars.ac_coeff_idx); + assert_eq!( + vk.gate_setup_commitments.len(), + vars.num_main_gate_selectors + ); + map.insert("NUM_MAIN_GATE_SELECTORS", vars.num_main_gate_selectors); + // a, b, c, d + println!("VK STATE WIDTH {}", vk.state_width); + map.insert("STATE_WIDTH", vk.state_width); + map.insert("DNEXT_INDEX", vk.state_width - 1); + map.insert("NUM_G2_ELS", vk.g2_elements.len()); + map.insert("NUM_LOOKUP_TABLES", vk.lookup_tables_commitments.len()); + let quotient_degree = + compute_quotient_degree(vk.state_width, vars.has_rescue_custom_gate, vars.has_lookup); + let serialized_proof_length = length_of_serialized_proof_from_vk( + vk, + vars.has_rescue_custom_gate, + vars.has_lookup, + vars.d_next_coeff_idx > 0, + quotient_degree, + ); + map.insert("SERIALIZED_PROOF_LENGTH", serialized_proof_length); + let mut num_commitments_at_z = 2 + 4 + 3; + let mut num_commitments_at_z_omega = 1 + 2; + + let mut num_alpha_challenges = 1 + 2; + if vars.has_rescue_custom_gate { + num_commitments_at_z += 1; + num_alpha_challenges += 3; + } + if vars.has_lookup { + num_commitments_at_z += 3; + num_alpha_challenges += 3; + num_commitments_at_z_omega += 3; + } + + map.insert("rescue_alpha_idx", 1); + map.insert("num_commitments_at_z", num_commitments_at_z); + map.insert("num_commitments_at_z_omega", num_commitments_at_z_omega); + map.insert("NUM_ALPHA_CHALLENGES", num_alpha_challenges); + if vars.has_rescue_custom_gate { + map.insert("copy_permutation_alpha_idx", 4); + map.insert("lookup_alpha_idx", 6); + } else { + map.insert("copy_permutation_alpha_idx", 1); + map.insert("lookup_alpha_idx", 3); + } + + // domain + map.insert("num_inputs".into(), vk.num_inputs); + // assert!(vk.num_inputs > 0); + let domain: Domain = Domain::new_for_size(vk.n as u64).expect("a domain"); + map.insert("domain_size".into(), domain.size); + map.insert( + "domain_generator".into(), + FieldElement::from(domain.generator), + ); + + // G1Points + let mut gate_setup_commitments = vec![]; + for cmt in vk.gate_setup_commitments.iter() { + gate_setup_commitments.push(G1Point::from_affine_point(cmt.clone())) + } + map.insert("gate_setup_commitments", gate_setup_commitments); + + let mut gate_selectors_commitments = vec![]; + for cmt in vk.gate_selectors_commitments.iter() { + gate_selectors_commitments.push(G1Point::from_affine_point(cmt.clone())) + } + map.insert("gate_selectors_commitments", gate_selectors_commitments); + + let mut permutation_commitments = vec![]; + for cmt in vk.permutation_commitments.iter() { + permutation_commitments.push(G1Point::from_affine_point(cmt.clone())) + } + map.insert("permutation_commitments", permutation_commitments); + + if vk.total_lookup_entries_length > 0 { + assert!(vk.lookup_selector_commitment.is_some()); + assert!(vk.lookup_tables_commitments.len() > 0); + assert!(vk.lookup_table_type_commitment.is_some()); + + map.insert("has_lookup", true); + map.insert( + "lookup_selector_commitment", + G1Point::from_affine_point( + vk.lookup_selector_commitment + .unwrap_or(::G1Affine::zero()), + ), + ); + if vk.total_lookup_entries_length > 0 { + assert!(vk.lookup_selector_commitment.is_some()); + } + let mut lookup_tables_commitments = vec![]; + for cmt in vk.lookup_tables_commitments.iter() { + lookup_tables_commitments.push(G1Point::from_affine_point(cmt.clone())) + } + map.insert("lookup_tables_commitments", lookup_tables_commitments); + map.insert( + "lookup_table_type_commitment", + G1Point::from_affine_point( + vk.lookup_table_type_commitment + .unwrap_or(::G1Affine::zero()), + ), + ); + } + + // non residues + let mut non_residues = vec![]; + for el in vk.non_residues.iter() { + non_residues.push(FieldElement::from(el.clone())); + } + map.insert("non_residues", non_residues); + + // pairing g2 elements + let mut g2_elements = vec![]; + for point in vk.g2_elements.iter() { + g2_elements.push(G2Point::from_affine_point(point.clone())); + } + map.insert("g2_elements", g2_elements); + + let mut src_dir = output_dir.clone(); + src_dir.push("src"); + for template_file_path in template_files_path { + let mut output_path = src_dir.clone(); + output_path.push(template_file_path.split('/').last().unwrap()); + let mut writer = std::fs::File::create(output_path).expect("output file"); + // register template from a file and assign a name to it + handlebars + .register_template_file("contract", template_file_path) + .expect(&format!( + "must read the template at path {}", + template_file_path + )); + + let rendered = handlebars.render("contract", &map.inner).unwrap(); + + writer + .write(rendered.as_bytes()) + .expect("must write to file"); + } +} + +fn render_expected_proofs( + proof: Proof, + proof_template_dir: &str, + output_dir: &PathBuf, + has_custom_gate: bool, + has_lookup: bool, +) { + let output_file = format!("{}/test/HardcodedValues.sol", output_dir.to_string_lossy()); + let mut writer = std::fs::File::create(output_file).expect("output file"); + let mut handlebars = Handlebars::new(); + handlebars + .register_template_file("contract", proof_template_dir) + .expect(&format!( + "must read the template at path {}", + proof_template_dir + )); + let json_proof = transform_proof_into_json(proof); + let serialized_inputs = json_proof.inputs.clone(); + let serialized_proof = serialize_proof(json_proof.clone(), has_custom_gate, has_lookup); + + let num_inputs = serialized_inputs.len(); + let serialized_proof_length = serialized_proof.len(); + let hardcoded_values = HardcodedProofValues { + proof: json_proof, + serialized_inputs, + serialized_proof, + num_inputs, + serialized_proof_length, + has_custom_gate, + has_lookup, + }; + let rendered = handlebars.render("contract", &hardcoded_values).unwrap(); + + writer + .write(rendered.as_bytes()) + .expect("must write to file"); +} + +#[derive(Clone, Default, serde::Serialize)] +pub struct HardcodedProofValues { + proof: JsonProof, + serialized_inputs: Vec, + serialized_proof: Vec, + num_inputs: usize, + serialized_proof_length: usize, + has_lookup: bool, + has_custom_gate: bool, +} + +#[derive(Clone, Default, serde::Serialize)] +pub struct JsonProof { + pub n: usize, + pub inputs: Vec, + pub state_polys_commitments: Vec<[String; 2]>, + pub copy_permutation_grand_product_commitment: [String; 2], + + pub lookup_s_poly_commitment: [String; 2], + pub lookup_grand_product_commitment: [String; 2], + + pub quotient_poly_parts_commitments: Vec<[String; 2]>, + + pub state_polys_openings_at_z: Vec, + pub state_polys_openings_at_z_omega: Vec, + + pub gate_setup_openings_at_z: Vec, + pub gate_selectors_openings_at_z: Vec, + + pub copy_permutation_polys_openings_at_z: Vec, + pub copy_permutation_grand_product_opening_at_z_omega: String, + + pub lookup_s_poly_opening_at_z_omega: String, + pub lookup_grand_product_opening_at_z_omega: String, + + pub lookup_t_poly_opening_at_z: String, + pub lookup_t_poly_opening_at_z_omega: String, + + pub lookup_selector_poly_opening_at_z: String, + pub lookup_table_type_poly_opening_at_z: String, + + pub quotient_poly_opening_at_z: String, + + pub linearization_poly_opening_at_z: String, + + pub opening_proof_at_z: [String; 2], + pub opening_proof_at_z_omega: [String; 2], +} + +pub fn to_hex(el: &F) -> String { + format!( + "0x{}", + rescue_poseidon::franklin_crypto::bellman::to_hex(el) + ) +} + +pub fn point_into_xy(point: &G1Affine) -> [String; 2] { + let (x, y) = point.as_xy(); + + [to_hex(x), to_hex(y)] +} + +pub fn transform_proof_into_json(proof: Proof) -> JsonProof { + let mut json_proof = JsonProof::default(); + json_proof.n = proof.n; + json_proof.inputs = proof.inputs.iter().map(|v| to_hex(v)).collect(); + json_proof.state_polys_commitments = proof + .state_polys_commitments + .iter() + .map(|p| point_into_xy(p)) + .collect(); + + json_proof.copy_permutation_grand_product_commitment = + point_into_xy(&proof.copy_permutation_grand_product_commitment); + + json_proof.lookup_s_poly_commitment = proof + .lookup_s_poly_commitment + .as_ref() + .map(|p| point_into_xy(p)) + .unwrap_or_default(); + json_proof.lookup_grand_product_commitment = proof + .lookup_grand_product_commitment + .as_ref() + .map(|p| point_into_xy(p)) + .unwrap_or_default(); + + json_proof.quotient_poly_parts_commitments = proof + .quotient_poly_parts_commitments + .iter() + .map(|p| point_into_xy(p)) + .collect(); + + json_proof.opening_proof_at_z = point_into_xy(&proof.opening_proof_at_z); + json_proof.opening_proof_at_z_omega = point_into_xy(&proof.opening_proof_at_z_omega); + + json_proof.state_polys_openings_at_z = proof + .state_polys_openings_at_z + .iter() + .map(|v| to_hex(v)) + .collect(); + assert_eq!( + proof.state_polys_openings_at_dilations.len(), + 1, + "only one dilation is allowed" + ); + json_proof.state_polys_openings_at_z_omega = proof + .state_polys_openings_at_dilations + .iter() + .map(|(_, _, v)| to_hex(v)) + .collect(); + json_proof.gate_setup_openings_at_z = proof + .gate_setup_openings_at_z + .iter() + .map(|(_, _, v)| to_hex(v)) + .collect(); + json_proof.gate_selectors_openings_at_z = proof + .gate_selectors_openings_at_z + .iter() + .map(|(_, v)| to_hex(v)) + .collect(); + json_proof.copy_permutation_polys_openings_at_z = proof + .copy_permutation_polys_openings_at_z + .iter() + .map(|v| to_hex(v)) + .collect(); + json_proof.copy_permutation_grand_product_opening_at_z_omega = + to_hex(&proof.copy_permutation_grand_product_opening_at_z_omega); + + json_proof.lookup_s_poly_opening_at_z_omega = proof + .lookup_s_poly_opening_at_z_omega + .as_ref() + .map(|v| to_hex(v)) + .unwrap_or_default(); + + json_proof.lookup_grand_product_opening_at_z_omega = proof + .lookup_grand_product_opening_at_z_omega + .as_ref() + .map(|v| to_hex(v)) + .unwrap_or_default(); + + json_proof.lookup_t_poly_opening_at_z = proof + .lookup_t_poly_opening_at_z + .as_ref() + .map(|v| to_hex(v)) + .unwrap_or_default(); + json_proof.lookup_t_poly_opening_at_z_omega = proof + .lookup_t_poly_opening_at_z_omega + .as_ref() + .map(|v| to_hex(v)) + .unwrap_or_default(); + json_proof.lookup_selector_poly_opening_at_z = proof + .lookup_selector_poly_opening_at_z + .as_ref() + .map(|v| to_hex(v)) + .unwrap_or_default(); + json_proof.lookup_table_type_poly_opening_at_z = proof + .lookup_table_type_poly_opening_at_z + .as_ref() + .map(|v| to_hex(v)) + .unwrap_or_default(); + + json_proof.quotient_poly_opening_at_z = to_hex(&proof.quotient_poly_opening_at_z); + json_proof.linearization_poly_opening_at_z = to_hex(&proof.linearization_poly_opening_at_z); + + json_proof +} + +pub fn serialize_proof(proof: JsonProof, has_custom_gate: bool, has_lookup: bool) -> Vec { + let JsonProof { + state_polys_commitments, + copy_permutation_grand_product_commitment, + lookup_s_poly_commitment, + lookup_grand_product_commitment, + quotient_poly_parts_commitments, + state_polys_openings_at_z, + state_polys_openings_at_z_omega, + gate_setup_openings_at_z, + gate_selectors_openings_at_z, + copy_permutation_polys_openings_at_z, + copy_permutation_grand_product_opening_at_z_omega, + lookup_s_poly_opening_at_z_omega, + lookup_grand_product_opening_at_z_omega, + lookup_t_poly_opening_at_z, + lookup_t_poly_opening_at_z_omega, + lookup_selector_poly_opening_at_z, + lookup_table_type_poly_opening_at_z, + quotient_poly_opening_at_z, + linearization_poly_opening_at_z, + opening_proof_at_z, + opening_proof_at_z_omega, + .. + } = proof; + + let mut serialized_proof = vec![]; + serialized_proof.extend( + state_polys_commitments + .iter() + .flat_map(|inner| inner.iter().cloned()), + ); + + serialized_proof.extend(copy_permutation_grand_product_commitment); + if has_lookup { + serialized_proof.extend(lookup_s_poly_commitment); + serialized_proof.extend(lookup_grand_product_commitment); + } + + serialized_proof.extend( + quotient_poly_parts_commitments + .iter() + .flat_map(|inner| inner.iter().cloned()), + ); + + serialized_proof.extend(state_polys_openings_at_z); + serialized_proof.extend(state_polys_openings_at_z_omega); + serialized_proof.extend(gate_setup_openings_at_z); + if has_custom_gate { + // linearization includes gate selector of the sbox gate + assert_eq!(gate_selectors_openings_at_z.len(), 1); + } else { + assert!(gate_selectors_openings_at_z.is_empty()); + } + serialized_proof.extend(gate_selectors_openings_at_z); + serialized_proof.extend(copy_permutation_polys_openings_at_z); + serialized_proof.push(copy_permutation_grand_product_opening_at_z_omega); + if has_lookup { + serialized_proof.push(lookup_s_poly_opening_at_z_omega); + serialized_proof.push(lookup_grand_product_opening_at_z_omega); + serialized_proof.push(lookup_t_poly_opening_at_z); + serialized_proof.push(lookup_t_poly_opening_at_z_omega); + serialized_proof.push(lookup_selector_poly_opening_at_z); + serialized_proof.push(lookup_table_type_poly_opening_at_z); + } + + serialized_proof.push(quotient_poly_opening_at_z); + serialized_proof.push(linearization_poly_opening_at_z); + + serialized_proof.extend(opening_proof_at_z); + serialized_proof.extend(opening_proof_at_z_omega); + + serialized_proof +} +struct MapWrapper { + inner: Map, +} +impl MapWrapper { + fn new() -> Self { + Self { inner: Map::new() } + } + + fn insert(&mut self, key: &str, value: T) -> Option { + self.inner.insert(key.into(), to_json(value)) + } +} diff --git a/crates/codegen/src/lib.rs b/crates/plonk-verifier-codegen/src/lib.rs similarity index 77% rename from crates/codegen/src/lib.rs rename to crates/plonk-verifier-codegen/src/lib.rs index 7094724..b9cd398 100644 --- a/crates/codegen/src/lib.rs +++ b/crates/plonk-verifier-codegen/src/lib.rs @@ -2,18 +2,19 @@ mod circuits; mod generate; mod serialize; +use std::str::FromStr; + +use circuits::MockCircuit; pub use generate::{generate, Encoding, MainGateType}; use ethereum_types::U256; -use franklin_crypto::bellman::pairing::bn256::{Bn256, Fr}; -use franklin_crypto::bellman::pairing::ff::*; -use franklin_crypto::bellman::pairing::*; -use franklin_crypto::bellman::plonk::better_better_cs::cs::Circuit; -use franklin_crypto::bellman::plonk::better_better_cs::gates::selector_optimized_with_d_next::SelectorOptimizedWidth4MainGateWithDNext; -use franklin_crypto::bellman::plonk::better_better_cs::proof::Proof; -use franklin_crypto::bellman::plonk::better_better_cs::setup::VerificationKey; - -use crate::circuits::DummyCircuit; +use rescue_poseidon::franklin_crypto::bellman::pairing::bn256::{Bn256, Fr}; +use rescue_poseidon::franklin_crypto::bellman::pairing::ff::*; +use rescue_poseidon::franklin_crypto::bellman::pairing::*; +use rescue_poseidon::franklin_crypto::bellman::plonk::better_better_cs::cs::{ + Circuit, VerificationKey, +}; +use rescue_poseidon::franklin_crypto::bellman::plonk::better_better_cs::proof::Proof; fn render_scalar_to_hex(el: &F) -> String { let mut buff = vec![]; @@ -39,7 +40,12 @@ fn render_g2_affine_to_hex(point: &::G2Affine) -> [Strin let (x, y) = <::G2Affine as CurveAffine>::into_xy_unchecked(*point); - [render_scalar_to_hex(&x.c0), render_scalar_to_hex(&x.c1), render_scalar_to_hex(&y.c0), render_scalar_to_hex(&y.c1)] + [ + render_scalar_to_hex(&x.c0), + render_scalar_to_hex(&x.c1), + render_scalar_to_hex(&y.c0), + render_scalar_to_hex(&y.c1) + ] } fn serialize_g1_for_ethereum(point: &::G1Affine) -> (U256, U256) { @@ -64,7 +70,10 @@ fn serialize_g1_for_ethereum(point: &::G1Affine) -> (U25 fn serialize_fe_for_ethereum(field_element: &Fr) -> U256 { let mut be_bytes = [0u8; 32]; - field_element.into_repr().write_be(&mut be_bytes[..]).expect("get new root BE bytes"); + field_element + .into_repr() + .write_be(&mut be_bytes[..]) + .expect("get new root BE bytes"); U256::from_big_endian(&be_bytes[..]) } @@ -133,6 +142,7 @@ pub fn serialize_proof>(proof: &Proof) -> (Vec serialized_proof.push(serialize_fe_for_ethereum(&proof.quotient_poly_opening_at_z)); serialized_proof.push(serialize_fe_for_ethereum(&proof.linearization_poly_opening_at_z)); + let (x, y) = serialize_g1_for_ethereum(&proof.opening_proof_at_z); serialized_proof.push(x); serialized_proof.push(y); @@ -144,29 +154,4 @@ pub fn serialize_proof>(proof: &Proof) -> (Vec dbg!(&serialized_proof.len()); (inputs, serialized_proof) -} - -#[test] -#[ignore] // TODO(ignored-test): Failure. -fn render_simple_proof() { - use franklin_crypto::bellman::pairing::bn256::*; - - let mut reader = std::io::BufReader::with_capacity(1 << 24, std::fs::File::open("../data/optimized/scheduler_proof.key").unwrap()); - let proof = Proof::::read(&mut reader).unwrap(); - let (inputs, proof) = serialize_proof(&proof); - - println!("Inputs"); - let mut vec = vec![]; - for i in inputs.into_iter() { - vec.push(format!("\"{}\"", i)); - } - println!("[{}]", vec.join(",")); - - println!("Proof"); - let mut vec = vec![]; - for i in proof.into_iter() { - vec.push(format!("\"{}\"", i)); - } - - println!("[{}]", vec.join(",")); -} +} \ No newline at end of file diff --git a/crates/codegen/src/serialize.rs b/crates/plonk-verifier-codegen/src/serialize.rs similarity index 92% rename from crates/codegen/src/serialize.rs rename to crates/plonk-verifier-codegen/src/serialize.rs index 4eaedb6..a2f0bea 100644 --- a/crates/codegen/src/serialize.rs +++ b/crates/plonk-verifier-codegen/src/serialize.rs @@ -1,7 +1,5 @@ -use franklin_crypto::bellman::{ - pairing::bn256::{Bn256, Fq, Fq2, Fr}, - CurveAffine, Engine, PrimeField, PrimeFieldRepr, -}; +use rescue_poseidon::franklin_crypto::bellman::{CurveAffine, Engine, PrimeField, PrimeFieldRepr, pairing::bn256::{Bn256, Fq, Fq2, Fr}}; + use serde::ser::{Serialize, SerializeStruct, Serializer}; @@ -31,7 +29,9 @@ impl Serialize for FieldElement { fn field_element_to_hex(el: &F) -> String { let mut buf = [0u8; 32]; - el.into_repr().write_be(&mut buf[..]).expect("consume buffer"); + el.into_repr() + .write_be(&mut buf[..]) + .expect("consume buffer"); let mut result = String::from("0x"); result.push_str(&hex::encode(buf)); diff --git a/crates/codegen/src/tests.rs b/crates/plonk-verifier-codegen/src/tests.rs similarity index 100% rename from crates/codegen/src/tests.rs rename to crates/plonk-verifier-codegen/src/tests.rs diff --git a/crates/plonk-verifier-codegen/template/HardcodedValues.sol b/crates/plonk-verifier-codegen/template/HardcodedValues.sol new file mode 100644 index 0000000..b26e7ba --- /dev/null +++ b/crates/plonk-verifier-codegen/template/HardcodedValues.sol @@ -0,0 +1,64 @@ +pragma solidity >=0.8.25 <0.9.0; +import {Proof} from "../src/Plonk4VerifierWithAccessToDNext.sol"; + +library HardcodedValues{ + function hardcoded_proof() internal pure returns(Proof memory proof){ + {{#each proof.inputs}} + proof.input_values[{{@index}}] = {{this}}; + {{/each}} + {{#each proof.state_polys_commitments}} + proof.state_polys_commitments[{{@index}}].X = {{this.[0]}}; + proof.state_polys_commitments[{{@index}}].Y = {{this.[1]}}; + {{/each}} + proof.copy_permutation_grand_product_commitment.X = {{proof.copy_permutation_grand_product_commitment.[0]}}; + proof.copy_permutation_grand_product_commitment.Y = {{proof.copy_permutation_grand_product_commitment.[1]}}; + {{#each proof.quotient_poly_parts_commitments}} + proof.quotient_poly_parts_commitments[{{@index}}].X = {{this.[0]}}; + proof.quotient_poly_parts_commitments[{{@index}}].Y = {{this.[1]}}; + {{/each}} + {{#if has_lookup}} + proof.lookup_s_poly_commitment.X = {{proof.lookup_s_poly_commitment.[0]}}; + proof.lookup_s_poly_commitment.Y = {{proof.lookup_s_poly_commitment.[1]}}; + proof.lookup_grand_product_commitment.X = {{proof.lookup_grand_product_commitment.[0]}}; + proof.lookup_grand_product_commitment.Y = {{proof.lookup_grand_product_commitment.[1]}}; + {{/if}} + proof.opening_proof_at_z.X = {{proof.opening_proof_at_z.[0]}}; + proof.opening_proof_at_z.Y = {{proof.opening_proof_at_z.[1]}}; + proof.opening_proof_at_z_omega.X = {{proof.opening_proof_at_z_omega.[0]}}; + proof.opening_proof_at_z_omega.Y = {{proof.opening_proof_at_z_omega.[1]}}; + + {{#each proof.state_polys_openings_at_z}} + proof.state_polys_openings_at_z[{{@index}}].value = {{this}}; + {{/each}} + {{#each proof.state_polys_openings_at_z_omega}} + proof.state_polys_openings_at_z_omega[{{@index}}].value = {{this}}; + {{/each}} + {{#each proof.gate_selectors_openings_at_z}} + proof.gate_selectors_openings_at_z[{{@index}}].value = {{this}}; + {{/each}} + {{#each proof.copy_permutation_polys_openings_at_z}} + proof.copy_permutation_polys_openings_at_z[{{@index}}].value = {{this}}; + {{/each}} + proof.copy_permutation_grand_product_opening_at_z_omega.value = {{proof.copy_permutation_grand_product_opening_at_z_omega}}; + proof.quotient_poly_opening_at_z.value = {{proof.quotient_poly_opening_at_z}}; + proof.linearization_poly_opening_at_z.value = {{proof.linearization_poly_opening_at_z}}; + {{#if has_lookup}} + proof.lookup_s_poly_opening_at_z_omega.value = {{proof.lookup_s_poly_opening_at_z_omega}}; + proof.lookup_grand_product_opening_at_z_omega.value = {{proof.lookup_grand_product_opening_at_z_omega}}; + proof.lookup_t_poly_opening_at_z.value = {{proof.lookup_t_poly_opening_at_z}}; + proof.lookup_selector_poly_opening_at_z.value = {{proof.lookup_selector_poly_opening_at_z}}; + proof.lookup_table_type_poly_opening_at_z.value = {{proof.lookup_table_type_poly_opening_at_z}}; + {{/if}} + } + + function hardcoded_serialized_proof() public pure returns(uint256[] memory serializedInputs, uint256[] memory serializedProof){ + serializedInputs = new uint256[]({{num_inputs}}); + {{#each serialized_inputs}} + serializedInputs[{{@index}}] = {{this}}; + {{/each}} + serializedProof = new uint256[]({{serialized_proof_length}}); + {{#each serialized_proof}} + serializedProof[{{@index}}] = {{this}}; + {{/each}} + } +} diff --git a/crates/codegen/template/PairingsBn254.sol b/crates/plonk-verifier-codegen/template/PairingsBn254.sol similarity index 100% rename from crates/codegen/template/PairingsBn254.sol rename to crates/plonk-verifier-codegen/template/PairingsBn254.sol diff --git a/crates/codegen/template/Plonk4VerifierWithAccessToDNext.sol b/crates/plonk-verifier-codegen/template/Plonk4VerifierWithAccessToDNext.sol similarity index 94% rename from crates/codegen/template/Plonk4VerifierWithAccessToDNext.sol rename to crates/plonk-verifier-codegen/template/Plonk4VerifierWithAccessToDNext.sol index 1af4d24..dc9d45f 100644 --- a/crates/codegen/template/Plonk4VerifierWithAccessToDNext.sol +++ b/crates/plonk-verifier-codegen/template/Plonk4VerifierWithAccessToDNext.sol @@ -11,7 +11,9 @@ struct VerificationKey { uint256 domain_size; uint256 num_inputs; PairingsBn254.Fr omega; - PairingsBn254.G1Point[{{NUM_GATES}}] gate_selectors_commitments; + {{#if has_rescue_custom_gate}} + PairingsBn254.G1Point[2] gate_selectors_commitments; + {{/if}} PairingsBn254.G1Point[{{NUM_MAIN_GATE_SELECTORS}}] gate_setup_commitments; PairingsBn254.G1Point[STATE_WIDTH] permutation_commitments; {{#if has_lookup}} @@ -25,6 +27,41 @@ struct VerificationKey { } +struct Proof { + uint256[] input_values; + // commitments + PairingsBn254.G1Point[STATE_WIDTH] state_polys_commitments; + PairingsBn254.G1Point copy_permutation_grand_product_commitment; + PairingsBn254.G1Point[STATE_WIDTH] quotient_poly_parts_commitments; + + // openings + PairingsBn254.Fr[STATE_WIDTH] state_polys_openings_at_z; + PairingsBn254.Fr[1] state_polys_openings_at_z_omega; + {{#if has_rescue_custom_gate}} + PairingsBn254.Fr[1] gate_selectors_openings_at_z; + {{/if}} + PairingsBn254.Fr[STATE_WIDTH-1] copy_permutation_polys_openings_at_z; + PairingsBn254.Fr copy_permutation_grand_product_opening_at_z_omega; + PairingsBn254.Fr quotient_poly_opening_at_z; + PairingsBn254.Fr linearization_poly_opening_at_z; + + {{#if has_lookup}} + // lookup commitments + PairingsBn254.G1Point lookup_s_poly_commitment; + PairingsBn254.G1Point lookup_grand_product_commitment; + // lookup openings + PairingsBn254.Fr lookup_s_poly_opening_at_z_omega; + PairingsBn254.Fr lookup_grand_product_opening_at_z_omega; + PairingsBn254.Fr lookup_t_poly_opening_at_z; + PairingsBn254.Fr lookup_t_poly_opening_at_z_omega; + PairingsBn254.Fr lookup_selector_poly_opening_at_z; + PairingsBn254.Fr lookup_table_type_poly_opening_at_z; + {{/if}} + PairingsBn254.G1Point opening_proof_at_z; + PairingsBn254.G1Point opening_proof_at_z_omega; +} + + contract Plonk4VerifierWithAccessToDNext { using PairingsBn254 for PairingsBn254.G1Point; using PairingsBn254 for PairingsBn254.G2Point; @@ -34,40 +71,6 @@ contract Plonk4VerifierWithAccessToDNext { using UncheckedMath for uint256; - struct Proof { - uint256[] input_values; - // commitments - PairingsBn254.G1Point[STATE_WIDTH] state_polys_commitments; - PairingsBn254.G1Point copy_permutation_grand_product_commitment; - PairingsBn254.G1Point[STATE_WIDTH] quotient_poly_parts_commitments; - - // openings - PairingsBn254.Fr[STATE_WIDTH] state_polys_openings_at_z; - PairingsBn254.Fr[1] state_polys_openings_at_z_omega; - {{#if has_rescue_custom_gate}} - PairingsBn254.Fr[1] gate_selectors_openings_at_z; - {{/if}} - PairingsBn254.Fr[STATE_WIDTH-1] copy_permutation_polys_openings_at_z; - PairingsBn254.Fr copy_permutation_grand_product_opening_at_z_omega; - PairingsBn254.Fr quotient_poly_opening_at_z; - PairingsBn254.Fr linearization_poly_opening_at_z; - - {{#if has_lookup}} - // lookup commitments - PairingsBn254.G1Point lookup_s_poly_commitment; - PairingsBn254.G1Point lookup_grand_product_commitment; - // lookup openings - PairingsBn254.Fr lookup_s_poly_opening_at_z_omega; - PairingsBn254.Fr lookup_grand_product_opening_at_z_omega; - PairingsBn254.Fr lookup_t_poly_opening_at_z; - PairingsBn254.Fr lookup_t_poly_opening_at_z_omega; - PairingsBn254.Fr lookup_selector_poly_opening_at_z; - PairingsBn254.Fr lookup_table_type_poly_opening_at_z; - {{/if}} - PairingsBn254.G1Point opening_proof_at_z; - PairingsBn254.G1Point opening_proof_at_z_omega; - } - struct PartialVerifierState { PairingsBn254.Fr zero; PairingsBn254.Fr alpha; @@ -251,8 +254,12 @@ contract Plonk4VerifierWithAccessToDNext { current_z.mul_assign(z_in_domain_size); } } - + {{#if has_lookup}} Queries memory queries = prepare_queries(vk, proof, state); + {{else}} + Queries memory queries = prepare_queries(vk, proof); + {{/if}} + queries.commitments_at_z[0] = quotient_result; queries.values_at_z[0] = proof.quotient_poly_opening_at_z; queries.commitments_at_z[1] = aggregated_linearization_commitment(vk, proof, state); @@ -599,12 +606,18 @@ contract Plonk4VerifierWithAccessToDNext { PairingsBn254.G1Point[{{num_commitments_at_z_omega}}] commitments_at_z_omega; PairingsBn254.Fr[{{num_commitments_at_z_omega}}] values_at_z_omega; } - + {{#if has_lookup}} function prepare_queries( VerificationKey memory vk, - Proof memory proof, + Proof memory proof, PartialVerifierState memory state - ) public view returns(Queries memory queries){ + ) public view returns(Queries memory queries) + {{else}} + function prepare_queries( + VerificationKey memory vk, + Proof memory proof + ) public pure returns(Queries memory queries) + {{/if}}{ // we set first two items in calee side so start idx from 2 uint256 idx = 2; for(uint256 i = 0; i diff --git a/crates/plonk-verifier-foundry/README.md b/crates/plonk-verifier-foundry/README.md new file mode 100644 index 0000000..efac030 --- /dev/null +++ b/crates/plonk-verifier-foundry/README.md @@ -0,0 +1,39 @@ +#

Forge Template

+ +**Template repository for getting started quickly with Foundry projects** + +![Github Actions](https://github.com/foundry-rs/forge-template/workflows/CI/badge.svg) + +## Getting Started + +Click "Use this template" on [GitHub](https://github.com/foundry-rs/forge-template) to create a new repository with this repo as the initial state. + +Or, if your repo already exists, run: +```sh +forge init +forge build +forge test +``` + +## Writing your first test + +All you need is to `import forge-std/Test.sol` and then inherit it from your test contract. Forge-std's Test contract comes with a pre-instatiated [cheatcodes environment](https://book.getfoundry.sh/cheatcodes/), the `vm`. It also has support for [ds-test](https://book.getfoundry.sh/reference/ds-test.html)-style logs and assertions. Finally, it supports Hardhat's [console.log](https://github.com/brockelmore/forge-std/blob/master/src/console.sol). The logging functionalities require `-vvvv`. + +```solidity +pragma solidity 0.8.10; + +import "forge-std/Test.sol"; + +contract ContractTest is Test { + function testExample() public { + vm.roll(100); + console.log(1); + emit log("hi"); + assertTrue(true); + } +} +``` + +## Development + +This project uses [Foundry](https://getfoundry.sh). See the [book](https://book.getfoundry.sh/getting-started/installation.html) for instructions on how to install and use Foundry. diff --git a/crates/plonk-verifier-foundry/bun.lockb b/crates/plonk-verifier-foundry/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..18290a2b4f788c6a0200c343d596201c79557adb GIT binary patch literal 28694 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 dIXZ2=!at@bK15}NhMI@5SRs;Q?f<#p{{a#A 0); + + PairingsBn254.Fr memory inputs_term = PairingsBn254.new_fr(0); + for(uint256 i =0; i < vk.num_inputs; i = i.uncheckedInc()) { + state.t = evaluate_lagrange_poly_out_of_domain(i, vk.domain_size, vk.omega, state.z); + state.t.mul_assign(PairingsBn254.new_fr(proof.input_values[i])); + inputs_term.add_assign(state.t); + } + + inputs_term.mul_assign(proof.gate_selectors_openings_at_z[0]); + + PairingsBn254.Fr memory result = proof.linearization_poly_opening_at_z.copy(); + result.add_assign(inputs_term); + + // compute powers of alpha + compute_powers_of_alpha(state); + PairingsBn254.Fr memory factor = state.alpha_values[4].copy(); + factor.mul_assign(proof.copy_permutation_grand_product_opening_at_z_omega); + + // - alpha_0 * (a + perm(z) * beta + gamma)*()*(d + gamma) * z(z*omega) + require(proof.copy_permutation_polys_openings_at_z.length == STATE_WIDTH-1); + PairingsBn254.Fr memory t; // TMP; + for(uint256 i = 0; i < proof.copy_permutation_polys_openings_at_z.length; i = i.uncheckedInc()){ + t = proof.copy_permutation_polys_openings_at_z[i].copy(); + t.mul_assign(state.beta); + t.add_assign(proof.state_polys_openings_at_z[i]); + t.add_assign(state.gamma); + + factor.mul_assign(t); + } + + t = proof.state_polys_openings_at_z[3].copy(); + t.add_assign(state.gamma); + factor.mul_assign(t); + result.sub_assign(factor); + + // - L_0(z) * alpha_1 + PairingsBn254.Fr memory l_0_at_z = evaluate_l0_at_point(vk.domain_size, state.z); + l_0_at_z.mul_assign(state.alpha_values[4 + 1]); + result.sub_assign(l_0_at_z); + + + + PairingsBn254.Fr memory lhs = proof.quotient_poly_opening_at_z.copy(); + lhs.mul_assign(evaluate_vanishing(vk.domain_size, state.z)); + return lhs.value == result.value; + } + + function aggregated_linearization_commitment(VerificationKey memory vk, Proof memory proof, PartialVerifierState memory state) internal view returns(PairingsBn254.G1Point memory result){ + // qMain*(Q_a * A + Q_b * B + Q_c * C + Q_d * D + Q_m * A*B + Q_const + Q_dNext * D_next) + result = PairingsBn254.new_g1(0, 0); + // Q_a * A + PairingsBn254.G1Point memory scaled = vk.gate_setup_commitments[0].point_mul(proof.state_polys_openings_at_z[0]); + result.point_add_assign(scaled); + // Q_b * B + scaled = vk.gate_setup_commitments[1].point_mul(proof.state_polys_openings_at_z[1]); + result.point_add_assign(scaled); + // Q_c * C + scaled = vk.gate_setup_commitments[2].point_mul(proof.state_polys_openings_at_z[2]); + result.point_add_assign(scaled); + // Q_d * D + scaled = vk.gate_setup_commitments[3].point_mul(proof.state_polys_openings_at_z[3]); + result.point_add_assign(scaled); + // Q_m* A*B or Q_ab*A*B + PairingsBn254.Fr memory t = proof.state_polys_openings_at_z[0].copy(); + t.mul_assign(proof.state_polys_openings_at_z[1]); + scaled = vk.gate_setup_commitments[4].point_mul(t); + result.point_add_assign(scaled); + + // Q_AC* A*C + t = proof.state_polys_openings_at_z[0].copy(); + t.mul_assign(proof.state_polys_openings_at_z[2]); + scaled = vk.gate_setup_commitments[5].point_mul(t); + result.point_add_assign(scaled); + + // Q_const + result.point_add_assign(vk.gate_setup_commitments[6]); + // Q_dNext * D_next + scaled = vk.gate_setup_commitments[7].point_mul(proof.state_polys_openings_at_z_omega[0]); + result.point_add_assign(scaled); + + result.point_mul_assign(proof.gate_selectors_openings_at_z[0]); + + PairingsBn254.G1Point memory rescue_custom_gate_linearization_contrib = rescue_custom_gate_linearization_contribution(vk, proof, state); + result.point_add_assign(rescue_custom_gate_linearization_contrib); + + require(vk.non_residues.length == STATE_WIDTH-1); + + PairingsBn254.Fr memory one = PairingsBn254.new_fr(1); + PairingsBn254.Fr memory factor = state.alpha_values[4].copy(); + for(uint256 i = 0; i < proof.state_polys_openings_at_z.length; ){ + t = state.z.copy(); + if(i == 0){ + t.mul_assign(one); + }else{ + t.mul_assign(vk.non_residues[i-1]); + } + t.mul_assign(state.beta); + t.add_assign(state.gamma); + t.add_assign(proof.state_polys_openings_at_z[i]); + + factor.mul_assign(t); + unchecked { + ++i; + } + } + + scaled = proof.copy_permutation_grand_product_commitment.point_mul(factor); + result.point_add_assign(scaled); + + // - (a(z) + beta*perm_a + gamma)*()*()*z(z*omega) * beta * perm_d(X) + factor = state.alpha_values[4].copy(); + factor.mul_assign(state.beta); + factor.mul_assign(proof.copy_permutation_grand_product_opening_at_z_omega); + for(uint256 i = 0; i < STATE_WIDTH-1; i = i.uncheckedInc()){ + t = proof.copy_permutation_polys_openings_at_z[i].copy(); + t.mul_assign(state.beta); + t.add_assign(state.gamma); + t.add_assign(proof.state_polys_openings_at_z[i]); + + factor.mul_assign(t); + } + scaled = vk.permutation_commitments[3].point_mul(factor); + result.point_sub_assign(scaled); + + // + L_0(z) * Z(x) + state.l_0_at_z = evaluate_lagrange_poly_out_of_domain(0, vk.domain_size, vk.omega, state.z); + require(state.l_0_at_z.value != 0); + factor = state.l_0_at_z.copy(); + factor.mul_assign(state.alpha_values[4 + 1]); + scaled = proof.copy_permutation_grand_product_commitment.point_mul(factor); + result.point_add_assign(scaled); + + + + } + + function rescue_custom_gate_linearization_contribution(VerificationKey memory vk, Proof memory proof, PartialVerifierState memory state) public view returns(PairingsBn254.G1Point memory result){ + PairingsBn254.Fr memory t; + PairingsBn254.Fr memory intermediate_result; + + // a^2 - b = 0 + t = proof.state_polys_openings_at_z[0].copy(); + t.mul_assign(t); + t.sub_assign(proof.state_polys_openings_at_z[1]); + // t.mul_assign(challenge1); + t.mul_assign(state.alpha_values[1]); + intermediate_result.add_assign(t); + + // b^2 - c = 0 + t = proof.state_polys_openings_at_z[1].copy(); + t.mul_assign(t); + t.sub_assign(proof.state_polys_openings_at_z[2]); + t.mul_assign(state.alpha_values[1+1]); + intermediate_result.add_assign(t); + + // c*a - d = 0; + t = proof.state_polys_openings_at_z[2].copy(); + t.mul_assign(proof.state_polys_openings_at_z[0]); + t.sub_assign(proof.state_polys_openings_at_z[3]); + t.mul_assign(state.alpha_values[1+2]); + intermediate_result.add_assign(t); + + result = vk.gate_selectors_commitments[1].point_mul(intermediate_result); + } + + + + + struct Queries { + PairingsBn254.G1Point[10] commitments_at_z; + PairingsBn254.Fr[10] values_at_z; + + PairingsBn254.G1Point[3] commitments_at_z_omega; + PairingsBn254.Fr[3] values_at_z_omega; + } + + function prepare_queries( + VerificationKey memory vk, + Proof memory proof + ) public pure returns(Queries memory queries) + { + // we set first two items in calee side so start idx from 2 + uint256 idx = 2; + for(uint256 i = 0; i=0.8.25 <0.9.0; +import {Proof} from "../src/Plonk4VerifierWithAccessToDNext.sol"; + +library HardcodedValues{ + function hardcoded_proof() internal pure returns(Proof memory proof){ + + proof.input_values[0] = 0x0000000000000000000000000000000000000000000000000000000000000002; + + + proof.state_polys_commitments[0].X = 0x125a96306030c34958b4ad672033277ea109a796adf28dc4976027a44c12ef22; + proof.state_polys_commitments[0].Y = 0x00946c4bb159e3d8576b2b0be5bf7b3fc0b61f1c2e72da4374f9f0ad26f293b7; + + proof.state_polys_commitments[1].X = 0x25bdc8e25058040ad05096a4fd2cd0a81cbad973deda5f7415840e6593439de9; + proof.state_polys_commitments[1].Y = 0x13d3fae4b771527d6283610904ee1c95f6d3e546ed861bd071f0c910af39d0e6; + + proof.state_polys_commitments[2].X = 0x0e0fb43d701a22c3fdd6670b69eca01b815ef2f6b3687191a4fb819d25c5e117; + proof.state_polys_commitments[2].Y = 0x22c377922737d710453e0e6efb6d8b5b6b6fc346f4bd811802db23d4f7fc8019; + + proof.state_polys_commitments[3].X = 0x2a0edd1ead0847b61d9b9e6e026c47a758afbe347ae119486b9ad1719f6c367d; + proof.state_polys_commitments[3].Y = 0x21e058312fc5a32072d821eadf55644320e7ca6e9ec236925edd632fc3ff463d; + + proof.copy_permutation_grand_product_commitment.X = 0x013bb8312203b14b634a689c6d4acef9d1f54e1068de1470e19279ede8bb991f; + proof.copy_permutation_grand_product_commitment.Y = 0x0c7b763a6bd20f6fd5295c9e85846c4b132b26bb5d5acf71bcb29ee2a42ed5be; + + proof.quotient_poly_parts_commitments[0].X = 0x1837c3c200f0aebb25d7e1a2af2685892fc0c701433996b3b80953505f4efd9c; + proof.quotient_poly_parts_commitments[0].Y = 0x1a9e03970fbb2ad6876f0f0bae91097eb19ac3face44eaae4396fc16ab9116ad; + + proof.quotient_poly_parts_commitments[1].X = 0x060df9de261271340128c4b3c77b2a41178e5b87db2355d3fe1930823abe56ac; + proof.quotient_poly_parts_commitments[1].Y = 0x022f38e477d4a7a8ad6d91d56443d53628bbfc2b5d48e577f8a28bbd0f9a90a7; + + proof.quotient_poly_parts_commitments[2].X = 0x1af9ec6291b5a9da75e943391bcd283a51cc8a7c1a4825c01395e6b840bd16b4; + proof.quotient_poly_parts_commitments[2].Y = 0x12b652f3ffe11917e28cd4731156df8a8143299d19c9a333a99e41e666c1baee; + + proof.quotient_poly_parts_commitments[3].X = 0x0daad57410d2430d709a9d5904c892b45189012336a110e6d89cf670d15a0b31; + proof.quotient_poly_parts_commitments[3].Y = 0x2c064d6c18d55c0d370f56cbb0548e21f7866f02a52e63ec774805f32bf5c0f0; + + + proof.opening_proof_at_z.X = 0x0d63c1990dcd7716af77977ce95bc0985cd416ca76bb65aebed69c79e85ae67f; + proof.opening_proof_at_z.Y = 0x11e0cd7c46cf5343986e816559536280ffcc362957c9074aa6b0cbce69cfd1a5; + proof.opening_proof_at_z_omega.X = 0x0c4d652ff36b77dc918b8df517d13a95c2150fd3163e03b19480bf733a6fdc39; + proof.opening_proof_at_z_omega.Y = 0x20ded5c2838da911842c0ca7e65095623e3d8e2dd177fc58377119834084022b; + + + proof.state_polys_openings_at_z[0].value = 0x260fb5a68c251e1d5fb776f1ae703a8c5e98ceb86cd57cfd03314b3a2dd78e44; + + proof.state_polys_openings_at_z[1].value = 0x22ca21b7257fb02fd9709e2c71c074e4fd8b2d3fbd969c2dc4624be529fd7cb2; + + proof.state_polys_openings_at_z[2].value = 0x1dc0e5fd84d3254929882dae104a0aa024caac4732894dedd1abb620c7d9f70a; + + proof.state_polys_openings_at_z[3].value = 0x28ae354f4b84775ea856462e682fda6e3489082b380423daadc97ed741a39eb9; + + + proof.state_polys_openings_at_z_omega[0].value = 0x2f926ea1197a008ab9a586b00063fd9a1c61627211d62932780ef7b3ff9c58dd; + + + proof.gate_selectors_openings_at_z[0].value = 0x0a6bf79bcd59025be43d0a022107876cf6adf94eb907448727c43ac75ec3c94e; + + + proof.copy_permutation_polys_openings_at_z[0].value = 0x2067b179640d9fbca42c4814286b9211e4de99fa74dcbf892d9cc88ae9b13bf9; + + proof.copy_permutation_polys_openings_at_z[1].value = 0x2094e6d2b8ae0afa2e548e05d3fda117da3e595a78f2818d54406627e85e69f6; + + proof.copy_permutation_polys_openings_at_z[2].value = 0x2c4b1065f0312db8067a3a627e06a07a72dbbcaadea183f7ab12b3cabc6611d8; + + proof.copy_permutation_grand_product_opening_at_z_omega.value = 0x06856e549033f929f5e4433bb0d2f7c80b2c27ce5c84cbb6745d315ea2db10a7; + proof.quotient_poly_opening_at_z.value = 0x201be4dd1d31bd3e0677b63dd095f21ecd194c240f9cbdb776ac3318fa1287cf; + proof.linearization_poly_opening_at_z.value = 0x02935a5e887039918f79ed4e98be063a48c6af224f8cbfde3e52ea936e524a6f; + + } + + function hardcoded_serialized_proof() public pure returns(uint256[] memory serializedInputs, uint256[] memory serializedProof){ + serializedInputs = new uint256[](1); + + serializedInputs[0] = 0x0000000000000000000000000000000000000000000000000000000000000002; + + serializedProof = new uint256[](34); + + serializedProof[0] = 0x125a96306030c34958b4ad672033277ea109a796adf28dc4976027a44c12ef22; + + serializedProof[1] = 0x00946c4bb159e3d8576b2b0be5bf7b3fc0b61f1c2e72da4374f9f0ad26f293b7; + + serializedProof[2] = 0x25bdc8e25058040ad05096a4fd2cd0a81cbad973deda5f7415840e6593439de9; + + serializedProof[3] = 0x13d3fae4b771527d6283610904ee1c95f6d3e546ed861bd071f0c910af39d0e6; + + serializedProof[4] = 0x0e0fb43d701a22c3fdd6670b69eca01b815ef2f6b3687191a4fb819d25c5e117; + + serializedProof[5] = 0x22c377922737d710453e0e6efb6d8b5b6b6fc346f4bd811802db23d4f7fc8019; + + serializedProof[6] = 0x2a0edd1ead0847b61d9b9e6e026c47a758afbe347ae119486b9ad1719f6c367d; + + serializedProof[7] = 0x21e058312fc5a32072d821eadf55644320e7ca6e9ec236925edd632fc3ff463d; + + serializedProof[8] = 0x013bb8312203b14b634a689c6d4acef9d1f54e1068de1470e19279ede8bb991f; + + serializedProof[9] = 0x0c7b763a6bd20f6fd5295c9e85846c4b132b26bb5d5acf71bcb29ee2a42ed5be; + + serializedProof[10] = 0x1837c3c200f0aebb25d7e1a2af2685892fc0c701433996b3b80953505f4efd9c; + + serializedProof[11] = 0x1a9e03970fbb2ad6876f0f0bae91097eb19ac3face44eaae4396fc16ab9116ad; + + serializedProof[12] = 0x060df9de261271340128c4b3c77b2a41178e5b87db2355d3fe1930823abe56ac; + + serializedProof[13] = 0x022f38e477d4a7a8ad6d91d56443d53628bbfc2b5d48e577f8a28bbd0f9a90a7; + + serializedProof[14] = 0x1af9ec6291b5a9da75e943391bcd283a51cc8a7c1a4825c01395e6b840bd16b4; + + serializedProof[15] = 0x12b652f3ffe11917e28cd4731156df8a8143299d19c9a333a99e41e666c1baee; + + serializedProof[16] = 0x0daad57410d2430d709a9d5904c892b45189012336a110e6d89cf670d15a0b31; + + serializedProof[17] = 0x2c064d6c18d55c0d370f56cbb0548e21f7866f02a52e63ec774805f32bf5c0f0; + + serializedProof[18] = 0x260fb5a68c251e1d5fb776f1ae703a8c5e98ceb86cd57cfd03314b3a2dd78e44; + + serializedProof[19] = 0x22ca21b7257fb02fd9709e2c71c074e4fd8b2d3fbd969c2dc4624be529fd7cb2; + + serializedProof[20] = 0x1dc0e5fd84d3254929882dae104a0aa024caac4732894dedd1abb620c7d9f70a; + + serializedProof[21] = 0x28ae354f4b84775ea856462e682fda6e3489082b380423daadc97ed741a39eb9; + + serializedProof[22] = 0x2f926ea1197a008ab9a586b00063fd9a1c61627211d62932780ef7b3ff9c58dd; + + serializedProof[23] = 0x0a6bf79bcd59025be43d0a022107876cf6adf94eb907448727c43ac75ec3c94e; + + serializedProof[24] = 0x2067b179640d9fbca42c4814286b9211e4de99fa74dcbf892d9cc88ae9b13bf9; + + serializedProof[25] = 0x2094e6d2b8ae0afa2e548e05d3fda117da3e595a78f2818d54406627e85e69f6; + + serializedProof[26] = 0x2c4b1065f0312db8067a3a627e06a07a72dbbcaadea183f7ab12b3cabc6611d8; + + serializedProof[27] = 0x06856e549033f929f5e4433bb0d2f7c80b2c27ce5c84cbb6745d315ea2db10a7; + + serializedProof[28] = 0x201be4dd1d31bd3e0677b63dd095f21ecd194c240f9cbdb776ac3318fa1287cf; + + serializedProof[29] = 0x02935a5e887039918f79ed4e98be063a48c6af224f8cbfde3e52ea936e524a6f; + + serializedProof[30] = 0x0d63c1990dcd7716af77977ce95bc0985cd416ca76bb65aebed69c79e85ae67f; + + serializedProof[31] = 0x11e0cd7c46cf5343986e816559536280ffcc362957c9074aa6b0cbce69cfd1a5; + + serializedProof[32] = 0x0c4d652ff36b77dc918b8df517d13a95c2150fd3163e03b19480bf733a6fdc39; + + serializedProof[33] = 0x20ded5c2838da911842c0ca7e65095623e3d8e2dd177fc58377119834084022b; + + } +} diff --git a/crates/plonk-verifier-foundry/test/Plonk.T.sol b/crates/plonk-verifier-foundry/test/Plonk.T.sol new file mode 100644 index 0000000..f75cd93 --- /dev/null +++ b/crates/plonk-verifier-foundry/test/Plonk.T.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.25 <0.9.0; + +import {Test, console} from "forge-std/src/Test.sol"; +import {Verifier} from "../src/Verifier.sol"; +import {HardcodedValues} from "./HardcodedValues.sol"; + +contract VerifierTest is Verifier { + Verifier public _verifier; + + function setUp() public { + _verifier = new Verifier(); + } + + function test1FullProtocol() public view { + uint256 _g0 = gasleft(); + ( + uint256[] memory serializedInputs, + uint256[] memory serializedProof + ) = HardcodedValues.hardcoded_serialized_proof(); + bool valid = verify_serialized_proof_helper( + serializedInputs, + serializedProof + ); + uint256 _g1 = gasleft(); + require(valid, "proof is valid"); + console.log("test8FullProtocol gas cost: %d", _g0 - _g1); + } + + function verify_serialized_proof_helper( + uint256[] memory serializedInputs, + uint256[] memory serializedProof + ) public view returns (bool) { + console.log("verifying proof"); + return this.verify_serialized_proof(serializedInputs, serializedProof); + } +} diff --git a/crates/plonk-verifier-foundry/tsconfig.json b/crates/plonk-verifier-foundry/tsconfig.json new file mode 100644 index 0000000..238655f --- /dev/null +++ b/crates/plonk-verifier-foundry/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} diff --git a/scripts/plonk-verifier/run-tests.sh b/scripts/plonk-verifier/run-tests.sh new file mode 100755 index 0000000..7e3871e --- /dev/null +++ b/scripts/plonk-verifier/run-tests.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# set -e + +# install foundry + +if [[ ! -d $HOME/.foundry/bin ]]; then + curl -L https://foundry.paradigm.xyz | bash + . $HOME/.foundry/bin/foundryup +fi + +# run reference test first +PLONK_VERIFIER_DATA_DIR=$PWD/data/plonk-verifier +mkdir -p $PLONK_VERIFIER_DATA_DIR +cargo run --bin generate -- --verification-key $PLONK_VERIFIER_DATA_DIR/reference_block_20_keccak.key --proof $PLONK_VERIFIER_DATA_DIR/reference_block_20_keccak.proof +cd - +cd crates/plonk-verifier-foundry +$HOME/.foundry/bin/forge test +cd - + +# then check sample proofs and vks +mkdir -p $PLONK_VERIFIER_DATA_DIR/std +rm -rf $PLONK_VERIFIER_DATA_DIR/std/* +mkdir -p $PLONK_VERIFIER_DATA_DIR/optimized +rm -rf $PLONK_VERIFIER_DATA_DIR/optimized/* + +cd crates/plonk-verifier-codegen +PLONK_VERIFIER_DATA_DIR=$PLONK_VERIFIER_DATA_DIR cargo test test_create_proof_for_all_circuits --release -- --nocapture +cd - + +for main_gate in "std" "optimized" +do + for vk_file in $(ls $PLONK_VERIFIER_DATA_DIR/$main_gate/*_vk.json) + do + proof_file=$(echo $vk_file | sed s/_vk/_proof/g) + + cargo run --bin generate -- --encoding json --verification-key $vk_file --proof $proof_file + cd crates/plonk-verifier-foundry + $HOME/.foundry/bin/forge test + cd - + done +done From 43b992dd0fa0ac11ab6abbb4a71ac4c71813b960 Mon Sep 17 00:00:00 2001 From: saitima Date: Thu, 15 Aug 2024 23:59:32 +0300 Subject: [PATCH 2/3] cargo fmt --- crates/plonk-verifier-codegen/src/circuits.rs | 137 ++----- crates/plonk-verifier-codegen/src/generate.rs | 371 ++++-------------- crates/plonk-verifier-codegen/src/lib.rs | 19 +- .../plonk-verifier-codegen/src/serialize.rs | 10 +- 4 files changed, 116 insertions(+), 421 deletions(-) diff --git a/crates/plonk-verifier-codegen/src/circuits.rs b/crates/plonk-verifier-codegen/src/circuits.rs index 2a90cc8..f5a95db 100644 --- a/crates/plonk-verifier-codegen/src/circuits.rs +++ b/crates/plonk-verifier-codegen/src/circuits.rs @@ -5,10 +5,8 @@ use rescue_poseidon::franklin_crypto::{ plonk::{ better_better_cs::{ cs::{ - ArithmeticTerm, Circuit, ConstraintSystem, Gate, GateInternal, - LookupTableApplication, MainGate, MainGateTerm, PlonkConstraintSystemParams, - PlonkCsWidth4WithNextStepAndCustomGatesParams, PlonkCsWidth4WithNextStepParams, - PolyIdentifier, TrivialAssembly, VerificationKey, Width4MainGateWithDNext, + ArithmeticTerm, Circuit, ConstraintSystem, Gate, GateInternal, LookupTableApplication, MainGate, MainGateTerm, PlonkConstraintSystemParams, + PlonkCsWidth4WithNextStepAndCustomGatesParams, PlonkCsWidth4WithNextStepParams, PolyIdentifier, TrivialAssembly, VerificationKey, Width4MainGateWithDNext, }, gates::selector_optimized_with_d_next::SelectorOptimizedWidth4MainGateWithDNext, proof::Proof, @@ -72,27 +70,22 @@ macro_rules! circuit_inner { macro_rules! circuit { ($id:ident, $main_gate:ty) => { circuit_inner!($id, $main_gate, false, inner_circuit_main_gate_part); - paste!{ + paste! { circuit_inner!([<$id WithLookup>], $main_gate, false, inner_circuit_lookup_part); } - paste!{ + paste! { circuit_inner!([<$id WithRescue>], $main_gate, true, inner_circuit_rescue_part); } - paste!{ + paste! { circuit_inner!([<$id WithLookupAndRescue>], $main_gate, true, inner_circuit_lookup_part, inner_circuit_rescue_part); } - } + }; } circuit!(MockCircuit, Width4MainGateWithDNext); -circuit!( - MockCircuitSelectorOptimized, - SelectorOptimizedWidth4MainGateWithDNext -); - -fn inner_circuit_main_gate_part>( - cs: &mut CS, -) -> Result<(), SynthesisError> { +circuit!(MockCircuitSelectorOptimized, SelectorOptimizedWidth4MainGateWithDNext); + +fn inner_circuit_main_gate_part>(cs: &mut CS) -> Result<(), SynthesisError> { for _ in 0..32 { let a = Num::alloc(cs, Some(E::Fr::one()))?; let b = Num::alloc(cs, Some(E::Fr::zero()))?; @@ -119,25 +112,17 @@ fn inner_circuit_main_gate_part>( let mut term = MainGateTerm::::new(); term.add_assign(ArithmeticTerm::from_variable(expected)); - term.sub_assign(ArithmeticTerm::from_variable( - actual.get_variable().get_variable(), - )); + term.sub_assign(ArithmeticTerm::from_variable(actual.get_variable().get_variable())); cs.allocate_main_gate(term)?; Ok(()) } -fn inner_circuit_lookup_part>( - cs: &mut CS, -) -> Result<(), SynthesisError> { +fn inner_circuit_lookup_part>(cs: &mut CS) -> Result<(), SynthesisError> { // add dummy lookup table queries let dummy = CS::get_dummy_variable(); // need to create a table (any) - let columns = vec![ - PolyIdentifier::VariablesPolynomial(0), - PolyIdentifier::VariablesPolynomial(1), - PolyIdentifier::VariablesPolynomial(2), - ]; + let columns = vec![PolyIdentifier::VariablesPolynomial(0), PolyIdentifier::VariablesPolynomial(1), PolyIdentifier::VariablesPolynomial(2)]; let range_table = LookupTableApplication::new_range_table_of_width_3(2, columns.clone())?; let _range_table_name = range_table.functional_name(); @@ -182,9 +167,7 @@ fn inner_circuit_lookup_part>( Ok(()) } -fn inner_circuit_rescue_part>( - cs: &mut CS, -) -> Result<(), SynthesisError> { +fn inner_circuit_rescue_part>(cs: &mut CS) -> Result<(), SynthesisError> { // make single rescue hash to satisfy gate requirements of declaration let mut params = RescueParams::default(); params.use_custom_gate(CustomGate::QuinticWidth4); @@ -200,83 +183,32 @@ fn test_create_proof_for_all_circuits() { type T = RollingKeccakTranscript; let base_dir = std::env::var("PLONK_VERIFIER_DATA_DIR").expect("output dir for output files"); - let out_dir = format!( - "{}/std", - base_dir, - ); + let out_dir = format!("{}/std", base_dir,); println!("out dir {}", out_dir); println!("Std main gate"); - create_proof_for_circuit::<_, PlonkCsWidth4WithNextStepParams, Width4MainGateWithDNext, T>( - MockCircuit {}, - &format!("{}/std", &out_dir), - ); + create_proof_for_circuit::<_, PlonkCsWidth4WithNextStepParams, Width4MainGateWithDNext, T>(MockCircuit {}, &format!("{}/std", &out_dir)); println!("Std main gate with lookup"); - create_proof_for_circuit::<_, PlonkCsWidth4WithNextStepParams, Width4MainGateWithDNext, T>( - MockCircuitWithLookup {}, - &format!("{}/std_with_lookup", &out_dir), - ); + create_proof_for_circuit::<_, PlonkCsWidth4WithNextStepParams, Width4MainGateWithDNext, T>(MockCircuitWithLookup {}, &format!("{}/std_with_lookup", &out_dir)); println!("Std main gate with sbox custom gate"); - create_proof_for_circuit::< - _, - PlonkCsWidth4WithNextStepAndCustomGatesParams, - Width4MainGateWithDNext, - T, - >( - MockCircuitWithRescue {}, - &format!("{}/std_with_rescue", &out_dir), - ); + create_proof_for_circuit::<_, PlonkCsWidth4WithNextStepAndCustomGatesParams, Width4MainGateWithDNext, T>(MockCircuitWithRescue {}, &format!("{}/std_with_rescue", &out_dir)); println!("Std main gate with lookup and sbox custom gate"); - create_proof_for_circuit::< - _, - PlonkCsWidth4WithNextStepAndCustomGatesParams, - Width4MainGateWithDNext, - T, - >( - MockCircuitWithLookupAndRescue {}, - &format!("{}/std_with_lookup_and_rescue", &out_dir), - ); + create_proof_for_circuit::<_, PlonkCsWidth4WithNextStepAndCustomGatesParams, Width4MainGateWithDNext, T>(MockCircuitWithLookupAndRescue {}, &format!("{}/std_with_lookup_and_rescue", &out_dir)); - let out_dir = format!( - "{}/optimized", - base_dir, - ); + let out_dir = format!("{}/optimized", base_dir,); println!("SelectorOptimized main gate"); - create_proof_for_circuit::< - _, - PlonkCsWidth4WithNextStepAndCustomGatesParams, - SelectorOptimizedWidth4MainGateWithDNext, - T, - >( - MockCircuitSelectorOptimized {}, - &format!("{}/optimized", &out_dir), - ); + create_proof_for_circuit::<_, PlonkCsWidth4WithNextStepAndCustomGatesParams, SelectorOptimizedWidth4MainGateWithDNext, T>(MockCircuitSelectorOptimized {}, &format!("{}/optimized", &out_dir)); println!("SelectorOptimized main gate with lookup"); - create_proof_for_circuit::< - _, - PlonkCsWidth4WithNextStepAndCustomGatesParams, - SelectorOptimizedWidth4MainGateWithDNext, - T, - >( + create_proof_for_circuit::<_, PlonkCsWidth4WithNextStepAndCustomGatesParams, SelectorOptimizedWidth4MainGateWithDNext, T>( MockCircuitSelectorOptimizedWithLookup {}, &format!("{}/optimized_with_lookup", &out_dir), ); println!("SelectorOptimized main gate with sbox custom gate"); - create_proof_for_circuit::< - _, - PlonkCsWidth4WithNextStepAndCustomGatesParams, - SelectorOptimizedWidth4MainGateWithDNext, - T, - >( + create_proof_for_circuit::<_, PlonkCsWidth4WithNextStepAndCustomGatesParams, SelectorOptimizedWidth4MainGateWithDNext, T>( MockCircuitSelectorOptimizedWithRescue {}, &format!("{}/optimized_with_rescue", &out_dir), ); println!("SelectorOptimized main gate with lookup and sbox custom gate"); - create_proof_for_circuit::< - _, - PlonkCsWidth4WithNextStepAndCustomGatesParams, - SelectorOptimizedWidth4MainGateWithDNext, - T, - >( + create_proof_for_circuit::<_, PlonkCsWidth4WithNextStepAndCustomGatesParams, SelectorOptimizedWidth4MainGateWithDNext, T>( MockCircuitSelectorOptimizedWithLookupAndRescue {}, &format!("{}/optimized_with_lookup_and_rescue", &out_dir), ); @@ -285,10 +217,8 @@ fn test_create_proof_for_all_circuits() { fn init_crs(worker: &Worker, domain_size: usize) -> Crs { let mon_crs = if let Ok(crs_file_path) = std::env::var("CRS_FILE") { println!("using crs file at {crs_file_path}"); - let crs_file = - std::fs::File::open(&crs_file_path).expect(&format!("crs file at {}", crs_file_path)); - let mon_crs = Crs::::read(crs_file) - .expect(&format!("read crs file at {}", crs_file_path)); + let crs_file = std::fs::File::open(&crs_file_path).expect(&format!("crs file at {}", crs_file_path)); + let mon_crs = Crs::::read(crs_file).expect(&format!("read crs file at {}", crs_file_path)); assert!(domain_size <= mon_crs.g1_bases.len()); mon_crs @@ -299,12 +229,7 @@ fn init_crs(worker: &Worker, domain_size: usize) -> Crs, - P: PlonkConstraintSystemParams + 'static, - MG: MainGate, - T: Transcript, ->( +fn create_proof_for_circuit, P: PlonkConstraintSystemParams + 'static, MG: MainGate, T: Transcript>( circuit: C, out_dir: &str, ) -> (VerificationKey, Proof) { @@ -325,20 +250,14 @@ fn create_proof_for_circuit< let vk = VerificationKey::from_setup(&setup, &worker, &crs).expect("vk from setup"); println!("Generating proof"); - let proof = assembly - .create_proof::(&worker, &setup, &crs, None) - .expect("proof"); + let proof = assembly.create_proof::(&worker, &setup, &crs, None).expect("proof"); save_proof_and_vk_into_file(&proof, &vk, &out_dir); (vk, proof) } -pub fn save_proof_and_vk_into_file>( - proof: &Proof, - vk: &VerificationKey, - output_path: &str, -) { +pub fn save_proof_and_vk_into_file>(proof: &Proof, vk: &VerificationKey, output_path: &str) { let proof_file_path = format!("{}_proof.json", output_path); let proof_file = std::fs::File::create(&proof_file_path).unwrap(); serde_json::to_writer(proof_file, &proof).unwrap(); diff --git a/crates/plonk-verifier-codegen/src/generate.rs b/crates/plonk-verifier-codegen/src/generate.rs index ef0ae85..f384c8b 100644 --- a/crates/plonk-verifier-codegen/src/generate.rs +++ b/crates/plonk-verifier-codegen/src/generate.rs @@ -20,9 +20,8 @@ use std::path::PathBuf; use serde::ser::Serialize; use crate::circuits::{ - MockCircuitSelectorOptimized, MockCircuitSelectorOptimizedWithLookup, - MockCircuitSelectorOptimizedWithLookupAndRescue, MockCircuitSelectorOptimizedWithRescue, - MockCircuitWithLookup, MockCircuitWithLookupAndRescue, MockCircuitWithRescue, + MockCircuitSelectorOptimized, MockCircuitSelectorOptimizedWithLookup, MockCircuitSelectorOptimizedWithLookupAndRescue, MockCircuitSelectorOptimizedWithRescue, MockCircuitWithLookup, + MockCircuitWithLookupAndRescue, MockCircuitWithRescue, }; use crate::{ circuits::MockCircuit, @@ -53,19 +52,12 @@ pub enum Encoding { // Generally it is okey to use MockCircuit in type definitions // and then transmute it to the corresponding type of circuit // by inspecting some values -pub fn generate( - vk_path: PathBuf, - proof_path: Option, - output_dir: PathBuf, - encoding_type: Encoding, - mut template_files_path: Vec<&str>, -) { +pub fn generate(vk_path: PathBuf, proof_path: Option, output_dir: PathBuf, encoding_type: Encoding, mut template_files_path: Vec<&str>) { let mut reader = std::fs::File::open(vk_path).expect("vk file"); let vk = match encoding_type { Encoding::Json => serde_json::from_reader(reader).expect("read vk from json encoded data"), - Encoding::Default => VerificationKey::::read(&mut reader) - .expect("read vk from default encoded data"), + Encoding::Default => VerificationKey::::read(&mut reader).expect("read vk from default encoded data"), }; // we know from the fact that vk belongs to a @@ -81,11 +73,7 @@ pub fn generate( }; let has_rescue_custom_gate = if vk.gate_selectors_commitments.len() > 1 { - assert_eq!( - vk.gate_selectors_commitments.len(), - 2, - "only sbox custom gate is supported" - ); + assert_eq!(vk.gate_selectors_commitments.len(), 2, "only sbox custom gate is supported"); true } else { assert!(vk.gate_selectors_commitments.is_empty()); @@ -104,30 +92,25 @@ pub fn generate( false }; - let (num_main_gate_selectors, ab_coeff_idx, constant_coeff_idx, d_next_coeff_idx, ac_coeff_idx) = - match main_gate { - MainGateType::Standard => ( - 7, - Width4MainGateWithDNext::AB_MULTIPLICATION_TERM_COEFF_INDEX, - Width4MainGateWithDNext::CONSTANT_TERM_COEFF_INDEX, - Width4MainGateWithDNext::D_NEXT_TERM_COEFF_INDEX, - None, - ), - MainGateType::SelectorOptimized => ( - 8, - SelectorOptimizedWidth4MainGateWithDNext::AB_MULTIPLICATION_TERM_COEFF_INDEX, - SelectorOptimizedWidth4MainGateWithDNext::CONSTANT_TERM_COEFF_INDEX, - SelectorOptimizedWidth4MainGateWithDNext::D_NEXT_TERM_COEFF_INDEX, - Some(SelectorOptimizedWidth4MainGateWithDNext::AC_MULTIPLICATION_TERM_COEFF_INDEX), - ), - }; + let (num_main_gate_selectors, ab_coeff_idx, constant_coeff_idx, d_next_coeff_idx, ac_coeff_idx) = match main_gate { + MainGateType::Standard => ( + 7, + Width4MainGateWithDNext::AB_MULTIPLICATION_TERM_COEFF_INDEX, + Width4MainGateWithDNext::CONSTANT_TERM_COEFF_INDEX, + Width4MainGateWithDNext::D_NEXT_TERM_COEFF_INDEX, + None, + ), + MainGateType::SelectorOptimized => ( + 8, + SelectorOptimizedWidth4MainGateWithDNext::AB_MULTIPLICATION_TERM_COEFF_INDEX, + SelectorOptimizedWidth4MainGateWithDNext::CONSTANT_TERM_COEFF_INDEX, + SelectorOptimizedWidth4MainGateWithDNext::D_NEXT_TERM_COEFF_INDEX, + Some(SelectorOptimizedWidth4MainGateWithDNext::AC_MULTIPLICATION_TERM_COEFF_INDEX), + ), + }; let is_selector_optimized_main_gate = ac_coeff_idx.is_some(); - let ac_coeff_idx = if let Some(coeff) = ac_coeff_idx { - coeff - } else { - 0 - }; + let ac_coeff_idx = if let Some(coeff) = ac_coeff_idx { coeff } else { 0 }; let vars = TemplateVars { has_rescue_custom_gate, @@ -147,28 +130,15 @@ pub fn generate( if let Some(proof_path) = proof_path { let mut reader = std::fs::File::open(proof_path).expect("proof file"); let proof = match encoding_type { - Encoding::Json => { - serde_json::from_reader(reader).expect("read proof from json encoded data") - } - Encoding::Default => Proof::::read(&mut reader) - .expect("read proof from default encoded data"), + Encoding::Json => serde_json::from_reader(reader).expect("read proof from json encoded data"), + Encoding::Default => Proof::::read(&mut reader).expect("read proof from default encoded data"), }; unsafe { verify_proof(&vk, &proof, main_gate) }; - render_expected_proofs( - proof, - proof_template_dir, - &output_dir, - has_rescue_custom_gate, - has_lookup, - ); + render_expected_proofs(proof, proof_template_dir, &output_dir, has_rescue_custom_gate, has_lookup); } } -unsafe fn verify_proof( - vk: &VerificationKey, - proof: &Proof, - main_gate_type: MainGateType, -) { +unsafe fn verify_proof(vk: &VerificationKey, proof: &Proof, main_gate_type: MainGateType) { use rescue_poseidon::franklin_crypto::bellman::plonk::better_better_cs::verifier::verify; assert_eq!(vk.n, proof.n); @@ -177,89 +147,40 @@ unsafe fn verify_proof( let has_lookup = vk.total_lookup_entries_length > 0; assert_eq!(has_lookup, proof.lookup_grand_product_commitment.is_some()); assert_eq!(has_lookup, proof.lookup_s_poly_commitment.is_some()); - assert_eq!( - has_lookup, - proof.lookup_grand_product_opening_at_z_omega.is_some() - ); + assert_eq!(has_lookup, proof.lookup_grand_product_opening_at_z_omega.is_some()); assert_eq!(has_lookup, proof.lookup_s_poly_opening_at_z_omega.is_some()); - assert_eq!( - has_lookup, - proof.lookup_selector_poly_opening_at_z.is_some() - ); + assert_eq!(has_lookup, proof.lookup_selector_poly_opening_at_z.is_some()); assert_eq!(has_lookup, proof.lookup_t_poly_opening_at_z.is_some()); assert_eq!(has_lookup, proof.lookup_t_poly_opening_at_z_omega.is_some()); - assert_eq!( - has_lookup, - proof.lookup_table_type_poly_opening_at_z.is_some() - ); + assert_eq!(has_lookup, proof.lookup_table_type_poly_opening_at_z.is_some()); let has_custom_gate = vk.gate_selectors_commitments.len() > 0; let is_valid = match main_gate_type { MainGateType::Standard => { if !has_lookup && !has_custom_gate { - verify::>( - std::mem::transmute(vk), - std::mem::transmute(proof), - None, - ) - .unwrap() + verify::>(std::mem::transmute(vk), std::mem::transmute(proof), None).unwrap() } else if has_lookup && !has_custom_gate { - verify::>( - std::mem::transmute(vk), - std::mem::transmute(proof), - None, - ) - .unwrap() + verify::>(std::mem::transmute(vk), std::mem::transmute(proof), None).unwrap() } else if has_custom_gate && !has_lookup { - verify::>( - std::mem::transmute(vk), - std::mem::transmute(proof), - None, - ) - .unwrap() + verify::>(std::mem::transmute(vk), std::mem::transmute(proof), None).unwrap() } else { assert!(has_lookup); assert!(has_custom_gate); - verify::>( - std::mem::transmute(vk), - std::mem::transmute(proof), - None, - ) - .unwrap() + verify::>(std::mem::transmute(vk), std::mem::transmute(proof), None).unwrap() } } MainGateType::SelectorOptimized => { if !has_lookup && !has_custom_gate { - verify::>( - std::mem::transmute(vk), - std::mem::transmute(proof), - None, - ) - .unwrap() + verify::>(std::mem::transmute(vk), std::mem::transmute(proof), None).unwrap() } else if has_lookup && !has_custom_gate { - verify::< - Bn256, - MockCircuitSelectorOptimizedWithLookup, - RollingKeccakTranscript, - >(std::mem::transmute(vk), std::mem::transmute(proof), None) - .unwrap() + verify::>(std::mem::transmute(vk), std::mem::transmute(proof), None).unwrap() } else if has_custom_gate && !has_lookup { - verify::< - Bn256, - MockCircuitSelectorOptimizedWithRescue, - RollingKeccakTranscript, - >(std::mem::transmute(vk), std::mem::transmute(proof), None) - .unwrap() + verify::>(std::mem::transmute(vk), std::mem::transmute(proof), None).unwrap() } else { assert!(has_lookup); assert!(has_custom_gate); - verify::< - Bn256, - MockCircuitSelectorOptimizedWithLookupAndRescue, - RollingKeccakTranscript, - >(std::mem::transmute(vk), std::mem::transmute(proof), None) - .unwrap() + verify::>(std::mem::transmute(vk), std::mem::transmute(proof), None).unwrap() } } }; @@ -267,13 +188,7 @@ unsafe fn verify_proof( assert!(is_valid, "proof verification failed at codegen"); } -fn length_of_serialized_proof_from_vk( - vk: &VerificationKey, - has_custom_gate: bool, - has_lookup: bool, - has_dnext: bool, - quotient_degree: usize, -) -> usize { +fn length_of_serialized_proof_from_vk(vk: &VerificationKey, has_custom_gate: bool, has_lookup: bool, has_dnext: bool, quotient_degree: usize) -> usize { assert_eq!(vk.state_width, quotient_degree); let mut num_commitments = vk.state_width; // trace @@ -325,30 +240,14 @@ fn compute_quotient_degree(state_width: usize, has_custom_gate: bool, has_lookup let lookup_quotient_degree = if has_lookup { 2 } else { 0 }; - [ - main_gate_quotient_degree, - copy_perm_quotient_degree, - lookup_quotient_degree, - ] - .iter() - .cloned() - .max() - .unwrap() + [main_gate_quotient_degree, copy_perm_quotient_degree, lookup_quotient_degree].iter().cloned().max().unwrap() } -fn render_verifier( - vars: TemplateVars, - vk: &VerificationKey, - output_dir: &PathBuf, - template_files_path: &[&str], -) { +fn render_verifier(vars: TemplateVars, vk: &VerificationKey, output_dir: &PathBuf, template_files_path: &[&str]) { let mut map = MapWrapper::new(); let mut handlebars = Handlebars::new(); - map.insert( - "is_selector_optimized_main_gate", - vars.is_selector_optimized_main_gate, - ); + map.insert("is_selector_optimized_main_gate", vars.is_selector_optimized_main_gate); // main gate + custom rescue map.insert("has_lookup", vars.has_lookup); map.insert("has_rescue_custom_gate", vars.has_rescue_custom_gate); @@ -357,10 +256,7 @@ fn render_verifier( map.insert("D_NEXT_TERM_COEFF_INDEX", vars.d_next_coeff_idx); assert_eq!(vars.ab_coeff_idx, 4); map.insert("MAIN_GATE_AC_COEFF_IDX", vars.ac_coeff_idx); - assert_eq!( - vk.gate_setup_commitments.len(), - vars.num_main_gate_selectors - ); + assert_eq!(vk.gate_setup_commitments.len(), vars.num_main_gate_selectors); map.insert("NUM_MAIN_GATE_SELECTORS", vars.num_main_gate_selectors); // a, b, c, d println!("VK STATE WIDTH {}", vk.state_width); @@ -368,15 +264,8 @@ fn render_verifier( map.insert("DNEXT_INDEX", vk.state_width - 1); map.insert("NUM_G2_ELS", vk.g2_elements.len()); map.insert("NUM_LOOKUP_TABLES", vk.lookup_tables_commitments.len()); - let quotient_degree = - compute_quotient_degree(vk.state_width, vars.has_rescue_custom_gate, vars.has_lookup); - let serialized_proof_length = length_of_serialized_proof_from_vk( - vk, - vars.has_rescue_custom_gate, - vars.has_lookup, - vars.d_next_coeff_idx > 0, - quotient_degree, - ); + let quotient_degree = compute_quotient_degree(vk.state_width, vars.has_rescue_custom_gate, vars.has_lookup); + let serialized_proof_length = length_of_serialized_proof_from_vk(vk, vars.has_rescue_custom_gate, vars.has_lookup, vars.d_next_coeff_idx > 0, quotient_degree); map.insert("SERIALIZED_PROOF_LENGTH", serialized_proof_length); let mut num_commitments_at_z = 2 + 4 + 3; let mut num_commitments_at_z_omega = 1 + 2; @@ -409,10 +298,7 @@ fn render_verifier( // assert!(vk.num_inputs > 0); let domain: Domain = Domain::new_for_size(vk.n as u64).expect("a domain"); map.insert("domain_size".into(), domain.size); - map.insert( - "domain_generator".into(), - FieldElement::from(domain.generator), - ); + map.insert("domain_generator".into(), FieldElement::from(domain.generator)); // G1Points let mut gate_setup_commitments = vec![]; @@ -441,10 +327,7 @@ fn render_verifier( map.insert("has_lookup", true); map.insert( "lookup_selector_commitment", - G1Point::from_affine_point( - vk.lookup_selector_commitment - .unwrap_or(::G1Affine::zero()), - ), + G1Point::from_affine_point(vk.lookup_selector_commitment.unwrap_or(::G1Affine::zero())), ); if vk.total_lookup_entries_length > 0 { assert!(vk.lookup_selector_commitment.is_some()); @@ -456,10 +339,7 @@ fn render_verifier( map.insert("lookup_tables_commitments", lookup_tables_commitments); map.insert( "lookup_table_type_commitment", - G1Point::from_affine_point( - vk.lookup_table_type_commitment - .unwrap_or(::G1Affine::zero()), - ), + G1Point::from_affine_point(vk.lookup_table_type_commitment.unwrap_or(::G1Affine::zero())), ); } @@ -486,35 +366,21 @@ fn render_verifier( // register template from a file and assign a name to it handlebars .register_template_file("contract", template_file_path) - .expect(&format!( - "must read the template at path {}", - template_file_path - )); + .expect(&format!("must read the template at path {}", template_file_path)); let rendered = handlebars.render("contract", &map.inner).unwrap(); - writer - .write(rendered.as_bytes()) - .expect("must write to file"); + writer.write(rendered.as_bytes()).expect("must write to file"); } } -fn render_expected_proofs( - proof: Proof, - proof_template_dir: &str, - output_dir: &PathBuf, - has_custom_gate: bool, - has_lookup: bool, -) { +fn render_expected_proofs(proof: Proof, proof_template_dir: &str, output_dir: &PathBuf, has_custom_gate: bool, has_lookup: bool) { let output_file = format!("{}/test/HardcodedValues.sol", output_dir.to_string_lossy()); let mut writer = std::fs::File::create(output_file).expect("output file"); let mut handlebars = Handlebars::new(); handlebars .register_template_file("contract", proof_template_dir) - .expect(&format!( - "must read the template at path {}", - proof_template_dir - )); + .expect(&format!("must read the template at path {}", proof_template_dir)); let json_proof = transform_proof_into_json(proof); let serialized_inputs = json_proof.inputs.clone(); let serialized_proof = serialize_proof(json_proof.clone(), has_custom_gate, has_lookup); @@ -532,9 +398,7 @@ fn render_expected_proofs( }; let rendered = handlebars.render("contract", &hardcoded_values).unwrap(); - writer - .write(rendered.as_bytes()) - .expect("must write to file"); + writer.write(rendered.as_bytes()).expect("must write to file"); } #[derive(Clone, Default, serde::Serialize)] @@ -587,10 +451,7 @@ pub struct JsonProof { } pub fn to_hex(el: &F) -> String { - format!( - "0x{}", - rescue_poseidon::franklin_crypto::bellman::to_hex(el) - ) + format!("0x{}", rescue_poseidon::franklin_crypto::bellman::to_hex(el)) } pub fn point_into_xy(point: &G1Affine) -> [String; 2] { @@ -603,100 +464,34 @@ pub fn transform_proof_into_json(proof: Proof) -> JsonProof let mut json_proof = JsonProof::default(); json_proof.n = proof.n; json_proof.inputs = proof.inputs.iter().map(|v| to_hex(v)).collect(); - json_proof.state_polys_commitments = proof - .state_polys_commitments - .iter() - .map(|p| point_into_xy(p)) - .collect(); - - json_proof.copy_permutation_grand_product_commitment = - point_into_xy(&proof.copy_permutation_grand_product_commitment); - - json_proof.lookup_s_poly_commitment = proof - .lookup_s_poly_commitment - .as_ref() - .map(|p| point_into_xy(p)) - .unwrap_or_default(); - json_proof.lookup_grand_product_commitment = proof - .lookup_grand_product_commitment - .as_ref() - .map(|p| point_into_xy(p)) - .unwrap_or_default(); - - json_proof.quotient_poly_parts_commitments = proof - .quotient_poly_parts_commitments - .iter() - .map(|p| point_into_xy(p)) - .collect(); + json_proof.state_polys_commitments = proof.state_polys_commitments.iter().map(|p| point_into_xy(p)).collect(); + + json_proof.copy_permutation_grand_product_commitment = point_into_xy(&proof.copy_permutation_grand_product_commitment); + + json_proof.lookup_s_poly_commitment = proof.lookup_s_poly_commitment.as_ref().map(|p| point_into_xy(p)).unwrap_or_default(); + json_proof.lookup_grand_product_commitment = proof.lookup_grand_product_commitment.as_ref().map(|p| point_into_xy(p)).unwrap_or_default(); + + json_proof.quotient_poly_parts_commitments = proof.quotient_poly_parts_commitments.iter().map(|p| point_into_xy(p)).collect(); json_proof.opening_proof_at_z = point_into_xy(&proof.opening_proof_at_z); json_proof.opening_proof_at_z_omega = point_into_xy(&proof.opening_proof_at_z_omega); - json_proof.state_polys_openings_at_z = proof - .state_polys_openings_at_z - .iter() - .map(|v| to_hex(v)) - .collect(); - assert_eq!( - proof.state_polys_openings_at_dilations.len(), - 1, - "only one dilation is allowed" - ); - json_proof.state_polys_openings_at_z_omega = proof - .state_polys_openings_at_dilations - .iter() - .map(|(_, _, v)| to_hex(v)) - .collect(); - json_proof.gate_setup_openings_at_z = proof - .gate_setup_openings_at_z - .iter() - .map(|(_, _, v)| to_hex(v)) - .collect(); - json_proof.gate_selectors_openings_at_z = proof - .gate_selectors_openings_at_z - .iter() - .map(|(_, v)| to_hex(v)) - .collect(); - json_proof.copy_permutation_polys_openings_at_z = proof - .copy_permutation_polys_openings_at_z - .iter() - .map(|v| to_hex(v)) - .collect(); - json_proof.copy_permutation_grand_product_opening_at_z_omega = - to_hex(&proof.copy_permutation_grand_product_opening_at_z_omega); - - json_proof.lookup_s_poly_opening_at_z_omega = proof - .lookup_s_poly_opening_at_z_omega - .as_ref() - .map(|v| to_hex(v)) - .unwrap_or_default(); - - json_proof.lookup_grand_product_opening_at_z_omega = proof - .lookup_grand_product_opening_at_z_omega - .as_ref() - .map(|v| to_hex(v)) - .unwrap_or_default(); - - json_proof.lookup_t_poly_opening_at_z = proof - .lookup_t_poly_opening_at_z - .as_ref() - .map(|v| to_hex(v)) - .unwrap_or_default(); - json_proof.lookup_t_poly_opening_at_z_omega = proof - .lookup_t_poly_opening_at_z_omega - .as_ref() - .map(|v| to_hex(v)) - .unwrap_or_default(); - json_proof.lookup_selector_poly_opening_at_z = proof - .lookup_selector_poly_opening_at_z - .as_ref() - .map(|v| to_hex(v)) - .unwrap_or_default(); - json_proof.lookup_table_type_poly_opening_at_z = proof - .lookup_table_type_poly_opening_at_z - .as_ref() - .map(|v| to_hex(v)) - .unwrap_or_default(); + json_proof.state_polys_openings_at_z = proof.state_polys_openings_at_z.iter().map(|v| to_hex(v)).collect(); + assert_eq!(proof.state_polys_openings_at_dilations.len(), 1, "only one dilation is allowed"); + json_proof.state_polys_openings_at_z_omega = proof.state_polys_openings_at_dilations.iter().map(|(_, _, v)| to_hex(v)).collect(); + json_proof.gate_setup_openings_at_z = proof.gate_setup_openings_at_z.iter().map(|(_, _, v)| to_hex(v)).collect(); + json_proof.gate_selectors_openings_at_z = proof.gate_selectors_openings_at_z.iter().map(|(_, v)| to_hex(v)).collect(); + json_proof.copy_permutation_polys_openings_at_z = proof.copy_permutation_polys_openings_at_z.iter().map(|v| to_hex(v)).collect(); + json_proof.copy_permutation_grand_product_opening_at_z_omega = to_hex(&proof.copy_permutation_grand_product_opening_at_z_omega); + + json_proof.lookup_s_poly_opening_at_z_omega = proof.lookup_s_poly_opening_at_z_omega.as_ref().map(|v| to_hex(v)).unwrap_or_default(); + + json_proof.lookup_grand_product_opening_at_z_omega = proof.lookup_grand_product_opening_at_z_omega.as_ref().map(|v| to_hex(v)).unwrap_or_default(); + + json_proof.lookup_t_poly_opening_at_z = proof.lookup_t_poly_opening_at_z.as_ref().map(|v| to_hex(v)).unwrap_or_default(); + json_proof.lookup_t_poly_opening_at_z_omega = proof.lookup_t_poly_opening_at_z_omega.as_ref().map(|v| to_hex(v)).unwrap_or_default(); + json_proof.lookup_selector_poly_opening_at_z = proof.lookup_selector_poly_opening_at_z.as_ref().map(|v| to_hex(v)).unwrap_or_default(); + json_proof.lookup_table_type_poly_opening_at_z = proof.lookup_table_type_poly_opening_at_z.as_ref().map(|v| to_hex(v)).unwrap_or_default(); json_proof.quotient_poly_opening_at_z = to_hex(&proof.quotient_poly_opening_at_z); json_proof.linearization_poly_opening_at_z = to_hex(&proof.linearization_poly_opening_at_z); @@ -731,11 +526,7 @@ pub fn serialize_proof(proof: JsonProof, has_custom_gate: bool, has_lookup: bool } = proof; let mut serialized_proof = vec![]; - serialized_proof.extend( - state_polys_commitments - .iter() - .flat_map(|inner| inner.iter().cloned()), - ); + serialized_proof.extend(state_polys_commitments.iter().flat_map(|inner| inner.iter().cloned())); serialized_proof.extend(copy_permutation_grand_product_commitment); if has_lookup { @@ -743,11 +534,7 @@ pub fn serialize_proof(proof: JsonProof, has_custom_gate: bool, has_lookup: bool serialized_proof.extend(lookup_grand_product_commitment); } - serialized_proof.extend( - quotient_poly_parts_commitments - .iter() - .flat_map(|inner| inner.iter().cloned()), - ); + serialized_proof.extend(quotient_poly_parts_commitments.iter().flat_map(|inner| inner.iter().cloned())); serialized_proof.extend(state_polys_openings_at_z); serialized_proof.extend(state_polys_openings_at_z_omega); diff --git a/crates/plonk-verifier-codegen/src/lib.rs b/crates/plonk-verifier-codegen/src/lib.rs index b9cd398..12d99cf 100644 --- a/crates/plonk-verifier-codegen/src/lib.rs +++ b/crates/plonk-verifier-codegen/src/lib.rs @@ -11,9 +11,7 @@ use ethereum_types::U256; use rescue_poseidon::franklin_crypto::bellman::pairing::bn256::{Bn256, Fr}; use rescue_poseidon::franklin_crypto::bellman::pairing::ff::*; use rescue_poseidon::franklin_crypto::bellman::pairing::*; -use rescue_poseidon::franklin_crypto::bellman::plonk::better_better_cs::cs::{ - Circuit, VerificationKey, -}; +use rescue_poseidon::franklin_crypto::bellman::plonk::better_better_cs::cs::{Circuit, VerificationKey}; use rescue_poseidon::franklin_crypto::bellman::plonk::better_better_cs::proof::Proof; fn render_scalar_to_hex(el: &F) -> String { @@ -40,12 +38,7 @@ fn render_g2_affine_to_hex(point: &::G2Affine) -> [Strin let (x, y) = <::G2Affine as CurveAffine>::into_xy_unchecked(*point); - [ - render_scalar_to_hex(&x.c0), - render_scalar_to_hex(&x.c1), - render_scalar_to_hex(&y.c0), - render_scalar_to_hex(&y.c1) - ] + [render_scalar_to_hex(&x.c0), render_scalar_to_hex(&x.c1), render_scalar_to_hex(&y.c0), render_scalar_to_hex(&y.c1)] } fn serialize_g1_for_ethereum(point: &::G1Affine) -> (U256, U256) { @@ -70,10 +63,7 @@ fn serialize_g1_for_ethereum(point: &::G1Affine) -> (U25 fn serialize_fe_for_ethereum(field_element: &Fr) -> U256 { let mut be_bytes = [0u8; 32]; - field_element - .into_repr() - .write_be(&mut be_bytes[..]) - .expect("get new root BE bytes"); + field_element.into_repr().write_be(&mut be_bytes[..]).expect("get new root BE bytes"); U256::from_big_endian(&be_bytes[..]) } @@ -142,7 +132,6 @@ pub fn serialize_proof>(proof: &Proof) -> (Vec serialized_proof.push(serialize_fe_for_ethereum(&proof.quotient_poly_opening_at_z)); serialized_proof.push(serialize_fe_for_ethereum(&proof.linearization_poly_opening_at_z)); - let (x, y) = serialize_g1_for_ethereum(&proof.opening_proof_at_z); serialized_proof.push(x); serialized_proof.push(y); @@ -154,4 +143,4 @@ pub fn serialize_proof>(proof: &Proof) -> (Vec dbg!(&serialized_proof.len()); (inputs, serialized_proof) -} \ No newline at end of file +} diff --git a/crates/plonk-verifier-codegen/src/serialize.rs b/crates/plonk-verifier-codegen/src/serialize.rs index a2f0bea..5c78754 100644 --- a/crates/plonk-verifier-codegen/src/serialize.rs +++ b/crates/plonk-verifier-codegen/src/serialize.rs @@ -1,5 +1,7 @@ -use rescue_poseidon::franklin_crypto::bellman::{CurveAffine, Engine, PrimeField, PrimeFieldRepr, pairing::bn256::{Bn256, Fq, Fq2, Fr}}; - +use rescue_poseidon::franklin_crypto::bellman::{ + pairing::bn256::{Bn256, Fq, Fq2, Fr}, + CurveAffine, Engine, PrimeField, PrimeFieldRepr, +}; use serde::ser::{Serialize, SerializeStruct, Serializer}; @@ -29,9 +31,7 @@ impl Serialize for FieldElement { fn field_element_to_hex(el: &F) -> String { let mut buf = [0u8; 32]; - el.into_repr() - .write_be(&mut buf[..]) - .expect("consume buffer"); + el.into_repr().write_be(&mut buf[..]).expect("consume buffer"); let mut result = String::from("0x"); result.push_str(&hex::encode(buf)); From a7cc4a34b4e184ea6a435faaadcef48ab6757296 Mon Sep 17 00:00:00 2001 From: saitima Date: Fri, 16 Aug 2024 00:23:54 +0300 Subject: [PATCH 3/3] update test script --- crates/plonk-verifier-codegen/src/circuits.rs | 1 + scripts/plonk-verifier/run-tests.sh | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/plonk-verifier-codegen/src/circuits.rs b/crates/plonk-verifier-codegen/src/circuits.rs index f5a95db..732c403 100644 --- a/crates/plonk-verifier-codegen/src/circuits.rs +++ b/crates/plonk-verifier-codegen/src/circuits.rs @@ -179,6 +179,7 @@ fn inner_circuit_rescue_part>(cs: &mut CS) -> } #[test] +#[ignore] fn test_create_proof_for_all_circuits() { type T = RollingKeccakTranscript; diff --git a/scripts/plonk-verifier/run-tests.sh b/scripts/plonk-verifier/run-tests.sh index 7e3871e..c8eab7b 100755 --- a/scripts/plonk-verifier/run-tests.sh +++ b/scripts/plonk-verifier/run-tests.sh @@ -12,7 +12,7 @@ fi PLONK_VERIFIER_DATA_DIR=$PWD/data/plonk-verifier mkdir -p $PLONK_VERIFIER_DATA_DIR cargo run --bin generate -- --verification-key $PLONK_VERIFIER_DATA_DIR/reference_block_20_keccak.key --proof $PLONK_VERIFIER_DATA_DIR/reference_block_20_keccak.proof -cd - + cd crates/plonk-verifier-foundry $HOME/.foundry/bin/forge test cd - @@ -23,9 +23,7 @@ rm -rf $PLONK_VERIFIER_DATA_DIR/std/* mkdir -p $PLONK_VERIFIER_DATA_DIR/optimized rm -rf $PLONK_VERIFIER_DATA_DIR/optimized/* -cd crates/plonk-verifier-codegen -PLONK_VERIFIER_DATA_DIR=$PLONK_VERIFIER_DATA_DIR cargo test test_create_proof_for_all_circuits --release -- --nocapture -cd - +PLONK_VERIFIER_DATA_DIR=$PLONK_VERIFIER_DATA_DIR cargo test circuits::test_create_proof_for_all_circuits --release -- --ignored --nocapture for main_gate in "std" "optimized" do