Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Commit

Permalink
feat(zkevm-circuits): improve supercircuit usage
Browse files Browse the repository at this point in the history
Add two new unit tests for the super circuit:
- block with 1 tx with max_txs=2
- block with 2 txs with max_txs=2
The super circuit unit tests are still marked as ignored so that they are
skipped in the github PR checks because they take a long time to run

Improve ergonomics of rows estimation per circuit.  Add a function
`min_num_rows_block` to each circuit (via the SubCircuit trait) to get the
minimum number of required rows to prove a given block. Related to
#982

Resolve #883
  • Loading branch information
ed255 committed Jan 4, 2023
1 parent e74c5e7 commit 8f934de
Show file tree
Hide file tree
Showing 19 changed files with 310 additions and 116 deletions.
2 changes: 1 addition & 1 deletion integration-tests/src/integration_test_circuits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ pub async fn test_super_circuit_block(block_num: u64) {
.unwrap();
let (builder, _) = cli.gen_inputs(block_num).await.unwrap();
let (k, circuit, instance) =
SuperCircuit::<_, MAX_TXS, MAX_CALLDATA, MAX_RWS>::build_from_circuit_input_builder(
SuperCircuit::<Fr, MAX_TXS, MAX_CALLDATA, MAX_RWS>::build_from_circuit_input_builder(
&builder,
)
.unwrap();
Expand Down
4 changes: 2 additions & 2 deletions testool/src/statetest/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use ethers_core::k256::ecdsa::SigningKey;
use ethers_core::types::TransactionRequest;
use ethers_signers::{LocalWallet, Signer};
use external_tracer::TraceConfig;
use halo2_proofs::dev::MockProver;
use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr};
use std::{collections::HashMap, str::FromStr};
use thiserror::Error;
use zkevm_circuits::{super_circuit::SuperCircuit, test_util::BytecodeTestConfig};
Expand Down Expand Up @@ -326,7 +326,7 @@ pub fn run_test(
geth_data.sign(&wallets);

let (k, circuit, instance, _builder) =
SuperCircuit::<_, 1, 32, 255>::build(geth_data).unwrap();
SuperCircuit::<Fr, 1, 32, 255>::build(geth_data).unwrap();
builder = _builder;

let prover = MockProver::run(k, &circuit, instance).unwrap();
Expand Down
9 changes: 9 additions & 0 deletions zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,15 @@ impl<F: Field> SubCircuit<F> for BytecodeCircuit<F> {
Self::new_from_block_sized(block, bytecode_size)
}

/// Return the minimum number of rows required to prove the block
fn min_num_rows_block(block: &witness::Block<F>) -> usize {
block
.bytecodes
.values()
.map(|bytecode| bytecode.bytes.len() + 1)
.sum()
}

/// Make the assignments to the TxCircuit
fn synthesize_sub(
&self,
Expand Down
14 changes: 10 additions & 4 deletions zkevm-circuits/src/copy_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,11 @@ impl<F: Field> SubCircuit<F> for CopyCircuit<F> {
Self::new(block.circuits_params.max_txs, block.clone())
}

/// Return the minimum number of rows required to prove the block
fn min_num_rows_block(block: &witness::Block<F>) -> usize {
block.copy_events.iter().map(|c| c.bytes.len() * 2).sum()
}

/// Make the assignments to the CopyCircuit
fn synthesize_sub(
&self,
Expand Down Expand Up @@ -754,6 +759,7 @@ mod tests {
mock::BlockData,
};
use eth_types::{bytecode, geth_types::GethData, Word};
use halo2_proofs::halo2curves::bn256::Fr;
use mock::test_ctx::helpers::account_0_code_account_1_no_code;
use mock::TestContext;

Expand Down Expand Up @@ -855,28 +861,28 @@ mod tests {
#[test]
fn copy_circuit_valid_calldatacopy() {
let builder = gen_calldatacopy_data();
let block = block_convert(&builder.block, &builder.code_db).unwrap();
let block = block_convert::<Fr>(&builder.block, &builder.code_db).unwrap();
assert_eq!(test_copy_circuit(14, block), Ok(()));
}

#[test]
fn copy_circuit_valid_codecopy() {
let builder = gen_codecopy_data();
let block = block_convert(&builder.block, &builder.code_db).unwrap();
let block = block_convert::<Fr>(&builder.block, &builder.code_db).unwrap();
assert_eq!(test_copy_circuit(10, block), Ok(()));
}

#[test]
fn copy_circuit_valid_sha3() {
let builder = gen_sha3_data();
let block = block_convert(&builder.block, &builder.code_db).unwrap();
let block = block_convert::<Fr>(&builder.block, &builder.code_db).unwrap();
assert_eq!(test_copy_circuit(20, block), Ok(()));
}

#[test]
fn copy_circuit_tx_log() {
let builder = gen_tx_log_data();
let block = block_convert(&builder.block, &builder.code_db).unwrap();
let block = block_convert::<Fr>(&builder.block, &builder.code_db).unwrap();
assert_eq!(test_copy_circuit(10, block), Ok(()));
}

Expand Down
77 changes: 44 additions & 33 deletions zkevm-circuits/src/evm_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ pub(crate) mod util;
pub mod table;

use crate::table::{BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, RwTable, TxTable};
use crate::util::{Challenges, SubCircuit, SubCircuitConfig};
use crate::util::{log2_ceil, Challenges, SubCircuit, SubCircuitConfig};
pub use crate::witness;
use bus_mapping::evm::OpcodeId;
use eth_types::Field;
use execution::ExecutionConfig;
use itertools::Itertools;
Expand Down Expand Up @@ -211,6 +212,20 @@ impl<F: Field> SubCircuit<F> for EvmCircuit<F> {
Self::new(block.clone())
}

/// Return the minimum number of rows required to prove the block
fn min_num_rows_block(block: &witness::Block<F>) -> usize {
let num_rows_required_for_execution_steps: usize =
EvmCircuit::<F>::get_num_rows_required(block);
let num_rows_required_for_fixed_table: usize = detect_fixed_table_tags(block)
.iter()
.map(|tag| tag.build::<F>().count())
.sum();
std::cmp::max(
num_rows_required_for_execution_steps,
num_rows_required_for_fixed_table,
)
}

/// Make the assignments to the EvmCircuit
fn synthesize_sub(
&self,
Expand All @@ -226,18 +241,42 @@ impl<F: Field> SubCircuit<F> for EvmCircuit<F> {
}
}

/// create fixed_table_tags needed given witness block
pub(crate) fn detect_fixed_table_tags<F: Field>(block: &Block<F>) -> Vec<FixedTableTag> {
let need_bitwise_lookup = block.txs.iter().any(|tx| {
tx.steps.iter().any(|step| {
matches!(
step.opcode,
Some(OpcodeId::AND)
| Some(OpcodeId::OR)
| Some(OpcodeId::XOR)
| Some(OpcodeId::NOT)
)
})
});
FixedTableTag::iter()
.filter(|t| {
!matches!(
t,
FixedTableTag::BitwiseAnd | FixedTableTag::BitwiseOr | FixedTableTag::BitwiseXor
) || need_bitwise_lookup
})
.collect()
}

#[cfg(any(feature = "test", test))]
pub mod test {
use super::*;
use crate::{
evm_circuit::{table::FixedTableTag, witness::Block, EvmCircuitConfig},
evm_circuit::{witness::Block, EvmCircuitConfig},
exp_circuit::OFFSET_INCREMENT,
table::{BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, RwTable, TxTable},
util::{power_of_randomness_from_instance, Challenges},
witness::block_convert,
};
use bus_mapping::{circuit_input_builder::CircuitsParams, evm::OpcodeId, mock::BlockData};
use bus_mapping::{circuit_input_builder::CircuitsParams, mock::BlockData};
use eth_types::{geth_types::GethData, Field, Word};
use halo2_proofs::halo2curves::bn256::Fr;
use halo2_proofs::{
circuit::{Layouter, SimpleFloorPlanner, Value},
dev::{MockProver, VerifyFailure},
Expand All @@ -247,7 +286,6 @@ pub mod test {
distributions::uniform::{SampleRange, SampleUniform},
random, thread_rng, Rng,
};
use strum::IntoEnumIterator;

pub(crate) fn rand_range<T, R>(range: R) -> T
where
Expand All @@ -269,31 +307,6 @@ pub mod test {
Word::from_big_endian(&rand_bytes_array::<32>())
}

/// create fixed_table_tags needed given witness block
pub(crate) fn detect_fixed_table_tags<F: Field>(block: &Block<F>) -> Vec<FixedTableTag> {
let need_bitwise_lookup = block.txs.iter().any(|tx| {
tx.steps.iter().any(|step| {
matches!(
step.opcode,
Some(OpcodeId::AND)
| Some(OpcodeId::OR)
| Some(OpcodeId::XOR)
| Some(OpcodeId::NOT)
)
})
});
FixedTableTag::iter()
.filter(|t| {
!matches!(
t,
FixedTableTag::BitwiseAnd
| FixedTableTag::BitwiseOr
| FixedTableTag::BitwiseXor
) || need_bitwise_lookup
})
.collect()
}

impl<F: Field> Circuit<F> for EvmCircuit<F> {
type Config = EvmCircuitConfig<F>;
type FloorPlanner = SimpleFloorPlanner;
Expand Down Expand Up @@ -391,7 +404,7 @@ pub mod test {
builder
.handle_block(&block.eth_block, &block.geth_traces)
.unwrap();
let block = block_convert(&builder.block, &builder.code_db).unwrap();
let block = block_convert::<Fr>(&builder.block, &builder.code_db).unwrap();
run_test_circuit(block)
}

Expand All @@ -404,7 +417,7 @@ pub mod test {
builder
.handle_block(&block.eth_block, &block.geth_traces)
.unwrap();
let block = block_convert(&builder.block, &builder.code_db).unwrap();
let block = block_convert::<Fr>(&builder.block, &builder.code_db).unwrap();
run_test_circuit(block)
}

Expand Down Expand Up @@ -432,8 +445,6 @@ pub mod test {
.map(|e| e.steps.len() * OFFSET_INCREMENT)
.sum();

let log2_ceil = |n| u32::BITS - (n as u32).leading_zeros() - (n & (n - 1) == 0) as u32;

const NUM_BLINDING_ROWS: usize = 64;

let rows_needed: usize = itertools::max([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ mod test {
use eth_types::evm_types::OpcodeId;
use eth_types::geth_types::Account;
use eth_types::{address, bytecode, Address, ToWord, Word};
use halo2_proofs::halo2curves::bn256::Fr;
use mock::TestContext;

fn test_invalid_jump(destination: usize, out_of_range: bool) {
Expand Down Expand Up @@ -448,7 +449,7 @@ mod test {
builder
.handle_block(&block_data.eth_block, &block_data.geth_traces)
.unwrap();
let block = block_convert(&builder.block, &builder.code_db).unwrap();
let block = block_convert::<Fr>(&builder.block, &builder.code_db).unwrap();
assert_eq!(run_test_circuit(block), Ok(()));
}

Expand Down
3 changes: 2 additions & 1 deletion zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ mod test {
use eth_types::{address, bytecode};
use eth_types::{bytecode::Bytecode, evm_types::OpcodeId, geth_types::Account};
use eth_types::{Address, ToWord, Word};
use halo2_proofs::halo2curves::bn256::Fr;
use itertools::Itertools;
use mock::TestContext;
use std::default::Default;
Expand Down Expand Up @@ -420,7 +421,7 @@ mod test {
builder
.handle_block(&block_data.eth_block, &block_data.geth_traces)
.unwrap();
let block = block_convert(&builder.block, &builder.code_db);
let block = block_convert::<Fr>(&builder.block, &builder.code_db);
assert_eq!(run_test_circuit(block.unwrap()), Ok(()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ mod test {
builder
.handle_block(&block_data.eth_block, &block_data.geth_traces)
.unwrap();
let block = block_convert(&builder.block, &builder.code_db).unwrap();
let block = block_convert::<Fr>(&builder.block, &builder.code_db).unwrap();
assert_eq!(run_test_circuit(block), Ok(()));
}

Expand Down
3 changes: 2 additions & 1 deletion zkevm-circuits/src/evm_circuit/execution/error_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ mod test {
use eth_types::{
self, address, bytecode, bytecode::Bytecode, geth_types::Account, Address, ToWord, Word,
};
use halo2_proofs::halo2curves::bn256::Fr;

use mock::TestContext;

Expand Down Expand Up @@ -320,7 +321,7 @@ mod test {
builder
.handle_block(&block_data.eth_block, &block_data.geth_traces)
.unwrap();
let block = block_convert(&builder.block, &builder.code_db);
let block = block_convert::<Fr>(&builder.block, &builder.code_db);
assert_eq!(run_test_circuit(block.unwrap()), Ok(()));
}

Expand Down
3 changes: 2 additions & 1 deletion zkevm-circuits/src/evm_circuit/execution/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ mod test {
};
use bus_mapping::mock::BlockData;
use eth_types::{address, bytecode, geth_types::GethData, Word};
use halo2_proofs::halo2curves::bn256::Fr;
use mock::TestContext;

fn test_ok() {
Expand Down Expand Up @@ -150,7 +151,7 @@ mod test {
builder
.handle_block(&block.eth_block, &block.geth_traces)
.expect("could not handle block tx");
let mut block = block_convert(&builder.block, &builder.code_db).unwrap();
let mut block = block_convert::<Fr>(&builder.block, &builder.code_db).unwrap();

// The above block has 2 steps (GAS and STOP). We forcefully assign a
// wrong `gas_left` value for the second step, to assert that
Expand Down
14 changes: 12 additions & 2 deletions zkevm-circuits/src/exp_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,15 @@ impl<F: Field> SubCircuit<F> for ExpCircuit<F> {
Self::new(block.clone())
}

/// Return the minimum number of rows required to prove the block
fn min_num_rows_block(block: &witness::Block<F>) -> usize {
block
.exp_events
.iter()
.map(|e| e.steps.len() * OFFSET_INCREMENT)
.sum()
}

/// Make the assignments to the ExpCircuit
fn synthesize_sub(
&self,
Expand Down Expand Up @@ -462,6 +471,7 @@ pub mod dev {
mod tests {
use bus_mapping::{circuit_input_builder::CircuitInputBuilder, evm::OpcodeId, mock::BlockData};
use eth_types::{bytecode, geth_types::GethData, Bytecode, Word};
use halo2_proofs::halo2curves::bn256::Fr;
use mock::TestContext;

use crate::{evm_circuit::witness::block_convert, exp_circuit::dev::test_exp_circuit};
Expand Down Expand Up @@ -499,14 +509,14 @@ mod tests {
fn test_ok(base: Word, exponent: Word, k: Option<u32>) {
let code = gen_code_single(base, exponent);
let builder = gen_data(code);
let block = block_convert(&builder.block, &builder.code_db).unwrap();
let block = block_convert::<Fr>(&builder.block, &builder.code_db).unwrap();
assert_eq!(test_exp_circuit(k.unwrap_or(10), block), Ok(()));
}

fn test_ok_multiple(args: Vec<(Word, Word)>) {
let code = gen_code_multiple(args);
let builder = gen_data(code);
let block = block_convert(&builder.block, &builder.code_db).unwrap();
let block = block_convert::<Fr>(&builder.block, &builder.code_db).unwrap();
assert_eq!(test_exp_circuit(20, block), Ok(()));
}

Expand Down
12 changes: 11 additions & 1 deletion zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const THETA_C_LOOKUP_RANGE: usize = 6;
const RHO_PI_LOOKUP_RANGE: usize = 4;
const CHI_BASE_LOOKUP_RANGE: usize = 5;

fn get_num_rows_per_round() -> usize {
pub(crate) fn get_num_rows_per_round() -> usize {
var("KECCAK_ROWS")
.unwrap_or_else(|_| "5".to_string())
.parse()
Expand Down Expand Up @@ -370,6 +370,16 @@ impl<F: Field> SubCircuit<F> for KeccakCircuit<F> {
)
}

/// Return the minimum number of rows required to prove the block
fn min_num_rows_block(block: &witness::Block<F>) -> usize {
let rows_per_chunk = (NUM_ROUNDS + 1) * get_num_rows_per_round();
block
.keccak_inputs
.iter()
.map(|bytes| (bytes.len() as f64 / 136.0).ceil() as usize * rows_per_chunk)
.sum()
}

/// Make the assignments to the KeccakCircuit
fn synthesize_sub(
&self,
Expand Down
Loading

0 comments on commit 8f934de

Please sign in to comment.