Skip to content
This repository was archived by the owner on Apr 18, 2025. It is now read-only.

Commit 6deaabd

Browse files
darth-cyroynalnarutolispc
authored
feat: refactor sig_circuit and ecc_circuit row capacity estimation (#669)
* feat: add trace-level log on halo2-lib ctx pos for ecc * add constant row accounting for ec ops * Add blinding factors to CircuitStats * feat: increase sig circuit degree to 20 * impl: correct sig circuit min_num_rows_block fn * remove unnecessary import * correct documentation * restore super circuit tests * impl unusable_row fn for ecc/sig to conform to blinding factor * preserve naming * add minimum row to sig circuit as a fractional repr for total capacity * correct min_row_num accounting for ecc/sig * remove unnecessary import * try super circuit integration tests * restore ignored tests * resolve max_tx_count for sig circuit * conform to rustfmt * fmt for clippy * correct tx circuit target degree * exclude tx circuit tests from default --------- Co-authored-by: Rohit Narurkar <[email protected]> Co-authored-by: Zhang Zhuo <[email protected]>
1 parent f05db90 commit 6deaabd

File tree

7 files changed

+173
-51
lines changed

7 files changed

+173
-51
lines changed

zkevm-circuits/src/ecc_circuit.rs

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ use itertools::Itertools;
3232
use log::error;
3333

3434
use crate::{
35+
evm_circuit::EvmCircuit,
36+
keccak_circuit::KeccakCircuit,
3537
table::{EccTable, LookupTable},
3638
util::{Challenges, SubCircuit, SubCircuitConfig},
3739
witness::Block,
@@ -47,6 +49,12 @@ use util::{
4749

4850
use self::util::LOG_TOTAL_NUM_ROWS;
4951

52+
macro_rules! log_context_cursor {
53+
($ctx: ident) => {{
54+
log::trace!("Ctx cell pos: {:?}", $ctx.advice_alloc);
55+
}};
56+
}
57+
5058
/// Arguments accepted to configure the EccCircuitConfig.
5159
#[derive(Clone, Debug)]
5260
pub struct EccCircuitConfigArgs<F: Field> {
@@ -405,10 +413,16 @@ impl<F: Field, const XI_0: i64> EccCircuit<F, XI_0> {
405413
powers_of_rand: &[QuantumCell<F>],
406414
op: &EcAddOp,
407415
) -> EcAddAssigned<F> {
416+
log::trace!("[ECC] ==> EcAdd Assignmnet START:");
417+
log_context_cursor!(ctx);
418+
408419
let point_p = self.assign_g1(ctx, ecc_chip, op.p, powers_of_rand);
409420
let point_q = self.assign_g1(ctx, ecc_chip, op.q, powers_of_rand);
410421
let point_r = self.assign_g1(ctx, ecc_chip, op.r, powers_of_rand);
411422

423+
log::trace!("[ECC] EcAdd Inputs Assigned:");
424+
log_context_cursor!(ctx);
425+
412426
// We follow the approach mentioned below to handle many edge cases for the points P, Q and
413427
// R so that we can maintain the same fixed and permutation columns and reduce the overall
414428
// validation process from the EVM Circuit.
@@ -472,6 +486,8 @@ impl<F: Field, const XI_0: i64> EccCircuit<F, XI_0> {
472486

473487
ecc_chip.assert_equal(ctx, &rand_point, &sum3);
474488

489+
log::trace!("[ECC] EcAdd Assignmnet END:");
490+
log_context_cursor!(ctx);
475491
EcAddAssigned {
476492
point_p,
477493
point_q,
@@ -490,9 +506,16 @@ impl<F: Field, const XI_0: i64> EccCircuit<F, XI_0> {
490506
powers_of_rand: &[QuantumCell<F>],
491507
op: &EcMulOp,
492508
) -> EcMulAssigned<F> {
509+
log::trace!("[ECC] ==> EcMul Assignmnet START:");
510+
log_context_cursor!(ctx);
511+
493512
let point_p = self.assign_g1(ctx, ecc_chip, op.p, powers_of_rand);
494513
let scalar_s = self.assign_fr(ctx, fr_chip, op.s);
495514
let point_r = self.assign_g1(ctx, ecc_chip, op.r, powers_of_rand);
515+
516+
log::trace!("[ECC] EcMul Inputs Assigned:");
517+
log_context_cursor!(ctx);
518+
496519
let point_r_got = ecc_chip.scalar_mult(
497520
ctx,
498521
&point_p.decomposed.ec_point,
@@ -501,6 +524,10 @@ impl<F: Field, const XI_0: i64> EccCircuit<F, XI_0> {
501524
4, // TODO: window bits?
502525
);
503526
ecc_chip.assert_equal(ctx, &point_r.decomposed.ec_point, &point_r_got);
527+
528+
log::trace!("[ECC] EcMul Assignmnet END:");
529+
log_context_cursor!(ctx);
530+
504531
EcMulAssigned {
505532
point_p,
506533
scalar_s,
@@ -519,6 +546,9 @@ impl<F: Field, const XI_0: i64> EccCircuit<F, XI_0> {
519546
powers_of_rand: &[QuantumCell<F>],
520547
op: &EcPairingOp,
521548
) -> EcPairingAssigned<F> {
549+
log::trace!("[ECC] ==> EcPairing Assignment START:");
550+
log_context_cursor!(ctx);
551+
522552
let g1s = op
523553
.pairs
524554
.iter()
@@ -544,6 +574,10 @@ impl<F: Field, const XI_0: i64> EccCircuit<F, XI_0> {
544574
}
545575
})
546576
.collect_vec();
577+
578+
log::trace!("[ECC] EcPairing g1s Assigned:");
579+
log_context_cursor!(ctx);
580+
547581
let g2s = op
548582
.pairs
549583
.iter()
@@ -583,6 +617,9 @@ impl<F: Field, const XI_0: i64> EccCircuit<F, XI_0> {
583617
})
584618
.collect_vec();
585619

620+
log::trace!("[ECC] EcPairing g2s Assigned:");
621+
log_context_cursor!(ctx);
622+
586623
// RLC over the entire input bytes.
587624
let input_cells = g1s
588625
.iter()
@@ -606,6 +643,9 @@ impl<F: Field, const XI_0: i64> EccCircuit<F, XI_0> {
606643
powers_of_rand.iter().cloned(),
607644
);
608645

646+
log::trace!("[ECC] EcPairing Inputs RLC Assigned:");
647+
log_context_cursor!(ctx);
648+
609649
let pairs = g1s
610650
.iter()
611651
.zip(g2s.iter())
@@ -630,6 +670,9 @@ impl<F: Field, const XI_0: i64> EccCircuit<F, XI_0> {
630670
)),
631671
);
632672

673+
log::trace!("[ECC] EcPairingAssignment END:");
674+
log_context_cursor!(ctx);
675+
633676
EcPairingAssigned {
634677
g1s,
635678
g2s,
@@ -732,6 +775,19 @@ impl<F: Field, const XI_0: i64> SubCircuit<F> for EccCircuit<F, XI_0> {
732775
}
733776
}
734777

778+
/// Returns number of unusable rows of the SubCircuit, which should be
779+
/// `meta.blinding_factors() + 1`.
780+
fn unusable_rows() -> usize {
781+
[
782+
KeccakCircuit::<F>::unusable_rows(),
783+
EvmCircuit::<F>::unusable_rows(),
784+
// may include additional subcircuits here
785+
]
786+
.into_iter()
787+
.max()
788+
.unwrap()
789+
}
790+
735791
fn synthesize_sub(
736792
&self,
737793
config: &Self::Config,
@@ -743,7 +799,33 @@ impl<F: Field, const XI_0: i64> SubCircuit<F> for EccCircuit<F, XI_0> {
743799
Ok(())
744800
}
745801

746-
fn min_num_rows_block(_block: &Block<F>) -> (usize, usize) {
747-
unimplemented!()
802+
fn min_num_rows_block(block: &Block<F>) -> (usize, usize) {
803+
// EccCircuit can't determine usable rows independently.
804+
// Instead, the blinding area is determined by other advise columns with most counts of
805+
// rotation queries. This value is typically determined by either the Keccak or EVM
806+
// circuit.
807+
808+
let max_blinding_factor = Self::unusable_rows() - 1;
809+
810+
// same formula as halo2-lib's FlexGate
811+
let row_num = (1 << LOG_TOTAL_NUM_ROWS) - (max_blinding_factor + 3);
812+
813+
let ec_adds = block.get_ec_add_ops().len();
814+
let ec_muls = block.get_ec_mul_ops().len();
815+
let ec_pairings = block.get_ec_pairing_ops().len();
816+
817+
// Instead of showing actual minimum row usage,
818+
// halo2-lib based circuits use min_row_num to represent a percentage of total-used capacity
819+
// This functionality allows l2geth to decide if additional ops can be added.
820+
let min_row_num = [
821+
(row_num / block.circuits_params.max_ec_ops.ec_add) * ec_adds,
822+
(row_num / block.circuits_params.max_ec_ops.ec_mul) * ec_muls,
823+
(row_num / block.circuits_params.max_ec_ops.ec_pairing) * ec_pairings,
824+
]
825+
.into_iter()
826+
.max()
827+
.unwrap();
828+
829+
(min_row_num, row_num)
748830
}
749831
}

zkevm-circuits/src/ecc_circuit/util.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@ use eth_types::Field;
22
use halo2_base::{AssignedValue, QuantumCell};
33
use halo2_ecc::{bigint::CRTInteger, ecc::EcPoint, fields::FieldExtPoint};
44

5+
// Total number of rows allowable for ECC circuit
56
pub const LOG_TOTAL_NUM_ROWS: u32 = 20;
67

8+
// Cell usage accounting for EcAdd, EcMul and EcPairing
9+
// Roud up to nearest 100
10+
pub(super) const EC_ADD_CELLS: usize = 6_900; // actual: 6_851
11+
pub(super) const EC_MUL_CELLS: usize = 405_500; // actual: 405_476
12+
pub(super) const EC_PAIRING_CELLS: usize = 6_627_500; // actual: 6_627_442
13+
pub(super) const COLUMN_NUM_LIMIT: usize = 150; // Max number of columns allowed
14+
715
pub struct G1Decomposed<F: Field> {
816
pub ec_point: EcPoint<F, CRTInteger<F>>,
917
pub x_cells: Vec<QuantumCell<F>>,

zkevm-circuits/src/sig_circuit.rs

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ mod dev;
1515
mod test;
1616

1717
use crate::{
18-
evm_circuit::util::{not, rlc},
18+
evm_circuit::{
19+
util::{not, rlc},
20+
EvmCircuit,
21+
},
22+
keccak_circuit::KeccakCircuit,
1923
sig_circuit::ecdsa::ecdsa_verify_no_pubkey_check,
2024
table::{KeccakTable, SigTable},
2125
util::{Challenges, Expr, SubCircuit, SubCircuitConfig},
@@ -221,6 +225,19 @@ impl<F: Field> SubCircuit<F> for SigCircuit<F> {
221225
}
222226
}
223227

228+
/// Returns number of unusable rows of the SubCircuit, which should be
229+
/// `meta.blinding_factors() + 1`.
230+
fn unusable_rows() -> usize {
231+
[
232+
KeccakCircuit::<F>::unusable_rows(),
233+
EvmCircuit::<F>::unusable_rows(),
234+
// may include additional subcircuits here
235+
]
236+
.into_iter()
237+
.max()
238+
.unwrap()
239+
}
240+
224241
fn synthesize_sub(
225242
&self,
226243
config: &Self::Config,
@@ -235,8 +252,17 @@ impl<F: Field> SubCircuit<F> for SigCircuit<F> {
235252
// Since sig circuit / halo2-lib use veticle cell assignment,
236253
// so the returned pair is consisted of same values
237254
fn min_num_rows_block(block: &crate::witness::Block<F>) -> (usize, usize) {
238-
let row_num = Self::min_num_rows(block.circuits_params.max_txs);
239-
(row_num, row_num)
255+
let row_num = Self::min_num_rows();
256+
257+
let tx_count = block.txs.len();
258+
let max_tx_count = block.circuits_params.max_txs;
259+
260+
// Instead of showing actual minimum row usage,
261+
// halo2-lib based circuits use min_row_num to represent a percentage of total-used capacity
262+
// This functionality allows l2geth to decide if additional ops can be added.
263+
let min_row_num = (row_num / max_tx_count) * tx_count;
264+
265+
(min_row_num, row_num)
240266
}
241267
}
242268

@@ -252,32 +278,20 @@ impl<F: Field> SigCircuit<F> {
252278

253279
/// Return the minimum number of rows required to prove an input of a
254280
/// particular size.
255-
/// TODO: minus 256?
256-
pub fn min_num_rows(num_verif: usize) -> usize {
281+
pub fn min_num_rows() -> usize {
282+
// SigCircuit can't determine usable rows independently.
283+
// Instead, the blinding area is determined by other advise columns with most counts of
284+
// rotation queries. This value is typically determined by either the Keccak or EVM
285+
// circuit.
286+
257287
// the cells are allocated vertically, i.e., given a TOTAL_NUM_ROWS * NUM_ADVICE
258288
// matrix, the allocator will try to use all the cells in the first column, then
259289
// the second column, etc.
260-
let row_num = 1 << LOG_TOTAL_NUM_ROWS;
261-
let col_num = calc_required_advices(num_verif);
262-
if num_verif * CELLS_PER_SIG > col_num * row_num {
263-
log::error!(
264-
"ecdsa chip not enough rows. rows: {}, advice {}, num of sigs {}, cells per sig {}",
265-
row_num,
266-
col_num,
267-
num_verif,
268-
CELLS_PER_SIG
269-
)
270-
} else {
271-
log::debug!(
272-
"ecdsa chip: rows: {}, advice {}, num of sigs {}, cells per sig {}",
273-
row_num,
274-
col_num,
275-
num_verif,
276-
CELLS_PER_SIG
277-
)
278-
}
279290

280-
row_num
291+
let max_blinding_factor = Self::unusable_rows() - 1;
292+
293+
// same formula as halo2-lib's FlexGate
294+
(1 << LOG_TOTAL_NUM_ROWS) - (max_blinding_factor + 3)
281295
}
282296
}
283297

zkevm-circuits/src/sig_circuit/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub(super) const MAX_NUM_SIG: usize = 32;
1717
// We set CELLS_PER_SIG = 535000 to allows for a few buffer
1818
pub(super) const CELLS_PER_SIG: usize = 535000;
1919
// Total number of rows allocated for ecdsa chip
20-
pub(super) const LOG_TOTAL_NUM_ROWS: usize = 19;
20+
pub(super) const LOG_TOTAL_NUM_ROWS: usize = 20;
2121
// Max number of columns allowed
2222
pub(super) const COLUMN_NUM_LIMIT: usize = 150;
2323

0 commit comments

Comments
 (0)