diff --git a/aggregator/src/aggregation/batch_data.rs b/aggregator/src/aggregation/batch_data.rs index 221a059e5b..bd28509635 100644 --- a/aggregator/src/aggregation/batch_data.rs +++ b/aggregator/src/aggregation/batch_data.rs @@ -1,6 +1,5 @@ use crate::{ - aggregation::rlc::POWS_OF_256, 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; @@ -401,7 +400,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 +417,7 @@ impl BatchDataConfig { challenge_value, rlc_config, chunks_are_padding, - barycentric_assignments, + challenge_digest, &assigned_rows, ) }, @@ -550,7 +549,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(); @@ -579,6 +578,15 @@ 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 + .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 + }; + 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 = @@ -996,41 +988,12 @@ 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( + rlc_config.constrain_crt_equals_bytes( region, - &challenge_digest[0..11], - &pows_of_256, + assigned_challenge_digest, + &challenge_digest, &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( - region, - &challenge_digest[22..32], - &pows_of_256[0..10], - &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 064dfe9d88..8aa17a0e95 100644 --- a/aggregator/src/aggregation/circuit.rs +++ b/aggregator/src/aggregation/circuit.rs @@ -509,7 +509,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; @@ -525,7 +524,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( @@ -535,7 +534,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/rlc/gates.rs b/aggregator/src/aggregation/rlc/gates.rs index cb78e9f307..a4abbe62cd 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,41 @@ 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()) + .try_for_each(|(a, b)| region.constrain_equal(a.cell(), b.cell())) + } } diff --git a/aggregator/src/blob_consistency/avail.rs b/aggregator/src/blob_consistency/avail.rs index 88b93eada7..95435fde55 100644 --- a/aggregator/src/blob_consistency/avail.rs +++ b/aggregator/src/blob_consistency/avail.rs @@ -99,6 +99,16 @@ pub struct AssignedBarycentricEvaluationConfig { 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] + } +} + /// Get the blob data bytes that will be populated in BlobDataConfig. pub fn get_blob_bytes(_batch_bytes: &[u8]) -> Vec { unimplemented!("trick for linting"); 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, )?;