From 0d48b6b67185f5696ef0b737584554732f4b0ae9 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Wed, 18 May 2022 21:41:51 +0800 Subject: [PATCH] cargo test --release --package zkevm-circuits --lib -- add_gadget --nocapture --- zkevm-circuits/src/evm_circuit/witness.rs | 4 +- zkevm-circuits/src/full_circuit.rs | 354 ++++++++++++++++++ zkevm-circuits/src/lib.rs | 1 + zkevm-circuits/src/state_circuit.rs | 39 +- .../state_circuit/lexicographic_ordering.rs | 2 +- .../random_linear_combination.rs | 10 +- zkevm-circuits/src/state_circuit/test.rs | 2 +- zkevm-circuits/src/test_util.rs | 8 + 8 files changed, 398 insertions(+), 22 deletions(-) create mode 100644 zkevm-circuits/src/full_circuit.rs diff --git a/zkevm-circuits/src/evm_circuit/witness.rs b/zkevm-circuits/src/evm_circuit/witness.rs index fe90497d37..71868ac427 100644 --- a/zkevm-circuits/src/evm_circuit/witness.rs +++ b/zkevm-circuits/src/evm_circuit/witness.rs @@ -629,7 +629,7 @@ pub enum Rw { }, } #[derive(Default, Clone, Copy, Debug)] -pub struct RwRow { +pub struct RwRow { pub rw_counter: u64, pub is_write: bool, pub tag: u64, @@ -1488,7 +1488,7 @@ pub fn block_convert( code_db: &bus_mapping::state_db::CodeDB, ) -> Block { Block { - randomness: Fr::rand(), + randomness: Fr::from(0x1234u64), //Fp::rand(), context: block.into(), rws: RwMap::from(&block.container), txs: block diff --git a/zkevm-circuits/src/full_circuit.rs b/zkevm-circuits/src/full_circuit.rs new file mode 100644 index 0000000000..da6d68eb2b --- /dev/null +++ b/zkevm-circuits/src/full_circuit.rs @@ -0,0 +1,354 @@ + + use std::convert::TryInto; + + use crate::{ + evm_circuit::{ + table::FixedTableTag, + witness::{Block, BlockContext, Bytecode, RwMap, Transaction}, + EvmCircuit, + }, + rw_table::RwTable, + util::Expr, state_circuit::{StateCircuit, StateConfig}, + }; + use eth_types::{Field, Word}; + use halo2_proofs::{ + arithmetic::BaseExt, + circuit::{Layouter, SimpleFloorPlanner}, + dev::{MockProver, VerifyFailure}, + pairing::bn256::Fr as Fp, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Expression}, + poly::Rotation, + }; + use itertools::Itertools; + use rand::{ + distributions::uniform::{SampleRange, SampleUniform}, + random, thread_rng, Rng, + }; + use strum::IntoEnumIterator; + + pub(crate) fn rand_range(range: R) -> T + where + T: SampleUniform, + R: SampleRange, + { + thread_rng().gen_range(range) + } + + pub(crate) fn rand_bytes(n: usize) -> Vec { + (0..n).map(|_| random()).collect() + } + + pub(crate) fn rand_bytes_array() -> [u8; N] { + [(); N].map(|_| random()) + } + + pub(crate) fn rand_word() -> Word { + Word::from_big_endian(&rand_bytes_array::<32>()) + } + + pub(crate) fn rand_fp() -> Fp { + Fp::rand() + } + + #[derive(Clone)] + pub struct TestCircuitConfig { + tx_table: [Column; 4], + rw_table: RwTable, + bytecode_table: [Column; 5], + block_table: [Column; 3], + evm_circuit: EvmCircuit, + state_circuit: StateConfig, + } + + impl TestCircuitConfig { + fn load_txs( + &self, + layouter: &mut impl Layouter, + txs: &[Transaction], + randomness: F, + ) -> Result<(), Error> { + layouter.assign_region( + || "tx table", + |mut region| { + let mut offset = 0; + for column in self.tx_table { + region.assign_advice( + || "tx table all-zero row", + column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + for tx in txs.iter() { + for row in tx.table_assignments(randomness) { + for (column, value) in self.tx_table.iter().zip_eq(row) { + region.assign_advice( + || format!("tx table row {}", offset), + *column, + offset, + || Ok(value), + )?; + } + offset += 1; + } + } + Ok(()) + }, + ) + } + + fn load_rws( + &self, + layouter: &mut impl Layouter, + rws: &RwMap, + randomness: F, + ) -> Result<(), Error> { + rws.check_rw_counter_sanity(); + /* + layouter.assign_region( + || "rw table", + |mut region| { + //self.rw_table.assign(&mut region, randomness, rws)?; + Ok(()) + }, + )*/ + Ok(()) + } + + fn load_bytecodes( + &self, + layouter: &mut impl Layouter, + bytecodes: &[Bytecode], + randomness: F, + ) -> Result<(), Error> { + layouter.assign_region( + || "bytecode table", + |mut region| { + let mut offset = 0; + for column in self.bytecode_table { + region.assign_advice( + || "bytecode table all-zero row", + column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + for bytecode in bytecodes.iter() { + for row in bytecode.table_assignments(randomness) { + for (column, value) in self.bytecode_table.iter().zip_eq(row) { + region.assign_advice( + || format!("bytecode table row {}", offset), + *column, + offset, + || Ok(value), + )?; + } + offset += 1; + } + } + Ok(()) + }, + ) + } + + fn load_block( + &self, + layouter: &mut impl Layouter, + block: &BlockContext, + randomness: F, + ) -> Result<(), Error> { + layouter.assign_region( + || "block table", + |mut region| { + let mut offset = 0; + for column in self.block_table { + region.assign_advice( + || "block table all-zero row", + column, + offset, + || Ok(F::zero()), + )?; + } + offset += 1; + + for row in block.table_assignments(randomness) { + for (column, value) in self.block_table.iter().zip_eq(row) { + region.assign_advice( + || format!("block table row {}", offset), + *column, + offset, + || Ok(value), + )?; + } + offset += 1; + } + + Ok(()) + }, + ) + } + } + + #[derive(Default)] + pub struct TestCircuit { + block: Block, + fixed_table_tags: Vec, + } + + impl TestCircuit { + pub fn new(block: Block, fixed_table_tags: Vec) -> Self { + Self { + block, + fixed_table_tags, + } + } + } + + impl Circuit for TestCircuit { + type Config = TestCircuitConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let tx_table = [(); 4].map(|_| meta.advice_column()); + //let rw_table = RwTable::construct(meta); + let bytecode_table = [(); 5].map(|_| meta.advice_column()); + let block_table = [(); 3].map(|_| meta.advice_column()); + + let power_of_randomness: [Expression; 31] = (1..32) + .map(|exp| Expression::Constant(F::from_u128(0x1234).pow(&[exp, 0, 0, 0]))) + .collect::>() + .try_into() + .unwrap(); + + + let state_circuit = StateCircuit::configure(meta); + + Self::Config { + tx_table, + rw_table: state_circuit.rw_table.clone(), + bytecode_table, + block_table, + evm_circuit: EvmCircuit::configure( + meta, + power_of_randomness, + &tx_table, + &state_circuit.rw_table, + &bytecode_table, + &block_table, + ), + state_circuit + } + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + config + .evm_circuit + .load_fixed_table(&mut layouter, self.fixed_table_tags.clone())?; + config.evm_circuit.load_byte_table(&mut layouter)?; + config.load_txs(&mut layouter, &self.block.txs, self.block.randomness)?; + //config.load_rws(&mut layouter, &self.block.rws, self.block.randomness)?; + config.load_bytecodes(&mut layouter, &self.block.bytecodes, self.block.randomness)?; + config.load_block(&mut layouter, &self.block.context, self.block.randomness)?; + config + .evm_circuit + .assign_block_exact(&mut layouter, &self.block)?; + + + let check_pass = true; + let stat_circut = if check_pass { + // correct + StateCircuit::new(self.block.randomness, self.block.rws.clone()) + } else { + // should be wrong + StateCircuit::new(self.block.randomness + F::from(1u64), self.block.rws.clone()) + }; + stat_circut.synthesize(config.state_circuit, layouter)?; + Ok(()) + } + } + + impl TestCircuit { + pub fn get_num_rows_required(block: &Block) -> usize { + let mut cs = ConstraintSystem::default(); + let config = TestCircuit::configure(&mut cs); + config.evm_circuit.get_num_rows_required(block) + } + + pub fn get_active_rows(block: &Block) -> (Vec, Vec) { + let mut cs = ConstraintSystem::default(); + let config = TestCircuit::configure(&mut cs); + let (r1, r2) = config.evm_circuit.get_active_rows(&block); + let max1: usize = (*r1.iter().max().unwrap()).max(*r2.iter().max().unwrap()); + let max2 = max1.max(4000); + ((0..max2).collect(), (0..max2).collect()) + } + } + + pub fn run_test_circuit( + block: Block, + fixed_table_tags: Vec, + ) -> Result<(), Vec> { + let log2_ceil = |n| u32::BITS - (n as u32).leading_zeros() - (n & (n - 1) == 0) as u32; + + let num_rows_required_for_steps = TestCircuit::get_num_rows_required(&block); + + let k = log2_ceil( + 64 + fixed_table_tags + .iter() + .map(|tag| tag.build::().count()) + .sum::(), + ); + let k = k.max(log2_ceil( + 64 + block + .bytecodes + .iter() + .map(|bytecode| bytecode.bytes.len()) + .sum::(), + )); + let k = k.max(log2_ceil(64 + num_rows_required_for_steps)); + let k = k.max(12); + println!("evm circuit uses k = {}", k); + + let (active_gate_rows, active_lookup_rows) = TestCircuit::get_active_rows(&block); + let circuit = TestCircuit::::new(block, fixed_table_tags); + let prover = MockProver::::run(k, &circuit, vec![]).unwrap(); + prover.verify_at_rows(active_gate_rows.into_iter(), active_lookup_rows.into_iter()) + } + + pub fn run_test_circuit_incomplete_fixed_table( + block: Block, + ) -> Result<(), Vec> { + run_test_circuit( + block, + vec![ + FixedTableTag::Zero, + FixedTableTag::Range5, + FixedTableTag::Range16, + FixedTableTag::Range32, + FixedTableTag::Range64, + FixedTableTag::Range256, + FixedTableTag::Range512, + FixedTableTag::Range1024, + FixedTableTag::SignByte, + FixedTableTag::ResponsibleOpcode, + ], + ) + } + + pub fn run_test_circuit_complete_fixed_table( + block: Block, + ) -> Result<(), Vec> { + run_test_circuit(block, FixedTableTag::iter().collect()) + } \ No newline at end of file diff --git a/zkevm-circuits/src/lib.rs b/zkevm-circuits/src/lib.rs index a40a1482f2..19af4d972d 100644 --- a/zkevm-circuits/src/lib.rs +++ b/zkevm-circuits/src/lib.rs @@ -15,6 +15,7 @@ pub mod bytecode_circuit; pub mod evm_circuit; pub mod rw_table; pub mod state_circuit; +mod full_circuit; #[cfg(test)] pub mod test_util; pub mod util; diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs index 9ef4b984eb..df05f35885 100644 --- a/zkevm-circuits/src/state_circuit.rs +++ b/zkevm-circuits/src/state_circuit.rs @@ -31,6 +31,7 @@ use multiple_precision_integer::{Chip as MpiChip, Config as MpiConfig, Queries a use random_linear_combination::{Chip as RlcChip, Config as RlcConfig, Queries as RlcQueries}; #[cfg(test)] use std::collections::HashMap; +use std::convert::TryInto; const N_LIMBS_RW_COUNTER: usize = 2; const N_LIMBS_ACCOUNT_ADDRESS: usize = 10; @@ -38,12 +39,12 @@ const N_LIMBS_ID: usize = 2; /// Config for StateCircuit #[derive(Clone)] -pub struct StateConfig { +pub struct StateConfig { // Figure out why you get errors when this is Selector. // https://github.com/appliedzkp/zkevm-circuits/issues/407 selector: Column, - rw_table: RwTable, + pub(crate) rw_table: RwTable, rw_counter_mpi: MpiConfig, //is_write: Column, @@ -57,15 +58,15 @@ pub struct StateConfig { is_storage_key_unchanged: IsZeroConfig, lookups: LookupsConfig, - power_of_randomness: [Column; N_BYTES_WORD - 1], + //power_of_randomness: [Column; N_BYTES_WORD - 1], lexicographic_ordering: LexicographicOrderingConfig, } type Lookup = (&'static str, Expression, Expression); /// State Circuit for proving RwTable is valid -#[derive(Default)] -pub struct StateCircuit { +#[derive(Default, Clone)] +pub struct StateCircuit { pub(crate) randomness: F, // use rows rather than RwMap here mainly for testing pub(crate) rows: Vec>, @@ -107,9 +108,6 @@ impl StateCircuit { ) -> Result<(), Error> { region.assign_fixed(|| "selector", config.selector, offset, || Ok(F::one()))?; - config - .rw_table - .assign_row(region, offset, self.randomness, &row)?; config .rw_counter_mpi @@ -172,7 +170,13 @@ impl Circuit for StateCircuit { fn configure(meta: &mut ConstraintSystem) -> Self::Config { let selector = meta.fixed_column(); let lookups = LookupsChip::configure(meta); - let power_of_randomness = [0; N_BYTES_WORD - 1].map(|_| meta.instance_column()); + + let power_of_randomness: [Expression; 31] = (1..32) + .map(|exp| Expression::Constant(F::from_u128(0x1234).pow(&[exp, 0, 0, 0]))) + .collect::>() + .try_into() + .unwrap(); + //let power_of_randomness = [0; N_BYTES_WORD - 1].map(|_| meta.instance_column()); let rw_table = RwTable::construct(meta); let is_storage_key_unchanged_column = meta.advice_column(); @@ -229,7 +233,7 @@ impl Circuit for StateCircuit { lexicographic_ordering, is_storage_key_unchanged, lookups, - power_of_randomness, + //power_of_randomness, rw_table, }; @@ -268,6 +272,13 @@ impl Circuit for StateCircuit { rows.insert(0, Rw::Start.table_assignment(self.randomness)); for (offset, row) in rows.iter().enumerate() { println!("offset {} row {:#?}", offset, row); + + // assign rw table + config + .rw_table + .assign_row(&mut region, offset, self.randomness, &row)?; + + // assign other parts self.assign_row( &config, &mut region, @@ -312,9 +323,11 @@ fn queries(meta: &mut VirtualCells<'_, F>, c: &StateConfig) -> Quer value_col_prev: meta.query_advice(c.rw_table.value, Rotation::prev()), value_prev: meta.query_advice(c.rw_table.value_prev, Rotation::cur()), lookups: LookupsQueries::new(meta, c.lookups), - power_of_randomness: c - .power_of_randomness - .map(|c| meta.query_instance(c, Rotation::cur())), + power_of_randomness: (1..32) + .map(|exp| Expression::Constant(F::from_u128(0x1234).pow(&[exp, 0, 0, 0]))) + .collect::>() + .try_into() + .unwrap(), is_storage_key_unchanged: c.is_storage_key_unchanged.is_zero_expression.clone(), lexicographic_ordering_upper_limb_difference_is_zero: c .lexicographic_ordering diff --git a/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs b/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs index 69295f252f..b7edb91ff4 100644 --- a/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs +++ b/zkevm-circuits/src/state_circuit/lexicographic_ordering.rs @@ -73,7 +73,7 @@ use std::ops::Mul; // = 480 bits #[derive(Clone)] -pub struct Config { +pub struct Config { pub(crate) selector: Column, upper_limb_difference: Column, pub(crate) upper_limb_difference_is_zero: IsZeroConfig, diff --git a/zkevm-circuits/src/state_circuit/random_linear_combination.rs b/zkevm-circuits/src/state_circuit/random_linear_combination.rs index 034d9b219f..36a9796093 100644 --- a/zkevm-circuits/src/state_circuit/random_linear_combination.rs +++ b/zkevm-circuits/src/state_circuit/random_linear_combination.rs @@ -75,7 +75,7 @@ impl Chip { selector: Column, encoded: Column, u8_lookup: Column, - power_of_randomness: [Column; 31], + power_of_randomness: [Expression; 31], ) -> Config { let bytes = [0; N].map(|_| meta.advice_column()); @@ -91,10 +91,10 @@ impl Chip { let selector = meta.query_fixed(selector, Rotation::cur()); let encoded = meta.query_advice(encoded, Rotation::cur()); let bytes = bytes.map(|c| meta.query_advice(c, Rotation::cur())); - let power_of_randomness: Vec<_> = power_of_randomness - .iter() - .map(|c| meta.query_instance(*c, Rotation::cur())) - .collect(); + //let power_of_randomness: Vec<_> = power_of_randomness + // .iter() + //.map(|c| meta.query_instance(*c, Rotation::cur())) + //.collect(); vec![ selector * (encoded - RLC::random_linear_combine_expr(bytes, &power_of_randomness)), ] diff --git a/zkevm-circuits/src/state_circuit/test.rs b/zkevm-circuits/src/state_circuit/test.rs index d6db62824f..16c8a4350d 100644 --- a/zkevm-circuits/src/state_circuit/test.rs +++ b/zkevm-circuits/src/state_circuit/test.rs @@ -19,7 +19,7 @@ use halo2_proofs::{ }; use std::collections::HashMap; -#[derive(Hash, Eq, PartialEq)] +#[derive(Hash, Eq, PartialEq, Clone)] pub enum AdviceColumn { IsWrite, Address, diff --git a/zkevm-circuits/src/test_util.rs b/zkevm-circuits/src/test_util.rs index b2122d4ec4..93d92d3fcf 100644 --- a/zkevm-circuits/src/test_util.rs +++ b/zkevm-circuits/src/test_util.rs @@ -80,6 +80,11 @@ pub fn test_circuits_using_witness_block( block: Block, config: BytecodeTestConfig, ) -> Result<(), Vec> { + + if config.enable_state_circuit_test { + crate::full_circuit::run_test_circuit(block.clone(), config.evm_circuit_lookup_tags)?; + } + /* // run evm circuit test if config.enable_evm_circuit_test { crate::evm_circuit::test::run_test_circuit(block.clone(), config.evm_circuit_lookup_tags)?; @@ -93,7 +98,10 @@ pub fn test_circuits_using_witness_block( let power_of_randomness = state_circuit.instance(); let prover = MockProver::::run(12, &state_circuit, power_of_randomness).unwrap(); prover.verify_at_rows(0..state_circuit.rows.len(), 0..state_circuit.rows.len())? + + } + */ Ok(()) }