diff --git a/integration-tests/tests/circuits.rs b/integration-tests/tests/circuits.rs
index 355d4a3736..83ceb117d5 100644
--- a/integration-tests/tests/circuits.rs
+++ b/integration-tests/tests/circuits.rs
@@ -113,7 +113,6 @@ async fn test_tx_circuit_block(block_num: u64) {
 
 pub async fn test_bytecode_circuit_block(block_num: u64) {
     const DEGREE: u32 = 16;
-    let randomness = Fr::from(123456);
 
     log::info!("test bytecode circuit, block number: {}", block_num);
     let cli = get_client();
@@ -121,7 +120,7 @@ pub async fn test_bytecode_circuit_block(block_num: u64) {
     let (builder, _) = cli.gen_inputs(block_num).await.unwrap();
     let bytecodes: Vec<Vec<u8>> = builder.code_db.0.values().cloned().collect();
 
-    test_bytecode_circuit(DEGREE, bytecodes, randomness);
+    test_bytecode_circuit::<Fr>(DEGREE, bytecodes);
 }
 
 pub async fn test_copy_circuit_block(block_num: u64) {
diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs
index d651e8a110..5c9dd2c158 100644
--- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs
+++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs
@@ -3,7 +3,7 @@ use crate::{
         and, constraint_builder::BaseConstraintBuilder, not, or, select, RandomLinearCombination,
     },
     table::{BytecodeFieldTag, BytecodeTable, DynamicTableColumns, KeccakTable},
-    util::Expr,
+    util::{Challenges, Expr},
 };
 use bus_mapping::evm::OpcodeId;
 use eth_types::{Field, ToLittleEndian, Word};
@@ -20,7 +20,7 @@ use super::param::PUSH_TABLE_WIDTH;
 /// Public data for the bytecode
 #[derive(Clone, Debug, PartialEq)]
 pub(crate) struct BytecodeRow<F: Field> {
-    code_hash: F,
+    code_hash: Word,
     tag: F,
     index: F,
     is_code: F,
@@ -37,7 +37,6 @@ pub struct UnrolledBytecode<F: Field> {
 #[derive(Clone, Debug)]
 /// Bytecode circuit configuration
 pub struct Config<F> {
-    randomness: Expression<F>,
     minimum_rows: usize,
     q_enable: Column<Fixed>,
     q_first: Column<Fixed>,
@@ -60,9 +59,9 @@ pub struct Config<F> {
 impl<F: Field> Config<F> {
     pub(crate) fn configure(
         meta: &mut ConstraintSystem<F>,
-        randomness: Expression<F>,
         bytecode_table: BytecodeTable,
         keccak_table: KeccakTable,
+        challenges: Challenges<Expression<F>>,
     ) -> Self {
         let q_enable = meta.fixed_column();
         let q_first = meta.fixed_column();
@@ -157,9 +156,9 @@ impl<F: Field> Config<F> {
                 ),
             );
             cb.require_equal(
-                "hash_input_rlc := hash_input_rlc_prev * randomness + byte",
+                "hash_input_rlc := hash_input_rlc_prev * challenges.keccak_input + byte",
                 meta.query_advice(hash_input_rlc, Rotation::cur()),
-                meta.query_advice(hash_input_rlc, Rotation::prev()) * randomness.clone()
+                meta.query_advice(hash_input_rlc, Rotation::prev()) * challenges.keccak_input()
                     + meta.query_advice(value, Rotation::cur()),
             );
             cb.require_equal(
@@ -362,7 +361,6 @@ impl<F: Field> Config<F> {
         });
 
         Config {
-            randomness,
             minimum_rows: meta.minimum_rows(),
             q_enable,
             q_first,
@@ -388,9 +386,9 @@ impl<F: Field> Config<F> {
         layouter: &mut impl Layouter<F>,
         size: usize,
         witness: &[UnrolledBytecode<F>],
-        randomness: F,
+        challenges: &Challenges<Value<F>>,
     ) -> Result<(), Error> {
-        self.assign_internal(layouter, size, witness, randomness, true)
+        self.assign_internal(layouter, size, witness, challenges, true)
     }
 
     pub(crate) fn assign_internal(
@@ -398,7 +396,7 @@ impl<F: Field> Config<F> {
         layouter: &mut impl Layouter<F>,
         size: usize,
         witness: &[UnrolledBytecode<F>],
-        randomness: F,
+        challenges: &Challenges<Value<F>>,
         fail_fast: bool,
     ) -> Result<(), Error> {
         let push_rindex_is_zero_chip = IsZeroChip::construct(self.push_rindex_is_zero.clone());
@@ -416,7 +414,7 @@ impl<F: Field> Config<F> {
                     // Run over all the bytes
                     let mut push_rindex = 0;
                     let mut byte_push_size = 0;
-                    let mut hash_input_rlc = F::zero();
+                    let mut hash_input_rlc = challenges.keccak_input().map(|_| F::zero());
                     let code_length = F::from(bytecode.bytes.len() as u64);
                     for (idx, row) in bytecode.rows.iter().enumerate() {
                         if fail_fast && offset > last_row_offset {
@@ -428,6 +426,13 @@ impl<F: Field> Config<F> {
                             return Err(Error::Synthesis);
                         }
 
+                        let code_hash = challenges.evm_word().map(|challenge| {
+                            RandomLinearCombination::<F, 32>::random_linear_combine(
+                                row.code_hash.to_le_bytes(),
+                                challenge,
+                            )
+                        });
+
                         // Track which byte is an opcode and which is push
                         // data
                         let is_code = push_rindex == 0;
@@ -438,7 +443,11 @@ impl<F: Field> Config<F> {
                             } else {
                                 push_rindex - 1
                             };
-                            hash_input_rlc = hash_input_rlc * randomness + row.value;
+                            hash_input_rlc.as_mut().zip(challenges.keccak_input()).map(
+                                |(hash_input_rlc, challenge)| {
+                                    *hash_input_rlc = *hash_input_rlc * challenge + row.value
+                                },
+                            );
                         }
 
                         // Set the data for this row
@@ -450,7 +459,7 @@ impl<F: Field> Config<F> {
                                 offset,
                                 true,
                                 offset == last_row_offset,
-                                row.code_hash,
+                                code_hash,
                                 row.tag,
                                 row.index,
                                 row.is_code,
@@ -478,13 +487,13 @@ impl<F: Field> Config<F> {
                         idx,
                         idx < last_row_offset,
                         idx == last_row_offset,
-                        F::zero(),
+                        Value::known(F::zero()),
                         F::from(BytecodeFieldTag::Padding as u64),
                         F::zero(),
                         F::one(),
                         F::zero(),
                         0,
-                        F::zero(),
+                        Value::known(F::zero()),
                         F::zero(),
                         F::zero(),
                         true,
@@ -507,13 +516,13 @@ impl<F: Field> Config<F> {
         offset: usize,
         enable: bool,
         last: bool,
-        code_hash: F,
+        code_hash: Value<F>,
         tag: F,
         index: F,
         is_code: F,
         value: F,
         push_rindex: u64,
-        hash_input_rlc: F,
+        hash_input_rlc: Value<F>,
         code_length: F,
         byte_push_size: F,
         is_final: bool,
@@ -542,14 +551,12 @@ impl<F: Field> Config<F> {
         }
 
         // Advices
-        for (name, column, value) in &[
-            ("code_hash", self.bytecode_table.code_hash, code_hash),
+        for (name, column, value) in [
             ("tag", self.bytecode_table.tag, tag),
             ("index", self.bytecode_table.index, index),
             ("is_code", self.bytecode_table.is_code, is_code),
             ("value", self.bytecode_table.value, value),
             ("push_rindex", self.push_rindex, F::from(push_rindex)),
-            ("hash_input_rlc", self.hash_input_rlc, hash_input_rlc),
             ("code_length", self.code_length, code_length),
             ("byte_push_size", self.byte_push_size, byte_push_size),
             ("is_final", self.is_final, F::from(is_final as u64)),
@@ -557,9 +564,20 @@ impl<F: Field> Config<F> {
         ] {
             region.assign_advice(
                 || format!("assign {} {}", name, offset),
-                *column,
+                column,
+                offset,
+                || Value::known(value),
+            )?;
+        }
+        for (name, column, value) in [
+            ("code_hash", self.bytecode_table.code_hash, code_hash),
+            ("hash_input_rlc", self.hash_input_rlc, hash_input_rlc),
+        ] {
+            region.assign_advice(
+                || format!("assign {} {}", name, offset),
+                column,
                 offset,
-                || Value::known(*value),
+                || value,
             )?;
         }
 
@@ -604,8 +622,8 @@ impl<F: Field> Config<F> {
 }
 
 /// Get unrolled bytecode from raw bytes
-pub fn unroll<F: Field>(bytes: Vec<u8>, randomness: F) -> UnrolledBytecode<F> {
-    let code_hash = keccak(&bytes[..], randomness);
+pub fn unroll<F: Field>(bytes: Vec<u8>) -> UnrolledBytecode<F> {
+    let code_hash = keccak(&bytes[..]);
     let mut rows = vec![BytecodeRow::<F> {
         code_hash,
         tag: F::from(BytecodeFieldTag::Length as u64),
@@ -647,13 +665,10 @@ fn get_push_size(byte: u8) -> u64 {
     }
 }
 
-fn keccak<F: Field>(msg: &[u8], randomness: F) -> F {
+fn keccak(msg: &[u8]) -> Word {
     let mut keccak = Keccak::default();
     keccak.update(msg);
-    RandomLinearCombination::<F, 32>::random_linear_combine(
-        Word::from_big_endian(keccak.digest().as_slice()).to_le_bytes(),
-        randomness,
-    )
+    Word::from_big_endian(keccak.digest().as_slice())
 }
 
 fn into_words(message: &[u8]) -> Vec<u64> {
@@ -684,7 +699,6 @@ mod tests {
     #[test]
     fn bytecode_unrolling() {
         let k = 10;
-        let randomness = get_randomness();
         let mut rows = vec![];
         let mut bytecode = Bytecode::default();
         // First add all non-push bytes, which should all be seen as code
@@ -692,7 +706,7 @@ mod tests {
             if !is_push(byte) {
                 bytecode.write(byte, true);
                 rows.push(BytecodeRow {
-                    code_hash: Fr::zero(),
+                    code_hash: Word::zero(),
                     tag: Fr::from(BytecodeFieldTag::Byte as u64),
                     index: Fr::from(rows.len() as u64),
                     is_code: Fr::from(true as u64),
@@ -705,7 +719,7 @@ mod tests {
             let data_byte = OpcodeId::PUSH32.as_u8();
             bytecode.push(n, Word::from_little_endian(&vec![data_byte; n][..]));
             rows.push(BytecodeRow {
-                code_hash: Fr::zero(),
+                code_hash: Word::zero(),
                 tag: Fr::from(BytecodeFieldTag::Byte as u64),
                 index: Fr::from(rows.len() as u64),
                 is_code: Fr::from(true as u64),
@@ -713,7 +727,7 @@ mod tests {
             });
             for _ in 0..n {
                 rows.push(BytecodeRow {
-                    code_hash: Fr::zero(),
+                    code_hash: Word::zero(),
                     tag: Fr::from(BytecodeFieldTag::Byte as u64),
                     index: Fr::from(rows.len() as u64),
                     is_code: Fr::from(false as u64),
@@ -722,7 +736,7 @@ mod tests {
             }
         }
         // Set the code_hash of the complete bytecode in the rows
-        let code_hash = keccak(&bytecode.to_vec()[..], randomness);
+        let code_hash = keccak(&bytecode.to_vec()[..]);
         for row in rows.iter_mut() {
             row.code_hash = code_hash;
         }
@@ -737,7 +751,7 @@ mod tests {
             },
         );
         // Unroll the bytecode
-        let unrolled = unroll(bytecode.to_vec(), randomness);
+        let unrolled = unroll(bytecode.to_vec());
         // Check if the bytecode was unrolled correctly
         assert_eq!(
             UnrolledBytecode {
@@ -747,83 +761,54 @@ mod tests {
             unrolled,
         );
         // Verify the unrolling in the circuit
-        test_bytecode_circuit_unrolled(k, vec![unrolled], randomness, true);
+        test_bytecode_circuit_unrolled::<Fr>(k, vec![unrolled], true);
     }
 
     /// Tests a fully empty circuit
     #[test]
     fn bytecode_empty() {
         let k = 9;
-        let randomness: Fr = get_randomness();
-        test_bytecode_circuit_unrolled(k, vec![unroll(vec![], randomness)], randomness, true);
+        test_bytecode_circuit_unrolled::<Fr>(k, vec![unroll(vec![])], true);
     }
 
     #[test]
     fn bytecode_simple() {
         let k = 9;
-        let randomness: Fr = get_randomness();
-        let bytecodes = vec![
-            unroll(vec![7u8], randomness),
-            unroll(vec![6u8], randomness),
-            unroll(vec![5u8], randomness),
-        ];
-        test_bytecode_circuit_unrolled(k, bytecodes, randomness, true);
+        let bytecodes = vec![unroll(vec![7u8]), unroll(vec![6u8]), unroll(vec![5u8])];
+        test_bytecode_circuit_unrolled::<Fr>(k, bytecodes, true);
     }
 
     /// Tests a fully full circuit
     #[test]
     fn bytecode_full() {
         let k = 9;
-        let randomness: Fr = get_randomness();
-        test_bytecode_circuit_unrolled(
-            k,
-            vec![unroll(vec![7u8; 2usize.pow(k) - 7], randomness)],
-            randomness,
-            true,
-        );
+        test_bytecode_circuit_unrolled::<Fr>(k, vec![unroll(vec![7u8; 2usize.pow(k) - 7])], true);
     }
 
     /// Tests a circuit with incomplete bytecode
     #[test]
     fn bytecode_incomplete() {
         let k = 9;
-        let randomness: Fr = get_randomness();
-        test_bytecode_circuit_unrolled(
-            k,
-            vec![unroll(vec![7u8; 2usize.pow(k) + 1], randomness)],
-            randomness,
-            false,
-        );
+        test_bytecode_circuit_unrolled::<Fr>(k, vec![unroll(vec![7u8; 2usize.pow(k) + 1])], false);
     }
 
     /// Tests multiple bytecodes in a single circuit
     #[test]
     fn bytecode_push() {
         let k = 9;
-        let randomness: Fr = get_randomness();
-        test_bytecode_circuit_unrolled(
+        test_bytecode_circuit_unrolled::<Fr>(
             k,
             vec![
-                unroll(vec![], randomness),
-                unroll(vec![OpcodeId::PUSH32.as_u8()], randomness),
-                unroll(
-                    vec![OpcodeId::PUSH32.as_u8(), OpcodeId::ADD.as_u8()],
-                    randomness,
-                ),
-                unroll(
-                    vec![OpcodeId::ADD.as_u8(), OpcodeId::PUSH32.as_u8()],
-                    randomness,
-                ),
-                unroll(
-                    vec![
-                        OpcodeId::ADD.as_u8(),
-                        OpcodeId::PUSH32.as_u8(),
-                        OpcodeId::ADD.as_u8(),
-                    ],
-                    randomness,
-                ),
+                unroll(vec![]),
+                unroll(vec![OpcodeId::PUSH32.as_u8()]),
+                unroll(vec![OpcodeId::PUSH32.as_u8(), OpcodeId::ADD.as_u8()]),
+                unroll(vec![OpcodeId::ADD.as_u8(), OpcodeId::PUSH32.as_u8()]),
+                unroll(vec![
+                    OpcodeId::ADD.as_u8(),
+                    OpcodeId::PUSH32.as_u8(),
+                    OpcodeId::ADD.as_u8(),
+                ]),
             ],
-            randomness,
             true,
         );
     }
@@ -832,29 +817,28 @@ mod tests {
     #[test]
     fn bytecode_invalid_hash_data() {
         let k = 9;
-        let randomness = get_randomness();
         let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128];
-        let unrolled = unroll(bytecode, randomness);
-        test_bytecode_circuit_unrolled(k, vec![unrolled.clone()], randomness, true);
+        let unrolled = unroll(bytecode);
+        test_bytecode_circuit_unrolled::<Fr>(k, vec![unrolled.clone()], true);
         // Change the code_hash on the first position
         {
             let mut invalid = unrolled.clone();
-            invalid.rows[0].code_hash += Fr::from(1u64);
-            test_bytecode_circuit_unrolled(k, vec![invalid], randomness, false);
+            invalid.rows[0].code_hash += Word::one();
+            test_bytecode_circuit_unrolled::<Fr>(k, vec![invalid], false);
         }
         // Change the code_hash on another position
         {
             let mut invalid = unrolled.clone();
-            invalid.rows[4].code_hash += Fr::from(1u64);
-            test_bytecode_circuit_unrolled(k, vec![invalid], randomness, false);
+            invalid.rows[4].code_hash += Word::one();
+            test_bytecode_circuit_unrolled::<Fr>(k, vec![invalid], false);
         }
         // Change all the hashes so it doesn't match the keccak lookup code_hash
         {
             let mut invalid = unrolled;
             for row in invalid.rows.iter_mut() {
-                row.code_hash = Fr::one();
+                row.code_hash = Word::one();
             }
-            test_bytecode_circuit_unrolled(k, vec![invalid], randomness, false);
+            test_bytecode_circuit_unrolled::<Fr>(k, vec![invalid], false);
         }
     }
 
@@ -863,23 +847,22 @@ mod tests {
     #[ignore]
     fn bytecode_invalid_index() {
         let k = 9;
-        let randomness: Fr = get_randomness();
         let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128];
-        let unrolled = unroll(bytecode, randomness);
-        test_bytecode_circuit_unrolled(k, vec![unrolled.clone()], randomness, true);
+        let unrolled = unroll(bytecode);
+        test_bytecode_circuit_unrolled::<Fr>(k, vec![unrolled.clone()], true);
         // Start the index at 1
         {
             let mut invalid = unrolled.clone();
             for row in invalid.rows.iter_mut() {
                 row.index += Fr::one();
             }
-            test_bytecode_circuit_unrolled(k, vec![invalid], randomness, false);
+            test_bytecode_circuit_unrolled::<Fr>(k, vec![invalid], false);
         }
         // Don't increment an index once
         {
             let mut invalid = unrolled;
             invalid.rows.last_mut().unwrap().index -= Fr::one();
-            test_bytecode_circuit_unrolled(k, vec![invalid], randomness, false);
+            test_bytecode_circuit_unrolled::<Fr>(k, vec![invalid], false);
         }
     }
 
@@ -887,27 +870,26 @@ mod tests {
     #[test]
     fn bytecode_invalid_byte_data() {
         let k = 9;
-        let randomness = get_randomness();
         let bytecode = vec![8u8, 2, 3, 8, 9, 7, 128];
-        let unrolled = unroll(bytecode, randomness);
-        test_bytecode_circuit_unrolled(k, vec![unrolled.clone()], randomness, true);
+        let unrolled = unroll(bytecode);
+        test_bytecode_circuit_unrolled::<Fr>(k, vec![unrolled.clone()], true);
         // Change the first byte
         {
             let mut invalid = unrolled.clone();
             invalid.rows[1].value = Fr::from(9u64);
-            test_bytecode_circuit_unrolled(k, vec![invalid], randomness, false);
+            test_bytecode_circuit_unrolled::<Fr>(k, vec![invalid], false);
         }
         // Change a byte on another position
         {
             let mut invalid = unrolled.clone();
             invalid.rows[5].value = Fr::from(6u64);
-            test_bytecode_circuit_unrolled(k, vec![invalid], randomness, false);
+            test_bytecode_circuit_unrolled::<Fr>(k, vec![invalid], false);
         }
         // Set a byte value out of range
         {
             let mut invalid = unrolled;
             invalid.rows[3].value = Fr::from(256u64);
-            test_bytecode_circuit_unrolled(k, vec![invalid], randomness, false);
+            test_bytecode_circuit_unrolled::<Fr>(k, vec![invalid], false);
         }
     }
 
@@ -915,7 +897,6 @@ mod tests {
     #[test]
     fn bytecode_invalid_is_code() {
         let k = 9;
-        let randomness = get_randomness();
         let bytecode = vec![
             OpcodeId::ADD.as_u8(),
             OpcodeId::PUSH1.as_u8(),
@@ -925,25 +906,25 @@ mod tests {
             OpcodeId::ADD.as_u8(),
             OpcodeId::PUSH6.as_u8(),
         ];
-        let unrolled = unroll(bytecode, randomness);
-        test_bytecode_circuit_unrolled(k, vec![unrolled.clone()], randomness, true);
+        let unrolled = unroll(bytecode);
+        test_bytecode_circuit_unrolled::<Fr>(k, vec![unrolled.clone()], true);
         // Mark the 3rd byte as code (is push data from the first PUSH1)
         {
             let mut invalid = unrolled.clone();
             invalid.rows[3].is_code = Fr::one();
-            test_bytecode_circuit_unrolled(k, vec![invalid], randomness, false);
+            test_bytecode_circuit_unrolled::<Fr>(k, vec![invalid], false);
         }
         // Mark the 4rd byte as data (is code)
         {
             let mut invalid = unrolled.clone();
             invalid.rows[4].is_code = Fr::zero();
-            test_bytecode_circuit_unrolled(k, vec![invalid], randomness, false);
+            test_bytecode_circuit_unrolled::<Fr>(k, vec![invalid], false);
         }
         // Mark the 7th byte as code (is data for the PUSH7)
         {
             let mut invalid = unrolled;
             invalid.rows[7].is_code = Fr::one();
-            test_bytecode_circuit_unrolled(k, vec![invalid], randomness, false);
+            test_bytecode_circuit_unrolled::<Fr>(k, vec![invalid], false);
         }
     }
 }
diff --git a/zkevm-circuits/src/bytecode_circuit/dev.rs b/zkevm-circuits/src/bytecode_circuit/dev.rs
index 59805dbffa..2608b1e4fa 100644
--- a/zkevm-circuits/src/bytecode_circuit/dev.rs
+++ b/zkevm-circuits/src/bytecode_circuit/dev.rs
@@ -1,27 +1,21 @@
 use super::bytecode_unroller::{unroll, Config, UnrolledBytecode};
 use crate::table::{BytecodeTable, KeccakTable};
-use crate::util::power_of_randomness_from_instance;
+use crate::util::Challenges;
 use eth_types::Field;
 use halo2_proofs::{
     circuit::Layouter,
     plonk::{ConstraintSystem, Error},
 };
 use halo2_proofs::{circuit::SimpleFloorPlanner, dev::MockProver, plonk::Circuit};
-use std::vec;
 
 #[derive(Default)]
 pub(crate) struct BytecodeCircuitTester<F: Field> {
     bytecodes: Vec<UnrolledBytecode<F>>,
     size: usize,
-    randomness: F,
-}
-
-fn get_randomness<F: Field>() -> F {
-    F::from(123456)
 }
 
 impl<F: Field> Circuit<F> for BytecodeCircuitTester<F> {
-    type Config = Config<F>;
+    type Config = (Config<F>, Challenges);
     type FloorPlanner = SimpleFloorPlanner;
 
     fn without_witnesses(&self) -> Self {
@@ -30,29 +24,35 @@ impl<F: Field> Circuit<F> for BytecodeCircuitTester<F> {
 
     fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
         let bytecode_table = BytecodeTable::construct(meta);
-
-        let randomness = power_of_randomness_from_instance::<_, 1>(meta);
         let keccak_table = KeccakTable::construct(meta);
+        let challenges = Challenges::construct(meta);
 
-        Config::configure(meta, randomness[0].clone(), bytecode_table, keccak_table)
+        let config = {
+            let challenges = challenges.exprs(meta);
+            Config::configure(meta, bytecode_table, keccak_table, challenges)
+        };
+
+        (config, challenges)
     }
 
     fn synthesize(
         &self,
-        config: Self::Config,
+        (config, challenges): Self::Config,
         mut layouter: impl Layouter<F>,
     ) -> Result<(), Error> {
+        let challenges = challenges.values(&mut layouter);
+
         config.load(&mut layouter)?;
         config.keccak_table.dev_load(
             &mut layouter,
             self.bytecodes.iter().map(|b| &b.bytes),
-            self.randomness,
+            &challenges,
         )?;
         config.assign_internal(
             &mut layouter,
             self.size,
             &self.bytecodes,
-            self.randomness,
+            &challenges,
             false,
         )?;
         Ok(())
@@ -61,30 +61,19 @@ impl<F: Field> Circuit<F> for BytecodeCircuitTester<F> {
 
 impl<F: Field> BytecodeCircuitTester<F> {
     /// Verify that the selected bytecode fulfills the circuit
-    pub fn verify_raw(k: u32, bytecodes: Vec<Vec<u8>>, randomness: F) {
-        let unrolled: Vec<_> = bytecodes
-            .iter()
-            .map(|b| unroll(b.clone(), randomness))
-            .collect();
-        Self::verify(k, unrolled, randomness, true);
+    pub fn verify_raw(k: u32, bytecodes: Vec<Vec<u8>>) {
+        let unrolled: Vec<_> = bytecodes.iter().map(|b| unroll(b.clone())).collect();
+        Self::verify(k, unrolled, true);
     }
 
-    pub(crate) fn verify(
-        k: u32,
-        bytecodes: Vec<UnrolledBytecode<F>>,
-        randomness: F,
-        success: bool,
-    ) {
+    pub(crate) fn verify(k: u32, bytecodes: Vec<UnrolledBytecode<F>>, success: bool) {
         let circuit = BytecodeCircuitTester::<F> {
             bytecodes,
             size: 2usize.pow(k),
-            randomness,
         };
 
-        let num_rows = 1 << k;
         const NUM_BLINDING_ROWS: usize = 7 - 1;
-        let instance = vec![vec![randomness; num_rows - NUM_BLINDING_ROWS]];
-        let prover = MockProver::<F>::run(k, &circuit, instance).unwrap();
+        let prover = MockProver::<F>::run(k, &circuit, Vec::new()).unwrap();
         let result = prover.verify();
         if let Err(failures) = &result {
             for failure in failures.iter() {
@@ -96,31 +85,24 @@ impl<F: Field> BytecodeCircuitTester<F> {
 }
 
 /// Test bytecode circuit with raw bytecode
-pub fn test_bytecode_circuit<F: Field>(k: u32, bytecodes: Vec<Vec<u8>>, randomness: F) {
-    let unrolled: Vec<_> = bytecodes
-        .iter()
-        .map(|b| unroll(b.clone(), randomness))
-        .collect();
-    test_bytecode_circuit_unrolled(k, unrolled, randomness, true);
+pub fn test_bytecode_circuit<F: Field>(k: u32, bytecodes: Vec<Vec<u8>>) {
+    let unrolled: Vec<_> = bytecodes.iter().map(|b| unroll::<F>(b.clone())).collect();
+    test_bytecode_circuit_unrolled(k, unrolled, true);
 }
 
 /// Test bytecode circuit with unrolled bytecode
 pub fn test_bytecode_circuit_unrolled<F: Field>(
     k: u32,
     bytecodes: Vec<UnrolledBytecode<F>>,
-    randomness: F,
     success: bool,
 ) {
     let circuit = BytecodeCircuitTester::<F> {
         bytecodes,
         size: 2usize.pow(k),
-        randomness,
     };
 
-    let num_rows = 1 << k;
     const NUM_BLINDING_ROWS: usize = 7 - 1;
-    let instance = vec![vec![randomness; num_rows - NUM_BLINDING_ROWS]];
-    let prover = MockProver::<F>::run(k, &circuit, instance).unwrap();
+    let prover = MockProver::<F>::run(k, &circuit, Vec::new()).unwrap();
     let result = prover.verify();
     if let Err(failures) = &result {
         for failure in failures.iter() {
diff --git a/zkevm-circuits/src/copy_circuit.rs b/zkevm-circuits/src/copy_circuit.rs
index c29612e115..c5139c55c4 100644
--- a/zkevm-circuits/src/copy_circuit.rs
+++ b/zkevm-circuits/src/copy_circuit.rs
@@ -741,7 +741,7 @@ pub mod dev {
     use crate::{
         evm_circuit::witness::Block,
         table::{BytecodeTable, RwTable, TxTable},
-        util::power_of_randomness_from_instance,
+        util::{power_of_randomness_from_instance, Challenges},
     };
 
     #[derive(Clone)]
@@ -810,6 +810,8 @@ pub mod dev {
             config: Self::Config,
             mut layouter: impl Layouter<F>,
         ) -> Result<(), halo2_proofs::plonk::Error> {
+            let challenges = Challenges::mock(Value::known(self.randomness));
+
             config
                 .tx_table
                 .load(&mut layouter, &self.block.txs, self.randomness)?;
@@ -822,7 +824,7 @@ pub mod dev {
             config.bytecode_table.load(
                 &mut layouter,
                 self.block.bytecodes.values(),
-                self.randomness,
+                &challenges,
             )?;
             config
                 .copy_circuit
diff --git a/zkevm-circuits/src/evm_circuit.rs b/zkevm-circuits/src/evm_circuit.rs
index a03c169d04..6198838ffc 100644
--- a/zkevm-circuits/src/evm_circuit.rs
+++ b/zkevm-circuits/src/evm_circuit.rs
@@ -154,12 +154,12 @@ pub mod test {
     use crate::{
         evm_circuit::{table::FixedTableTag, witness::Block, EvmCircuit},
         table::{BlockTable, BytecodeTable, CopyTable, KeccakTable, RwTable, TxTable},
-        util::power_of_randomness_from_instance,
+        util::{power_of_randomness_from_instance, Challenges},
     };
     use bus_mapping::evm::OpcodeId;
     use eth_types::{Field, Word};
     use halo2_proofs::{
-        circuit::{Layouter, SimpleFloorPlanner},
+        circuit::{Layouter, SimpleFloorPlanner, Value},
         dev::{MockProver, VerifyFailure},
         plonk::{Circuit, ConstraintSystem, Error},
     };
@@ -285,6 +285,8 @@ pub mod test {
             config: Self::Config,
             mut layouter: impl Layouter<F>,
         ) -> Result<(), Error> {
+            let challenges = Challenges::mock(Value::known(self.block.randomness));
+
             config
                 .evm_circuit
                 .load_fixed_table(&mut layouter, self.fixed_table_tags.clone())?;
@@ -302,7 +304,7 @@ pub mod test {
             config.bytecode_table.load(
                 &mut layouter,
                 self.block.bytecodes.values(),
-                self.block.randomness,
+                &challenges,
             )?;
             config
                 .block_table
@@ -311,11 +313,9 @@ pub mod test {
                 .copy_table
                 .load(&mut layouter, &self.block, self.block.randomness)?;
 
-            config.keccak_table.dev_load(
-                &mut layouter,
-                &self.block.sha3_inputs,
-                self.block.randomness,
-            )?;
+            config
+                .keccak_table
+                .dev_load(&mut layouter, &self.block.sha3_inputs, &challenges)?;
 
             config
                 .evm_circuit
diff --git a/zkevm-circuits/src/evm_circuit/execution.rs b/zkevm-circuits/src/evm_circuit/execution.rs
index ccc9c74a09..1e3d8d371f 100644
--- a/zkevm-circuits/src/evm_circuit/execution.rs
+++ b/zkevm-circuits/src/evm_circuit/execution.rs
@@ -11,7 +11,7 @@ use crate::{
         witness::{Block, Call, ExecStep, Transaction},
     },
     table::LookupTable,
-    util::Expr,
+    util::{query_expression, Expr},
 };
 use eth_types::Field;
 use halo2_proofs::{
@@ -559,11 +559,8 @@ impl<F: Field> ExecutionConfig<F> {
         let gadget = G::configure(&mut cb);
 
         // Enforce the step height for this opcode
-        let mut num_rows_until_next_step_next = 0.expr();
-        meta.create_gate("query num rows", |meta| {
-            num_rows_until_next_step_next =
-                meta.query_advice(num_rows_until_next_step, Rotation::next());
-            vec![0.expr()]
+        let num_rows_until_next_step_next = query_expression(meta, |meta| {
+            meta.query_advice(num_rows_until_next_step, Rotation::next())
         });
         cb.require_equal(
             "num_rows_until_next_step_next := height - 1",
diff --git a/zkevm-circuits/src/evm_circuit/util.rs b/zkevm-circuits/src/evm_circuit/util.rs
index e047182690..af93434667 100644
--- a/zkevm-circuits/src/evm_circuit/util.rs
+++ b/zkevm-circuits/src/evm_circuit/util.rs
@@ -3,7 +3,7 @@ use crate::{
         param::{LOOKUP_CONFIG, N_BYTES_MEMORY_ADDRESS},
         table::Table,
     },
-    util::Expr,
+    util::{query_expression, Expr},
 };
 use eth_types::U256;
 use halo2_proofs::{
@@ -218,7 +218,7 @@ impl<F: FieldExt> CellManager<F> {
         let width = advices.len();
         let mut cells = Vec::with_capacity(height * width);
         let mut columns = Vec::with_capacity(width);
-        meta.create_gate("Query rows for step", |meta| {
+        query_expression(meta, |meta| {
             for c in 0..width {
                 for r in 0..height {
                     cells.push(Cell::new(meta, advices[c], height_offset + r));
@@ -230,7 +230,6 @@ impl<F: FieldExt> CellManager<F> {
                     expr: cells[c * height].expr(),
                 });
             }
-            vec![0.expr()]
         });
 
         // Mark columns used for lookups
diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs
index 8b1137a6cf..d75ea352f3 100644
--- a/zkevm-circuits/src/super_circuit.rs
+++ b/zkevm-circuits/src/super_circuit.rs
@@ -57,11 +57,11 @@ use crate::bytecode_circuit::bytecode_unroller::{
 
 use crate::evm_circuit::{table::FixedTableTag, EvmCircuit};
 use crate::table::{BlockTable, BytecodeTable, CopyTable, MptTable, RwTable, TxTable};
-use crate::util::power_of_randomness_from_instance;
+use crate::util::{power_of_randomness_from_instance, Challenges};
 use crate::witness::Block;
 use eth_types::Field;
 use halo2_proofs::{
-    circuit::{Layouter, SimpleFloorPlanner},
+    circuit::{Layouter, SimpleFloorPlanner, Value},
     plonk::{Circuit, ConstraintSystem, Error},
 };
 
@@ -197,9 +197,9 @@ impl<F: Field, const MAX_TXS: usize, const MAX_CALLDATA: usize> Circuit<F>
             ),
             bytecode_circuit: BytecodeConfig::configure(
                 meta,
-                power_of_randomness[0].clone(),
                 bytecode_table,
                 keccak_table,
+                Challenges::mock(power_of_randomness[0].clone()),
             ),
             keccak_circuit,
         }
@@ -210,6 +210,8 @@ impl<F: Field, const MAX_TXS: usize, const MAX_CALLDATA: usize> Circuit<F>
         config: Self::Config,
         mut layouter: impl Layouter<F>,
     ) -> Result<(), Error> {
+        let challenges = Challenges::mock(Value::known(self.block.randomness));
+
         // --- EVM Circuit ---
         config
             .evm_circuit
@@ -244,14 +246,14 @@ impl<F: Field, const MAX_TXS: usize, const MAX_CALLDATA: usize> Circuit<F>
             .block
             .bytecodes
             .iter()
-            .map(|(_, b)| unroll(b.bytes.clone(), self.block.randomness))
+            .map(|(_, b)| unroll(b.bytes.clone()))
             .collect();
         config.bytecode_circuit.load(&mut layouter)?;
         config.bytecode_circuit.assign(
             &mut layouter,
             self.bytecode_size,
             &bytecodes,
-            self.block.randomness,
+            &challenges,
         )?;
         // --- Keccak Table ---
         config.keccak_circuit.load(&mut layouter)?;
diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs
index 1aab0ef0b8..1bc5ac1747 100644
--- a/zkevm-circuits/src/table.rs
+++ b/zkevm-circuits/src/table.rs
@@ -3,6 +3,7 @@
 use crate::copy_circuit::number_or_hash_to_field;
 use crate::evm_circuit::util::{rlc, RandomLinearCombination};
 use crate::impl_expr;
+use crate::util::Challenges;
 use crate::witness::{
     Block, BlockContext, Bytecode, MptUpdateRow, MptUpdates, Rw, RwMap, RwRow, Transaction,
 };
@@ -17,6 +18,7 @@ use halo2_proofs::{
 use halo2_proofs::{circuit::Layouter, plonk::*, poly::Rotation};
 use itertools::Itertools;
 use keccak256::plain::Keccak;
+use std::array;
 use strum_macros::{EnumCount, EnumIter};
 
 /// Trait used for dynamic tables.  Used to get an automatic implementation of
@@ -539,12 +541,14 @@ pub struct BytecodeTable {
 impl BytecodeTable {
     /// Construct a new BytecodeTable
     pub fn construct<F: Field>(meta: &mut ConstraintSystem<F>) -> Self {
+        let [tag, index, is_code, value] = array::from_fn(|_| meta.advice_column());
+        let code_hash = meta.advice_column_in(SecondPhase);
         Self {
-            code_hash: meta.advice_column(),
-            tag: meta.advice_column(),
-            index: meta.advice_column(),
-            is_code: meta.advice_column(),
-            value: meta.advice_column(),
+            code_hash,
+            tag,
+            index,
+            is_code,
+            value,
         }
     }
 
@@ -554,7 +558,7 @@ impl BytecodeTable {
         &self,
         layouter: &mut impl Layouter<F>,
         bytecodes: impl IntoIterator<Item = &'a Bytecode> + Clone,
-        randomness: F,
+        challenges: &Challenges<Value<F>>,
     ) -> Result<(), Error> {
         layouter.assign_region(
             || "bytecode table",
@@ -572,13 +576,13 @@ impl BytecodeTable {
 
                 let bytecode_table_columns = self.columns();
                 for bytecode in bytecodes.clone() {
-                    for row in bytecode.table_assignments(randomness) {
+                    for row in bytecode.table_assignments(challenges) {
                         for (column, value) in bytecode_table_columns.iter().zip_eq(row) {
                             region.assign_advice(
                                 || format!("bytecode table row {}", offset),
                                 *column,
                                 offset,
-                                || Value::known(value),
+                                || value,
                             )?;
                         }
                         offset += 1;
@@ -711,25 +715,37 @@ impl KeccakTable {
     pub fn construct<F: Field>(meta: &mut ConstraintSystem<F>) -> Self {
         Self {
             is_enabled: meta.advice_column(),
-            input_rlc: meta.advice_column(),
+            input_rlc: meta.advice_column_in(SecondPhase),
             input_len: meta.advice_column(),
-            output_rlc: meta.advice_column(),
+            output_rlc: meta.advice_column_in(SecondPhase),
         }
     }
 
     /// Generate the keccak table assignments from a byte array input.
-    pub fn assignments<F: Field>(input: &[u8], randomness: F) -> Vec<[F; 4]> {
-        let input_rlc: F = rlc::value(input.iter().rev(), randomness);
+    pub fn assignments<F: Field>(
+        input: &[u8],
+        challenges: &Challenges<Value<F>>,
+    ) -> Vec<[Value<F>; 4]> {
+        let input_rlc = challenges
+            .keccak_input()
+            .map(|challenge| rlc::value(input.iter().rev(), challenge));
         let input_len = F::from(input.len() as u64);
         let mut keccak = Keccak::default();
         keccak.update(input);
         let output = keccak.digest();
-        let output_rlc = RandomLinearCombination::<F, 32>::random_linear_combine(
-            Word::from_big_endian(output.as_slice()).to_le_bytes(),
-            randomness,
-        );
+        let output_rlc = challenges.evm_word().map(|challenge| {
+            RandomLinearCombination::<F, 32>::random_linear_combine(
+                Word::from_big_endian(output.as_slice()).to_le_bytes(),
+                challenge,
+            )
+        });
 
-        vec![[F::one(), input_rlc, input_len, output_rlc]]
+        vec![[
+            Value::known(F::one()),
+            input_rlc,
+            Value::known(input_len),
+            output_rlc,
+        ]]
     }
 
     /// Assign a table row for keccak table
@@ -756,7 +772,7 @@ impl KeccakTable {
         &self,
         layouter: &mut impl Layouter<F>,
         inputs: impl IntoIterator<Item = &'a Vec<u8>> + Clone,
-        randomness: F,
+        challenges: &Challenges<Value<F>>,
     ) -> Result<(), Error> {
         layouter.assign_region(
             || "keccak table",
@@ -774,14 +790,14 @@ impl KeccakTable {
 
                 let keccak_table_columns = self.columns();
                 for input in inputs.clone() {
-                    for row in Self::assignments(input, randomness) {
+                    for row in Self::assignments(input, challenges) {
                         // let mut column_index = 0;
                         for (column, value) in keccak_table_columns.iter().zip_eq(row) {
                             region.assign_advice(
                                 || format!("keccak table row {}", offset),
                                 *column,
                                 offset,
-                                || Value::known(value),
+                                || value,
                             )?;
                         }
                         offset += 1;
diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs
index 8d5f94bd06..10df199dc2 100644
--- a/zkevm-circuits/src/tx_circuit.rs
+++ b/zkevm-circuits/src/tx_circuit.rs
@@ -7,7 +7,9 @@
 pub mod sign_verify;
 
 use crate::table::{KeccakTable, TxFieldTag, TxTable};
-use crate::util::{power_of_randomness_from_instance, random_linear_combine_word as rlc};
+use crate::util::{
+    power_of_randomness_from_instance, random_linear_combine_word as rlc, Challenges,
+};
 use bus_mapping::circuit_input_builder::keccak_inputs_tx_circuit;
 use eth_types::{
     sign_types::SignData,
@@ -307,6 +309,8 @@ impl<F: Field, const MAX_TXS: usize, const MAX_CALLDATA: usize> Circuit<F>
         config: Self::Config,
         mut layouter: impl Layouter<F>,
     ) -> Result<(), Error> {
+        let challenges = Challenges::mock(Value::known(self.randomness));
+
         config.sign_verify.load_range(&mut layouter)?;
         self.assign(&config, &mut layouter)?;
         config.keccak_table.dev_load(
@@ -315,7 +319,7 @@ impl<F: Field, const MAX_TXS: usize, const MAX_CALLDATA: usize> Circuit<F>
                 error!("keccak_inputs_tx_circuit error: {:?}", e);
                 Error::Synthesis
             })?,
-            self.randomness,
+            &challenges,
         )
     }
 }
diff --git a/zkevm-circuits/src/tx_circuit/sign_verify.rs b/zkevm-circuits/src/tx_circuit/sign_verify.rs
index 6d9bd15bd2..ccf56e7c6a 100644
--- a/zkevm-circuits/src/tx_circuit/sign_verify.rs
+++ b/zkevm-circuits/src/tx_circuit/sign_verify.rs
@@ -631,7 +631,7 @@ fn pub_key_hash_to_address<F: Field>(pk_hash: &[u8]) -> F {
 #[cfg(test)]
 mod sign_verify_tests {
     use super::*;
-    use crate::util::power_of_randomness_from_instance;
+    use crate::util::{power_of_randomness_from_instance, Challenges};
     use bus_mapping::circuit_input_builder::keccak_inputs_sign_verify;
     use eth_types::sign_types::sign;
     use halo2_proofs::arithmetic::Field as HaloField;
@@ -688,6 +688,8 @@ mod sign_verify_tests {
             config: Self::Config,
             mut layouter: impl Layouter<F>,
         ) -> Result<(), Error> {
+            let challenges = Challenges::mock(Value::known(self.randomness));
+
             self.sign_verify.assign(
                 &config.sign_verify,
                 &mut layouter,
@@ -697,7 +699,7 @@ mod sign_verify_tests {
             config.sign_verify.keccak_table.dev_load(
                 &mut layouter,
                 &keccak_inputs_sign_verify(&self.signatures),
-                self.randomness,
+                &challenges,
             )?;
             config.sign_verify.load_range(&mut layouter)?;
             Ok(())
diff --git a/zkevm-circuits/src/util.rs b/zkevm-circuits/src/util.rs
index 5a650be787..3416b15191 100644
--- a/zkevm-circuits/src/util.rs
+++ b/zkevm-circuits/src/util.rs
@@ -1,20 +1,33 @@
 //! Common utility traits and functions.
-use eth_types::Field;
 use halo2_proofs::{
-    plonk::{ConstraintSystem, Expression},
+    arithmetic::FieldExt,
+    circuit::{Layouter, Value},
+    plonk::{Challenge, ConstraintSystem, Expression, FirstPhase, VirtualCells},
     poly::Rotation,
 };
 
 pub use gadgets::util::Expr;
 
-pub(crate) fn random_linear_combine_word<F: Field>(bytes: [u8; 32], randomness: F) -> F {
+pub(crate) fn query_expression<F: FieldExt, T>(
+    meta: &mut ConstraintSystem<F>,
+    mut f: impl FnMut(&mut VirtualCells<F>) -> T,
+) -> T {
+    let mut expr = None;
+    meta.create_gate("Query expression", |meta| {
+        expr = Some(f(meta));
+        Some(0.expr())
+    });
+    expr.unwrap()
+}
+
+pub(crate) fn random_linear_combine_word<F: FieldExt>(bytes: [u8; 32], randomness: F) -> F {
     crate::evm_circuit::util::Word::random_linear_combine(bytes, randomness)
 }
 
 /// Query N instances at current rotation and return their expressions.  This
 /// function is used to get the power of randomness (passed as
 /// instances) in our tests.
-pub fn power_of_randomness_from_instance<F: Field, const N: usize>(
+pub fn power_of_randomness_from_instance<F: FieldExt, const N: usize>(
     meta: &mut ConstraintSystem<F>,
 ) -> [Expression<F>; N] {
     // This gate is used just to get the array of expressions from the power of
@@ -23,14 +36,62 @@ pub fn power_of_randomness_from_instance<F: Field, const N: usize>(
     // expression everywhere.  The gate itself doesn't add any constraints.
 
     let columns = [(); N].map(|_| meta.instance_column());
-    let mut power_of_randomness = None;
+    query_expression(meta, |meta| {
+        columns.map(|column| meta.query_instance(column, Rotation::cur()))
+    })
+}
+
+/// All challenges used in `SuperCircuit`.
+#[derive(Clone, Copy, Debug)]
+pub struct Challenges<T = Challenge> {
+    evm_word: T,
+    keccak_input: T,
+}
 
-    meta.create_gate("power of randomness from instance", |meta| {
-        power_of_randomness =
-            Some(columns.map(|column| meta.query_instance(column, Rotation::cur())));
+impl Challenges {
+    /// Construct `Challenges` by allocating challenges in specific phases.
+    pub fn construct<F: FieldExt>(meta: &mut ConstraintSystem<F>) -> Self {
+        Self {
+            evm_word: meta.challenge_usable_after(FirstPhase),
+            keccak_input: meta.challenge_usable_after(FirstPhase),
+        }
+    }
 
-        [0.expr()]
-    });
+    /// Returns `Expression` of challenges from `ConstraintSystem`.
+    pub fn exprs<F: FieldExt>(&self, meta: &mut ConstraintSystem<F>) -> Challenges<Expression<F>> {
+        let [evm_word, keccak_input] = query_expression(meta, |meta| {
+            [self.evm_word, self.keccak_input].map(|challenge| meta.query_challenge(challenge))
+        });
+        Challenges {
+            evm_word,
+            keccak_input,
+        }
+    }
+
+    /// Returns `Value` of challenges from `Layouter`.
+    pub fn values<F: FieldExt>(&self, layouter: &mut impl Layouter<F>) -> Challenges<Value<F>> {
+        Challenges {
+            evm_word: layouter.get_challenge(self.evm_word),
+            keccak_input: layouter.get_challenge(self.keccak_input),
+        }
+    }
+}
+
+impl<T: Clone> Challenges<T> {
+    /// Returns challenge of `evm_word`.
+    pub fn evm_word(&self) -> T {
+        self.evm_word.clone()
+    }
+
+    /// Returns challenge of `keccak_input`.
+    pub fn keccak_input(&self) -> T {
+        self.keccak_input.clone()
+    }
 
-    power_of_randomness.unwrap()
+    pub(crate) fn mock(challenge: T) -> Self {
+        Self {
+            evm_word: challenge.clone(),
+            keccak_input: challenge,
+        }
+    }
 }
diff --git a/zkevm-circuits/src/witness/bytecode.rs b/zkevm-circuits/src/witness/bytecode.rs
index 1c700d2e44..1acb6261ac 100644
--- a/zkevm-circuits/src/witness/bytecode.rs
+++ b/zkevm-circuits/src/witness/bytecode.rs
@@ -1,8 +1,11 @@
 use bus_mapping::evm::OpcodeId;
 use eth_types::{Field, ToLittleEndian, Word};
+use halo2_proofs::circuit::Value;
 use sha3::{Digest, Keccak256};
 
-use crate::{evm_circuit::util::RandomLinearCombination, table::BytecodeFieldTag};
+use crate::{
+    evm_circuit::util::RandomLinearCombination, table::BytecodeFieldTag, util::Challenges,
+};
 
 /// Bytecode
 #[derive(Clone, Debug)]
@@ -21,18 +24,22 @@ impl Bytecode {
     }
 
     /// Assignments for bytecode table
-    pub fn table_assignments<F: Field>(&self, randomness: F) -> Vec<[F; 5]> {
+    pub fn table_assignments<F: Field>(
+        &self,
+        challenges: &Challenges<Value<F>>,
+    ) -> Vec<[Value<F>; 5]> {
         let n = 1 + self.bytes.len();
         let mut rows = Vec::with_capacity(n);
-        let hash =
-            RandomLinearCombination::random_linear_combine(self.hash.to_le_bytes(), randomness);
+        let hash = challenges.evm_word().map(|challenge| {
+            RandomLinearCombination::random_linear_combine(self.hash.to_le_bytes(), challenge)
+        });
 
         rows.push([
             hash,
-            F::from(BytecodeFieldTag::Length as u64),
-            F::zero(),
-            F::zero(),
-            F::from(self.bytes.len() as u64),
+            Value::known(F::from(BytecodeFieldTag::Length as u64)),
+            Value::known(F::zero()),
+            Value::known(F::zero()),
+            Value::known(F::from(self.bytes.len() as u64)),
         ]);
 
         let mut push_data_left = 0;
@@ -46,10 +53,10 @@ impl Bytecode {
             }
             rows.push([
                 hash,
-                F::from(BytecodeFieldTag::Byte as u64),
-                F::from(idx as u64),
-                F::from(is_code as u64),
-                F::from(*byte as u64),
+                Value::known(F::from(BytecodeFieldTag::Byte as u64)),
+                Value::known(F::from(idx as u64)),
+                Value::known(F::from(is_code as u64)),
+                Value::known(F::from(*byte as u64)),
             ])
         }
         rows