diff --git a/Cargo.toml b/Cargo.toml index d594baa1..6371a68e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,3 +36,6 @@ rand_chacha = "0.3" [build-dependencies] lalrpop = "0.20.0" + +[features] +debug_pil = [] diff --git a/examples/blake2f.rs b/examples/blake2f.rs index b459bfba..558461ce 100644 --- a/examples/blake2f.rs +++ b/examples/blake2f.rs @@ -7,7 +7,7 @@ use chiquito::{ CircuitContext, StepTypeSetupContext, StepTypeWGHandler, }, plonkish::{ - backend::halo2::{halo2_verify, Halo2Provable}, + backend::halo2_legacy::{chiquitoSuperCircuit2Halo2, ChiquitoHalo2SuperCircuit}, compiler::{ cell_manager::{MaxWidthCellManager, SingleRowCellManager}, config, @@ -18,7 +18,10 @@ use chiquito::{ poly::ToExpr, sbpir::query::Queriable, }; -use halo2_proofs::halo2curves::{bn256::Fr, group::ff::PrimeField}; +use halo2_proofs::{ + dev::MockProver, + halo2curves::{bn256::Fr, group::ff::PrimeField}, +}; use std::{fmt::Write, hash::Hash}; pub const IV_LEN: usize = 8; @@ -1394,7 +1397,8 @@ fn blake2f_super_circuit() -> SuperCircuit } fn main() { - let mut super_circuit = blake2f_super_circuit::(); + let super_circuit = blake2f_super_circuit::(); + let compiled = chiquitoSuperCircuit2Halo2(&super_circuit); // h[0] = hex"48c9bdf267e6096a 3ba7ca8485ae67bb 2bf894fe72f36e3c f1361d5f3af54fa5"; // h[1] = hex"d182e6ad7f520e51 1f6c3e2b8c68059b 6bbd41fbabd9831f 79217e1319cde05b"; @@ -1476,24 +1480,17 @@ fn main() { f: true, // 8bits }; - let witness = super_circuit.get_mapping().generate(values); - - let params_path = "examples/ptau/hermez-raw-11"; - let halo2_prover = super_circuit.create_halo2_prover(params_path); - println!("k={}", halo2_prover.get_k()); + let circuit = + ChiquitoHalo2SuperCircuit::new(compiled, super_circuit.get_mapping().generate(values)); - let (proof, instance) = halo2_prover.generate_proof(witness); - - let result = halo2_verify( - proof, - halo2_prover.get_params(), - halo2_prover.get_vk(), - instance, - ); + let prover = MockProver::run(9, &circuit, Vec::new()).unwrap(); + let result = prover.verify(); println!("result = {:#?}", result); - if let Err(failure) = &result { - println!("{}", failure); + if let Err(failures) = &result { + for failure in failures.iter() { + println!("{}", failure); + } } } diff --git a/examples/factorial.rs b/examples/factorial.rs index c9d6beb2..9bef03aa 100644 --- a/examples/factorial.rs +++ b/examples/factorial.rs @@ -5,7 +5,7 @@ use chiquito::{ frontend::dsl::{circuit, trace::DSLTraceGenerator}, /* main function for constructing an AST * circuit */ plonkish::{ - backend::halo2::{halo2_verify, Halo2Provable}, + backend::halo2_legacy::{chiquito2Halo2, ChiquitoHalo2Circuit}, compiler::{ cell_manager::SingleRowCellManager, // input for constructing the compiler compile, // input for constructing the compiler @@ -22,7 +22,7 @@ use chiquito::{ * circuit */ poly::ToField, }; -use halo2_proofs::halo2curves::bn256::Fr; +use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; const MAX_FACTORIAL: usize = 10; @@ -134,47 +134,24 @@ fn generate + Hash>() -> PlonkishCompilationResult(); - let params_path = "examples/ptau/hermez-raw-11"; - - let halo2_prover = plonkish.create_halo2_prover(params_path); - println!("k={}", halo2_prover.get_k()); - - let (proof, instance) = - halo2_prover.generate_proof(plonkish.assignment_generator.unwrap().generate(0)); - - let result = halo2_verify( - proof, - halo2_prover.get_params(), - halo2_prover.get_vk(), - instance, + let compilation_result = generate::(); + let compiled = chiquito2Halo2(compilation_result.circuit); + let circuit = ChiquitoHalo2Circuit::new( + compiled, + compilation_result + .assignment_generator + .map(|g| g.generate(0)), ); - println!("result = {:#?}", result); - - if let Err(error) = &result { - println!("{}", error); - } - - let mut plonkish = generate::(); - let params_path = "examples/ptau/hermez-raw-11"; - - let halo2_prover = plonkish.create_halo2_prover(params_path); - println!("k={}", halo2_prover.get_k()); + let prover = MockProver::::run(10, &circuit, circuit.instance()).unwrap(); - let (proof, instance) = - halo2_prover.generate_proof(plonkish.assignment_generator.unwrap().generate(7)); - - let result = halo2_verify( - proof, - halo2_prover.get_params(), - halo2_prover.get_vk(), - instance, - ); + let result = prover.verify(); println!("result = {:#?}", result); - if let Err(error) = &result { - println!("{}", error); + if let Err(failures) = &result { + for failure in failures.iter() { + println!("{}", failure); + } } } diff --git a/examples/fibo_with_padding.rs b/examples/fibo_with_padding.rs index f63b8cba..d93c5bbd 100644 --- a/examples/fibo_with_padding.rs +++ b/examples/fibo_with_padding.rs @@ -5,7 +5,7 @@ use chiquito::{ frontend::dsl::{circuit, trace::DSLTraceGenerator}, /* main function for constructing an AST * circuit */ plonkish::{ - backend::halo2::{halo2_verify, Halo2Provable}, + backend::halo2_legacy::{chiquito2Halo2, ChiquitoHalo2Circuit}, compiler::{ cell_manager::SingleRowCellManager, // input for constructing the compiler compile, // input for constructing the compiler @@ -22,7 +22,7 @@ use chiquito::{ * circuit */ poly::ToField, }; -use halo2_proofs::halo2curves::bn256::Fr; +use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; // This example file extends the rust example file 'fibonacci.rs', // describing usage of multiple steptypes, padding, and exposing signals. @@ -204,25 +204,24 @@ fn fibo_circuit + Hash>( // standard main function for a Halo2 circuit fn main() { - let mut plonkish = fibo_circuit::(); - let params_path = "examples/ptau/hermez-raw-11"; - - let halo2_prover = plonkish.create_halo2_prover(params_path); - println!("k={}", halo2_prover.get_k()); + let compilation_result = fibo_circuit::(); + let compiled = chiquito2Halo2(compilation_result.circuit); + let circuit = ChiquitoHalo2Circuit::new( + compiled, + compilation_result + .assignment_generator + .map(|g| g.generate(7)), + ); - let (proof, instance) = - halo2_prover.generate_proof(plonkish.assignment_generator.unwrap().generate(7)); + let prover = MockProver::::run(7, &circuit, circuit.instance()).unwrap(); - let result = halo2_verify( - proof, - halo2_prover.get_params(), - halo2_prover.get_vk(), - instance, - ); + let result = prover.verify(); println!("{:#?}", result); - if let Err(failure) = &result { - println!("{}", failure); + if let Err(failures) = &result { + for failure in failures.iter() { + println!("{}", failure); + } } } diff --git a/examples/fibonacci.rs b/examples/fibonacci.rs index 4dd28ce1..a388425f 100644 --- a/examples/fibonacci.rs +++ b/examples/fibonacci.rs @@ -6,7 +6,7 @@ use chiquito::{ * circuit */ plonkish::{ backend::{ - halo2::{halo2_verify, Halo2Provable}, + halo2_legacy::{chiquito2Halo2, ChiquitoHalo2Circuit}, hyperplonk::ChiquitoHyperPlonkCircuit, }, compiler::{ @@ -26,7 +26,7 @@ use chiquito::{ poly::ToField, sbpir::SBPIRLegacy, }; -use halo2_proofs::halo2curves::bn256::Fr; +use halo2_proofs::dev::MockProver; // the main circuit function: returns the compiled IR of a Chiquito circuit // Generic types F, (), (u64, 64) stand for: @@ -97,12 +97,12 @@ fn fibo_circuit + Hash>() -> FiboReturn { ctx.pragma_num_steps(16); - // Trace function is responsible for adding step instantiations defined in `step_type_def` - // function above. Trace function is Turing-complete and allows arbitrary user-defined - // logic for assigning witness values + // trace function is responsible for adding step instantiations defined in step_type_def + // function above trace function is Turing complete and allows arbitrary user + // defined logics for assigning witness values ctx.trace(move |ctx: _, _| { - // Add function adds a step instantiation to the main circuit and calls witness - // generation function defined in step_type_def. Input values for witness + // add function adds a step instantiation to the main circuit and calls witness + // generation function defined in step_type_def input values for witness // generation function are (1, 1) in this step instance ctx.add(&fibo_step, (1, 1)); let mut a = 1; @@ -131,60 +131,52 @@ fn fibo_circuit + Hash>() -> FiboReturn { // standard main function for a Halo2 circuit fn main() { - let (mut chiquito, _) = fibo_circuit::(); - - let params_path = "examples/ptau/hermez-raw-11"; - - let halo2_prover = chiquito.create_halo2_prover(params_path); - println!("k={}", halo2_prover.get_k()); + let (chiquito, _) = fibo_circuit::(); + let compiled = chiquito2Halo2(chiquito.circuit); + let circuit = ChiquitoHalo2Circuit::new( + compiled, + chiquito.assignment_generator.map(|g| g.generate(())), + ); - let (proof, instance) = - halo2_prover.generate_proof(chiquito.assignment_generator.unwrap().generate(())); + let prover = MockProver::::run(7, &circuit, circuit.instance()).unwrap(); - let result = halo2_verify( - proof, - halo2_prover.get_params(), - halo2_prover.get_vk(), - instance, - ); + let result = prover.verify(); - println!("result = {:#?}", result); + println!("{:#?}", result); - if let Err(error) = &result { - println!("{}", error); + if let Err(failures) = &result { + for failure in failures.iter() { + println!("{}", failure); + } } // hyperplonk boilerplate use hyperplonk_benchmark::proof_system::{bench_plonkish_backend, System}; use plonkish_backend::{ backend, - halo2_curves::bn256::{Bn256, Fr as hpFr}, + halo2_curves::bn256::{Bn256, Fr}, pcs::{multilinear, univariate}, }; // get Chiquito ir - let (plonkish_compilation_result, _) = fibo_circuit::(); + let (plonkish, _) = fibo_circuit::(); // get assignments - let assignments = plonkish_compilation_result - .assignment_generator - .unwrap() - .generate(()); + let assignments = plonkish.assignment_generator.unwrap().generate(()); // get hyperplonk circuit - let mut hyperplonk_circuit = - ChiquitoHyperPlonkCircuit::new(4, plonkish_compilation_result.circuit); + let mut hyperplonk_circuit = ChiquitoHyperPlonkCircuit::new(4, plonkish.circuit); hyperplonk_circuit.set_assignment(assignments); type GeminiKzg = multilinear::Gemini>; type HyperPlonk = backend::hyperplonk::HyperPlonk; - bench_plonkish_backend::(System::HyperPlonk, 4, &hyperplonk_circuit); + bench_plonkish_backend::(System::HyperPlonk, 4, &hyperplonk_circuit); // pil boilerplate use chiquito::pil::backend::powdr_pil::chiquito2Pil; - let (plonkish_compilation_result, circuit) = fibo_circuit::(); + let (plonkish, circuit) = fibo_circuit::(); let pil = chiquito2Pil( circuit, Some( - plonkish_compilation_result + plonkish .assignment_generator .unwrap() .generate_trace_witness(()), diff --git a/examples/keccak.rs b/examples/keccak.rs index cb491bcd..5a22f07e 100644 --- a/examples/keccak.rs +++ b/examples/keccak.rs @@ -3,7 +3,7 @@ use chiquito::{ lb::LookupTable, super_circuit, trace::DSLTraceGenerator, CircuitContext, StepTypeWGHandler, }, plonkish::{ - backend::halo2::{halo2_verify, Halo2Provable}, + backend::halo2_legacy::{chiquitoSuperCircuit2Halo2, ChiquitoHalo2SuperCircuit}, compiler::{ cell_manager::{MaxWidthCellManager, SingleRowCellManager}, config, @@ -16,7 +16,10 @@ use chiquito::{ }; use std::{hash::Hash, ops::Neg}; -use halo2_proofs::halo2curves::{bn256::Fr, group::ff::PrimeField}; +use halo2_proofs::{ + dev::MockProver, + halo2curves::{bn256::Fr, group::ff::PrimeField}, +}; const BIT_COUNT: u64 = 3; const PART_SIZE: u64 = 5; @@ -2246,32 +2249,36 @@ fn keccak_super_circuit + Eq + Hash>( }) } -fn main() { - let circuit_param = KeccakCircuit { - bytes: vec![0, 1, 2, 3, 4, 5, 6, 7], - }; - - let mut super_circuit = keccak_super_circuit::(circuit_param.bytes.len()); - - let params_path = "examples/ptau/hermez-raw-11"; - - let witness = super_circuit.get_mapping().generate(circuit_param); - - let halo2_prover = super_circuit.create_halo2_prover(params_path); - println!("k={}", halo2_prover.get_k()); +fn keccak_run(circuit_param: KeccakCircuit, k: u32) -> bool { + let super_circuit = keccak_super_circuit::(circuit_param.bytes.len()); - let (proof, instance) = halo2_prover.generate_proof(witness); + let compiled = chiquitoSuperCircuit2Halo2(&super_circuit); - let result = halo2_verify( - proof, - halo2_prover.get_params(), - halo2_prover.get_vk(), - instance, + let circuit = ChiquitoHalo2SuperCircuit::new( + compiled, + super_circuit.get_mapping().generate(circuit_param), ); + let prover = MockProver::::run(k, &circuit, Vec::new()).unwrap(); + let result = prover.verify(); + println!("result = {:#?}", result); - if let Err(failure) = &result { - println!("{}", failure); + if let Err(failures) = &result { + for failure in failures.iter() { + println!("{}", failure); + } + false + } else { + true } } + +fn main() { + let circuit_param = KeccakCircuit { + bytes: vec![0, 1, 2, 3, 4, 5, 6, 7], + }; + + let res = keccak_run(circuit_param, 9); + assert!(res); +} diff --git a/examples/mimc7.rs b/examples/mimc7.rs index a5c5bd7d..468d0868 100644 --- a/examples/mimc7.rs +++ b/examples/mimc7.rs @@ -1,11 +1,14 @@ use std::hash::Hash; -use halo2_proofs::halo2curves::{bn256::Fr, group::ff::PrimeField}; +use halo2_proofs::{ + dev::MockProver, + halo2curves::{bn256::Fr, group::ff::PrimeField}, +}; use chiquito::{ frontend::dsl::{lb::LookupTable, super_circuit, trace::DSLTraceGenerator, CircuitContext}, plonkish::{ - backend::halo2::{halo2_verify, Halo2Provable}, + backend::halo2_legacy::{chiquitoSuperCircuit2Halo2, ChiquitoHalo2SuperCircuit}, compiler::{ cell_manager::SingleRowCellManager, config, step_selector::SimpleStepSelectorBuilder, }, @@ -198,28 +201,23 @@ fn main() { let x_in_value = Fr::from_str_vartime("1").expect("expected a number"); let k_value = Fr::from_str_vartime("2").expect("expected a number"); - let mut super_circuit = mimc7_super_circuit::(); - - let params_path = "examples/ptau/hermez-raw-11"; - - let witness = super_circuit.get_mapping().generate((x_in_value, k_value)); - - let halo2_prover = super_circuit.create_halo2_prover(params_path); - println!("k={}", halo2_prover.get_k()); + let super_circuit = mimc7_super_circuit::(); + let compiled = chiquitoSuperCircuit2Halo2(&super_circuit); + let circuit = ChiquitoHalo2SuperCircuit::new( + compiled, + super_circuit.get_mapping().generate((x_in_value, k_value)), + ); - let (proof, instance) = halo2_prover.generate_proof(witness); + let prover = MockProver::::run(10, &circuit, circuit.instance()).unwrap(); - let result = halo2_verify( - proof, - halo2_prover.get_params(), - halo2_prover.get_vk(), - instance, - ); + let result = prover.verify(); println!("result = {:#?}", result); - if let Err(failure) = &result { - println!("{}", failure); + if let Err(failures) = &result { + for failure in failures.iter() { + println!("{}", failure); + } } // pil boilerplate diff --git a/examples/poseidon.rs b/examples/poseidon.rs index 598d8491..56b5f3e3 100644 --- a/examples/poseidon.rs +++ b/examples/poseidon.rs @@ -1,7 +1,7 @@ use chiquito::{ frontend::dsl::{lb::LookupTable, super_circuit, trace::DSLTraceGenerator, CircuitContext}, plonkish::{ - backend::halo2::{halo2_verify, Halo2Provable}, + backend::halo2_legacy::{chiquitoSuperCircuit2Halo2, ChiquitoHalo2SuperCircuit}, compiler::{ cell_manager::{MaxWidthCellManager, SingleRowCellManager}, config, @@ -14,7 +14,10 @@ use chiquito::{ use std::hash::Hash; -use halo2_proofs::halo2curves::{bn256::Fr, group::ff::PrimeField}; +use halo2_proofs::{ + dev::MockProver, + halo2curves::{bn256::Fr, group::ff::PrimeField}, +}; #[derive(Clone)] struct RoundValues { @@ -700,27 +703,21 @@ fn main() { n_outputs: 1, }; - let mut super_circuit = poseidon_super_circuit(lens); - let witness = super_circuit.get_mapping().generate(values); - - let params_path = "examples/ptau/hermez-raw-11"; + let super_circuit = poseidon_super_circuit(lens); + let compiled = chiquitoSuperCircuit2Halo2(&super_circuit); + let circuit = + ChiquitoHalo2SuperCircuit::new(compiled, super_circuit.get_mapping().generate(values)); - let halo2_prover = super_circuit.create_halo2_prover(params_path); - println!("k={}", halo2_prover.get_k()); + let prover = MockProver::::run(12, &circuit, Vec::new()).unwrap(); - let (proof, instance) = halo2_prover.generate_proof(witness); - - let result = halo2_verify( - proof, - halo2_prover.get_params(), - halo2_prover.get_vk(), - instance, - ); + let result = prover.verify(); println!("result = {:#?}", result); - if let Err(failure) = &result { - println!("{}", failure); + if let Err(failures) = &result { + for failure in failures.iter() { + println!("{}", failure); + } } } diff --git a/examples/ptau/hermez-raw-12 b/examples/ptau/hermez-raw-12 new file mode 100644 index 00000000..7edfd9a7 Binary files /dev/null and b/examples/ptau/hermez-raw-12 differ diff --git a/src/pil/backend/powdr_pil.rs b/src/pil/backend/powdr_pil.rs index f28ca1f6..0a3c6e28 100644 --- a/src/pil/backend/powdr_pil.rs +++ b/src/pil/backend/powdr_pil.rs @@ -161,6 +161,7 @@ fn generate_pil_fixed_columns(pil: &mut String, pil_ir: &PILCircuit "// === Fixed Columns for Signals and Step Type Selectors ===" ) .unwrap(); + #[cfg(feature = "debug_pil")] for (col, assignments) in pil_ir.col_fixed.iter() { let fixed_name = match col { PILColumn::Fixed(_, annotation) => annotation.clone(), diff --git a/src/plonkish/backend/halo2.rs b/src/plonkish/backend/halo2.rs index aef4a75c..50b934c6 100644 --- a/src/plonkish/backend/halo2.rs +++ b/src/plonkish/backend/halo2.rs @@ -7,8 +7,12 @@ use halo2_backend::plonk::{ Error as ErrorBack, }; use halo2_middleware::{ - circuit::{Any as Columns, Cell as CellMid, ColumnMid, CompiledCircuit, Preprocessing}, - permutation::AssemblyMid, + circuit::{ + Any as Columns, Cell as CellMid, ColumnMid, CompiledCircuit, ExpressionMid, GateMid, + Preprocessing, QueryMid, VarMid, + }, + lookup, + permutation::{self, AssemblyMid}, zal::impls::{H2cEngine, PlonkEngineConfig}, }; use halo2_proofs::{ @@ -17,10 +21,7 @@ use halo2_proofs::{ bn256::{Bn256, Fr, G1Affine}, ff::PrimeField, }, - plonk::{ - Advice, Any, Column, ConstraintSystem, ConstraintSystemMid, Error, Expression, FirstPhase, - Fixed, Instance, ProvingKey, SecondPhase, ThirdPhase, VerifyingKey, VirtualCells, - }, + plonk::{Any, Column, ConstraintSystemMid, Error, ProvingKey, VerifyingKey}, poly::{ commitment::Params, kzg::{ @@ -51,7 +52,6 @@ use crate::{ PolyExpr, }, }, - poly::ToField, util::UUID, wit_gen::TraceGenerator, }; @@ -77,30 +77,30 @@ impl> ChiquitoField for T { } } -trait Halo2Configurable { +trait Halo2Configurable { fn compile_middleware( &mut self, num_circuit_rows: usize, ) -> Result<(CompiledCircuit, u32), Error> { - let mut cs = self.configure_cs(); + let mut cs_builder = self.configure_cs(); - let preprocessing = self.preprocessing(&mut cs); + let preprocessing = self.preprocessing(&mut cs_builder); - let occupied_rows = num_circuit_rows + cs.minimum_rows(); + let occupied_rows = num_circuit_rows + cs_builder.minimum_rows(); let k = occupied_rows.next_power_of_two().trailing_zeros(); let n = 2usize.pow(k); Ok(( CompiledCircuit { - cs: cs.clone().into(), + cs: cs_builder.into(), preprocessing: preprocessing.extend(n), }, k, )) } - fn configure_cs(&mut self) -> ConstraintSystem; - fn preprocessing(&self, cs: &mut ConstraintSystem) -> PreprocessingCompact; + fn configure_cs(&mut self) -> ConstraintSystemBuilder; + fn preprocessing(&self, cs: &mut ConstraintSystemBuilder) -> PreprocessingCompact; } pub trait Halo2WitnessGenerator { @@ -119,26 +119,28 @@ pub struct ChiquitoHalo2> { pub(crate) plonkish_ir: Circuit, - advice_columns: HashMap>, - fixed_columns: HashMap>, - instance_column: Option>, + advice_columns: HashMap, + fixed_columns: HashMap, ir_id: UUID, } impl Halo2Configurable for ChiquitoHalo2 { - fn preprocessing(&self, cs: &mut ConstraintSystem) -> PreprocessingCompact { + fn preprocessing( + &self, + cs_builder: &mut ConstraintSystemBuilder, + ) -> PreprocessingCompact { let fixed_count = self.plonkish_ir.fixed_assignments.0.len(); let mut fixed = vec![vec![]; fixed_count]; for (column, values) in self.plonkish_ir.fixed_assignments.iter() { - let column = self.convert_fixed_column(column); + let column = cs_builder.convert_fixed_column(column); fixed[column.index].extend(values.iter().cloned()); } let mut copies = vec![]; - self.collect_permutations(cs, &mut copies); + cs_builder.collect_permutations(&mut copies, &self.plonkish_ir.exposed); PreprocessingCompact { permutation: AssemblyMid { copies }, @@ -146,14 +148,12 @@ impl Halo2Configurable for ChiquitoHalo2 { } } - fn configure_cs(&mut self) -> ConstraintSystem { - let mut cs: ConstraintSystem = ConstraintSystem::default(); + fn configure_cs(&mut self) -> ConstraintSystemBuilder { + let mut cs_builder = ConstraintSystemBuilder::new(); - self.configure_columns_sub_circuit(&mut cs); + self.configure_halo2_columns(&mut cs_builder); - self.configure_sub_circuit(&mut cs); - - cs + cs_builder } } @@ -187,193 +187,225 @@ impl + Hash> ChiquitoHalo2 { plonkish_ir: circuit, advice_columns: Default::default(), fixed_columns: Default::default(), - instance_column: Default::default(), ir_id, } } - fn configure_columns_sub_circuit(&mut self, meta: &mut ConstraintSystem) { - let mut advice_columns = HashMap::>::new(); - let mut fixed_columns = HashMap::>::new(); + fn configure_halo2_columns(&mut self, cs_builder: &mut ConstraintSystemBuilder) { + let mut advice_columns: HashMap = HashMap::new(); + let mut fixed_columns: HashMap = HashMap::new(); - for column in self.plonkish_ir.columns.iter() { - match column.ctype { + self.plonkish_ir + .columns + .iter() + .for_each(|column| match column.ctype { cAdvice => { - let halo2_column = to_halo2_advice(meta, column); + let halo2_column = cs_builder.advice_column(column); advice_columns.insert(column.uuid(), halo2_column); - meta.annotate_lookup_any_column(halo2_column, || column.annotation.clone()); } cFixed => { - let halo2_column = meta.fixed_column(); + let halo2_column = cs_builder.fixed_column(column); fixed_columns.insert(column.uuid(), halo2_column); - meta.annotate_lookup_any_column(halo2_column, || column.annotation.clone()); } - Halo2Advice => { - let halo2_column = column - .halo2_advice - .unwrap_or_else(|| { - panic!("halo2 advice column not found {}", column.annotation) - }) - .column; - advice_columns.insert(column.uuid(), halo2_column); - meta.annotate_lookup_any_column(halo2_column, || column.annotation.clone()); - } - Halo2Fixed => { - let halo2_column = column - .halo2_fixed - .unwrap_or_else(|| { - panic!("halo2 advice column not found {}", column.annotation) - }) - .column; - fixed_columns.insert(column.uuid(), halo2_column); - meta.annotate_lookup_any_column(halo2_column, || column.annotation.clone()); - } - } - } - - self.advice_columns = advice_columns; - self.fixed_columns = fixed_columns; - } + Halo2Advice | Halo2Fixed => panic!( + "Use src/plonkish/backend/halo2_legacy.rs to compile a circuit with imported Halo2 columns" + ), + }); - fn configure_sub_circuit(&mut self, meta: &mut ConstraintSystem) { if !self.plonkish_ir.exposed.is_empty() { - self.instance_column = Some(meta.instance_column()); + cs_builder.has_instance_column = true; } - if !self.plonkish_ir.polys.is_empty() { - meta.create_gate("main", |meta| { - let mut constraints: Vec<(&'static str, Expression)> = Vec::new(); - - for poly in self.plonkish_ir.polys.iter() { - let converted = self.convert_poly(meta, &poly.expr); - let annotation = Box::leak( - format!("{} => {:?}", poly.annotation, converted).into_boxed_str(), - ); - constraints.push((annotation, converted)); - } - - constraints - }); - } + self.plonkish_ir.polys.iter().for_each(|poly| { + cs_builder.gates.push(GateMid { + name: "main".to_string(), + poly: cs_builder.convert_poly(&poly.expr), + }) + }); for lookup in self.plonkish_ir.lookups.iter() { let annotation: &'static str = Box::leak(lookup.annotation.clone().into_boxed_str()); - meta.lookup_any(annotation, |meta| { - let mut exprs = Vec::new(); - for (src, dest) in lookup.exprs.iter() { - exprs.push((self.convert_poly(meta, src), self.convert_poly(meta, dest))) - } - - exprs + let mut exprs = Vec::new(); + for (src, dest) in lookup.exprs.iter() { + exprs.push((cs_builder.convert_poly(src), cs_builder.convert_poly(dest))) + } + cs_builder.lookups.push(lookup::ArgumentMid { + name: annotation.to_string(), + input_expressions: exprs.iter().map(|(src, _)| src.clone()).collect(), + table_expressions: exprs.iter().map(|(_, dest)| dest.clone()).collect(), }); } + + self.advice_columns = advice_columns; + self.fixed_columns = fixed_columns; } +} + +#[derive(Default)] +struct ConstraintSystemBuilder { + num_fixed_columns: usize, + num_advice_columns: usize, + has_instance_column: bool, + gates: Vec>, + lookups: Vec>, + /// Map from advice column UUID to index + advice_idx_map: HashMap, + /// Map from fixed column UUID to index + fixed_idx_map: HashMap, + permutation: PermutationArgument, + advice_queries: HashMap, + fixed_queries: HashMap, + instance_queries: HashMap, + annotations: HashMap, +} - fn convert_poly(&self, meta: &mut VirtualCells<'_, F>, src: &PolyExpr) -> Expression { +impl ConstraintSystemBuilder { + fn convert_poly(&self, src: &PolyExpr) -> ExpressionMid { match src { - PolyExpr::Const(c, _) => Expression::Constant(*c), + PolyExpr::Const(c, _) => ExpressionMid::Constant(*c), PolyExpr::Sum(es, _) => { let mut iter = es.iter(); - let first = self.convert_poly(meta, iter.next().unwrap()); - iter.fold(first, |acc, e| acc + self.convert_poly(meta, e)) + let first = self.convert_poly(iter.next().unwrap()); + iter.fold(first, |acc, e| acc + self.convert_poly(e)) } PolyExpr::Mul(es, _) => { let mut iter = es.iter(); - let first = self.convert_poly(meta, iter.next().unwrap()); - iter.fold(first, |acc, e| acc * self.convert_poly(meta, e)) + let first = self.convert_poly(iter.next().unwrap()); + iter.fold(first, |acc, e| acc * self.convert_poly(e)) } - PolyExpr::Neg(e, _) => -self.convert_poly(meta, e), + PolyExpr::Neg(e, _) => -self.convert_poly(e), PolyExpr::Pow(e, n, _) => { if *n == 0 { - Expression::Constant(1.field()) + ExpressionMid::Constant(F::ONE) } else { - let e = self.convert_poly(meta, e); + let e = self.convert_poly(e); (1..*n).fold(e.clone(), |acc, _| acc * e.clone()) } } - PolyExpr::Halo2Expr(e, _) => e.clone(), - PolyExpr::Query((column, rotation, _), _) => { - self.convert_query(meta, column, *rotation) - } + PolyExpr::Halo2Expr(e, _) => ExpressionMid::from(e.clone()), + PolyExpr::Query((column, rotation, _), _) => self.convert_query(column, *rotation), PolyExpr::MI(_, _) => panic!("mi elimination not done"), } } - fn convert_query( - &self, - meta: &mut VirtualCells<'_, F>, - column: &cColumn, - rotation: i32, - ) -> Expression { + fn convert_query(&self, column: &cColumn, rotation: i32) -> ExpressionMid { match column.ctype { - cAdvice | Halo2Advice => { - let c = self - .advice_columns - .get(&column.uuid()) - .unwrap_or_else(|| panic!("column not found {}", column.annotation)); - - meta.query_advice(*c, Rotation(rotation)) - } - cFixed | Halo2Fixed => { - let c = self - .fixed_columns - .get(&column.uuid()) - .unwrap_or_else(|| panic!("column not found {}", column.annotation)); - - meta.query_fixed(*c, Rotation(rotation)) - } + cAdvice => ExpressionMid::Var(VarMid::Query(QueryMid { + column_index: self.advice_idx_map[&column.uuid()], + column_type: Any::Advice, + rotation: Rotation(rotation), + })), + cFixed => ExpressionMid::Var(VarMid::Query(QueryMid { + column_index: self.fixed_idx_map[&column.uuid()], + column_type: Any::Fixed, + rotation: Rotation(rotation), + })), + Halo2Advice | Halo2Fixed => panic!( + "Use src/plonkish/backend/halo2_legacy.rs to compile a circuit with imported Halo2 columns" + ), } } - fn convert_advice_column(&self, column: &cColumn) -> Column { + fn convert_advice_column(&self, column: &cColumn) -> ColumnMid { match column.ctype { - cAdvice | Halo2Advice => *self - .advice_columns - .get(&column.uuid()) - .unwrap_or_else(|| panic!("column not found {}", column.annotation)), + cAdvice => ColumnMid { + column_type: Columns::Advice, + index: *self + .advice_idx_map + .get(&column.uuid()) + .unwrap_or_else(|| panic!("column not found {}", column.annotation)), + }, + Halo2Advice => panic!( + "Use src/plonkish/backend/halo2_legacy.rs to compile a circuit with imported Halo2 columns" + ), _ => panic!("wrong column type"), } } - fn convert_fixed_column(&self, column: &cColumn) -> Column { + fn convert_fixed_column(&self, column: &cColumn) -> ColumnMid { match column.ctype { - cFixed | Halo2Fixed => *self - .fixed_columns - .get(&column.uuid()) - .unwrap_or_else(|| panic!("column not found {}", column.annotation)), + cFixed => ColumnMid { + column_type: Columns::Fixed, + index: *self + .fixed_idx_map + .get(&column.uuid()) + .unwrap_or_else(|| panic!("column not found {}", column.annotation)), + }, + Halo2Fixed => panic!( + "Use src/plonkish/backend/halo2_legacy.rs to compile a circuit with imported Halo2 columns" + ), _ => panic!("wrong column type"), } } + fn annotate(&mut self, index: usize, column: &cColumn, column_type: Any) { + self.annotations + .insert(ColumnMid { index, column_type }, column.annotation.clone()); + } + + fn count_query(&mut self, column: Column) { + match column.column_type { + Any::Advice => { + let advice_queries = &mut self.advice_queries; + *advice_queries.entry(column.index).or_insert(0) += 1; + } + Any::Fixed => { + let fixed_queries = &mut self.fixed_queries; + *fixed_queries.entry(column.index).or_insert(0) += 1; + } + Any::Instance => { + let instance_queries = &mut self.instance_queries; + *instance_queries.entry(column.index).or_insert(0) += 1; + } + } + } + + /// Compute the minimum number of rows of the circuit. + /// For constants explanation see https://github.com/privacy-scaling-explorations/halo2/blob/bc857a701715ac3608056cb9b1999ad7cbc00b59/halo2_frontend/src/plonk/circuit/constraint_system.rs#L1055 + fn minimum_rows(&self) -> usize { + self.blinding_factors() + 3 + } + + /// Compute the number of blinding factors necessary to perfectly blind + /// each of the prover's witness polynomials. + /// For constants explanation see https://github.com/privacy-scaling-explorations/halo2/blob/main/halo2_frontend/src/plonk/circuit/constraint_system.rs#L1026 + pub(crate) fn blinding_factors(&self) -> usize { + let factors = *self.advice_queries.values().max().unwrap_or(&1); + let factors = std::cmp::max(3, factors); + factors + 2 + } + fn collect_permutations( - &self, - cs: &mut ConstraintSystem, + &mut self, copies: &mut Vec<(CellMid, CellMid)>, + exposed: &[(cColumn, i32)], ) { - self.plonkish_ir - .exposed + exposed .iter() .enumerate() .for_each(|(row, (column, offset))| { let col_type: Columns = match column.ctype { - cAdvice | Halo2Advice => Columns::Advice, - cFixed | Halo2Fixed => Columns::Fixed, + cAdvice => Columns::Advice, + cFixed => Columns::Fixed, + Halo2Advice | Halo2Fixed => panic!( + "Use src/plonkish/backend/halo2_legacy.rs to compile a circuit with imported Halo2 columns" + ), }; let index = if col_type == Columns::Advice { let column = self.convert_advice_column(column); - cs.enable_equality(column); + self.collect_permutation(column); column.index } else { let column = self.convert_fixed_column(column); - cs.enable_equality(column); + self.collect_permutation(column); column.index }; let column_mid = ColumnMid::new(col_type, index); let instance_column = ColumnMid::new(Columns::Instance, 0); - cs.enable_equality(instance_column); + self.collect_permutation(instance_column); copies.push(( CellMid { column: column_mid, @@ -386,6 +418,64 @@ impl + Hash> ChiquitoHalo2 { )); }); } + + fn collect_permutation>>(&mut self, column: C) { + let column: Column = column.into(); + self.count_query(column); + if !self.permutation.columns.contains(&ColumnMid { + column_type: column.column_type, + index: column.index, + }) { + self.permutation = PermutationArgument { + columns: self + .permutation + .columns + .iter() + .cloned() + .chain(iter::once(ColumnMid { + column_type: column.column_type, + index: column.index, + })) + .collect(), + }; + } + } + + fn new() -> Self { + Self::default() + } + + fn advice_column(&mut self, column: &cColumn) -> ColumnMid { + let index = self.num_advice_columns; + self.allocate_advice(index, column) + } + + fn fixed_column(&mut self, column: &cColumn) -> ColumnMid { + let index = self.num_fixed_columns; + self.allocate_fixed(index, column) + } + + fn allocate_fixed(&mut self, index: usize, column: &cColumn) -> ColumnMid { + let column_mid = ColumnMid { + column_type: Any::Fixed, + index, + }; + self.fixed_idx_map.insert(column.uuid(), index); + self.annotate(index, column, Any::Fixed); + self.num_fixed_columns += 1; + column_mid + } + + fn allocate_advice(&mut self, index: usize, column: &cColumn) -> ColumnMid { + let column_mid = ColumnMid { + column_type: Any::Advice, + index, + }; + self.advice_idx_map.insert(column.uuid(), index); + self.annotate(index, column, Any::Advice); + self.num_advice_columns += 1; + column_mid + } } impl Halo2WitnessGenerator> for ChiquitoHalo2 { @@ -459,21 +549,21 @@ impl Halo2WitnessGenerator> for ChiquitoHa } impl Halo2Configurable for ChiquitoHalo2SuperCircuit { - fn configure_cs(&mut self) -> ConstraintSystem { - let mut cs = ConstraintSystem::default(); + fn configure_cs(&mut self) -> ConstraintSystemBuilder { + let mut cs_builder = ConstraintSystemBuilder::new(); self.sub_circuits .iter_mut() - .for_each(|c| c.configure_columns_sub_circuit(&mut cs)); + .for_each(|c| c.configure_halo2_columns(&mut cs_builder)); - let advice_columns: HashMap> = + let advice_columns: HashMap = self.sub_circuits .iter() .fold(HashMap::default(), |mut acc, s| { acc.extend(s.advice_columns.clone()); acc }); - let fixed_columns: HashMap> = + let fixed_columns: HashMap = self.sub_circuits .iter() .fold(HashMap::default(), |mut acc, s| { @@ -484,14 +574,16 @@ impl Halo2Configurable for ChiquitoHalo2SuperCircuit self.sub_circuits.iter_mut().for_each(|sub_circuit| { sub_circuit.advice_columns = advice_columns.clone(); sub_circuit.fixed_columns = fixed_columns.clone(); - sub_circuit.configure_sub_circuit(&mut cs) }); - cs + cs_builder } - fn preprocessing(&self, cs: &mut ConstraintSystem) -> PreprocessingCompact { - let fixed_columns: HashMap> = + fn preprocessing( + &self, + cs_builder: &mut ConstraintSystemBuilder, + ) -> PreprocessingCompact { + let fixed_columns: HashMap = self.sub_circuits .iter() .fold(HashMap::default(), |mut acc, s| { @@ -509,7 +601,7 @@ impl Halo2Configurable for ChiquitoHalo2SuperCircuit fixed[column.index].extend(values.iter().cloned()); } - subcircuit.collect_permutations(cs, &mut copies); + cs_builder.collect_permutations(&mut copies, &subcircuit.plonkish_ir.exposed); } PreprocessingCompact { @@ -519,6 +611,34 @@ impl Halo2Configurable for ChiquitoHalo2SuperCircuit } } +#[derive(Debug, Clone, Default)] +pub struct PermutationArgument { + /// A sequence of columns involved in the argument. + pub columns: Vec, +} + +impl From> for ConstraintSystemMid { + fn from(val: ConstraintSystemBuilder) -> Self { + ConstraintSystemMid { + num_fixed_columns: val.num_fixed_columns, + num_advice_columns: val.num_advice_columns, + num_instance_columns: if val.has_instance_column { 1 } else { 0 }, + num_challenges: 0, + unblinded_advice_columns: Vec::new(), + advice_column_phase: (0..val.num_advice_columns).map(|_| 0).collect(), + challenge_phase: Vec::new(), + gates: val.gates, + permutation: permutation::ArgumentMid { + columns: val.permutation.columns, + }, + lookups: val.lookups, + shuffles: Vec::new(), + general_column_annotations: val.annotations, + minimum_degree: None, + } + } +} + /// Verify Halo2 proof /// ### Arguments /// * `proof` - Halo2 proof @@ -784,15 +904,3 @@ impl BlockRngCore for DummyRng { } } } - -fn to_halo2_advice( - meta: &mut ConstraintSystem, - column: &cColumn, -) -> Column { - match column.phase { - 0 => meta.advice_column_in(FirstPhase), - 1 => meta.advice_column_in(SecondPhase), - 2 => meta.advice_column_in(ThirdPhase), - _ => panic!("jarll wrong phase"), - } -} diff --git a/src/plonkish/backend/halo2_legacy.rs b/src/plonkish/backend/halo2_legacy.rs new file mode 100644 index 00000000..b899bf3b --- /dev/null +++ b/src/plonkish/backend/halo2_legacy.rs @@ -0,0 +1,501 @@ +use std::{collections::HashMap, hash::Hash}; + +use halo2_proofs::{ + circuit::{Cell, Layouter, Region, RegionIndex, SimpleFloorPlanner, Value}, + halo2curves::ff::PrimeField, + plonk::{ + Advice, Any, Circuit as h2Circuit, Column, ConstraintSystem, ErrorFront, Expression, + FirstPhase, Fixed, Instance, SecondPhase, ThirdPhase, VirtualCells, + }, + poly::Rotation, +}; + +use crate::{ + plonkish::ir::{ + assignments::Assignments, + sc::{SuperAssignments, SuperCircuit}, + Circuit, Column as cColumn, + ColumnType::{Advice as cAdvice, Fixed as cFixed, Halo2Advice, Halo2Fixed}, + PolyExpr, + }, + poly::ToField, + util::UUID, +}; + +#[allow(non_snake_case)] +pub fn chiquito2Halo2 + Hash>(circuit: Circuit) -> ChiquitoHalo2 { + ChiquitoHalo2::new(circuit) +} + +#[allow(non_snake_case)] +pub fn chiquitoSuperCircuit2Halo2 + Hash, MappingArgs>( + super_circuit: &SuperCircuit, +) -> Vec> { + super_circuit + .get_sub_circuits() + .iter() + .map(|c| chiquito2Halo2((*c).clone())) + .collect() +} + +#[derive(Clone, Debug, Default)] +pub struct ChiquitoHalo2> { + pub debug: bool, + + circuit: Circuit, + + advice_columns: HashMap>, + fixed_columns: HashMap>, + instance_column: Option>, + + ir_id: UUID, +} + +impl + Hash> ChiquitoHalo2 { + pub fn new(circuit: Circuit) -> ChiquitoHalo2 { + let ir_id = circuit.id; + ChiquitoHalo2 { + debug: true, + circuit, + advice_columns: Default::default(), + fixed_columns: Default::default(), + instance_column: Default::default(), + ir_id, + } + } + + pub fn configure(&mut self, meta: &mut ConstraintSystem) { + self.configure_columns_sub_circuit(meta); + + self.configure_sub_circuit(meta); + } + + fn configure_columns_sub_circuit(&mut self, meta: &mut ConstraintSystem) { + let mut advice_columns = HashMap::>::new(); + let mut fixed_columns = HashMap::>::new(); + + for column in self.circuit.columns.iter() { + match column.ctype { + cAdvice => { + let halo2_column = to_halo2_advice(meta, column); + advice_columns.insert(column.uuid(), halo2_column); + meta.annotate_lookup_any_column(halo2_column, || column.annotation.clone()); + } + cFixed => { + let halo2_column = meta.fixed_column(); + fixed_columns.insert(column.uuid(), halo2_column); + meta.annotate_lookup_any_column(halo2_column, || column.annotation.clone()); + } + Halo2Advice => { + let halo2_column = column + .halo2_advice + .unwrap_or_else(|| { + panic!("halo2 advice column not found {}", column.annotation) + }) + .column; + advice_columns.insert(column.uuid(), halo2_column); + meta.annotate_lookup_any_column(halo2_column, || column.annotation.clone()); + } + Halo2Fixed => { + let halo2_column = column + .halo2_fixed + .unwrap_or_else(|| { + panic!("halo2 advice column not found {}", column.annotation) + }) + .column; + fixed_columns.insert(column.uuid(), halo2_column); + meta.annotate_lookup_any_column(halo2_column, || column.annotation.clone()); + } + } + } + + self.advice_columns = advice_columns; + self.fixed_columns = fixed_columns; + } + + pub fn configure_sub_circuit(&mut self, meta: &mut ConstraintSystem) { + if !self.circuit.exposed.is_empty() { + self.instance_column = Some(meta.instance_column()); + } + + if !self.circuit.polys.is_empty() { + meta.create_gate("main", |meta| { + let mut constraints: Vec<(&'static str, Expression)> = Vec::new(); + + for poly in self.circuit.polys.iter() { + let converted = self.convert_poly(meta, &poly.expr); + let annotation = Box::leak( + format!("{} => {:?}", poly.annotation, converted).into_boxed_str(), + ); + constraints.push((annotation, converted)); + } + + constraints + }); + } + + for lookup in self.circuit.lookups.iter() { + let annotation: &'static str = Box::leak(lookup.annotation.clone().into_boxed_str()); + meta.lookup_any(annotation, |meta| { + let mut exprs = Vec::new(); + for (src, dest) in lookup.exprs.iter() { + exprs.push((self.convert_poly(meta, src), self.convert_poly(meta, dest))) + } + + exprs + }); + } + } + + pub fn synthesize(&self, layouter: &mut impl Layouter, witness: Option<&Assignments>) { + let _ = layouter.assign_region( + || "circuit", + |mut region| { + self.annotate_circuit(&mut region); + + self.assign_fixed(&mut region, &self.circuit.fixed_assignments)?; + + if let Some(witness) = &witness { + self.assign_advice(&mut region, witness)?; + } + + Ok(()) + }, + ); + + for (index, (column, rotation)) in self.circuit.exposed.iter().enumerate() { + let halo2_column = + Column::::from(*self.advice_columns.get(&column.uuid()).unwrap()); + let cell = new_cell( + halo2_column, + // For single row cell manager, forward signal rotation is always zero. + // For max width cell manager, rotation can be non-zero. + // Offset is absolute row index calculated in `compile_exposed`. + *rotation as usize, + ); + let _ = layouter.constrain_instance(cell, self.instance_column.unwrap(), index); + } + } + + fn assign_advice( + &self, + region: &mut Region, + witness: &Assignments, + ) -> Result<(), ErrorFront> { + for (column, assignments) in witness.iter() { + let column = self.convert_advice_column(column); + + for (offset, value) in assignments.iter().enumerate() { + region.assign_advice(|| "", column, offset, || Value::known(*value))?; + } + } + + Ok(()) + } + + fn assign_fixed( + &self, + region: &mut Region, + fixed: &Assignments, + ) -> Result<(), ErrorFront> { + for (column, values) in fixed.iter() { + let column = self.convert_fixed_column(column); + + for (offset, value) in values.iter().enumerate() { + region.assign_fixed(|| "", column, offset, || Value::known(*value))?; + } + } + + Ok(()) + } + + fn annotate_circuit(&self, region: &mut Region) { + for column in self.circuit.columns.iter() { + match column.ctype { + cAdvice | Halo2Advice => { + let halo2_column = self + .advice_columns + .get(&column.uuid()) + .expect("advice column not found"); + + region.name_column(|| column.annotation.clone(), *halo2_column); + } + cFixed | Halo2Fixed => { + let halo2_column = self + .fixed_columns + .get(&column.uuid()) + .expect("fixed column not found"); + + region.name_column(|| column.annotation.clone(), *halo2_column); + } + } + } + } + + fn convert_poly(&self, meta: &mut VirtualCells<'_, F>, src: &PolyExpr) -> Expression { + match src { + PolyExpr::Const(c, _) => Expression::Constant(*c), + PolyExpr::Sum(es, _) => { + let mut iter = es.iter(); + let first = self.convert_poly(meta, iter.next().unwrap()); + iter.fold(first, |acc, e| acc + self.convert_poly(meta, e)) + } + PolyExpr::Mul(es, _) => { + let mut iter = es.iter(); + let first = self.convert_poly(meta, iter.next().unwrap()); + iter.fold(first, |acc, e| acc * self.convert_poly(meta, e)) + } + PolyExpr::Neg(e, _) => -self.convert_poly(meta, e), + PolyExpr::Pow(e, n, _) => { + if *n == 0 { + Expression::Constant(1.field()) + } else { + let e = self.convert_poly(meta, e); + (1..*n).fold(e.clone(), |acc, _| acc * e.clone()) + } + } + PolyExpr::Halo2Expr(e, _) => e.clone(), + PolyExpr::Query((column, rotation, _), _) => { + self.convert_query(meta, column, *rotation) + } + PolyExpr::MI(_, _) => panic!("mi elimination not done"), + } + } + + fn convert_query( + &self, + meta: &mut VirtualCells<'_, F>, + column: &cColumn, + rotation: i32, + ) -> Expression { + match column.ctype { + cAdvice | Halo2Advice => { + let c = self + .advice_columns + .get(&column.uuid()) + .unwrap_or_else(|| panic!("column not found {}", column.annotation)); + + meta.query_advice(*c, Rotation(rotation)) + } + cFixed | Halo2Fixed => { + let c = self + .fixed_columns + .get(&column.uuid()) + .unwrap_or_else(|| panic!("column not found {}", column.annotation)); + + meta.query_fixed(*c, Rotation(rotation)) + } + } + } + + fn convert_advice_column(&self, column: &cColumn) -> Column { + match column.ctype { + cAdvice | Halo2Advice => *self + .advice_columns + .get(&column.uuid()) + .unwrap_or_else(|| panic!("column not found {}", column.annotation)), + _ => panic!("wrong column type"), + } + } + + fn convert_fixed_column(&self, column: &cColumn) -> Column { + match column.ctype { + cFixed | Halo2Fixed => *self + .fixed_columns + .get(&column.uuid()) + .unwrap_or_else(|| panic!("column not found {}", column.annotation)), + _ => panic!("wrong column type"), + } + } +} + +#[allow(dead_code)] +// From Plaf Halo2 backend. +// _Cell is a helper struct used for constructing Halo2 Cell. +struct _Cell { + region_index: RegionIndex, + row_offset: usize, + column: Column, +} +// From Plaf Halo2 backend. +fn new_cell(column: Column, offset: usize) -> Cell { + let cell = _Cell { + region_index: RegionIndex::from(0), + row_offset: offset, + column, + }; + // NOTE: We use unsafe here to construct a Cell, which doesn't have a public constructor. This + // helps us set the copy constraints easily (without having to store all assigned cells + // previously) + unsafe { std::mem::transmute::<_Cell, Cell>(cell) } +} + +pub fn to_halo2_advice( + meta: &mut ConstraintSystem, + column: &cColumn, +) -> Column { + match column.phase { + 0 => meta.advice_column_in(FirstPhase), + 1 => meta.advice_column_in(SecondPhase), + 2 => meta.advice_column_in(ThirdPhase), + _ => panic!("jarll wrong phase"), + } +} + +#[derive(Clone, Default, Debug)] +pub struct ChiquitoHalo2Circuit> { + compiled: ChiquitoHalo2, + witness: Option>, +} + +impl + Hash> ChiquitoHalo2Circuit { + pub fn new(compiled: ChiquitoHalo2, witness: Option>) -> Self { + Self { compiled, witness } + } + + pub fn instance(&self) -> Vec> { + if !self.compiled.circuit.exposed.is_empty() { + if let Some(witness) = &self.witness { + return vec![self.compiled.circuit.instance(witness)]; + } + } + Vec::new() + } +} + +impl + Hash> h2Circuit for ChiquitoHalo2Circuit { + type Config = ChiquitoHalo2; + + type FloorPlanner = SimpleFloorPlanner; + + type Params = ChiquitoHalo2; + + fn without_witnesses(&self) -> Self { + Self { + compiled: self.compiled.clone(), + witness: self.witness.clone().map(|mut w| { + w.clear(); + w + }), + } + } + + fn params(&self) -> Self::Params { + self.compiled.clone() + } + + fn configure_with_params( + meta: &mut ConstraintSystem, + mut compiled: Self::Params, + ) -> Self::Config { + compiled.configure(meta); + + compiled + } + + fn synthesize( + &self, + compiled: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), ErrorFront> { + compiled.synthesize(&mut layouter, self.witness.as_ref()); + + Ok(()) + } + + fn configure(_: &mut ConstraintSystem) -> Self::Config { + unreachable!() + } +} + +#[derive(Debug, Default)] +pub struct ChiquitoHalo2SuperCircuit> { + sub_circuits: Vec>, + witness: SuperAssignments, +} + +impl + Hash> ChiquitoHalo2SuperCircuit { + pub fn new(sub_circuits: Vec>, witness: SuperAssignments) -> Self { + Self { + sub_circuits, + witness, + } + } + + pub fn instance(&self) -> Vec> { + let mut result = Vec::new(); + + for sub_circuit in &self.sub_circuits { + if !sub_circuit.circuit.exposed.is_empty() { + let instance_values = sub_circuit.circuit.instance( + self.witness + .get(&sub_circuit.ir_id) + .expect("No matching witness found for given UUID."), + ); + result.push(instance_values); + } + } + + result + } +} + +impl + Hash> h2Circuit for ChiquitoHalo2SuperCircuit { + type Config = Vec>; + + type FloorPlanner = SimpleFloorPlanner; + + type Params = Vec>; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn params(&self) -> Self::Params { + self.sub_circuits.clone() + } + + fn configure_with_params( + meta: &mut ConstraintSystem, + mut sub_circuits: Self::Params, + ) -> Self::Config { + sub_circuits + .iter_mut() + .for_each(|c| c.configure_columns_sub_circuit(meta)); + + let advice_columns: HashMap> = + sub_circuits.iter().fold(HashMap::default(), |mut acc, s| { + acc.extend(s.advice_columns.clone()); + acc + }); + let fixed_columns: HashMap> = + sub_circuits.iter().fold(HashMap::default(), |mut acc, s| { + acc.extend(s.fixed_columns.clone()); + acc + }); + + sub_circuits.iter_mut().for_each(|sub_circuit| { + sub_circuit.advice_columns = advice_columns.clone(); + sub_circuit.fixed_columns = fixed_columns.clone(); + sub_circuit.configure_sub_circuit(meta) + }); + + sub_circuits + } + + fn synthesize( + &self, + sub_circuits: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), ErrorFront> { + for sub_circuit in sub_circuits { + sub_circuit.synthesize(&mut layouter, self.witness.get(&sub_circuit.ir_id)) + } + + Ok(()) + } + + fn configure(_: &mut ConstraintSystem) -> Self::Config { + unreachable!() + } +} diff --git a/src/plonkish/backend/mod.rs b/src/plonkish/backend/mod.rs index 66cb822b..e9aab62b 100644 --- a/src/plonkish/backend/mod.rs +++ b/src/plonkish/backend/mod.rs @@ -1,2 +1,3 @@ pub mod halo2; +pub mod halo2_legacy; pub mod hyperplonk;