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<const N_SNARKS: usize> BatchDataConfig<N_SNARKS> {
         chunks_are_padding: &[AssignedCell<Fr, Fr>],
         batch_data: &BatchData<N_SNARKS>,
         versioned_hash: H256,
-        barycentric_assignments: &[CRTInteger<Fr>],
+        challenge_digest: &CRTInteger<Fr>,
     ) -> Result<AssignedBatchDataExport, Error> {
         self.load_range_tables(layouter)?;
 
@@ -418,7 +417,7 @@ impl<const N_SNARKS: usize> BatchDataConfig<N_SNARKS> {
                     challenge_value,
                     rlc_config,
                     chunks_are_padding,
-                    barycentric_assignments,
+                    challenge_digest,
                     &assigned_rows,
                 )
             },
@@ -550,7 +549,7 @@ impl<const N_SNARKS: usize> BatchDataConfig<N_SNARKS> {
         // 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<Fr, Fr>],
-        barycentric_assignments: &[CRTInteger<Fr>],
+        assigned_challenge_digest: &CRTInteger<Fr>,
         assigned_rows: &[AssignedBatchDataConfig],
     ) -> Result<AssignedBatchDataExport, Error> {
         let n_rows_metadata = BatchData::<N_SNARKS>::n_rows_metadata();
@@ -579,6 +578,15 @@ impl<const N_SNARKS: usize> BatchDataConfig<N_SNARKS> {
             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<const N_SNARKS: usize> BatchDataConfig<N_SNARKS> {
         };
         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<const N_SNARKS: usize> BatchDataConfig<N_SNARKS> {
         ////////////////////////////////////////////////////////////////////////////////
         //////////////////////////// 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<const N_SNARKS: usize> Circuit<Fr> for BatchCircuit<N_SNARKS> {
 
         // 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<const N_SNARKS: usize> Circuit<Fr> for BatchCircuit<N_SNARKS> {
             BlobConsistencyConfig::<N_SNARKS>::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<const N_SNARKS: usize> Circuit<Fr> for BatchCircuit<N_SNARKS> {
                 &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<Fr>,
+        crt: &CRTInteger<Fr>,
+        bytes: &[AssignedCell<Fr, Fr>],
+        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<AssignedValue<Fr>>,
 }
 
+impl AssignedBarycentricEvaluationConfig {
+    pub fn blob_crts(&self) -> &[CRTInteger<Fr>] {
+        &self.barycentric_assignments[0..BLOB_WIDTH]
+    }
+
+    pub fn challenge_digest(&self) -> &CRTInteger<Fr> {
+        &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<u8> {
     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<CRTInteger<Fr>>,
+    barycentric_assignments: Vec<CRTInteger<Fr>>,
     /// 32 Assigned cells representing the LE-bytes of challenge z.
     pub(crate) z_le: Vec<AssignedValue<Fr>>,
     /// 32 Assigned cells representing the LE-bytes of evaluation y.
     pub(crate) y_le: Vec<AssignedValue<Fr>>,
 }
 
+impl AssignedBarycentricEvaluationConfig {
+    pub fn blob_crts(&self) -> &[CRTInteger<Fr>] {
+        &self.barycentric_assignments[0..BLOB_WIDTH]
+    }
+
+    pub fn challenge_digest(&self) -> &CRTInteger<Fr> {
+        &self.barycentric_assignments[BLOB_WIDTH]
+    }
+}
+
 impl BarycentricEvaluationConfig {
     pub fn construct(range: RangeConfig<Fr>) -> 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<Fr> for BlobCircuit {
                     challenge_values,
                     &config.rlc,
                     &chunks_are_padding,
-                    &barycentric_assignments.barycentric_assignments,
+                    barycentric_assignments.challenge_digest(),
                     &assigned_rows,
                 )?;