From 25eb964a177d0e9a53da10713c919872e0c84e6c Mon Sep 17 00:00:00 2001 From: z2trillion Date: Tue, 5 Nov 2024 09:49:13 -0500 Subject: [PATCH 1/8] Add constrain_crt_equals_bytes, blob_crts, and challenge_digest functions --- aggregator/src/aggregation/batch_data.rs | 46 ++++------------ aggregator/src/aggregation/circuit.rs | 5 +- aggregator/src/aggregation/util.rs | 52 ++++++++++++++++++- .../blob_consistency/eip4844/barycentric.rs | 12 ++++- .../src/blob_consistency/eip4844/tests.rs | 2 +- 5 files changed, 74 insertions(+), 43 deletions(-) diff --git a/aggregator/src/aggregation/batch_data.rs b/aggregator/src/aggregation/batch_data.rs index 221a059e5b..4ea98a7725 100644 --- a/aggregator/src/aggregation/batch_data.rs +++ b/aggregator/src/aggregation/batch_data.rs @@ -1,6 +1,6 @@ use crate::{ - aggregation::rlc::POWS_OF_256, blob_consistency::BLOB_WIDTH, constants::N_BYTES_U256, - BatchHash, ChunkInfo, RlcConfig, + aggregation::rlc::POWS_OF_256, aggregation::util::constrain_crt_equals_bytes, + blob_consistency::BLOB_WIDTH, constants::N_BYTES_U256, BatchHash, ChunkInfo, RlcConfig, }; use eth_types::{H256, U256}; use ethers_core::utils::keccak256; @@ -401,7 +401,7 @@ impl BatchDataConfig { chunks_are_padding: &[AssignedCell], batch_data: &BatchData, versioned_hash: H256, - barycentric_assignments: &[CRTInteger], + challenge_digest: &CRTInteger, ) -> Result { self.load_range_tables(layouter)?; @@ -418,7 +418,7 @@ impl BatchDataConfig { challenge_value, rlc_config, chunks_are_padding, - barycentric_assignments, + challenge_digest, &assigned_rows, ) }, @@ -550,7 +550,7 @@ impl BatchDataConfig { // The chunks_are_padding assigned cells are exports from the conditional constraints in // `core.rs`. Since these are already constrained, we can just use them as is. chunks_are_padding: &[AssignedCell], - barycentric_assignments: &[CRTInteger], + assigned_challenge_digest: &CRTInteger, assigned_rows: &[AssignedBatchDataConfig], ) -> Result { let n_rows_metadata = BatchData::::n_rows_metadata(); @@ -996,41 +996,13 @@ impl BatchDataConfig { //////////////////////////////////////////////////////////////////////////////// //////////////////////////// CHALLENGE DIGEST CHECK //////////////////////////// //////////////////////////////////////////////////////////////////////////////// - - assert_eq!(barycentric_assignments.len(), BLOB_WIDTH + 1); - let challenge_digest_crt = barycentric_assignments - .get(BLOB_WIDTH) - .expect("challenge digest CRT"); - let challenge_digest_limb1 = rlc_config.inner_product( - region, - &challenge_digest[0..11], - &pows_of_256, - &mut rlc_config_offset, - )?; - let challenge_digest_limb2 = rlc_config.inner_product( - region, - &challenge_digest[11..22], - &pows_of_256, - &mut rlc_config_offset, - )?; - let challenge_digest_limb3 = rlc_config.inner_product( + constrain_crt_equals_bytes( region, - &challenge_digest[22..32], - &pows_of_256[0..10], + rlc_config, + assigned_challenge_digest, + &challenge_digest, &mut rlc_config_offset, )?; - region.constrain_equal( - challenge_digest_limb1.cell(), - challenge_digest_crt.truncation.limbs[0].cell(), - )?; - region.constrain_equal( - challenge_digest_limb2.cell(), - challenge_digest_crt.truncation.limbs[1].cell(), - )?; - region.constrain_equal( - challenge_digest_limb3.cell(), - challenge_digest_crt.truncation.limbs[2].cell(), - )?; Ok(export) } diff --git a/aggregator/src/aggregation/circuit.rs b/aggregator/src/aggregation/circuit.rs index b9a3cc7c79..2b85863065 100644 --- a/aggregator/src/aggregation/circuit.rs +++ b/aggregator/src/aggregation/circuit.rs @@ -394,7 +394,6 @@ impl Circuit for BatchCircuit { // blob data config { - let barycentric_assignments = &barycentric.barycentric_assignments; let challenge_le = &barycentric.z_le; let evaluation_le = &barycentric.y_le; @@ -410,7 +409,7 @@ impl Circuit for BatchCircuit { BlobConsistencyConfig::::link( &mut layouter, &blob_data_exports.blob_crts_limbs, - barycentric_assignments, + barycentric.blob_crts(), )?; let batch_data_exports = config.batch_data_config.assign( @@ -420,7 +419,7 @@ impl Circuit for BatchCircuit { &assigned_batch_hash.chunks_are_padding, &batch_data, self.batch_hash.blob_consistency_witness.id(), - barycentric_assignments, + barycentric.challenge_digest(), )?; // conditionally encode those bytes. By default we use a worked example. diff --git a/aggregator/src/aggregation/util.rs b/aggregator/src/aggregation/util.rs index 95ff9061f0..58b73a2fe3 100644 --- a/aggregator/src/aggregation/util.rs +++ b/aggregator/src/aggregation/util.rs @@ -1,8 +1,13 @@ +use crate::RlcConfig; use gadgets::util::Expr; +use halo2_ecc::bigint::CRTInteger; use halo2_proofs::{ - plonk::{Advice, Column, ConstraintSystem, Expression, VirtualCells}, + circuit::{AssignedCell, Region}, + halo2curves::{bn256::Fr, group::ff::PrimeField}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells}, poly::Rotation, }; +use itertools::Itertools; use zkevm_circuits::util::Field; #[derive(Clone, Copy, Debug)] @@ -29,3 +34,48 @@ impl BooleanAdvice { meta.query_advice(self.column, at) } } + +pub fn constrain_crt_equals_bytes( + region: &mut Region, + rlc_config: &RlcConfig, + crt: &CRTInteger, + bytes: &[AssignedCell], + rlc_config_offset: &mut usize, +) -> Result<(), Error> { + let mut powers_of_256 = vec![]; + for i in 0..11 { + let assigned_cell = + rlc_config.load_private(region, &Fr::from_u128(256u128.pow(i)), rlc_config_offset)?; + let region_index = assigned_cell.cell().region_index; + let fixed_cell = if i == 0 { + rlc_config.one_cell(region_index) + } else { + rlc_config + .pow_of_two_hundred_and_fifty_six_cell(region_index, usize::try_from(i).unwrap()) + }; + region.constrain_equal(fixed_cell, assigned_cell.cell())?; + powers_of_256.push(assigned_cell); + } + + let limb_from_bytes_lo = + rlc_config.inner_product(region, &bytes[0..11], &powers_of_256, rlc_config_offset)?; + let limb_from_bytes_mid = + rlc_config.inner_product(region, &bytes[11..22], &powers_of_256, rlc_config_offset)?; + let limb_from_bytes_hi = rlc_config.inner_product( + region, + &bytes[22..32], + &powers_of_256[0..10], + rlc_config_offset, + )?; + + for (limb_from_bytes, crt_limb) in [limb_from_bytes_lo, limb_from_bytes_mid, limb_from_bytes_hi] + .iter() + .zip_eq(crt.limbs()) + { + region.constrain_equal(limb_from_bytes.cell(), crt_limb.cell())? + } + + Ok(()) + + // This can just be a collect.... +} diff --git a/aggregator/src/blob_consistency/eip4844/barycentric.rs b/aggregator/src/blob_consistency/eip4844/barycentric.rs index c46f20c068..6c3e916eaf 100644 --- a/aggregator/src/blob_consistency/eip4844/barycentric.rs +++ b/aggregator/src/blob_consistency/eip4844/barycentric.rs @@ -55,13 +55,23 @@ pub struct BarycentricEvaluationConfig { pub struct AssignedBarycentricEvaluationConfig { /// CRTIntegers for the BLOB_WIDTH number of blob polynomial coefficients, followed by a /// CRTInteger for the challenge digest. - pub(crate) barycentric_assignments: Vec>, + barycentric_assignments: Vec>, /// 32 Assigned cells representing the LE-bytes of challenge z. pub(crate) z_le: Vec>, /// 32 Assigned cells representing the LE-bytes of evaluation y. pub(crate) y_le: Vec>, } +impl AssignedBarycentricEvaluationConfig { + pub fn blob_crts(&self) -> &[CRTInteger] { + &self.barycentric_assignments[0..BLOB_WIDTH] + } + + pub fn challenge_digest(&self) -> &CRTInteger { + &self.barycentric_assignments[BLOB_WIDTH] + } +} + impl BarycentricEvaluationConfig { pub fn construct(range: RangeConfig) -> Self { Self { diff --git a/aggregator/src/blob_consistency/eip4844/tests.rs b/aggregator/src/blob_consistency/eip4844/tests.rs index 891b492ec1..9783f8091d 100644 --- a/aggregator/src/blob_consistency/eip4844/tests.rs +++ b/aggregator/src/blob_consistency/eip4844/tests.rs @@ -199,7 +199,7 @@ impl Circuit for BlobCircuit { challenge_values, &config.rlc, &chunks_are_padding, - &barycentric_assignments.barycentric_assignments, + barycentric_assignments.challenge_digest(), &assigned_rows, )?; From 71a30dd5d8d5b79e9d2948401a2241d9199a82c8 Mon Sep 17 00:00:00 2001 From: z2trillion Date: Tue, 5 Nov 2024 10:00:20 -0500 Subject: [PATCH 2/8] use iterator --- aggregator/src/aggregation/util.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/aggregator/src/aggregation/util.rs b/aggregator/src/aggregation/util.rs index 58b73a2fe3..d71ad32b2e 100644 --- a/aggregator/src/aggregation/util.rs +++ b/aggregator/src/aggregation/util.rs @@ -68,14 +68,9 @@ pub fn constrain_crt_equals_bytes( rlc_config_offset, )?; - for (limb_from_bytes, crt_limb) in [limb_from_bytes_lo, limb_from_bytes_mid, limb_from_bytes_hi] + [limb_from_bytes_lo, limb_from_bytes_mid, limb_from_bytes_hi] .iter() .zip_eq(crt.limbs()) - { - region.constrain_equal(limb_from_bytes.cell(), crt_limb.cell())? - } - - Ok(()) - - // This can just be a collect.... + .map(|(a, b)| region.constrain_equal(a.cell(), b.cell())) + .collect() } From 8afe2f5b0dc32980c92b7a95cf59b4eca67875a8 Mon Sep 17 00:00:00 2001 From: z2trillion Date: Tue, 5 Nov 2024 14:41:47 -0500 Subject: [PATCH 3/8] don't make unused powers of 256 --- aggregator/src/aggregation/batch_data.rs | 28 +++++++++--------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/aggregator/src/aggregation/batch_data.rs b/aggregator/src/aggregation/batch_data.rs index 4ea98a7725..a88dd82e78 100644 --- a/aggregator/src/aggregation/batch_data.rs +++ b/aggregator/src/aggregation/batch_data.rs @@ -1,6 +1,6 @@ use crate::{ - aggregation::rlc::POWS_OF_256, aggregation::util::constrain_crt_equals_bytes, - blob_consistency::BLOB_WIDTH, constants::N_BYTES_U256, BatchHash, ChunkInfo, RlcConfig, + aggregation::util::constrain_crt_equals_bytes, blob_consistency::BLOB_WIDTH, + constants::N_BYTES_U256, BatchHash, ChunkInfo, RlcConfig, }; use eth_types::{H256, U256}; use ethers_core::utils::keccak256; @@ -579,6 +579,14 @@ impl BatchDataConfig { region.constrain_equal(four.cell(), four_cell)?; four }; + let two_fifty_six = { + let two_fifty_six = + rlc_config.load_private(region, &Fr::from(256), &mut rlc_config_offset)?; + let two_fifty_six_cell = rlc_config.four_cell(two_fifty_six.cell().region_index); + region.constrain_equal(two_fifty_six.cell(), two_fifty_six_cell)?; + two_fifty_six + }; + let fixed_chunk_indices = { let mut fixed_chunk_indices = vec![one.clone()]; for i in 2..=N_SNARKS { @@ -594,22 +602,6 @@ impl BatchDataConfig { }; let two = fixed_chunk_indices.get(1).expect("N_SNARKS >= 2"); let n_snarks = fixed_chunk_indices.last().expect("N_SNARKS >= 2"); - let pows_of_256 = { - let mut pows_of_256 = vec![one.clone()]; - for (exponent, pow_of_256) in (1..=POWS_OF_256).zip_eq( - std::iter::successors(Some(Fr::from(256)), |n| Some(n * Fr::from(256))) - .take(POWS_OF_256), - ) { - let pow_cell = - rlc_config.load_private(region, &pow_of_256, &mut rlc_config_offset)?; - let fixed_pow_cell = rlc_config - .pow_of_two_hundred_and_fifty_six_cell(pow_cell.cell().region_index, exponent); - region.constrain_equal(pow_cell.cell(), fixed_pow_cell)?; - pows_of_256.push(pow_cell); - } - pows_of_256 - }; - let two_fifty_six = pows_of_256[1].clone(); // read randomness challenges for RLC computations. let r_keccak = From ad0828db8c1d3c72f6c051b1caf01e04966fbb5a Mon Sep 17 00:00:00 2001 From: z2trillion Date: Tue, 5 Nov 2024 15:49:02 -0500 Subject: [PATCH 4/8] move constrain_crt_equals_bytes to RlcConfig --- aggregator/src/aggregation/batch_data.rs | 6 +-- aggregator/src/aggregation/rlc/gates.rs | 42 ++++++++++++++++++++- aggregator/src/aggregation/util.rs | 47 +----------------------- 3 files changed, 44 insertions(+), 51 deletions(-) diff --git a/aggregator/src/aggregation/batch_data.rs b/aggregator/src/aggregation/batch_data.rs index a88dd82e78..e54d787b2a 100644 --- a/aggregator/src/aggregation/batch_data.rs +++ b/aggregator/src/aggregation/batch_data.rs @@ -1,6 +1,5 @@ use crate::{ - aggregation::util::constrain_crt_equals_bytes, blob_consistency::BLOB_WIDTH, - constants::N_BYTES_U256, BatchHash, ChunkInfo, RlcConfig, + blob_consistency::BLOB_WIDTH, constants::N_BYTES_U256, BatchHash, ChunkInfo, RlcConfig, }; use eth_types::{H256, U256}; use ethers_core::utils::keccak256; @@ -988,9 +987,8 @@ impl BatchDataConfig { //////////////////////////////////////////////////////////////////////////////// //////////////////////////// CHALLENGE DIGEST CHECK //////////////////////////// //////////////////////////////////////////////////////////////////////////////// - constrain_crt_equals_bytes( + rlc_config.constrain_crt_equals_bytes( region, - rlc_config, assigned_challenge_digest, &challenge_digest, &mut rlc_config_offset, diff --git a/aggregator/src/aggregation/rlc/gates.rs b/aggregator/src/aggregation/rlc/gates.rs index cb78e9f307..616ff1861c 100644 --- a/aggregator/src/aggregation/rlc/gates.rs +++ b/aggregator/src/aggregation/rlc/gates.rs @@ -1,9 +1,11 @@ use ethers_core::utils::keccak256; +use halo2_ecc::bigint::CRTInteger; use halo2_proofs::{ circuit::{AssignedCell, Cell, Region, RegionIndex, Value}, - halo2curves::bn256::Fr, + halo2curves::{bn256::Fr, group::ff::PrimeField}, plonk::Error, }; +use itertools::Itertools; use zkevm_circuits::util::Challenges; // TODO: remove MAX_AGG_SNARKS and make this generic over N_SNARKS @@ -547,4 +549,42 @@ impl RlcConfig { Ok(()) } + + pub fn constrain_crt_equals_bytes( + &self, + region: &mut Region, + crt: &CRTInteger, + bytes: &[AssignedCell], + offset: &mut usize, + ) -> Result<(), Error> { + let mut powers_of_256 = vec![]; + for i in 0..11 { + let assigned_cell = + self.load_private(region, &Fr::from_u128(256u128.pow(i)), offset)?; + let region_index = assigned_cell.cell().region_index; + let fixed_cell = if i == 0 { + self.one_cell(region_index) + } else { + self.pow_of_two_hundred_and_fifty_six_cell( + region_index, + usize::try_from(i).unwrap(), + ) + }; + region.constrain_equal(fixed_cell, assigned_cell.cell())?; + powers_of_256.push(assigned_cell); + } + + let limb_from_bytes_lo = + self.inner_product(region, &bytes[0..11], &powers_of_256, offset)?; + let limb_from_bytes_mid = + self.inner_product(region, &bytes[11..22], &powers_of_256, offset)?; + let limb_from_bytes_hi = + self.inner_product(region, &bytes[22..32], &powers_of_256[0..10], offset)?; + + [limb_from_bytes_lo, limb_from_bytes_mid, limb_from_bytes_hi] + .iter() + .zip_eq(crt.limbs()) + .map(|(a, b)| region.constrain_equal(a.cell(), b.cell())) + .collect() + } } diff --git a/aggregator/src/aggregation/util.rs b/aggregator/src/aggregation/util.rs index d71ad32b2e..95ff9061f0 100644 --- a/aggregator/src/aggregation/util.rs +++ b/aggregator/src/aggregation/util.rs @@ -1,13 +1,8 @@ -use crate::RlcConfig; use gadgets::util::Expr; -use halo2_ecc::bigint::CRTInteger; use halo2_proofs::{ - circuit::{AssignedCell, Region}, - halo2curves::{bn256::Fr, group::ff::PrimeField}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells}, + plonk::{Advice, Column, ConstraintSystem, Expression, VirtualCells}, poly::Rotation, }; -use itertools::Itertools; use zkevm_circuits::util::Field; #[derive(Clone, Copy, Debug)] @@ -34,43 +29,3 @@ impl BooleanAdvice { meta.query_advice(self.column, at) } } - -pub fn constrain_crt_equals_bytes( - region: &mut Region, - rlc_config: &RlcConfig, - crt: &CRTInteger, - bytes: &[AssignedCell], - rlc_config_offset: &mut usize, -) -> Result<(), Error> { - let mut powers_of_256 = vec![]; - for i in 0..11 { - let assigned_cell = - rlc_config.load_private(region, &Fr::from_u128(256u128.pow(i)), rlc_config_offset)?; - let region_index = assigned_cell.cell().region_index; - let fixed_cell = if i == 0 { - rlc_config.one_cell(region_index) - } else { - rlc_config - .pow_of_two_hundred_and_fifty_six_cell(region_index, usize::try_from(i).unwrap()) - }; - region.constrain_equal(fixed_cell, assigned_cell.cell())?; - powers_of_256.push(assigned_cell); - } - - let limb_from_bytes_lo = - rlc_config.inner_product(region, &bytes[0..11], &powers_of_256, rlc_config_offset)?; - let limb_from_bytes_mid = - rlc_config.inner_product(region, &bytes[11..22], &powers_of_256, rlc_config_offset)?; - let limb_from_bytes_hi = rlc_config.inner_product( - region, - &bytes[22..32], - &powers_of_256[0..10], - rlc_config_offset, - )?; - - [limb_from_bytes_lo, limb_from_bytes_mid, limb_from_bytes_hi] - .iter() - .zip_eq(crt.limbs()) - .map(|(a, b)| region.constrain_equal(a.cell(), b.cell())) - .collect() -} From 8b489da90a5521449b2f8c1e35c50581f678b894 Mon Sep 17 00:00:00 2001 From: z2trillion Date: Fri, 15 Nov 2024 13:08:56 -0500 Subject: [PATCH 5/8] add methods for da-avail --- aggregator/src/blob_consistency/avail.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/aggregator/src/blob_consistency/avail.rs b/aggregator/src/blob_consistency/avail.rs index 7c7474c8be..b30bedb9d1 100644 --- a/aggregator/src/blob_consistency/avail.rs +++ b/aggregator/src/blob_consistency/avail.rs @@ -98,3 +98,13 @@ pub struct AssignedBarycentricEvaluationConfig { /// 32 Assigned cells representing the LE-bytes of evaluation y. pub(crate) y_le: Vec>, } + +impl AssignedBarycentricEvaluationConfig { + pub fn blob_crts(&self) -> &[CRTInteger] { + &self.barycentric_assignments[0..BLOB_WIDTH] + } + + pub fn challenge_digest(&self) -> &CRTInteger { + &self.barycentric_assignments[BLOB_WIDTH] + } +} From 23851aa5e257a620755573d94fcbba59b8831588 Mon Sep 17 00:00:00 2001 From: z2trillion Date: Fri, 15 Nov 2024 13:52:20 -0500 Subject: [PATCH 6/8] constrain equality to correct cell --- aggregator/src/aggregation/batch_data.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aggregator/src/aggregation/batch_data.rs b/aggregator/src/aggregation/batch_data.rs index e54d787b2a..bd28509635 100644 --- a/aggregator/src/aggregation/batch_data.rs +++ b/aggregator/src/aggregation/batch_data.rs @@ -581,7 +581,8 @@ impl BatchDataConfig { let two_fifty_six = { let two_fifty_six = rlc_config.load_private(region, &Fr::from(256), &mut rlc_config_offset)?; - let two_fifty_six_cell = rlc_config.four_cell(two_fifty_six.cell().region_index); + let two_fifty_six_cell = rlc_config + .pow_of_two_hundred_and_fifty_six_cell(two_fifty_six.cell().region_index, 1); region.constrain_equal(two_fifty_six.cell(), two_fifty_six_cell)?; two_fifty_six }; From d1ff593e94bfeb3e61ec8dcdf70d8d73b18293bf Mon Sep 17 00:00:00 2001 From: z2trillion Date: Fri, 15 Nov 2024 14:07:51 -0500 Subject: [PATCH 7/8] fix merge --- aggregator/src/blob_consistency/avail.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/aggregator/src/blob_consistency/avail.rs b/aggregator/src/blob_consistency/avail.rs index bef0c188a1..95435fde55 100644 --- a/aggregator/src/blob_consistency/avail.rs +++ b/aggregator/src/blob_consistency/avail.rs @@ -107,6 +107,7 @@ impl AssignedBarycentricEvaluationConfig { pub fn challenge_digest(&self) -> &CRTInteger { &self.barycentric_assignments[BLOB_WIDTH] } +} /// Get the blob data bytes that will be populated in BlobDataConfig. pub fn get_blob_bytes(_batch_bytes: &[u8]) -> Vec { From 1ad637572d829fd83a424dc6df07eef941918a13 Mon Sep 17 00:00:00 2001 From: z2trillion Date: Fri, 15 Nov 2024 15:30:25 -0500 Subject: [PATCH 8/8] use try_for_each --- aggregator/src/aggregation/rlc/gates.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aggregator/src/aggregation/rlc/gates.rs b/aggregator/src/aggregation/rlc/gates.rs index 616ff1861c..a4abbe62cd 100644 --- a/aggregator/src/aggregation/rlc/gates.rs +++ b/aggregator/src/aggregation/rlc/gates.rs @@ -584,7 +584,6 @@ impl RlcConfig { [limb_from_bytes_lo, limb_from_bytes_mid, limb_from_bytes_hi] .iter() .zip_eq(crt.limbs()) - .map(|(a, b)| region.constrain_equal(a.cell(), b.cell())) - .collect() + .try_for_each(|(a, b)| region.constrain_equal(a.cell(), b.cell())) } }