Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* Add tx circuit benchmark

* Use halo2wrong tags, revert bench profile changes

* Fix typo

* Use non-empty public inputs
  • Loading branch information
ed255 authored Jun 8, 2022
1 parent c9e0d42 commit e99f95c
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 21 deletions.
4 changes: 4 additions & 0 deletions .github/proverCiScripts/execBench.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ case $circuit in
"state")
run_suffix="state_circuit_prover"
;;
"tx")
run_suffix="tx_circuit_prover"
;;
*)
echo "No proper value"
exit 1
Expand All @@ -32,4 +35,5 @@ esac
cd $target_dir;
logfile=$_date--${circuit}_bench-$k.proverlog

export RUST_BACKTRACE=1
DEGREE=$k ~/.cargo/bin/cargo test --profile bench bench_${run_suffix} -p circuit-benchmarks --features benches -- --nocapture > "$target_dir/$logfile" 2>&1
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions circuit-benchmarks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ rand_xorshift = "0.3"
rand = "0.8"
itertools = "0.10"
eth-types = { path = "../eth-types" }
secp256k1 = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_06_03", features = ["kzg"] }
group = "0.11"
env_logger = "0.9"

[features]
default = []
Expand Down
4 changes: 4 additions & 0 deletions circuit-benchmarks/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ pub mod bench_params;
#[cfg(test)]
#[cfg(feature = "benches")]
pub mod keccak_permutation;

#[cfg(test)]
#[cfg(feature = "benches")]
pub mod tx_circuit;
128 changes: 128 additions & 0 deletions circuit-benchmarks/src/tx_circuit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
//! Tx circuit benchmarks
#[cfg(test)]
mod tests {
use crate::bench_params::DEGREE;
use ark_std::{end_timer, start_timer};
use env_logger::Env;
use eth_types::{address, geth_types::Transaction, word, Bytes};
use group::{Curve, Group};
use halo2_proofs::arithmetic::{BaseExt, CurveAffine, Field};
use halo2_proofs::plonk::{create_proof, keygen_pk, keygen_vk, verify_proof, SingleVerifier};
use halo2_proofs::{
pairing::bn256::{Bn256, Fr, G1Affine},
poly::commitment::{Params, ParamsVerifier},
transcript::{Blake2bRead, Blake2bWrite, Challenge255},
};
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;
use secp256k1::Secp256k1Affine;
use std::marker::PhantomData;
use zkevm_circuits::tx_circuit::{
sign_verify::{SignVerifyChip, POW_RAND_SIZE, VERIF_HEIGHT},
TxCircuit,
};

#[cfg_attr(not(feature = "benches"), ignore)]
#[test]
fn bench_tx_circuit_prover() {
env_logger::Builder::from_env(Env::default().default_filter_or("debug")).init();

// Approximate value, adjust with changes on the TxCircuit.
const ROWS_PER_TX: usize = 175_000;
const MAX_TXS: usize = 2_usize.pow(DEGREE as u32) / ROWS_PER_TX;
const MAX_CALLDATA: usize = 1024;

let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let aux_generator =
<Secp256k1Affine as CurveAffine>::CurveExt::random(&mut rng).to_affine();
let chain_id: u64 = 1337;

// Transaction generated with `zkevm-circuits/src/tx_circuit.rs:rand_tx` using
// `rng = ChaCha20Rng::seed_from_u64(42)`
let txs = vec![Transaction {
from: address!("0x5f9b7e36af4ff81688f712fb738bbbc1b7348aae"),
to: Some(address!("0x701653d7ae8ddaa5c8cee1ee056849f271827926")),
nonce: word!("0x3"),
gas_limit: word!("0x7a120"),
value: word!("0x3e8"),
gas_price: word!("0x4d2"),
gas_fee_cap: word!("0x0"),
gas_tip_cap: word!("0x0"),
call_data: Bytes::from(b"hello"),
access_list: None,
v: 2710,
r: word!("0xaf180d27f90b2b20808bc7670ce0aca862bc2b5fa39c195ab7b1a96225ee14d7"),
s: word!("0x61159fa4664b698ea7d518526c96cd94cf4d8adf418000754be106a3a133f866"),
}];

let randomness = Fr::random(&mut rng);
let mut instance: Vec<Vec<Fr>> = (1..POW_RAND_SIZE + 1)
.map(|exp| vec![randomness.pow(&[exp as u64, 0, 0, 0]); MAX_TXS * VERIF_HEIGHT])
.collect();
// SignVerifyChip -> ECDSAChip -> MainGate instance column
instance.push(vec![]);
let circuit = TxCircuit::<Fr, MAX_TXS, MAX_CALLDATA> {
sign_verify: SignVerifyChip {
aux_generator,
window_size: 2,
_marker: PhantomData,
},
randomness,
txs,
chain_id,
};

// Bench setup generation
let setup_message = format!(
"Setup generation with degree = {} (MAX_TXS = {})",
DEGREE, MAX_TXS
);
let start1 = start_timer!(|| setup_message);
let general_params: Params<G1Affine> =
Params::<G1Affine>::unsafe_setup::<Bn256>(DEGREE.try_into().unwrap());
let verifier_params: ParamsVerifier<Bn256> =
general_params.verifier(MAX_TXS * VERIF_HEIGHT).unwrap();
end_timer!(start1);

// Initialize the proving key
let vk = keygen_vk(&general_params, &circuit).expect("keygen_vk should not fail");
let pk = keygen_pk(&general_params, vk, &circuit).expect("keygen_pk should not fail");
// Create a proof
let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]);

// Bench proof generation time
let proof_message = format!("Tx Proof generation with {} degree", DEGREE);
let start2 = start_timer!(|| proof_message);
let instance_slices: Vec<&[Fr]> = instance.iter().map(|v| &v[..]).collect();
create_proof(
&general_params,
&pk,
&[circuit],
&[&instance_slices[..]],
rng,
&mut transcript,
)
.expect("proof generation should not fail");
let proof = transcript.finalize();
end_timer!(start2);

// Bench verification time
let start3 = start_timer!(|| "Tx Proof verification");
let mut verifier_transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]);
let strategy = SingleVerifier::new(&verifier_params);

verify_proof(
&verifier_params,
pk.get_vk(),
strategy,
&[&instance_slices[..]],
&mut verifier_transcript,
)
.expect("failed to verify bench circuit");
end_timer!(start3);
}
}
26 changes: 16 additions & 10 deletions zkevm-circuits/src/tx_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// - *_be: Big-Endian bytes
// - *_le: Little-Endian bytes

mod sign_verify;
pub mod sign_verify;

use crate::util::{random_linear_combine_word as rlc, Expr};
use eth_types::{
Expand Down Expand Up @@ -165,8 +165,9 @@ pub enum TxFieldTag {
CallData,
}

/// Config for TxCircuit
#[derive(Clone, Debug)]
struct TxCircuitConfig<F: Field> {
pub struct TxCircuitConfig<F: Field> {
tx_id: Column<Advice>,
tag: Column<Advice>,
index: Column<Advice>,
Expand Down Expand Up @@ -230,12 +231,17 @@ impl<F: Field> TxCircuitConfig<F> {
}
}

/// Tx Circuit for verifying transaction signatures
#[derive(Default)]
struct TxCircuit<F: Field, const MAX_TXS: usize, const MAX_CALLDATA: usize> {
sign_verify: SignVerifyChip<F, MAX_TXS>,
randomness: F,
txs: Vec<Transaction>,
chain_id: u64,
pub struct TxCircuit<F: Field, const MAX_TXS: usize, const MAX_CALLDATA: usize> {
/// SignVerify chip
pub sign_verify: SignVerifyChip<F, MAX_TXS>,
/// Randomness for RLC encoding
pub randomness: F,
/// List of Transactions
pub txs: Vec<Transaction>,
/// Chain ID
pub chain_id: u64,
}

impl<F: Field, const MAX_TXS: usize, const MAX_CALLDATA: usize> Circuit<F>
Expand Down Expand Up @@ -414,11 +420,11 @@ mod tx_circuit_tests {
<Secp256k1Affine as CurveAffine>::CurveExt::random(&mut rng).to_affine();

let randomness = F::random(&mut rng);
let mut power_of_randomness: Vec<Vec<F>> = (1..POW_RAND_SIZE + 1)
let mut instance: Vec<Vec<F>> = (1..POW_RAND_SIZE + 1)
.map(|exp| vec![randomness.pow(&[exp as u64, 0, 0, 0]); txs.len() * VERIF_HEIGHT])
.collect();
// SignVerifyChip -> ECDSAChip -> MainGate instance column
power_of_randomness.push(vec![]);
instance.push(vec![]);
let circuit = TxCircuit::<F, MAX_TXS, MAX_CALLDATA> {
sign_verify: SignVerifyChip {
aux_generator,
Expand All @@ -430,7 +436,7 @@ mod tx_circuit_tests {
chain_id,
};

let prover = match MockProver::run(k, &circuit, power_of_randomness) {
let prover = match MockProver::run(k, &circuit, instance) {
Ok(prover) => prover,
Err(e) => panic!("{:#?}", e),
};
Expand Down
28 changes: 17 additions & 11 deletions zkevm-circuits/src/tx_circuit/sign_verify.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Circuit to verify multiple ECDSA secp256k1 signatures.
// Naming notes:
// - *_be: Big-Endian bytes
// - *_le: Little-Endian bytes
Expand Down Expand Up @@ -45,9 +47,12 @@ pub const VERIF_HEIGHT: usize = 1;
/// Auxiliary Gadget to verify a that a message hash is signed by the public
/// key corresponding to an Ethereum Address.
#[derive(Default, Debug)]
pub(crate) struct SignVerifyChip<F: FieldExt, const MAX_VERIF: usize> {
pub struct SignVerifyChip<F: FieldExt, const MAX_VERIF: usize> {
/// Aux generator for EccChip
pub aux_generator: Secp256k1Affine,
/// Window size for EccChip
pub window_size: usize,
/// Marker
pub _marker: PhantomData<F>,
}

Expand Down Expand Up @@ -102,8 +107,9 @@ fn copy_integer_bytes_le<F: FieldExt>(
Ok(())
}

/// SignVerify Configuration
#[derive(Debug, Clone)]
pub struct SignVerifyConfig<F: FieldExt> {
pub(crate) struct SignVerifyConfig<F: FieldExt> {
q_enable: Selector,
pk_hash: [Column<Advice>; 32],
// When address is 0, we disable the signature verification by using a dummy pk, msg_hash and
Expand All @@ -127,7 +133,7 @@ pub struct SignVerifyConfig<F: FieldExt> {
}

impl<F: FieldExt> SignVerifyConfig<F> {
pub fn new(
pub(crate) fn new(
meta: &mut ConstraintSystem<F>,
power_of_randomness: [Expression<F>; POW_RAND_SIZE],
) -> Self {
Expand Down Expand Up @@ -259,13 +265,13 @@ impl<F: FieldExt> SignVerifyConfig<F> {
}
}

pub struct KeccakAux {
pub(crate) struct KeccakAux {
input: [u8; 64],
output: [u8; 32],
}

impl<F: FieldExt> SignVerifyConfig<F> {
pub fn load_range(&self, layouter: &mut impl Layouter<F>) -> Result<(), Error> {
pub(crate) fn load_range(&self, layouter: &mut impl Layouter<F>) -> Result<(), Error> {
let bit_len_lookup = BIT_LEN_LIMB / NUMBER_OF_LOOKUP_LIMBS;
let range_chip = RangeChip::<F>::new(self.range_config.clone(), bit_len_lookup);
range_chip.load_limb_range_table(layouter)?;
Expand Down Expand Up @@ -299,7 +305,7 @@ impl<F: FieldExt> SignVerifyConfig<F> {
Ok(())
}

pub fn load_keccak(
pub(crate) fn load_keccak(
&self,
layouter: &mut impl Layouter<F>,
auxs: Vec<KeccakAux>,
Expand Down Expand Up @@ -335,16 +341,16 @@ impl<F: FieldExt> SignVerifyConfig<F> {
Ok(())
}

pub fn ecc_chip_config(&self) -> EccConfig {
pub(crate) fn ecc_chip_config(&self) -> EccConfig {
EccConfig::new(self.range_config.clone(), self.main_gate_config.clone())
}

pub fn integer_chip_config(&self) -> IntegerConfig {
pub(crate) fn integer_chip_config(&self) -> IntegerConfig {
IntegerConfig::new(self.range_config.clone(), self.main_gate_config.clone())
}
}

pub struct AssignedECDSA<F: FieldExt> {
pub(crate) struct AssignedECDSA<F: FieldExt> {
pk_x_le: [AssignedValue<F>; 32],
pk_y_le: [AssignedValue<F>; 32],
msg_hash_le: [AssignedValue<F>; 32],
Expand Down Expand Up @@ -627,7 +633,7 @@ impl<F: FieldExt, const MAX_VERIF: usize> SignVerifyChip<F, MAX_VERIF> {
))
}

pub fn assign(
pub(crate) fn assign(
&self,
config: &SignVerifyConfig<F>,
layouter: &mut impl Layouter<F>,
Expand Down Expand Up @@ -809,7 +815,7 @@ mod sign_verify_tests {
}

impl<F: FieldExt> TestCircuitSignVerifyConfig<F> {
pub fn new(meta: &mut ConstraintSystem<F>) -> Self {
pub(crate) fn new(meta: &mut ConstraintSystem<F>) -> Self {
// This gate is used just to get the array of expressions from the power of
// randomness instance column, so that later on we don't need to query
// columns everywhere, and can pass the power of randomness array
Expand Down

0 comments on commit e99f95c

Please sign in to comment.