diff --git a/aggregator/src/core.rs b/aggregator/src/core.rs
index f0bb11a84b..bc21e44982 100644
--- a/aggregator/src/core.rs
+++ b/aggregator/src/core.rs
@@ -284,7 +284,8 @@ pub(crate) fn extract_hash_cells(
                     keccak_packed_multi::get_input_bytes_col_idx_in_cell_manager()
                         + <KeccakTable as LookupTable<Fr>>::columns(&keccak_config.keccak_table)
                             .len()
-                        - 1;
+                        - 1
+                        - 2; // exclude last word limbs' columns
                 for (offset, keccak_row) in witness.iter().enumerate() {
                     let row = keccak_config.set_row(&mut region, offset, keccak_row)?;
 
diff --git a/aggregator/src/tests/aggregation.rs b/aggregator/src/tests/aggregation.rs
index bac29f28c6..6df4c0f0ad 100644
--- a/aggregator/src/tests/aggregation.rs
+++ b/aggregator/src/tests/aggregation.rs
@@ -11,8 +11,6 @@ use crate::{
     tests::mock_chunk::MockChunkCircuit, ChunkHash,
 };
 
-//TODO: renable this test after pi/tx circuit supooort word hi lo feature.
-#[ignore = "renable after all circuits support word hi-lo done"]
 #[test]
 fn test_aggregation_circuit() {
     env_logger::init();
diff --git a/gadgets/src/comparator.rs b/gadgets/src/comparator.rs
index ce9f395604..2cb1dc83c0 100644
--- a/gadgets/src/comparator.rs
+++ b/gadgets/src/comparator.rs
@@ -4,7 +4,7 @@
 use eth_types::Field;
 use halo2_proofs::{
     circuit::{Chip, Region, Value},
-    plonk::{ConstraintSystem, Error, Expression, TableColumn, VirtualCells},
+    plonk::{Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells},
     poly::Rotation,
 };
 
@@ -64,7 +64,7 @@ impl<F: Field, const N_BYTES: usize> ComparatorChip<F, N_BYTES> {
         q_enable: impl FnOnce(&mut VirtualCells<F>) -> Expression<F> + Clone,
         lhs: impl FnOnce(&mut VirtualCells<F>) -> Expression<F> + Clone,
         rhs: impl FnOnce(&mut VirtualCells<F>) -> Expression<F> + Clone,
-        u8_table: TableColumn,
+        u8_table: Column<Fixed>,
     ) -> ComparatorConfig<F, N_BYTES> {
         let lt_config =
             LtChip::configure(meta, q_enable.clone(), lhs.clone(), rhs.clone(), u8_table);
diff --git a/gadgets/src/less_than.rs b/gadgets/src/less_than.rs
index ebde33a37b..b12f8b3158 100644
--- a/gadgets/src/less_than.rs
+++ b/gadgets/src/less_than.rs
@@ -3,7 +3,7 @@
 use eth_types::Field;
 use halo2_proofs::{
     circuit::{Chip, Region, Value},
-    plonk::{Advice, Column, ConstraintSystem, Error, Expression, TableColumn, VirtualCells},
+    plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells},
     poly::Rotation,
 };
 
@@ -37,7 +37,9 @@ pub struct LtConfig<F, const N_BYTES: usize> {
     /// Denotes the bytes representation of the difference between lhs and rhs.
     pub diff: [Column<Advice>; N_BYTES],
     /// Denotes the range within which each byte should lie.
-    pub u8_table: TableColumn,
+    //pub u8_table: TableColumn,
+    pub u8_table: Column<Fixed>,
+
     /// Denotes the range within which both lhs and rhs lie.
     pub range: F,
 }
@@ -68,7 +70,8 @@ impl<F: Field, const N_BYTES: usize> LtChip<F, N_BYTES> {
         q_enable: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression<F> + Clone,
         lhs: impl FnOnce(&mut VirtualCells<F>) -> Expression<F>,
         rhs: impl FnOnce(&mut VirtualCells<F>) -> Expression<F>,
-        u8_table: TableColumn,
+        //u8_table: TableColumn,
+        u8_table: Column<Fixed>,
     ) -> LtConfig<F, N_BYTES> {
         let lt = meta.advice_column();
         let diff = [(); N_BYTES].map(|_| meta.advice_column());
@@ -94,11 +97,11 @@ impl<F: Field, const N_BYTES: usize> LtChip<F, N_BYTES> {
         });
 
         for cell_column in diff {
-            meta.lookup("range check for u8", |meta| {
+            meta.lookup_any("range check for u8", |meta| {
                 let q_enable = q_enable.clone()(meta);
                 vec![(
                     q_enable * meta.query_advice(cell_column, Rotation::cur()),
-                    u8_table,
+                    meta.query_fixed(u8_table, Rotation::cur()),
                 )]
             });
         }
@@ -156,11 +159,12 @@ impl<F: Field, const N_BYTES: usize> LtInstruction<F> for LtChip<F, N_BYTES> {
     ) -> Result<(), Error> {
         const RANGE: usize = u8::MAX as usize;
 
-        layouter.assign_table(
+        //layouter.assign_table(
+        layouter.assign_region(
             || "load u8 range check table",
-            |mut table| {
+            |mut region| {
                 for i in 0..=RANGE {
-                    table.assign_cell(
+                    region.assign_fixed(
                         || "assign cell in fixed column",
                         self.config.u8_table,
                         i,
@@ -265,7 +269,7 @@ mod test {
                 let q_enable = meta.complex_selector();
                 let value = meta.advice_column();
                 let check = meta.advice_column();
-                let u8_table = meta.lookup_table_column();
+                let u8_table = meta.fixed_column();
 
                 let lt = LtChip::configure(
                     meta,
@@ -389,7 +393,7 @@ mod test {
                 let q_enable = meta.complex_selector();
                 let (value_a, value_b) = (meta.advice_column(), meta.advice_column());
                 let check = meta.advice_column();
-                let u16_table = meta.lookup_table_column();
+                let u16_table = meta.fixed_column();
 
                 let lt = LtChip::configure(
                     meta,
diff --git a/gadgets/src/mul_add.rs b/gadgets/src/mul_add.rs
index e10fb58183..9834383a6d 100644
--- a/gadgets/src/mul_add.rs
+++ b/gadgets/src/mul_add.rs
@@ -19,7 +19,7 @@
 use eth_types::{Field, Word, ToU16LittleEndian};
 use halo2_proofs::{
     circuit::{Region, Value},
-    plonk::{Advice, Column, ConstraintSystem, Error, Expression, TableColumn, VirtualCells},
+    plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells},
     poly::Rotation,
 };
 
@@ -46,7 +46,8 @@ pub struct MulAddConfig<F> {
     /// Sum of the parts higher than 256-bit in the product.
     pub overflow: Expression<F>,
     /// Lookup table for LtChips and carry_lo/hi.
-    pub u16_table: TableColumn,
+    // pub u16_table: TableColumn,
+    pub u16_table: Column<Fixed>,
     /// Range check of a, b which needs to be in [0, 2^64)
     pub range_check_64: UIntRangeCheckChip<F, { UIntRangeCheckChip::SIZE_U64 }, 8>,
     /// Range check of c, d which needs to be in [0, 2^128)
@@ -118,7 +119,8 @@ impl<F: Field> MulAddChip<F> {
     pub fn configure(
         meta: &mut ConstraintSystem<F>,
         q_enable: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression<F> + Clone,
-        u16_table: TableColumn,
+        //u16_table: TableColumn,
+        u16_table: Column<Fixed>,
     ) -> MulAddConfig<F> {
         let col0 = meta.advice_column();
         let col1 = meta.advice_column();
@@ -157,9 +159,10 @@ impl<F: Field> MulAddChip<F> {
             carry_cols.append(&mut carry_hi_cols.clone());
 
             for (col, rot) in carry_cols.into_iter() {
-                meta.lookup("mul carry range check lo/hi lookup u16", |meta| {
+                meta.lookup_any("mul carry range check lo/hi lookup u16", |meta| {
                     let q_enable = q_enable.clone()(meta);
-                    vec![(q_enable * meta.query_advice(col, Rotation(rot)), u16_table)]
+                    let u16_expr = meta.query_fixed(u16_table, Rotation::cur());
+                    vec![(q_enable * meta.query_advice(col, Rotation(rot)), u16_expr)]
                 });
             }
         }
@@ -506,7 +509,8 @@ mod test {
 
             fn configure(meta: &mut halo2_proofs::plonk::ConstraintSystem<F>) -> Self::Config {
                 let q_enable = meta.complex_selector();
-                let u16_table = meta.lookup_table_column();
+                //let u16_table = meta.lookup_table_column();
+                let u16_table = meta.fixed_column();
                 let mul_config =
                     MulAddChip::configure(meta, |meta| meta.query_selector(q_enable), u16_table);
                 Self::Config {
@@ -522,11 +526,12 @@ mod test {
             ) -> Result<(), halo2_proofs::plonk::Error> {
                 let chip = MulAddChip::construct(config.mul_config);
 
-                layouter.assign_table(
+                //layouter.assign_table(
+                layouter.assign_region(
                     || "u16 table",
-                    |mut table| {
+                    |mut region| {
                         for i in 0..=65535 {
-                            table.assign_cell(
+                            region.assign_fixed(
                                 || format!("u16 table row {i}"),
                                 chip.config.u16_table,
                                 i,
diff --git a/gadgets/src/range.rs b/gadgets/src/range.rs
index 81cdebaba4..4888caca7e 100644
--- a/gadgets/src/range.rs
+++ b/gadgets/src/range.rs
@@ -10,7 +10,7 @@ use crate::util::Expr;
 use eth_types::Field;
 use halo2_proofs::{
     circuit::{Chip, Region, Value},
-    plonk::{Advice, Column, ConstraintSystem, Error, Expression, TableColumn, VirtualCells},
+    plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells},
     poly::Rotation,
 };
 
@@ -36,7 +36,8 @@ pub struct UIntRangeCheckConfig<F, const N_2BYTE: usize, const N_EXPR: usize> {
     /// Denotes the little-endian representation of expression in u16.
     pub u16_repr: [Column<Advice>; N_2BYTE],
     /// Denotes the u16 lookup table.
-    pub u16_table: TableColumn,
+    //pub u16_table: TableColumn,
+    pub u16_table: Column<Fixed>,
     _marker: std::marker::PhantomData<F>,
 }
 
@@ -61,7 +62,8 @@ impl<F: Field, const N_2BYTE: usize, const N_EXPR: usize> UIntRangeCheckChip<F,
         meta: &mut ConstraintSystem<F>,
         q_enable: impl FnOnce(&mut VirtualCells<F>) -> Expression<F> + Clone,
         expressions: impl FnOnce(&mut VirtualCells<F>) -> [Expression<F>; N_EXPR],
-        u16_table: TableColumn,
+        //u16_table: TableColumn,
+        u16_table: Column<Fixed>,
     ) -> UIntRangeCheckConfig<F, N_2BYTE, N_EXPR> {
         let u16_repr = [(); N_2BYTE].map(|_| meta.advice_column());
 
@@ -83,9 +85,10 @@ impl<F: Field, const N_2BYTE: usize, const N_EXPR: usize> UIntRangeCheckChip<F,
         });
 
         for column in u16_repr {
-            meta.lookup(concat!("u16 cell range check"), |meta| {
+            meta.lookup_any(concat!("u16 cell range check"), |meta| {
                 let cell = meta.query_advice(column, Rotation::cur());
-                vec![(cell, u16_table)]
+                let u16_expr = meta.query_fixed(u16_table, Rotation::cur());
+                vec![(cell, u16_expr)]
             });
         }
 
diff --git a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs
index 6cf8ffe15b..197f22268f 100644
--- a/zkevm-circuits/src/evm_circuit/execution/calldataload.rs
+++ b/zkevm-circuits/src/evm_circuit/execution/calldataload.rs
@@ -157,8 +157,8 @@ impl<F: Field> ExecutionGadget<F> for CallDataLoadGadget<F> {
                             src_id.expr(),
                             TxContextFieldTag::CallData,
                             Some(src_addr.expr() + idx.expr()),
-                            //Word::from_lo_unchecked(buffer_reader.byte(idx)),
-                            buffer_reader.byte(idx),
+                            Word::from_lo_unchecked(buffer_reader.byte(idx)),
+                            // buffer_reader.byte(idx),
                         );
                     },
                 );
diff --git a/zkevm-circuits/src/evm_circuit/execution/end_block.rs b/zkevm-circuits/src/evm_circuit/execution/end_block.rs
index ac738933d7..494f0fb556 100644
--- a/zkevm-circuits/src/evm_circuit/execution/end_block.rs
+++ b/zkevm-circuits/src/evm_circuit/execution/end_block.rs
@@ -121,8 +121,8 @@ impl<F: Field> ExecutionGadget<F> for EndBlockGadget<F> {
                 total_txs.expr() + 1.expr(),
                 TxContextFieldTag::CallerAddress,
                 None,
-                //Word::zero(),
-                0.expr(),
+                Word::zero(),
+                // 0.expr(),
             );
             // Since every tx lookup done in the EVM circuit must succeed
             // and uses a unique tx_id, we know that at
diff --git a/zkevm-circuits/src/evm_circuit/execution/end_inner_block.rs b/zkevm-circuits/src/evm_circuit/execution/end_inner_block.rs
index b290cffc19..b8ad1b033b 100644
--- a/zkevm-circuits/src/evm_circuit/execution/end_inner_block.rs
+++ b/zkevm-circuits/src/evm_circuit/execution/end_inner_block.rs
@@ -10,7 +10,7 @@ use crate::{
         witness::{Block, Call, ExecStep, Transaction},
     },
     table::{BlockContextFieldTag, TxFieldTag::BlockNumber},
-    //util::word::Word,
+    util::word::Word,
 };
 use eth_types::Field;
 use gadgets::util::{not, Expr};
@@ -72,8 +72,8 @@ impl<F: Field> ExecutionGadget<F> for EndInnerBlockGadget<F> {
                 last_tx_id.expr(),
                 BlockNumber,
                 None,
-                // Word::from_lo_unchecked(cb.curr.state.block_number.expr()),
-                cb.curr.state.block_number.expr(),
+                Word::from_lo_unchecked(cb.curr.state.block_number.expr()),
+                // cb.curr.state.block_number.expr(),
             );
         });
 
diff --git a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs
index c9e16e6564..7a4d594818 100644
--- a/zkevm-circuits/src/evm_circuit/execution/gasprice.rs
+++ b/zkevm-circuits/src/evm_circuit/execution/gasprice.rs
@@ -11,7 +11,7 @@ use crate::{
     },
     table::{CallContextFieldTag, TxContextFieldTag},
     util::{
-        word::{WordCell, WordExpr},
+        word::{Word, Word32Cell, WordExpr},
         Expr,
     },
 };
@@ -22,9 +22,8 @@ use halo2_proofs::{circuit::Value, plonk::Error};
 #[derive(Clone, Debug)]
 pub(crate) struct GasPriceGadget<F> {
     tx_id: Cell<F>,
-    gas_price: WordCell<F>,
-    // TODO: remove gas_price_rlc in word hi lo stage2 (txtable to word)
-    gas_price_rlc: Cell<F>,
+    gas_price: Word32Cell<F>,
+    // gas_price_rlc: Cell<F>,
     same_context: SameContextGadget<F>,
 }
 
@@ -35,8 +34,9 @@ impl<F: Field> ExecutionGadget<F> for GasPriceGadget<F> {
 
     fn configure(cb: &mut EVMConstraintBuilder<F>) -> Self {
         // Query gasprice value
-        let gas_price = cb.query_word_unchecked();
-        let gas_price_rlc = cb.query_cell();
+        let gas_price = cb.query_word32();
+        // let gas_price_rlc = cb.query_cell();
+        let gas_price_rlc = cb.word_rlc(gas_price.limbs.clone().map(|l| l.expr()));
 
         // Lookup in call_ctx the TxId
         let tx_id = cb.call_context(None, CallContextFieldTag::TxId);
@@ -45,8 +45,9 @@ impl<F: Field> ExecutionGadget<F> for GasPriceGadget<F> {
             tx_id.expr(),
             TxContextFieldTag::GasPrice,
             None,
-            //gas_price.to_word(),
-            gas_price_rlc.expr(),
+            // gas_price.to_word(),
+            // gas_price_rlc.expr(),
+            Word::from_lo_unchecked(gas_price_rlc.expr()),
         );
 
         // Push the value to the stack
@@ -66,7 +67,7 @@ impl<F: Field> ExecutionGadget<F> for GasPriceGadget<F> {
         Self {
             tx_id,
             gas_price,
-            gas_price_rlc,
+            //gas_price_rlc,
             same_context,
         }
     }
@@ -85,8 +86,8 @@ impl<F: Field> ExecutionGadget<F> for GasPriceGadget<F> {
         self.tx_id
             .assign(region, offset, Value::known(F::from(tx.id as u64)))?;
 
-        self.gas_price_rlc
-            .assign(region, offset, region.word_rlc(gas_price))?;
+        // self.gas_price_rlc
+        //     .assign(region, offset, region.word_rlc(gas_price))?;
 
         self.gas_price.assign_u256(region, offset, gas_price)?;
 
diff --git a/zkevm-circuits/src/evm_circuit/execution/origin.rs b/zkevm-circuits/src/evm_circuit/execution/origin.rs
index ef7b52592c..a3c2d1bad1 100644
--- a/zkevm-circuits/src/evm_circuit/execution/origin.rs
+++ b/zkevm-circuits/src/evm_circuit/execution/origin.rs
@@ -10,7 +10,10 @@ use crate::{
         witness::{Block, Call, ExecStep, Transaction},
     },
     table::{CallContextFieldTag, TxContextFieldTag},
-    util::{word::WordExpr, Expr},
+    util::{
+        word::{Word, WordExpr},
+        Expr,
+    },
 };
 use bus_mapping::evm::OpcodeId;
 use eth_types::Field;
@@ -30,16 +33,18 @@ impl<F: Field> ExecutionGadget<F> for OriginGadget<F> {
 
     fn configure(cb: &mut EVMConstraintBuilder<F>) -> Self {
         let origin = cb.query_account_address();
+        // let address_rlc = cb.word_rlc(origin.limbs.clone().map(|l| l.expr()));
 
         // Lookup in call_ctx the TxId
         let tx_id = cb.call_context(None, CallContextFieldTag::TxId);
+        let address_value = from_bytes::expr(&origin.limbs);
         // Lookup rw_table -> call_context with tx origin address
         cb.tx_context_lookup(
             tx_id.expr(),
             TxContextFieldTag::CallerAddress,
             None, // None because unrelated to calldata
-            //origin.to_word(), used in word hi lo stage2
-            from_bytes::expr(&origin.limbs),
+            //origin.to_word(),
+            Word::from_lo_unchecked(address_value),
         );
 
         // Push the value to the stack
@@ -78,7 +83,7 @@ impl<F: Field> ExecutionGadget<F> for OriginGadget<F> {
         self.tx_id
             .assign(region, offset, Value::known(F::from(tx.id as u64)))?;
 
-        // Assign Origin addr RLC.
+        // Assign Origin addr word.
         self.origin.assign_u256(region, offset, origin)?;
 
         // Assign SameContextGadget witnesses.
diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs
index 620f7b1b5b..535a8b32af 100644
--- a/zkevm-circuits/src/evm_circuit/table.rs
+++ b/zkevm-circuits/src/evm_circuit/table.rs
@@ -229,8 +229,8 @@ pub(crate) enum Lookup<F> {
         /// field_tag is Calldata, otherwise should be set to 0.
         index: Expression<F>,
         /// Value of the field.
-        // value: Word<Expression<F>>, change to word in stage2
-        value: Expression<F>,
+        value: Word<Expression<F>>,
+        // value: Expression<F>,
     },
     /// Lookup to read-write table, which contains read-write access records of
     /// time-aware data.
@@ -403,9 +403,9 @@ impl<F: Field> Lookup<F> {
                 id.clone(),
                 field_tag.clone(),
                 index.clone(),
-                // value.lo(),
-                // value.hi(),
-                value.clone(),
+                value.lo(),
+                value.hi(),
+                // value.clone(),
             ],
             Self::Rw {
                 counter,
diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs
index c012c28ab6..60a8443f36 100644
--- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs
+++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs
@@ -799,8 +799,8 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> {
         index: Option<Expression<F>>,
     ) -> Cell<F> {
         let cell = self.query_cell();
-        //self.tx_context_lookup(id, field_tag, index, Word::from_lo_unchecked(cell.expr()));
-        self.tx_context_lookup(id, field_tag, index, cell.expr());
+        self.tx_context_lookup(id, field_tag, index, Word::from_lo_unchecked(cell.expr()));
+        // self.tx_context_lookup(id, field_tag, index, cell.expr());
         cell
     }
 
@@ -832,8 +832,8 @@ impl<'a, F: Field> EVMConstraintBuilder<'a, F> {
         id: Expression<F>,
         field_tag: TxContextFieldTag,
         index: Option<Expression<F>>,
-        //value: Word<Expression<F>>, used in stage2 for tx table to word
-        value: Expression<F>,
+        value: Word<Expression<F>>,
+        //value: Expression<F>,
     ) {
         self.add_lookup(
             "Tx lookup",
diff --git a/zkevm-circuits/src/exp_circuit.rs b/zkevm-circuits/src/exp_circuit.rs
index afc3582b4c..fc0eba1c26 100644
--- a/zkevm-circuits/src/exp_circuit.rs
+++ b/zkevm-circuits/src/exp_circuit.rs
@@ -10,7 +10,7 @@ pub use dev::ExpCircuit as TestExpCircuit;
 
 use crate::{
     evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon},
-    table::{ExpTable, LookupTable, U16Table},
+    table::{ExpTable, LookupTable, UXTable},
     util::{Challenges, SubCircuit, SubCircuitConfig},
     witness,
 };
@@ -38,7 +38,8 @@ pub struct ExpCircuitConfig<F> {
     /// The Exponentiation circuit's table.
     pub exp_table: ExpTable,
     /// u16 lookup table,
-    pub u16_table: U16Table,
+    // pub u16_table: U16Table,
+    pub u16_table: UXTable<16>,
     /// Multiplication gadget for verification of each step.
     pub mul_gadget: MulAddConfig<F>,
     /// Multiplication gadget to perform 2*n + k.
@@ -50,7 +51,8 @@ pub struct ExpCircuitArgs {
     /// The Exponentiation circuit's table.
     pub exp_table: ExpTable,
     /// u16 lookup table,
-    pub u16_table: U16Table,
+    // pub u16_table: U16Table,
+    pub u16_table: UXTable<16>,
 }
 
 impl<F: Field> SubCircuitConfig<F> for ExpCircuitConfig<F> {
@@ -74,7 +76,7 @@ impl<F: Field> SubCircuitConfig<F> for ExpCircuitConfig<F> {
                     meta.query_fixed(exp_table.is_step, Rotation::cur()),
                 ])
             },
-            u16_table.into(),
+            u16_table.col,
         );
         let parity_check = MulAddChip::configure(
             meta,
@@ -84,7 +86,7 @@ impl<F: Field> SubCircuitConfig<F> for ExpCircuitConfig<F> {
                     meta.query_fixed(exp_table.is_step, Rotation::cur()),
                 ])
             },
-            u16_table.into(),
+            u16_table.col,
         );
 
         // multiplier <- 2^64
diff --git a/zkevm-circuits/src/exp_circuit/dev.rs b/zkevm-circuits/src/exp_circuit/dev.rs
index 1c2114186b..779cae8372 100644
--- a/zkevm-circuits/src/exp_circuit/dev.rs
+++ b/zkevm-circuits/src/exp_circuit/dev.rs
@@ -2,7 +2,7 @@ pub use super::ExpCircuit;
 
 use crate::{
     exp_circuit::{ExpCircuitArgs, ExpCircuitConfig},
-    table::{ExpTable, U16Table},
+    table::{ExpTable, UXTable},
     util::{Challenges, SubCircuit, SubCircuitConfig},
 };
 use eth_types::Field;
@@ -24,7 +24,7 @@ impl<F: Field> Circuit<F> for ExpCircuit<F> {
     fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
         let exp_table = ExpTable::construct(meta);
         let challenges = Challenges::construct(meta);
-        let u16_table = U16Table::construct(meta);
+        let u16_table = UXTable::construct(meta);
         (
             ExpCircuitConfig::new(
                 meta,
diff --git a/zkevm-circuits/src/keccak_circuit.rs b/zkevm-circuits/src/keccak_circuit.rs
index 67320bdfab..2bc37d6aa2 100644
--- a/zkevm-circuits/src/keccak_circuit.rs
+++ b/zkevm-circuits/src/keccak_circuit.rs
@@ -950,11 +950,16 @@ impl<F: Field> KeccakCircuitConfig<F> {
                 row.data_rlc,
                 Value::known(F::from(row.length as u64)),
                 row.hash_rlc,
-                //row.hash.lo(),
-                //row.hash.hi(),
+                row.hash.lo(),
+                row.hash.hi(),
             ],
         )?;
 
+        // work around to remove last two items(hi + lo parts), avoid to mistake hash output cells
+        // in method `extract_hash_cells` of aggregation circuit.
+        res.remove(res.len() - 1);
+        res.remove(res.len() - 1);
+
         // Cell values
         for (idx, (bit, column)) in row
             .cell_values
diff --git a/zkevm-circuits/src/pi_circuit.rs b/zkevm-circuits/src/pi_circuit.rs
index 73a15814f4..2bc82324b0 100644
--- a/zkevm-circuits/src/pi_circuit.rs
+++ b/zkevm-circuits/src/pi_circuit.rs
@@ -33,7 +33,7 @@ use crate::{
     },
     state_circuit::StateCircuitExports,
     tx_circuit::{CHAIN_ID_OFFSET as CHAIN_ID_OFFSET_IN_TX, TX_HASH_OFFSET, TX_LEN},
-    //util::word,
+    util::word,
     witness::{self, Block, BlockContext, BlockContexts, Transaction},
 };
 use bus_mapping::util::read_env_var;
@@ -343,8 +343,8 @@ pub struct PiCircuitConfig<F: Field> {
     rpi_field_bytes: Column<Advice>,   // rpi in bytes
     rpi_field_bytes_acc: Column<Advice>,
     rpi_rlc_acc: Column<Advice>, // RLC(rpi) as the input to Keccak table
-    // the input word type to Keccak table, TODO: enable rpi_rlc_acc_word in stage2
-    // rpi_rlc_acc_word: word::Word<Column<Advice>>,
+    // the input word type to Keccak table
+    rpi_rlc_acc_word: word::Word<Column<Advice>>,
     rpi_length_acc: Column<Advice>,
 
     // columns for padding in block context and tx hashes
@@ -423,7 +423,7 @@ impl<F: Field> SubCircuitConfig<F> for PiCircuitConfig<F> {
         let rpi_bytes_acc = meta.advice_column_in(SecondPhase);
         // hold the accumulated value of rlc(rpi_bytes, keccak_input)
         let rpi_rlc_acc = meta.advice_column_in(SecondPhase);
-        //let rpi_rlc_acc_word = word::Word::new([meta.advice_column(), meta.advice_column()]);
+        let rpi_rlc_acc_word = word::Word::new([meta.advice_column(), meta.advice_column()]);
 
         // hold the accumulated length of rpi_bytes for looking into keccak table
         let rpi_length_acc = meta.advice_column();
@@ -465,9 +465,12 @@ impl<F: Field> SubCircuitConfig<F> for PiCircuitConfig<F> {
         meta.enable_equality(real_rpi);
         meta.enable_equality(block_table.value); // copy block to rpi
         meta.enable_equality(block_table.index);
-        meta.enable_equality(tx_table.value); // copy tx hashes to rpi
+        meta.enable_equality(tx_table.value.lo()); // copy tx hashes to rpi
+        meta.enable_equality(tx_table.value.hi()); // copy tx hashes to rpi
         meta.enable_equality(cum_num_txs);
         meta.enable_equality(pi);
+        meta.enable_equality(rpi_rlc_acc_word.lo());
+        meta.enable_equality(rpi_rlc_acc_word.hi());
 
         // 1. constrain rpi_bytes, rpi_bytes_acc, and rpi for each field
         meta.create_gate(
@@ -638,33 +641,32 @@ impl<F: Field> SubCircuitConfig<F> for PiCircuitConfig<F> {
         // q_keccak = 1     |pi_bs_rlc|     ..    |      ...      | pi_hash_rlc |      136       |
         //   pi hash        |   hi    |     ..    |      ...      |     ...     |       16       |
         //                  |   lo    |     ..    |      ...      | pi_hash_rlc |       32       |
-        // TODO: enable this lookup in stage2
-        // meta.lookup_any("keccak(rpi)", |meta| {
-        //     let q_keccak = meta.query_selector(q_keccak);
-
-        //     let rpi_rlc = meta.query_advice(rpi, Rotation::cur());
-        //     let rpi_length = meta.query_advice(rpi_length_acc, Rotation::cur());
-        //     let output = meta.query_advice(rpi_rlc_acc, Rotation::cur());
-        //     //let output_word = rpi_rlc_acc_word.query_advice(meta, Rotation::cur());
-
-        //     let input_exprs = vec![
-        //         1.expr(), // q_enable = true
-        //         1.expr(), // is_final = true
-        //         rpi_rlc,
-        //         rpi_length,
-        //         output,
-        //         //output_word.lo(),
-        //         //soutput_word.hi(),
-        //     ];
-        //     let keccak_table_exprs = keccak_table.table_exprs(meta);
-        //     assert_eq!(input_exprs.len(), keccak_table_exprs.len());
-
-        //     input_exprs
-        //         .into_iter()
-        //         .zip(keccak_table_exprs)
-        //         .map(|(input, table)| (q_keccak.expr() * input, table))
-        //         .collect()
-        // });
+        meta.lookup_any("keccak(rpi)", |meta| {
+            let q_keccak = meta.query_selector(q_keccak);
+
+            let rpi_rlc = meta.query_advice(rpi, Rotation::cur());
+            let rpi_length = meta.query_advice(rpi_length_acc, Rotation::cur());
+            let output = meta.query_advice(rpi_rlc_acc, Rotation::cur());
+            let output_word = rpi_rlc_acc_word.query_advice(meta, Rotation::cur());
+
+            let input_exprs = vec![
+                1.expr(), // q_enable = true
+                1.expr(), // is_final = true
+                rpi_rlc,
+                rpi_length,
+                output,
+                output_word.lo(),
+                output_word.hi(),
+            ];
+            let keccak_table_exprs = keccak_table.table_exprs(meta);
+            assert_eq!(input_exprs.len(), keccak_table_exprs.len());
+
+            input_exprs
+                .into_iter()
+                .zip(keccak_table_exprs)
+                .map(|(input, table)| (q_keccak.expr() * input, table))
+                .collect()
+        });
 
         // 3. constrain block_table
         meta.create_gate(
@@ -707,7 +709,7 @@ impl<F: Field> SubCircuitConfig<F> for PiCircuitConfig<F> {
             rpi_field_bytes: rpi_bytes,
             rpi_field_bytes_acc: rpi_bytes_acc,
             rpi_rlc_acc,
-            //rpi_rlc_acc_word,
+            rpi_rlc_acc_word,
             rpi_length_acc,
             is_rpi_padding,
             real_rpi,
@@ -732,10 +734,10 @@ type PiHashExport<F> = Vec<AssignedCell<F, F>>;
 
 #[derive(Debug, Clone)]
 struct Connections<F: Field> {
-    //start_state_root: word::Word<AssignedCell<F, F>>,
-    start_state_root: AssignedCell<F, F>,
-    //end_state_root: word::Word<AssignedCell<F, F>>,
-    end_state_root: AssignedCell<F, F>,
+    start_state_root: word::Word<AssignedCell<F, F>>,
+    //start_state_root: AssignedCell<F, F>,
+    end_state_root: word::Word<AssignedCell<F, F>>,
+    //end_state_root: AssignedCell<F, F>,
     withdraw_root: AssignedCell<F, F>,
 }
 
@@ -802,7 +804,7 @@ impl<F: Field> PiCircuitConfig<F> {
         region: &mut Region<'_, F>,
         public_data: &PublicData,
         block_value_cells: &[AssignedCell<F, F>],
-        tx_value_cells: &[AssignedCell<F, F>],
+        tx_value_cells: &[word::Word<AssignedCell<F, F>>],
         challenges: &Challenges<Value<F>>,
     ) -> Result<(PiHashExport<F>, Connections<F>), Error> {
         // 1. Assign data bytes.
@@ -849,7 +851,7 @@ impl<F: Field> PiCircuitConfig<F> {
         offset: usize,
         public_data: &PublicData,
         block_value_cells: &[AssignedCell<F, F>],
-        tx_value_cells: &[AssignedCell<F, F>],
+        tx_value_cells: &[word::Word<AssignedCell<F, F>>],
         challenges: &Challenges<Value<F>>,
     ) -> Result<(usize, AssignedCell<F, F>), Error> {
         // Initialise the RLC accumulator and length values.
@@ -983,6 +985,7 @@ impl<F: Field> PiCircuitConfig<F> {
             rpi_rlc_acc = tmp_rpi_rlc_acc;
             rpi_length = tmp_rpi_length;
             tx_copy_cells.push(cells[RPI_CELL_IDX].clone());
+
             if i == public_data.max_txs - 1 {
                 data_bytes_rlc = Some(cells[RPI_RLC_ACC_CELL_IDX].clone());
                 data_bytes_length = Some(cells[RPI_LENGTH_ACC_CELL_IDX].clone());
@@ -990,9 +993,10 @@ impl<F: Field> PiCircuitConfig<F> {
         }
         // Copy tx_hashes to tx table
         for (i, tx_hash_cell) in tx_copy_cells.into_iter().enumerate() {
+            // tx hash value still use rlc format in tx circuit.
             region.constrain_equal(
                 tx_hash_cell.cell(),
-                tx_value_cells[i * TX_LEN + TX_HASH_OFFSET - 1].cell(),
+                tx_value_cells[i * TX_LEN + TX_HASH_OFFSET - 1].lo().cell(),
             )?;
         }
 
@@ -1015,6 +1019,15 @@ impl<F: Field> PiCircuitConfig<F> {
                 &public_data.get_data_hash().to_fixed_bytes(),
                 challenges.evm_word(),
             );
+
+            let data_hash_word =
+                word::Word::from(public_data.get_data_hash().to_word()).map(Value::known);
+            data_hash_word.assign_advice(
+                region,
+                || "assign rpi_rlc_acc_word",
+                self.rpi_rlc_acc_word,
+                offset,
+            )?;
             region.assign_advice(
                 || "data_hash_rlc",
                 self.rpi_rlc_acc,
@@ -1037,7 +1050,7 @@ impl<F: Field> PiCircuitConfig<F> {
         offset: usize,
         public_data: &PublicData,
         block_value_cells: &[AssignedCell<F, F>],
-        tx_value_cells: &[AssignedCell<F, F>],
+        tx_value_cells: &[word::Word<AssignedCell<F, F>>],
         data_hash_rlc_cell: &AssignedCell<F, F>,
         challenges: &Challenges<Value<F>>,
     ) -> Result<(usize, AssignedCell<F, F>, Connections<F>), Error> {
@@ -1068,29 +1081,43 @@ impl<F: Field> PiCircuitConfig<F> {
                 rpi_length,
                 challenges,
             )?;
-            Ok(cells[RPI_CELL_IDX].clone())
+            Ok((cells[0].clone(), cells[3].clone(), cells[4].clone()))
         })
         .collect::<Result<Vec<_>, Error>>()?;
 
         // copy chain_id to block table
         for block_idx in 0..public_data.max_inner_blocks {
             region.constrain_equal(
-                rpi_cells[0].cell(),
+                rpi_cells[0].0.cell(),
                 block_value_cells[block_idx * BLOCK_LEN + CHAIN_ID_OFFSET].cell(),
             )?;
         }
         // copy chain_id to tx table
         for tx_id in 0..public_data.max_txs {
+            // region.constrain_equal(
+            //     rpi_cells[0].0.cell(),
+            //     tx_value_cells[tx_id * TX_LEN + CHAIN_ID_OFFSET_IN_TX - 1].cell(),
+            // )?;
             region.constrain_equal(
-                rpi_cells[0].cell(),
-                tx_value_cells[tx_id * TX_LEN + CHAIN_ID_OFFSET_IN_TX - 1].cell(),
+                rpi_cells[0].1.cell(),
+                tx_value_cells[tx_id * TX_LEN + CHAIN_ID_OFFSET_IN_TX - 1]
+                    .lo()
+                    .cell(),
+            )?;
+            region.constrain_equal(
+                rpi_cells[0].2.cell(),
+                tx_value_cells[tx_id * TX_LEN + CHAIN_ID_OFFSET_IN_TX - 1]
+                    .hi()
+                    .cell(),
             )?;
         }
         // connections to be done with other sub-circuits.
         let connections = Connections {
-            start_state_root: rpi_cells[1].clone(),
-            end_state_root: rpi_cells[2].clone(),
-            withdraw_root: rpi_cells[3].clone(),
+            //start_state_root: rpi_cells[1].clone(),
+            start_state_root: word::Word::new([rpi_cells[1].1.clone(), rpi_cells[1].2.clone()]),
+            // end_state_root: rpi_cells[2].clone(),
+            end_state_root: word::Word::new([rpi_cells[2].1.clone(), rpi_cells[2].2.clone()]),
+            withdraw_root: rpi_cells[3].0.clone(),
         };
 
         // Assign data_hash
@@ -1125,6 +1152,14 @@ impl<F: Field> PiCircuitConfig<F> {
             self.rpi_length_acc,
             offset,
         )?;
+
+        let pi_hash_word = word::Word::from(public_data.get_pi().to_word()).map(Value::known);
+        pi_hash_word.assign_advice(
+            region,
+            || "assign rpi_rlc_acc_word",
+            self.rpi_rlc_acc_word,
+            offset,
+        )?;
         let pi_hash_rlc_cell = {
             let pi_hash_rlc = rlc_be_bytes(
                 &public_data.get_pi().to_fixed_bytes(),
@@ -1165,7 +1200,7 @@ impl<F: Field> PiCircuitConfig<F> {
             challenges,
         )?;
         (offset, rpi_rlc_acc, rpi_length) = (tmp_offset, tmp_rpi_rlc_acc, tmp_rpi_length);
-        let pi_hash_hi_cells = cells[3..].to_vec();
+        let pi_hash_hi_cells = cells[5..].to_vec();
 
         // the low 16 bytes of keccak output
         let (tmp_offset, _, _, cells) = self.assign_field(
@@ -1179,7 +1214,7 @@ impl<F: Field> PiCircuitConfig<F> {
             challenges,
         )?;
         offset = tmp_offset;
-        let pi_hash_lo_cells = cells[3..].to_vec();
+        let pi_hash_lo_cells = cells[5..].to_vec();
 
         // Copy pi_hash value we collected from assigning pi bytes.
         region.constrain_equal(pi_hash_rlc_cell.cell(), cells[RPI_RLC_ACC_CELL_IDX].cell())?;
@@ -1254,7 +1289,6 @@ impl<F: Field> PiCircuitConfig<F> {
             F::zero(),
         )?;
 
-        //let rpi_rlc_acc_word = word::Word::new([F::zero(), F::zero()]);
         region.assign_advice_from_constant(
             || "rpi_length_acc[0]",
             self.rpi_length_acc,
@@ -1320,9 +1354,13 @@ impl<F: Field> PiCircuitConfig<F> {
             self.q_field_step.enable(region, q_offset)?;
         }
 
-        let (mut final_rpi_cell, mut final_rpi_rlc_cell, mut final_rpi_length_cell) =
-            (None, None, None);
-        let cells =
+        let (
+            mut final_rpi_cell,
+            mut final_rpi_rlc_cell,
+            mut final_rpi_word_cells,
+            mut final_rpi_length_cell,
+        ) = (None, None, None, None);
+        let cells: Vec<(AssignedCell<F, F>, (AssignedCell<F, F>, AssignedCell<F, F>))> =
             value_be_bytes
                 .iter()
                 .zip(rpi_bytes_acc.iter())
@@ -1386,6 +1424,30 @@ impl<F: Field> PiCircuitConfig<F> {
                         row_offset,
                         || rpi_rlc_acc,
                     )?;
+
+                    let rpi_word = if value_be_bytes.len() >= 32 {
+                        let value_word = Word::from_big_endian(&value_be_bytes[..32]);
+                        word::Word::from(value_word).map(Value::known)
+                    } else {
+                        // no meaningful, just for final_rpi_word_cells dummy value
+                        let len = value_be_bytes.len();
+                        let zero_iter = std::iter::repeat(0); // 生成一个无限重复0的迭代器
+                        let value_bytes_with_zero = zero_iter
+                            .take(32 - len)
+                            .chain(value_be_bytes.to_vec())
+                            .collect::<Vec<u8>>();
+                        // pad zero and take 32 bytes
+                        let value_word = Word::from_big_endian(&value_bytes_with_zero[..32]);
+                        word::Word::from(value_word).map(Value::known)
+                    };
+
+                    final_rpi_word_cells = Some(rpi_word.assign_advice(
+                        region,
+                        || "assign rpi_rlc_acc_word",
+                        self.rpi_rlc_acc_word,
+                        row_offset,
+                    )?);
+
                     let rpi_length_cell = region.assign_advice(
                         || "rpi_length_acc",
                         self.rpi_length_acc,
@@ -1452,6 +1514,7 @@ impl<F: Field> PiCircuitConfig<F> {
         //      ...
         //      byte_cell[n_bytes - 1]
         // ]
+        let final_rpi_word_cells_unwrap = final_rpi_word_cells.unwrap();
         Ok((
             offset + n_bytes,
             rpi_rlc_acc,
@@ -1461,6 +1524,8 @@ impl<F: Field> PiCircuitConfig<F> {
                     final_rpi_cell.unwrap(),
                     final_rpi_rlc_cell.unwrap(),
                     final_rpi_length_cell.unwrap(),
+                    final_rpi_word_cells_unwrap.lo(),
+                    final_rpi_word_cells_unwrap.hi(),
                 ],
                 byte_cells,
             ]
@@ -1627,7 +1692,8 @@ pub struct PiCircuit<F: Field> {
     _marker: PhantomData<F>,
 
     connections: RefCell<Option<Connections<F>>>,
-    tx_value_cells: RefCell<Option<Vec<AssignedCell<F, F>>>>,
+    #[allow(clippy::type_complexity)]
+    tx_value_cells: RefCell<Option<Vec<word::Word<AssignedCell<F, F>>>>>,
 }
 
 impl<F: Field> PiCircuit<F> {
@@ -1679,7 +1745,7 @@ impl<F: Field> PiCircuit<F> {
     }
 
     /// Import tx value cells from Tx circuit
-    pub fn import_tx_values(&self, values: Vec<AssignedCell<F, F>>) {
+    pub fn import_tx_values(&self, values: Vec<word::Word<AssignedCell<F, F>>>) {
         *self.tx_value_cells.borrow_mut() = Some(values);
     }
 
@@ -1706,15 +1772,22 @@ impl<F: Field> PiCircuit<F> {
                         (&state_roots.start_state_root, &state_roots.end_state_root)
                     );
 
-                    // TODO: enable this constraint later after pi circuit, tx circuit updated
-                    // region.constrain_equal(
-                    //     local_conn.start_state_root.cell(),
-                    //     state_roots.start_state_root.0,
-                    // )?;
-                    // region.constrain_equal(
-                    //     local_conn.end_state_root.cell(),
-                    //     state_roots.end_state_root.0,
-                    // )?;
+                    region.constrain_equal(
+                        local_conn.start_state_root.lo().cell(),
+                        state_roots.start_state_root.0.lo(),
+                    )?;
+                    region.constrain_equal(
+                        local_conn.start_state_root.hi().cell(),
+                        state_roots.start_state_root.0.hi(),
+                    )?;
+                    region.constrain_equal(
+                        local_conn.end_state_root.lo().cell(),
+                        state_roots.end_state_root.0.lo(),
+                    )?;
+                    region.constrain_equal(
+                        local_conn.end_state_root.hi().cell(),
+                        state_roots.end_state_root.0.hi(),
+                    )?;
                 } else {
                     log::warn!("state roots are not set, skip connection with state circuit");
                 }
diff --git a/zkevm-circuits/src/rlp_circuit_fsm.rs b/zkevm-circuits/src/rlp_circuit_fsm.rs
index 8218d23133..de9d6df3c3 100644
--- a/zkevm-circuits/src/rlp_circuit_fsm.rs
+++ b/zkevm-circuits/src/rlp_circuit_fsm.rs
@@ -7,7 +7,7 @@ mod test;
 
 use crate::{
     evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon},
-    table::{LookupTable, RlpFsmRlpTable, U8Table},
+    table::{LookupTable, RlpFsmRlpTable, UXTable},
     util::{
         is_zero::{IsZeroChip, IsZeroConfig},
         Challenges, SubCircuit, SubCircuitConfig,
@@ -284,7 +284,8 @@ pub struct RlpCircuitConfig<F> {
     /// ROM table
     rom_table: RlpFsmRomTable,
     /// Range u8 table
-    u8_table: U8Table,
+    // u8_table: U8Table,
+    u8_table: UXTable<8>,
 }
 
 impl<F: Field> RlpCircuitConfig<F> {
@@ -293,7 +294,8 @@ impl<F: Field> RlpCircuitConfig<F> {
         meta: &mut ConstraintSystem<F>,
         rom_table: RlpFsmRomTable,
         data_table: RlpFsmDataTable,
-        u8_table: U8Table,
+        //u8_table: U8Table,
+        u8_table: UXTable<8>,
         rlp_table: RlpFsmRlpTable,
         challenges: &Challenges<Expression<F>>,
     ) -> Self {
@@ -562,7 +564,7 @@ impl<F: Field> RlpCircuitConfig<F> {
             cb.gate(meta.query_fixed(q_enabled, Rotation::cur()))
         });
 
-        meta.lookup("byte value check", |meta| {
+        meta.lookup_any("byte value check", |meta| {
             let cond = and::expr([
                 meta.query_fixed(q_enabled, Rotation::cur()),
                 not::expr(is_padding_in_dt.expr(Rotation::cur())(meta)),
@@ -570,7 +572,7 @@ impl<F: Field> RlpCircuitConfig<F> {
 
             vec![(
                 cond * meta.query_advice(data_table.byte_value, Rotation::cur()),
-                u8_table.into(),
+                meta.query_fixed(u8_table.col, Rotation::cur()),
             )]
         });
 
@@ -643,7 +645,7 @@ impl<F: Field> RlpCircuitConfig<F> {
                     cmp_enabled,
                     |meta| meta.query_advice(byte_value, Rotation::cur()),
                     |_| $value.expr(),
-                    u8_table.into(),
+                    u8_table.col,
                 );
             };
         }
@@ -654,7 +656,7 @@ impl<F: Field> RlpCircuitConfig<F> {
                     cmp_enabled,
                     |_| $value.expr(),
                     |meta| meta.query_advice(byte_value, Rotation::cur()),
-                    u8_table.into(),
+                    u8_table.col,
                 );
             };
         }
@@ -737,21 +739,21 @@ impl<F: Field> RlpCircuitConfig<F> {
             cmp_enabled,
             |meta| meta.query_advice(tag_idx, Rotation::cur()),
             |meta| meta.query_advice(tag_length, Rotation::cur()),
-            u8_table.into(),
+            u8_table.col,
         );
         let mlength_lte_0x20 = ComparatorChip::configure(
             meta,
             cmp_enabled,
             |meta| meta.query_advice(max_length, Rotation::cur()),
             |_meta| 0x20.expr(),
-            u8_table.into(),
+            u8_table.col,
         );
         let tlength_lte_mlength = ComparatorChip::configure(
             meta,
             cmp_enabled,
             |meta| meta.query_advice(tag_length, Rotation::cur()),
             |meta| meta.query_advice(max_length, Rotation::cur()),
-            u8_table.into(),
+            u8_table.col,
         );
         let depth_check = IsEqualChip::configure(
             meta,
@@ -1894,7 +1896,8 @@ pub struct RlpCircuitConfigArgs<F: Field> {
     /// RLP table.
     pub rlp_table: RlpFsmRlpTable,
     /// u8 table
-    pub u8_table: U8Table,
+    // pub u8_table: U8Table,
+    pub u8_table: UXTable<8>,
     /// Challenge API.
     pub challenges: Challenges<Expression<F>>,
 }
diff --git a/zkevm-circuits/src/rlp_circuit_fsm/dev.rs b/zkevm-circuits/src/rlp_circuit_fsm/dev.rs
index ec775f397c..f2fc56f943 100644
--- a/zkevm-circuits/src/rlp_circuit_fsm/dev.rs
+++ b/zkevm-circuits/src/rlp_circuit_fsm/dev.rs
@@ -1,6 +1,6 @@
 use crate::{
     rlp_circuit_fsm::{RlpCircuit, RlpCircuitConfig, RlpCircuitConfigArgs},
-    table::{RlpFsmRlpTable, U8Table},
+    table::{RlpFsmRlpTable, UXTable},
     util::{Challenges, SubCircuit, SubCircuitConfig},
     witness::Transaction,
 };
@@ -23,8 +23,9 @@ impl<F: Field> Circuit<F> for RlpCircuit<F, Transaction> {
     fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
         let rlp_table = RlpFsmRlpTable::construct(meta);
         let challenges = Challenges::construct(meta);
-        let challenge_exprs = challenges.exprs(meta);
-        let u8_table = U8Table::construct(meta);
+        let challenge_exprs: Challenges<halo2_proofs::plonk::Expression<F>> =
+            challenges.exprs(meta);
+        let u8_table = UXTable::construct(meta);
 
         let config = RlpCircuitConfig::new(
             meta,
diff --git a/zkevm-circuits/src/sig_circuit.rs b/zkevm-circuits/src/sig_circuit.rs
index 62a83f605f..5676590fa4 100644
--- a/zkevm-circuits/src/sig_circuit.rs
+++ b/zkevm-circuits/src/sig_circuit.rs
@@ -22,12 +22,12 @@ use crate::{
     keccak_circuit::KeccakCircuit,
     sig_circuit::ecdsa::ecdsa_verify_no_pubkey_check,
     table::{KeccakTable, SigTable},
-    util::{Challenges, Expr, SubCircuit, SubCircuitConfig},
+    util::{word, Challenges, Expr, SubCircuit, SubCircuitConfig},
 };
 use eth_types::{
     self,
     sign_types::{pk_bytes_le, pk_bytes_swap_endianness, SignData},
-    Field,
+    Field, Word,
 };
 use halo2_base::{
     gates::{range::RangeConfig, GateInstructions, RangeInstructions},
@@ -58,7 +58,7 @@ use halo2_proofs::{
 use ethers_core::utils::keccak256;
 use itertools::Itertools;
 use log::error;
-use std::{iter, marker::PhantomData};
+use std::{iter, iter::Iterator, marker::PhantomData, vec::Vec};
 
 /// Circuit configuration arguments
 pub struct SigCircuitConfigArgs<F: Field> {
@@ -77,6 +77,8 @@ pub struct SigCircuitConfig<F: Field> {
     ecdsa_config: FpChip<F>,
     /// An advice column to store RLC witnesses
     rlc_column: Column<Advice>,
+    /// An advice column to store word keccak result
+    rlc_column_word: word::Word<Column<Advice>>,
     /// selector for keccak lookup table
     q_keccak: Selector,
     /// Used to lookup pk->pk_hash(addr)
@@ -143,7 +145,7 @@ impl<F: Field> SubCircuitConfig<F> for SigCircuitConfig<F> {
         let rlc_column = meta.advice_column_in(halo2_proofs::plonk::FirstPhase);
         #[cfg(not(feature = "onephase"))]
         let rlc_column = meta.advice_column_in(halo2_proofs::plonk::SecondPhase);
-
+        let rlc_column_word = word::Word::new([meta.advice_column(), meta.advice_column()]);
         meta.enable_equality(rlc_column);
 
         meta.enable_equality(sig_table.recovered_addr);
@@ -152,6 +154,8 @@ impl<F: Field> SubCircuitConfig<F> for SigCircuitConfig<F> {
         meta.enable_equality(sig_table.sig_v);
         meta.enable_equality(sig_table.is_valid);
         meta.enable_equality(sig_table.msg_hash_rlc);
+        // meta.enable_equality(sig_table.msg_hash_word.lo());
+        // meta.enable_equality(sig_table.msg_hash_word.hi());
 
         // Ref. spec SignVerifyChip 1. Verify that keccak(pub_key_bytes) = pub_key_hash
         // by keccak table lookup, where pub_key_bytes is built from the pub_key
@@ -177,7 +181,9 @@ impl<F: Field> SubCircuitConfig<F> for SigCircuitConfig<F> {
                 is_enable.clone(),
                 is_enable.clone() * meta.query_advice(rlc_column, Rotation(1)),
                 is_enable.clone() * 64usize.expr(),
-                is_enable * meta.query_advice(rlc_column, Rotation(2)),
+                is_enable.clone() * meta.query_advice(rlc_column, Rotation(2)),
+                is_enable.clone() * meta.query_advice(rlc_column_word.lo(), Rotation::cur()),
+                is_enable * meta.query_advice(rlc_column_word.hi(), Rotation::cur()),
             ];
             let table = [
                 meta.query_fixed(keccak_table.q_enable, Rotation::cur()),
@@ -185,6 +191,8 @@ impl<F: Field> SubCircuitConfig<F> for SigCircuitConfig<F> {
                 meta.query_advice(keccak_table.input_rlc, Rotation::cur()),
                 meta.query_advice(keccak_table.input_len, Rotation::cur()),
                 meta.query_advice(keccak_table.output_rlc, Rotation::cur()),
+                meta.query_advice(keccak_table.output.lo(), Rotation::cur()),
+                meta.query_advice(keccak_table.output.hi(), Rotation::cur()),
             ];
 
             input.into_iter().zip(table).collect()
@@ -196,6 +204,7 @@ impl<F: Field> SubCircuitConfig<F> for SigCircuitConfig<F> {
             sig_table,
             q_keccak,
             rlc_column,
+            rlc_column_word,
         }
     }
 }
@@ -473,6 +482,14 @@ impl<F: Field> SigCircuit<F> {
             offset,
             || is_address_zero.value,
         )?;
+        let word_zero = word::Word::new([Value::known(F::zero()), Value::known(F::zero())]);
+        word_zero.assign_advice(
+            &mut ctx.region,
+            || "assign rlc_column_word",
+            config.rlc_column_word,
+            offset + 1,
+        )?;
+
         ctx.region
             .constrain_equal(is_address_zero.cell, tmp_cell.cell())?;
 
@@ -483,6 +500,14 @@ impl<F: Field> SigCircuit<F> {
             offset + 1,
             || pk_rlc.value,
         )?;
+
+        word_zero.assign_advice(
+            &mut ctx.region,
+            || "assign rlc_column_word",
+            config.rlc_column_word,
+            offset + 2,
+        )?;
+
         ctx.region.constrain_equal(pk_rlc.cell, tmp_cell.cell())?;
 
         // pk_hash_rlc
@@ -507,7 +532,7 @@ impl<F: Field> SigCircuit<F> {
         ecdsa_chip: &FpChip<F>,
         sign_data: &SignData,
         assigned_data: &AssignedECDSA<F, FpChip<F>>,
-    ) -> Result<SignDataDecomposed<F>, Error> {
+    ) -> Result<(SignDataDecomposed<F>, Word), Error> {
         // build ecc chip from Fp chip
         let ecc_chip = EccChip::<F, FpChip<F>>::construct(ecdsa_chip.clone());
 
@@ -528,6 +553,7 @@ impl<F: Field> SigCircuit<F> {
         let pk_le = pk_bytes_le(&sign_data.pk);
         let pk_be = pk_bytes_swap_endianness(&pk_le);
         let pk_hash = keccak256(pk_be).map(|byte| Value::known(F::from(byte as u64)));
+        let pk_hash_word = Word::from_big_endian(&keccak256(pk_be));
 
         log::trace!("pk hash {:0x?}", pk_hash);
         let pk_hash_cells = pk_hash
@@ -575,6 +601,7 @@ impl<F: Field> SigCircuit<F> {
                 &byte_cells,
                 &powers_of_256_cells,
             )?;
+
             Ok(byte_cells)
         };
 
@@ -634,15 +661,18 @@ impl<F: Field> SigCircuit<F> {
             &assigned_data.integer_s,
         )?;
 
-        Ok(SignDataDecomposed {
-            pk_hash_cells,
-            msg_hash_cells: assigned_msg_hash_le,
-            pk_cells: assigned_pk_le_selected,
-            address,
-            is_address_zero,
-            r_cells,
-            s_cells,
-        })
+        Ok((
+            SignDataDecomposed {
+                pk_hash_cells,
+                msg_hash_cells: assigned_msg_hash_le,
+                pk_cells: assigned_pk_le_selected,
+                address,
+                is_address_zero,
+                r_cells,
+                s_cells,
+            },
+            pk_hash_word,
+        ))
     }
 
     #[allow(clippy::too_many_arguments)]
@@ -710,6 +740,7 @@ impl<F: Field> SigCircuit<F> {
             evm_challenge_powers.clone(),
         );
 
+        // TODO:calculate pk hash word [QuantumCell<F>;32]
         // step 4: r,s rlc
         let r_rlc = rlc_chip.gate.inner_product(
             ctx,
@@ -737,6 +768,7 @@ impl<F: Field> SigCircuit<F> {
             s_rlc,
             v: assigned_ecdsa.v,
         };
+
         Ok((to_be_keccak_checked, assigned_sig_verif))
     }
 
@@ -759,7 +791,7 @@ impl<F: Field> SigCircuit<F> {
         let mut first_pass = SKIP_FIRST_PASS;
         let ecdsa_chip = &config.ecdsa_config;
 
-        let assigned_sig_verifs = layouter.assign_region(
+        let assigned_sig_verifys = layouter.assign_region(
             || "ecdsa chip verification",
             |region| {
                 if first_pass {
@@ -795,7 +827,7 @@ impl<F: Field> SigCircuit<F> {
                             assigned_ecdsa,
                         )
                     })
-                    .collect::<Result<Vec<SignDataDecomposed<F>>, Error>>()?;
+                    .collect::<Result<Vec<(SignDataDecomposed<F>, Word)>, Error>>()?;
 
                 // IMPORTANT: Move to Phase2 before RLC
                 log::info!("before proceeding to the next phase");
@@ -814,34 +846,38 @@ impl<F: Field> SigCircuit<F> {
                 let (assigned_keccak_values, assigned_sig_values): (
                     Vec<[AssignedValue<F>; 3]>,
                     Vec<AssignedSignatureVerify<F>>,
-                ) = signatures
-                    .iter()
-                    .chain(std::iter::repeat(&SignData::default()))
-                    .take(self.max_verif)
-                    .zip_eq(assigned_ecdsas.iter())
-                    .zip_eq(sign_data_decomposed.iter())
-                    .map(|((sign_data, assigned_ecdsa), sign_data_decomp)| {
-                        self.assign_sig_verify(
-                            &mut ctx,
-                            &ecdsa_chip.range,
-                            sign_data,
-                            sign_data_decomp,
-                            challenges,
-                            assigned_ecdsa,
-                        )
-                    })
-                    .collect::<Result<
-                        Vec<([AssignedValue<F>; 3], AssignedSignatureVerify<F>)>,
-                        Error,
-                    >>()?
-                    .into_iter()
-                    .unzip();
+                ) =
+                    signatures
+                        .iter()
+                        .chain(std::iter::repeat(&SignData::default()))
+                        .take(self.max_verif)
+                        .zip_eq(assigned_ecdsas.iter())
+                        .zip_eq(sign_data_decomposed.iter())
+                        .map(|((sign_data, assigned_ecdsa), sign_data_decomp)| {
+                            self.assign_sig_verify(
+                                &mut ctx,
+                                &ecdsa_chip.range,
+                                sign_data,
+                                &sign_data_decomp.0,
+                                challenges,
+                                assigned_ecdsa,
+                            )
+                        })
+                        .collect::<Result<
+                            Vec<([AssignedValue<F>; 3], AssignedSignatureVerify<F>)>,
+                            Error,
+                        >>()?
+                        .into_iter()
+                        .unzip();
 
                 // ================================================
                 // step 4: deferred keccak checks
                 // ================================================
-                for (i, [is_address_zero, pk_rlc, pk_hash_rlc]) in
-                    assigned_keccak_values.iter().enumerate()
+                for (i, ([is_address_zero, pk_rlc, pk_hash_rlc], sign_data)) in
+                    assigned_keccak_values
+                        .iter()
+                        .zip_eq(sign_data_decomposed.iter())
+                        .enumerate()
                 {
                     let offset = i * 3;
                     self.enable_keccak_lookup(
@@ -852,6 +888,14 @@ impl<F: Field> SigCircuit<F> {
                         pk_rlc,
                         pk_hash_rlc,
                     )?;
+
+                    let pk_hash_word = word::Word::from(sign_data.1).map(Value::known);
+                    pk_hash_word.assign_advice(
+                        &mut ctx.region,
+                        || "assign rlc_column_word",
+                        config.rlc_column_word,
+                        offset,
+                    )?;
                 }
 
                 // IMPORTANT: this assigns all constants to the fixed columns
@@ -871,7 +915,7 @@ impl<F: Field> SigCircuit<F> {
             || "expose sig table",
             |mut region| {
                 // step 5: export as a lookup table
-                for (idx, assigned_sig_verif) in assigned_sig_verifs.iter().enumerate() {
+                for (idx, assigned_sig_verif) in assigned_sig_verifys.iter().enumerate() {
                     region.assign_fixed(
                         || "assign sig_table selector",
                         config.sig_table.q_enable,
@@ -917,7 +961,7 @@ impl<F: Field> SigCircuit<F> {
             },
         )?;
 
-        Ok(assigned_sig_verifs)
+        Ok(assigned_sig_verifys)
     }
 
     /// Assert an CRTInteger's byte representation is correct.
diff --git a/zkevm-circuits/src/state_circuit.rs b/zkevm-circuits/src/state_circuit.rs
index 505827f85b..4651e54da4 100644
--- a/zkevm-circuits/src/state_circuit.rs
+++ b/zkevm-circuits/src/state_circuit.rs
@@ -445,18 +445,18 @@ impl<F: Field> StateCircuitConfig<F> {
         Ok(StateCircuitExports {
             start_state_root: (
                 //start_state_root,
-                word::Word::new([start_state_root.hi().cell(), start_state_root.lo().cell()]),
+                word::Word::new([start_state_root.lo().cell(), start_state_root.hi().cell()]),
                 word::Word::new([
-                    start_state_root.hi().value_field(),
                     start_state_root.lo().value_field(),
+                    start_state_root.hi().value_field(),
                 ]),
                 //start_state_root.into_value(),
             ),
             end_state_root: (
-                word::Word::new([end_state_root.hi().cell(), end_state_root.lo().cell()]),
+                word::Word::new([end_state_root.lo().cell(), end_state_root.hi().cell()]),
                 word::Word::new([
-                    end_state_root.hi().value_field(),
                     end_state_root.lo().value_field(),
+                    end_state_root.hi().value_field(),
                 ]),
             ),
         })
@@ -672,17 +672,17 @@ impl<F: Field> StateCircuitConfig<F> {
 
         Ok(StateCircuitExports {
             start_state_root: (
-                word::Word::new([start_state_root.hi().cell(), start_state_root.lo().cell()]),
+                word::Word::new([start_state_root.lo().cell(), start_state_root.hi().cell()]),
                 word::Word::new([
-                    start_state_root.hi().value_field(),
                     start_state_root.lo().value_field(),
+                    start_state_root.hi().value_field(),
                 ]),
             ),
             end_state_root: (
-                word::Word::new([start_state_root.hi().cell(), start_state_root.lo().cell()]),
+                word::Word::new([end_state_root.lo().cell(), end_state_root.hi().cell()]),
                 word::Word::new([
-                    end_state_root.hi().value_field(),
                     end_state_root.lo().value_field(),
+                    end_state_root.hi().value_field(),
                 ]),
             ),
         })
diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs
index 22af5a357a..2dc4fca96a 100644
--- a/zkevm-circuits/src/super_circuit.rs
+++ b/zkevm-circuits/src/super_circuit.rs
@@ -82,7 +82,7 @@ use crate::{
     table::{
         BlockTable, BytecodeTable, CopyTable, EccTable, ExpTable, KeccakTable, ModExpTable,
         MptTable, PoseidonTable, PowOfRandTable, RlpFsmRlpTable as RlpTable, RwTable, SHA256Table,
-        SigTable, TxTable, U16Table, U8Table, UXTable,
+        SigTable, TxTable, UXTable,
     },
     tx_circuit::{TxCircuit, TxCircuitConfig, TxCircuitConfigArgs},
     util::{circuit_stats, log2_ceil, Challenges, SubCircuit, SubCircuitConfig},
@@ -113,10 +113,10 @@ pub struct SuperCircuitConfig<F: Field> {
     rlp_table: RlpTable,
     tx_table: TxTable,
     poseidon_table: PoseidonTable,
-    u8_table: U8Table,
-    u16_table: U16Table,
+    // u8_table: U8Table,
+    // u16_table: U16Table,
     ux8_table: UXTable<8>,
-    u10_table: UXTable<10>,
+    ux10_table: UXTable<10>,
     ux16_table: UXTable<16>,
     evm_circuit: EvmCircuitConfig<F>,
     state_circuit: StateCircuitConfig<F>,
@@ -208,9 +208,9 @@ impl SubCircuitConfig<Fr> for SuperCircuitConfig<Fr> {
         let pow_of_rand_table = PowOfRandTable::construct(meta, &challenges_expr);
         log_circuit_info(meta, "power of randomness table");
 
-        let u8_table = U8Table::construct(meta);
+        // let u8_table = U8Table::construct(meta);
         // log_circuit_info(meta, "u8 table");
-        let u16_table = U16Table::construct(meta);
+        // let u16_table = U16Table::construct(meta);
         // log_circuit_info(meta, "u16 table");
 
         let ux8_table = UXTable::construct(meta);
@@ -244,7 +244,8 @@ impl SubCircuitConfig<Fr> for SuperCircuitConfig<Fr> {
             meta,
             RlpCircuitConfigArgs {
                 rlp_table,
-                u8_table,
+                //u8_table,
+                u8_table: ux8_table,
                 challenges: challenges_expr.clone(),
             },
         );
@@ -269,8 +270,8 @@ impl SubCircuitConfig<Fr> for SuperCircuitConfig<Fr> {
                 keccak_table: keccak_table.clone(),
                 rlp_table,
                 sig_table,
-                u8_table,
-                u16_table,
+                u8_table: ux8_table,
+                u16_table: ux16_table,
                 challenges: challenges_expr.clone(),
             },
         );
@@ -344,7 +345,7 @@ impl SubCircuitConfig<Fr> for SuperCircuitConfig<Fr> {
             meta,
             ExpCircuitArgs {
                 exp_table,
-                u16_table,
+                u16_table: ux16_table,
             },
         );
         log_circuit_info(meta, "exp circuit");
@@ -402,10 +403,10 @@ impl SubCircuitConfig<Fr> for SuperCircuitConfig<Fr> {
             tx_table,
             rlp_table,
             poseidon_table,
-            u8_table,
+            // u8_table,
             ux8_table,
-            u10_table,
-            u16_table,
+            ux10_table: u10_table,
+            // u16_table,
             ux16_table,
             evm_circuit,
             state_circuit,
@@ -780,8 +781,9 @@ impl<
     ) -> Result<(), Error> {
         let challenges = challenges.values(&layouter);
 
-        config.u8_table.load(&mut layouter)?;
-        config.u16_table.load(&mut layouter)?;
+        config.ux8_table.load(&mut layouter)?;
+        config.ux10_table.load(&mut layouter)?;
+        config.ux16_table.load(&mut layouter)?;
 
         self.synthesize_sub(&config, &challenges, &mut layouter)
     }
diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs
index ed9bc313e7..7eb3e355c4 100644
--- a/zkevm-circuits/src/table.rs
+++ b/zkevm-circuits/src/table.rs
@@ -210,7 +210,8 @@ pub struct TxTable {
     /// Index for Tag = CallData
     pub index: Column<Advice>,
     /// Value
-    pub value: Column<Advice>,
+    //pub value: Column<Advice>,
+    pub value: word::Word<Column<Advice>>,
 }
 
 impl TxTable {
@@ -223,7 +224,8 @@ impl TxTable {
             tx_id: meta.advice_column(),
             tag,
             index: meta.advice_column(),
-            value: meta.advice_column_in(SecondPhase),
+            //value: meta.advice_column_in(SecondPhase),
+            value: word::Word::new([meta.advice_column(), meta.advice_column()]),
         }
     }
 
@@ -237,7 +239,7 @@ impl TxTable {
         max_calldata: usize,
         chain_id: u64,
         challenges: &Challenges<Value<F>>,
-    ) -> Result<Vec<AssignedCell<F, F>>, Error> {
+    ) -> Result<Vec<word::Word<AssignedCell<F, F>>>, Error> {
         assert!(
             txs.len() <= max_txs,
             "txs.len() <= max_txs: txs.len()={}, max_txs={}",
@@ -260,10 +262,11 @@ impl TxTable {
             q_enable: Column<Fixed>,
             advice_columns: &[Column<Advice>],
             tag: &Column<Fixed>,
-            row: &[Value<F>; 4],
+            row: &[Value<F>; 5],
             msg: &str,
-        ) -> Result<AssignedCell<F, F>, Error> {
-            let mut value_cell = None;
+        ) -> Result<word::Word<AssignedCell<F, F>>, Error> {
+            let mut value_cell_lo: Option<AssignedCell<F, F>> = None;
+            let mut value_cell_hi: Option<AssignedCell<F, F>> = None;
             for (index, column) in advice_columns.iter().enumerate() {
                 let cell = region.assign_advice(
                     || format!("tx table {msg} row {offset}"),
@@ -271,11 +274,15 @@ impl TxTable {
                     offset,
                     || row[if index > 0 { index + 1 } else { index }],
                 )?;
-                // tx_id, index, value
+                // tx_id, index, value_lo, value_hi
                 if index == 2 {
-                    value_cell = Some(cell);
+                    value_cell_lo = Some(cell.clone());
+                }
+                if index == 3 {
+                    value_cell_hi = Some(cell);
                 }
             }
+
             region.assign_fixed(
                 || format!("tx table q_enable row {offset}"),
                 q_enable,
@@ -288,7 +295,10 @@ impl TxTable {
                 offset,
                 || row[1],
             )?;
-            Ok(value_cell.unwrap())
+            Ok(word::Word::new([
+                value_cell_lo.unwrap(),
+                value_cell_hi.unwrap(),
+            ]))
         }
 
         layouter.assign_region(
@@ -296,14 +306,14 @@ impl TxTable {
             |mut region| {
                 let mut offset = 0;
                 let mut tx_value_cells = vec![];
-                let advice_columns = [self.tx_id, self.index, self.value];
+                let advice_columns = [self.tx_id, self.index, self.value.lo(), self.value.hi()];
                 assign_row(
                     &mut region,
                     offset,
                     self.q_enable,
                     &advice_columns,
                     &self.tag,
-                    &[(); 4].map(|_| Value::known(F::zero())),
+                    &[(); 5].map(|_| Value::known(F::zero())),
                     "all-zero",
                 )?;
                 offset += 1;
@@ -313,7 +323,7 @@ impl TxTable {
                 // region that has a size parametrized by max_calldata with all
                 // the tx calldata.  This is required to achieve a constant fixed column tag
                 // regardless of the number of input txs or the calldata size of each tx.
-                let mut calldata_assignments: Vec<[Value<F>; 4]> = Vec::new();
+                let mut calldata_assignments: Vec<[Value<F>; 5]> = Vec::new();
                 // Assign Tx data (all tx fields except for calldata)
                 let padding_txs = (txs.len()..max_txs)
                     .map(|tx_id| {
@@ -367,7 +377,8 @@ impl<F: Field> LookupTable<F> for TxTable {
             self.tx_id.into(),
             self.tag.into(),
             self.index.into(),
-            self.value.into(),
+            self.value.lo().into(),
+            self.value.hi().into(),
         ]
     }
 
@@ -377,7 +388,8 @@ impl<F: Field> LookupTable<F> for TxTable {
             String::from("tx_id"),
             String::from("tag"),
             String::from("index"),
-            String::from("value"),
+            String::from("value lo"),
+            String::from("value hi"),
         ]
     }
 
@@ -387,7 +399,8 @@ impl<F: Field> LookupTable<F> for TxTable {
             meta.query_advice(self.tx_id, Rotation::cur()),
             meta.query_fixed(self.tag, Rotation::cur()),
             meta.query_advice(self.index, Rotation::cur()),
-            meta.query_advice(self.value, Rotation::cur()),
+            meta.query_advice(self.value.lo(), Rotation::cur()),
+            meta.query_advice(self.value.hi(), Rotation::cur()),
         ]
     }
 }
@@ -1459,7 +1472,7 @@ impl KeccakTable {
         &self,
         region: &mut Region<F>,
         offset: usize,
-        values: [Value<F>; 4],
+        values: [Value<F>; 6],
     ) -> Result<Vec<AssignedCell<F, F>>, Error> {
         let mut res = vec![];
         for (&column, value) in <KeccakTable as LookupTable<F>>::advice_columns(self)
@@ -2443,7 +2456,9 @@ pub struct SigTable {
     /// Indicates whether or not the gates are enabled on the current row.
     pub q_enable: Column<Fixed>,
     /// Random-linear combination of the Keccak256 hash of the message that's signed.
+    /// do not change to word hi lo (msg_hash_word) becuase it is related to ecc chip.
     pub msg_hash_rlc: Column<Advice>,
+    // TODO: sig_r_rlc, sig_s_rlc to word as well ?
     /// should be in range [0, 1]
     pub sig_v: Column<Advice>,
     /// Random-linear combination of the signature's `r` component.
@@ -2462,6 +2477,7 @@ impl SigTable {
         Self {
             q_enable: meta.fixed_column(),
             msg_hash_rlc: meta.advice_column_in(SecondPhase),
+            // msg_hash_word: word::Word::new([meta.advice_column(), meta.advice_column()]),
             sig_v: meta.advice_column(),
             sig_s_rlc: meta.advice_column_in(SecondPhase),
             sig_r_rlc: meta.advice_column_in(SecondPhase),
@@ -2490,6 +2506,11 @@ impl SigTable {
                             challenge,
                         )
                     });
+
+                    // let msg_hash_word =
+                    //     word::Word::from(Word::from_big_endian(&sign_data.msg_hash.to_bytes()))
+                    //         .map(Value::<F>::known);
+
                     let sig_r_rlc = evm_word.map(|challenge| {
                         rlc::value(
                             sign_data.signature.0.to_bytes().iter().collect_vec(),
@@ -2529,6 +2550,13 @@ impl SigTable {
                             || value,
                         )?;
                     }
+
+                    // msg_hash_word.assign_advice(
+                    //     &mut region,
+                    //     || format!("sig table msg_hash_word {offset}"),
+                    //     self.msg_hash_word,
+                    //     offset,
+                    // )?;
                 }
 
                 Ok(())
@@ -2544,6 +2572,8 @@ impl<F: Field> LookupTable<F> for SigTable {
         vec![
             self.q_enable.into(),
             self.msg_hash_rlc.into(),
+            // self.msg_hash_word.lo().into(),
+            // self.msg_hash_word.hi().into(),
             self.sig_v.into(),
             self.sig_r_rlc.into(),
             self.sig_s_rlc.into(),
@@ -2556,6 +2586,8 @@ impl<F: Field> LookupTable<F> for SigTable {
         vec![
             String::from("q_enable"),
             String::from("msg_hash_rlc"),
+            String::from("msg_hash_word lo"),
+            String::from("msg_hash_word hi"),
             String::from("sig_v"),
             String::from("sig_r_rlc"),
             String::from("sig_s_rlc"),
@@ -3142,7 +3174,9 @@ impl<const MAX: usize> From<RangeTable<MAX>> for TableColumn {
 /// Lookup table for max n bits range check
 #[derive(Clone, Copy, Debug)]
 pub struct UXTable<const N_BITS: usize> {
-    col: Column<Fixed>,
+    /// content col in the table
+    pub col: Column<Fixed>,
+    // col: TableColumn,
 }
 
 impl<const N_BITS: usize> UXTable<N_BITS> {
@@ -3150,14 +3184,17 @@ impl<const N_BITS: usize> UXTable<N_BITS> {
     pub fn construct<F: Field>(meta: &mut ConstraintSystem<F>) -> Self {
         Self {
             col: meta.fixed_column(),
+            // col: meta.lookup_table_column(),
         }
     }
 
     /// Load the `UXTable` for range check
     pub fn load<F: Field>(&self, layouter: &mut impl Layouter<F>) -> Result<(), Error> {
+        //layouter.assign_table(
         layouter.assign_region(
             || format!("assign u{} fixed column", 8),
             |mut region| {
+                // |mut table| {
                 for i in 0..(1 << N_BITS) {
                     region.assign_fixed(
                         || format!("assign {i} in u{N_BITS} fixed column"),
@@ -3165,6 +3202,12 @@ impl<const N_BITS: usize> UXTable<N_BITS> {
                         i,
                         || Value::known(F::from(i as u64)),
                     )?;
+                    // table.assign_cell(
+                    //     || format!("range at offset = {i}"),
+                    //     self.col,
+                    //     i,
+                    //     || Value::known(F::from(i as u64)),
+                    // )?;
                 }
                 Ok(())
             },
@@ -3175,6 +3218,7 @@ impl<const N_BITS: usize> UXTable<N_BITS> {
 
 impl<F: Field, const N_BITS: usize> LookupTable<F> for UXTable<N_BITS> {
     fn columns(&self) -> Vec<Column<Any>> {
+        // vec![self.col.into()]
         vec![self.col.into()]
     }
 
@@ -3186,3 +3230,12 @@ impl<F: Field, const N_BITS: usize> LookupTable<F> for UXTable<N_BITS> {
         vec![meta.query_fixed(self.col, Rotation::cur())]
     }
 }
+
+// impl<const N_BITS: usize> From<UXTable<N_BITS>> for TableColumn {
+//     fn from(table: UXTable<N_BITS>) -> TableColumn {
+//        //table.col
+//        TableColumn {
+//         inner: table.col,
+//        }
+//     }
+// }
diff --git a/zkevm-circuits/src/tx_circuit.rs b/zkevm-circuits/src/tx_circuit.rs
index bd886e5c5c..ce4509e1c7 100644
--- a/zkevm-circuits/src/tx_circuit.rs
+++ b/zkevm-circuits/src/tx_circuit.rs
@@ -24,11 +24,11 @@ use crate::{
             Gas, GasPrice, IsCreate, Nonce, SigR, SigS, SigV, TxDataGasCost, TxHashLength,
             TxHashRLC, TxSignHash, TxSignLength, TxSignRLC,
         },
-        TxTable, U16Table, U8Table,
+        TxTable, UXTable,
     },
     util::{
         is_zero::{IsZeroChip, IsZeroConfig},
-        keccak, rlc_be_bytes, SubCircuit, SubCircuitConfig,
+        keccak, rlc_be_bytes, word, SubCircuit, SubCircuitConfig,
     },
     witness,
     witness::{
@@ -47,7 +47,7 @@ use eth_types::{
         TxType::{Eip155, L1Msg, PreEip155},
     },
     sign_types::SignData,
-    Address, Field, ToAddress, ToBigEndian, ToScalar,
+    Address, Field, ToAddress, ToBigEndian, ToScalar, ToWord, U256,
 };
 use ethers_core::utils::{keccak256, rlp::Encodable};
 use gadgets::{
@@ -79,6 +79,8 @@ use halo2_proofs::plonk::Fixed;
 use halo2_proofs::plonk::SecondPhase;
 use itertools::Itertools;
 
+use halo2_proofs::dev::unwrap_value;
+
 /// Number of rows of one tx occupies in the fixed part of tx table
 pub const TX_LEN: usize = 26;
 /// Offset of TxHash tag in the tx table
@@ -126,21 +128,29 @@ pub struct TxCircuitConfig<F: Field> {
     // Whether tag's RLP-encoded value is 0x80 = rlp([])
     is_none: Column<Advice>,
     tx_value_length: Column<Advice>,
+    // keccak rlc
     tx_value_rlc: Column<Advice>,
+    // evm word rlc, use for rlp table lookup
+    tx_value_evm_rlc: Column<Advice>,
+    // keccak lookup needs additional output word field, this word field targets for it.
+    tx_hash_word: word::Word<Column<Advice>>,
 
-    u8_table: U8Table,
-    u16_table: U16Table,
+    //u8_table: U8Table,
+    u8_table: UXTable<8>,
+    u16_table: UXTable<16>,
 
     /// Verify if the tx_id is zero or not.
     tx_id_is_zero: IsZeroConfig<F>,
     /// Primarily used to verify if the `CallDataLength` is zero or non-zero
     ///  and `CallData` byte is zero or non-zero.
-    value_is_zero: IsZeroConfig<F>,
+    value_limb_is_zero: [IsZeroConfig<F>; 2],
+
     /// We use an equality gadget to know whether the tx id changes between
     /// subsequent rows or not.
     tx_id_unchanged: IsEqualConfig<F>,
 
     /// Columns used to reduce degree
+    is_value_zero: Column<Advice>,
     is_tag_block_num: Column<Advice>,
     is_calldata: Column<Advice>,
     is_caller_address: Column<Advice>,
@@ -205,9 +215,10 @@ pub struct TxCircuitConfigArgs<F: Field> {
     /// SigTable
     pub sig_table: SigTable,
     /// Reusable u8 lookup table,
-    pub u8_table: U8Table,
+    // pub u8_table: U8Table,
+    pub u8_table: UXTable<8>,
     /// Reusable u16 lookup table,
-    pub u16_table: U16Table,
+    pub u16_table: UXTable<16>,
     /// Challenges
     pub challenges: crate::util::Challenges<Expression<F>>,
 }
@@ -260,7 +271,9 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
         let tx_type = meta.advice_column();
         let rlp_tag = meta.advice_column();
         let tx_value_rlc = meta.advice_column_in(SecondPhase);
+        let tx_value_evm_rlc = meta.advice_column_in(SecondPhase);
         let tx_value_length = meta.advice_column();
+        let tx_hash_word = word::Word::new([meta.advice_column(), meta.advice_column()]);
         let is_none = meta.advice_column();
         let tag_bits = BinaryNumberChip::configure(meta, q_enable, Some(tx_table.tag.into()));
         let tx_type_bits = BinaryNumberChip::configure(meta, q_enable, Some(tx_type.into()));
@@ -282,6 +295,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
         let is_calldata = meta.advice_column();
         let is_caller_address = meta.advice_column();
         let is_chain_id = meta.advice_column();
+        let is_value_zero = meta.advice_column();
         let is_tag_block_num = meta.advice_column();
         let lookup_conditions = [
             LookupCondition::TxCalldata,
@@ -296,9 +310,11 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
 
         // TODO: add lookup to SignVerify table for sv_address
         let sv_address = meta.advice_column();
-        meta.enable_equality(tx_table.value);
+        meta.enable_equality(tx_table.value.lo());
+        meta.enable_equality(tx_table.value.hi());
 
         let log_deg = |s: &'static str, meta: &mut ConstraintSystem<F>| {
+            //TODO: decrease degree to old nubmer 9.
             debug_assert!(meta.degree() <= 9);
             log::info!("after {}, meta.degree: {}", s, meta.degree());
         };
@@ -358,7 +374,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
         );
 
         // testing if value is zero for tags
-        let value_is_zero = IsZeroChip::configure(
+        let value_is_zero_lo = IsZeroChip::configure(
             meta,
             |meta| {
                 and::expr(vec![
@@ -373,7 +389,25 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                     ]),
                 ])
             },
-            tx_table.value,
+            tx_table.value.lo(),
+            |meta| meta.advice_column_in(SecondPhase), // value is at 2nd phase
+        );
+        let value_is_zero_hi = IsZeroChip::configure(
+            meta,
+            |meta| {
+                and::expr(vec![
+                    meta.query_fixed(q_enable, Rotation::cur()),
+                    sum::expr(vec![
+                        // if caller_address is zero, then skip the sig verify.
+                        is_caller_addr(meta),
+                        // if call_data_length is zero, then skip lookup to tx table for call data
+                        is_data_length(meta),
+                        // if call data byte is zero, then gas_cost = 4 (16 otherwise)
+                        is_data(meta),
+                    ]),
+                ])
+            },
+            tx_table.value.hi(),
             |meta| meta.advice_column_in(SecondPhase), // value is at 2nd phase
         );
 
@@ -500,7 +534,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                 cb.require_equal(
                     "associated tx type to tag",
                     meta.query_advice(tx_type, Rotation::cur()),
-                    meta.query_advice(tx_table.value, Rotation::cur()),
+                    // tx type value only uses lo column
+                    meta.query_advice(tx_table.value.lo(), Rotation::cur()),
                 );
             });
 
@@ -516,7 +551,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                 cb.require_equal(
                     "is_create == is_none",
                     // we rely on the assumption that IsCreate is next to CalleeAddress
-                    meta.query_advice(tx_table.value, Rotation::next()),
+                    meta.query_advice(tx_table.value.lo(), Rotation::next()),
                     meta.query_advice(is_none, Rotation::cur()),
                 );
             });
@@ -525,10 +560,10 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
             // is_none == true
             cb.condition(is_none_expr.expr(), |cb| {
                 // value == 0
-                cb.require_equal(
-                    "is_none is true => value == 0",
-                    meta.query_advice(tx_table.value, Rotation::cur()),
-                    0.expr(),
+                cb.require_equal_word(
+                    "is_none is true => value == 0 (value_hi = value_lo = 0)",
+                    tx_table.value.query_advice(meta, Rotation::cur()),
+                    word::Word::zero(),
                 );
             });
 
@@ -538,15 +573,15 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
             cb.condition(and::expr([is_data_rlc(meta), is_none_expr.expr()]), |cb| {
                 // we rely on the assumption that CallDataLength and CallDataGasCost are after
                 // CallDataRLC
-                cb.require_equal(
+                cb.require_equal_word(
                     "CallDataLength.value == 0",
-                    meta.query_advice(tx_table.value, Rotation::next()),
-                    0.expr(),
+                    tx_table.value.query_advice(meta, Rotation::next()),
+                    word::Word::zero(),
                 );
-                cb.require_equal(
+                cb.require_equal_word(
                     "CallDataGasCost.value == 0",
-                    meta.query_advice(tx_table.value, Rotation(2)),
-                    0.expr(),
+                    tx_table.value.query_advice(meta, Rotation(2)),
+                    word::Word::zero(),
                 );
             });
 
@@ -556,7 +591,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                 |cb| {
                     cb.require_zero(
                         "CallDataLength != 0",
-                        value_is_zero.expr(Rotation::next())(meta),
+                        meta.query_advice(is_value_zero, Rotation::next()),
                     );
                 },
             );
@@ -618,6 +653,23 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
             cb.gate(meta.query_fixed(q_enable, Rotation::cur()))
         });
 
+        meta.create_gate("is_value_zero", |meta| {
+            let mut cb = BaseConstraintBuilder::default();
+
+            cb.require_boolean(
+                "is_value_zero is bool",
+                meta.query_advice(is_value_zero, Rotation::cur()),
+            );
+            cb.require_equal(
+                "is_value_zero = value_is_zero_lo && value_is_zero_hi",
+                meta.query_advice(is_value_zero, Rotation::cur()),
+                value_is_zero_lo.expr(Rotation::cur())(meta)
+                    * value_is_zero_hi.expr(Rotation::cur())(meta),
+            );
+
+            cb.gate(meta.query_fixed(q_enable, Rotation::cur()))
+        });
+
         meta.create_gate("is_l1_msg", |meta| {
             let mut cb = BaseConstraintBuilder::default();
 
@@ -637,7 +689,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                 "condition",
                 and::expr([
                     is_data_length(meta),
-                    not::expr(value_is_zero.expr(Rotation::cur())(meta)),
+                    not::expr(meta.query_advice(is_value_zero, Rotation::cur())),
                 ]),
                 meta.query_advice(
                     lookup_conditions[&LookupCondition::TxCalldata],
@@ -767,7 +819,9 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
             q_enable,
             rlp_tag,
             tx_value_rlc,
+            tx_value_evm_rlc,
             tx_value_length,
+            tx_hash_word,
             tx_type_bits,
             tx_id_is_zero.clone(),
             is_none,
@@ -776,6 +830,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
             is_calldata,
             is_chain_id,
             is_l1_msg,
+            //is_value,
             sv_address,
             calldata_gas_cost_acc,
             calldata_rlc,
@@ -789,9 +844,9 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
             let mut cb = BaseConstraintBuilder::default();
 
             cb.condition(is_tx_gas_cost(meta), |cb| {
-                cb.require_zero(
+                cb.require_zero_word(
                     "tx_gas_cost == 0",
-                    meta.query_advice(tx_table.value, Rotation::cur()),
+                    tx_table.value.query_advice(meta, Rotation::cur()),
                 );
             });
 
@@ -810,7 +865,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
             cb.condition(is_nonce(meta), |cb| {
                 cb.require_equal(
                     "tx_nonce = tx_table.value if tag == Nonce",
-                    meta.query_advice(tx_table.value, Rotation::cur()),
+                    // value.lo() should cover tx_nonce value.
+                    meta.query_advice(tx_table.value.lo(), Rotation::cur()),
                     meta.query_advice(tx_nonce, Rotation::cur()),
                 );
             });
@@ -824,7 +880,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
             cb.condition(meta.query_advice(is_tag_block_num, Rotation::cur()), |cb| {
                 cb.require_equal(
                     "block_num = tx_table.value if tag == BlockNum",
-                    meta.query_advice(tx_table.value, Rotation::cur()),
+                    meta.query_advice(tx_table.value.lo(), Rotation::cur()),
                     meta.query_advice(block_num, Rotation::cur()),
                 );
             });
@@ -848,7 +904,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
             |meta| meta.query_advice(block_num, Rotation::cur()),
         );
 
-        meta.lookup("block_num is non-decreasing till padding txs", |meta| {
+        meta.lookup_any("block_num is non-decreasing till padding txs", |meta| {
             // Block nums like this [1, 3, 5, 4, 0] is rejected by this. But [1, 2, 3, 5, 0] is
             // acceptable.
             let lookup_condition = and::expr([
@@ -862,7 +918,10 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
             let block_num_diff = meta.query_advice(block_num, Rotation::next())
                 - meta.query_advice(block_num, Rotation::cur());
 
-            vec![(lookup_condition * block_num_diff, u16_table.into())]
+            vec![(
+                lookup_condition * block_num_diff,
+                meta.query_fixed(u16_table.col, Rotation::cur()),
+            )]
         });
 
         meta.create_gate("num_all_txs in a block", |meta| {
@@ -975,7 +1034,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
 
         meta.lookup_any("num_all_txs in block table", |meta| {
             let is_tag_block_num = meta.query_advice(is_tag_block_num, Rotation::cur());
-            let block_num = meta.query_advice(tx_table.value, Rotation::cur());
+            //  tx_table.value.lo can cover block_num
+            let block_num = meta.query_advice(tx_table.value.lo(), Rotation::cur());
             let num_all_txs_acc = meta.query_advice(num_all_txs_acc, Rotation::cur());
 
             let input_expr = vec![NumAllTxs.expr(), block_num, num_all_txs_acc];
@@ -1005,7 +1065,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                 cb.require_equal(
                     "is_padding_tx = true if caller_address = 0",
                     meta.query_advice(is_padding_tx, Rotation::cur()),
-                    value_is_zero.expr(Rotation::cur())(meta),
+                    meta.query_advice(is_value_zero, Rotation::cur()),
                 );
             });
             cb.gate(meta.query_fixed(q_enable, Rotation::cur()))
@@ -1027,7 +1087,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                 cum_num_txs - num_txs
             },
             |meta| meta.query_advice(tx_table.tx_id, Rotation::cur()),
-            u8_table.into(),
+            u8_table.col,
         );
 
         // last non-padding tx must have tx_id == cum_num_txs
@@ -1065,7 +1125,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
             },
             |meta| meta.query_advice(tx_table.tx_id, Rotation::cur()),
             |meta| meta.query_advice(cum_num_txs, Rotation::cur()),
-            u8_table.into(),
+            u8_table.col,
         );
 
         meta.create_gate("tx_id <= cum_num_txs", |meta| {
@@ -1084,7 +1144,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
 
         meta.lookup_any("num_txs in block table", |meta| {
             let is_tag_block_num = meta.query_advice(is_tag_block_num, Rotation::cur());
-            let block_num = meta.query_advice(tx_table.value, Rotation::cur());
+            // TODO: check why block_num come from tx table ?
+            let block_num = meta.query_advice(tx_table.value.lo(), Rotation::cur());
             let num_txs = meta.query_advice(num_txs, Rotation::cur());
 
             let input_expr = vec![NumTxs.expr(), block_num, num_txs];
@@ -1104,7 +1165,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
 
         meta.lookup_any("cum_num_txs in block table", |meta| {
             let is_tag_block_num = meta.query_advice(is_tag_block_num, Rotation::cur());
-            let block_num = meta.query_advice(tx_table.value, Rotation::cur());
+            let block_num = meta.query_advice(tx_table.value.lo(), Rotation::cur());
             let cum_num_txs = meta.query_advice(cum_num_txs, Rotation::cur());
 
             let input_expr = vec![CumNumTxs.expr(), block_num, cum_num_txs];
@@ -1125,7 +1186,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
         ////////////////////////////////////////////////////////////////////////
         ///////////  CallData length and gas_cost calculation  /////////////////
         ////////////////////////////////////////////////////////////////////////
-        meta.lookup("tx_id_diff must in u16", |meta| {
+        meta.lookup_any("tx_id_diff must in u16", |meta| {
             let q_enable = meta.query_fixed(q_enable, Rotation::next());
             let is_calldata = meta.query_advice(is_calldata, Rotation::cur());
             let tx_id = meta.query_advice(tx_table.tx_id, Rotation::cur());
@@ -1134,8 +1195,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
 
             let lookup_condition =
                 and::expr([q_enable, is_calldata, not::expr(tx_id_next_is_zero)]);
-
-            vec![(lookup_condition * (tx_id_next - tx_id), u16_table.into())]
+            let u16_expr = meta.query_fixed(u16_table.col, Rotation::cur());
+            vec![(lookup_condition * (tx_id_next - tx_id), u16_expr)]
         });
 
         meta.create_gate("last row of call data", |meta| {
@@ -1152,7 +1213,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                 cb.require_equal(
                     "calldata_byte == tx_table.value",
                     meta.query_advice(calldata_byte, Rotation::cur()),
-                    meta.query_advice(tx_table.value, Rotation::cur()),
+                    // byte only use value.lo
+                    meta.query_advice(tx_table.value.lo(), Rotation::cur()),
                 );
             });
 
@@ -1161,8 +1223,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
 
         meta.create_gate("tx call data init", |meta| {
             let mut cb = BaseConstraintBuilder::default();
+            let value_is_zero = meta.query_advice(is_value_zero, Rotation::cur());
 
-            let value_is_zero = value_is_zero.expr(Rotation::cur())(meta);
             let gas_cost = select::expr(value_is_zero, 4.expr(), 16.expr());
 
             cb.require_equal(
@@ -1178,7 +1240,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
             cb.require_equal(
                 "calldata_rlc == byte",
                 meta.query_advice(calldata_rlc, Rotation::cur()),
-                meta.query_advice(tx_table.value, Rotation::cur()),
+                meta.query_advice(tx_table.value.lo(), Rotation::cur()),
             );
 
             cb.gate(and::expr([
@@ -1206,7 +1268,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                     1.expr(),
                 );
 
-                let value_next_is_zero = value_is_zero.expr(Rotation::next())(meta);
+                let value_next_is_zero = meta.query_advice(is_value_zero, Rotation::next());
+
                 let gas_cost_next = select::expr(value_next_is_zero, 4.expr(), 16.expr());
                 // call data gas cost accumulator check.
                 cb.require_equal(
@@ -1218,7 +1281,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                     "calldata_rlc' = calldata_rlc * r + byte'",
                     meta.query_advice(calldata_rlc, Rotation::next()),
                     meta.query_advice(calldata_rlc, Rotation::cur()) * challenges.keccak_input()
-                        + meta.query_advice(tx_table.value, Rotation::next()),
+                    // TODO: check if value.lo() can cover calldata_rlc
+                        + meta.query_advice(tx_table.value.lo(), Rotation::next()),
                 );
             });
 
@@ -1236,7 +1300,9 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                     not::expr(tx_id_is_zero.expr(Rotation::next())(meta)),
                 ]),
                 |cb| {
-                    let value_next_is_zero = value_is_zero.expr(Rotation::next())(meta);
+                    //let value_next_is_zero = value_is_zero.expr(Rotation::next())(meta);
+                    let value_next_is_zero = meta.query_advice(is_value_zero, Rotation::next());
+
                     let gas_cost_next = select::expr(value_next_is_zero, 4.expr(), 16.expr());
 
                     cb.require_equal(
@@ -1252,7 +1318,7 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                     cb.require_equal(
                         "calldata_rlc' == byte'",
                         meta.query_advice(calldata_rlc, Rotation::next()),
-                        meta.query_advice(tx_table.value, Rotation::next()),
+                        meta.query_advice(tx_table.value.lo(), Rotation::next()),
                     );
                 },
             );
@@ -1279,8 +1345,9 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                 ]),
                 |cb| {
                     // we rely on the assumption that SigV is on the next of ChainID
-                    let v = meta.query_advice(tx_table.value, Rotation::next());
-                    let chain_id = meta.query_advice(tx_table.value, Rotation::cur());
+                    let v = meta.query_advice(tx_table.value.lo(), Rotation::next());
+                    // tx_table.value.lo() can cover chain_id range.
+                    let chain_id = meta.query_advice(tx_table.value.lo(), Rotation::cur());
 
                     cb.require_boolean(
                         "V - (chain_id * 2 + 35) Є {0, 1}",
@@ -1296,7 +1363,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                     tx_type_bits.value_equals(PreEip155, Rotation::cur())(meta),
                 ]),
                 |cb| {
-                    let v = meta.query_advice(tx_table.value, Rotation::next());
+                    // use value.lo() for v
+                    let v = meta.query_advice(tx_table.value.lo(), Rotation::next());
                     cb.require_boolean("V - 27 Є {0, 1}", v - 27.expr());
                 },
             );
@@ -1308,8 +1376,8 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
                     tx_type_bits.value_equals(L1Msg, Rotation::cur())(meta),
                 ]),
                 |cb| {
-                    let v = meta.query_advice(tx_table.value, Rotation::next());
-                    cb.require_zero("V == 0", v);
+                    let v = tx_table.value.query_advice(meta, Rotation::next());
+                    cb.require_zero_word("V == 0", v);
                 },
             );
 
@@ -1324,11 +1392,13 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
             "caller address == sv_address if it's not zero and tx_type != L1Msg",
             |meta| {
                 let mut cb = BaseConstraintBuilder::default();
+                let value_is_zero = meta.query_advice(is_value_zero, Rotation::cur());
 
-                cb.condition(not::expr(value_is_zero.expr(Rotation::cur())(meta)), |cb| {
+                cb.condition(not::expr(value_is_zero), |cb| {
                     cb.require_equal(
                         "caller address == sv_address",
-                        meta.query_advice(tx_table.value, Rotation::cur()),
+                        // TODO: check if value.lo can cover address in this case
+                        meta.query_advice(tx_table.value.lo(), Rotation::cur()),
                         meta.query_advice(sv_address, Rotation::cur()),
                     );
                 });
@@ -1354,12 +1424,15 @@ impl<F: Field> SubCircuitConfig<F> for TxCircuitConfig<F> {
             rlp_tag,
             is_none,
             tx_value_rlc,
+            tx_value_evm_rlc,
             tx_value_length,
+            tx_hash_word,
             u8_table,
             u16_table,
             tx_id_is_zero,
-            value_is_zero,
+            value_limb_is_zero: [value_is_zero_lo, value_is_zero_hi],
             tx_id_unchanged,
+            is_value_zero,
             is_calldata,
             is_caller_address,
             tx_id_cmp_cum_num_txs,
@@ -1398,7 +1471,9 @@ impl<F: Field> TxCircuitConfig<F> {
         q_enable: Column<Fixed>,
         rlp_tag: Column<Advice>,
         tx_value_rlc: Column<Advice>,
+        tx_value_evm_rlc: Column<Advice>,
         tx_value_length: Column<Advice>,
+        tx_hash_word: word::Word<Column<Advice>>,
         tx_type_bits: BinaryNumberConfig<TxType, 3>,
         tx_id_is_zero: IsZeroConfig<F>,
         is_none: Column<Advice>,
@@ -1407,6 +1482,7 @@ impl<F: Field> TxCircuitConfig<F> {
         is_calldata: Column<Advice>,
         is_chain_id: Column<Advice>,
         is_l1_msg_col: Column<Advice>,
+        //is_value: VirtualCells<>, // is tx field tag::value
         sv_address: Column<Advice>,
         calldata_gas_cost_acc: Column<Advice>,
         calldata_rlc: Column<Advice>,
@@ -1444,8 +1520,9 @@ impl<F: Field> TxCircuitConfig<F> {
             vec![
                 meta.query_advice(tx_table.tx_id, Rotation::cur()),
                 CallData.expr(),
-                meta.query_advice(tx_table.value, Rotation::next()), // calldata_gas_cost
-                1.expr(),                                            // is_final = 1
+                //TODO: check if lo covers calldata_gas_cost_acc
+                meta.query_advice(tx_table.value.lo(), Rotation::next()), // calldata_gas_cost
+                1.expr(),                                                 // is_final = 1
             ]
             .into_iter()
             .zip(vec![
@@ -1472,8 +1549,8 @@ impl<F: Field> TxCircuitConfig<F> {
             vec![
                 meta.query_advice(tx_table.tx_id, Rotation::cur()),
                 CallData.expr(),
-                meta.query_advice(tx_table.value, Rotation::cur()) - 1.expr(), /* index starts
-                                                                                * from 0 */
+                meta.query_advice(tx_table.value.lo(), Rotation::cur()) - 1.expr(), /* index starts
+                                                                                     * from 0 */
                 1.expr(), // is_final = true
             ]
             .into_iter()
@@ -1504,7 +1581,8 @@ impl<F: Field> TxCircuitConfig<F> {
             let table_exprs = vec![
                 meta.query_advice(tx_table.tx_id, Rotation::cur()),
                 meta.query_fixed(tx_table.tag, Rotation::cur()),
-                meta.query_advice(tx_table.value, Rotation::cur()),
+                //TODO: check lo covers calldata_rlc ?
+                meta.query_advice(tx_table.value.lo(), Rotation::cur()),
             ];
 
             input_exprs
@@ -1562,14 +1640,14 @@ impl<F: Field> TxCircuitConfig<F> {
             let is_none = meta.query_advice(is_none, Rotation::cur());
             let sign_format = is_pre_eip155(meta) * TxSignPreEip155.expr()
                 + is_eip155(meta) * TxSignEip155.expr();
-
             // q_enable, tx_id, format, rlp_tag, tag_value, is_output, is_none
             vec![
                 1.expr(), // q_enable = true
                 meta.query_advice(tx_table.tx_id, Rotation::cur()),
                 sign_format,
                 rlp_tag,
-                meta.query_advice(tx_table.value, Rotation::cur()),
+                //meta.query_advice(tx_table.value.lo(), Rotation::cur()), // lo covers tag
+                meta.query_advice(tx_value_evm_rlc, Rotation::cur()),
                 meta.query_advice(tx_value_rlc, Rotation::cur()),
                 meta.query_advice(tx_value_length, Rotation::cur()),
                 1.expr(), // is_output = true
@@ -1607,7 +1685,8 @@ impl<F: Field> TxCircuitConfig<F> {
                 meta.query_advice(tx_table.tx_id, Rotation::cur()),
                 hash_format,
                 rlp_tag,
-                meta.query_advice(tx_table.value, Rotation::cur()),
+                //meta.query_advice(tx_table.value.lo(), Rotation::cur()),
+                meta.query_advice(tx_value_evm_rlc, Rotation::cur()),
                 meta.query_advice(tx_value_rlc, Rotation::cur()),
                 meta.query_advice(tx_value_length, Rotation::cur()),
                 1.expr(), // is_output = true
@@ -1632,22 +1711,26 @@ impl<F: Field> TxCircuitConfig<F> {
                 meta.query_advice(is_chain_id, Rotation::cur()),
             ]);
 
-            let msg_hash_rlc = meta.query_advice(tx_table.value, Rotation(6));
-            let chain_id = meta.query_advice(tx_table.value, Rotation::cur());
-            let sig_v = meta.query_advice(tx_table.value, Rotation(1));
-            let sig_r = meta.query_advice(tx_table.value, Rotation(2));
-            let sig_s = meta.query_advice(tx_table.value, Rotation(3));
+            // TODO: check if lo covers msg_hash_rlc, sig(v,r,s)
+            let msg_hash_lo = meta.query_advice(tx_table.value.lo(), Rotation(6));
+            // let msg_hash_hi = meta.query_advice(tx_table.value.hi(), Rotation(6));
+            let chain_id = meta.query_advice(tx_table.value.lo(), Rotation::cur());
+            let sig_v = meta.query_advice(tx_table.value.lo(), Rotation(1));
+            let sig_r = meta.query_advice(tx_table.value.lo(), Rotation(2));
+            let sig_s = meta.query_advice(tx_table.value.lo(), Rotation(3));
             let sv_address = meta.query_advice(sv_address, Rotation::cur());
 
             let v = is_eip155(meta) * (sig_v.expr() - 2.expr() * chain_id - 35.expr())
                 + is_pre_eip155(meta) * (sig_v.expr() - 27.expr());
 
             let input_exprs = vec![
-                1.expr(),     // q_enable = true
-                msg_hash_rlc, // msg_hash_rlc
-                v,            // sig_v
-                sig_r,        // sig_r
-                sig_s,        // sig_s
+                1.expr(), // q_enable = true
+                // msg_hash_rlc, // msg_hash_rlc
+                msg_hash_lo,
+                // msg_hash_hi,
+                v,     // sig_v
+                sig_r, // sig_r
+                sig_s, // sig_s
                 sv_address,
                 1.expr(), // is_valid
             ];
@@ -1657,6 +1740,8 @@ impl<F: Field> TxCircuitConfig<F> {
                 meta.query_fixed(sig_table.q_enable, Rotation::cur()),
                 // msg_hash_rlc not needed to be looked up for tx circuit?
                 meta.query_advice(sig_table.msg_hash_rlc, Rotation::cur()),
+                // meta.query_advice(sig_table.msg_hash_word.lo(), Rotation::cur()),
+                // meta.query_advice(sig_table.msg_hash_word.hi(), Rotation::cur()),
                 meta.query_advice(sig_table.sig_v, Rotation::cur()),
                 meta.query_advice(sig_table.sig_r_rlc, Rotation::cur()),
                 meta.query_advice(sig_table.sig_s_rlc, Rotation::cur()),
@@ -1684,11 +1769,13 @@ impl<F: Field> TxCircuitConfig<F> {
             ]);
 
             vec![
-                1.expr(),                                            // q_enable
-                1.expr(),                                            // is_final
-                meta.query_advice(tx_table.value, Rotation::next()), // input_rlc
-                meta.query_advice(tx_table.value, Rotation::cur()),  // input_len
-                meta.query_advice(tx_table.value, Rotation(2)),      // output_rlc
+                1.expr(),                                                 // q_enable
+                1.expr(),                                                 // is_final
+                meta.query_advice(tx_table.value.lo(), Rotation::next()), // input_rlc
+                meta.query_advice(tx_table.value.lo(), Rotation::cur()),  // input_len
+                meta.query_advice(tx_table.value.lo(), Rotation(2)),      // output_rlc
+                meta.query_advice(tx_hash_word.lo(), Rotation::cur()),    // output_word lo
+                meta.query_advice(tx_hash_word.hi(), Rotation::cur()),    // output_word hi
             ]
             .into_iter()
             .zip(keccak_table.table_exprs(meta))
@@ -1706,7 +1793,7 @@ impl<F: Field> TxCircuitConfig<F> {
             1,
             TxFieldTag::Null,
             0,
-            Value::known(F::zero()),
+            word::Word::new([Value::known(F::zero()), Value::known(F::zero())]),
         )?;
         let (col_anno, col, col_val) = ("rlp_tag", self.rlp_tag, F::from(usize::from(Null) as u64));
         region.assign_advice(|| col_anno, col, *offset, || Value::known(col_val))?;
@@ -1729,7 +1816,7 @@ impl<F: Field> TxCircuitConfig<F> {
         num_txs: u64,
         cum_num_txs: u64,
         challenges: &Challenges<Value<F>>,
-    ) -> Result<Vec<AssignedCell<F, F>>, Error> {
+    ) -> Result<Vec<word::Word<AssignedCell<F, F>>>, Error> {
         let keccak_input = challenges.keccak_input();
         let evm_word = challenges.evm_word();
         let zero_rlc = keccak_input.map(|_| F::zero());
@@ -1758,7 +1845,7 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: tx.nonce.tag_length(),
                     be_bytes_rlc: rlc_be_bytes(&tx.nonce.to_be_bytes(), keccak_input),
                 }),
-                Value::known(F::from(tx.nonce)),
+                word::Word::new([Value::known(F::from(tx.nonce)), Value::known(F::zero())]),
             ),
             (
                 GasPrice,
@@ -1768,7 +1855,12 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: tx.gas_price.tag_length(),
                     be_bytes_rlc: rlc_be_bytes(&tx.gas_price.to_be_bytes(), keccak_input),
                 }),
-                rlc_be_bytes(&tx.gas_price.to_be_bytes(), evm_word),
+                // rlc_be_bytes(&tx.gas_price.to_be_bytes(), evm_word),
+                // word::Word::from(tx.gas_price).map(Value::known),
+                word::Word::new([
+                    rlc_be_bytes(&tx.gas_price.to_be_bytes(), evm_word),
+                    Value::known(F::zero()),
+                ]),
             ),
             (
                 Gas,
@@ -1778,7 +1870,8 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: tx.gas.tag_length(),
                     be_bytes_rlc: rlc_be_bytes(&tx.gas.to_be_bytes(), keccak_input),
                 }),
-                Value::known(F::from(tx.gas)),
+                //Value::known(F::from(tx.gas)),
+                word::Word::new([Value::known(F::from(tx.gas)), Value::known(F::zero())]),
             ),
             (
                 CallerAddress,
@@ -1788,7 +1881,14 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: tx.caller_address.tag_length(),
                     be_bytes_rlc: rlc_be_bytes(&tx.caller_address.to_fixed_bytes(), keccak_input),
                 }),
-                Value::known(tx.caller_address.to_scalar().expect("tx.from too big")),
+                //Value::known(tx.caller_address.to_scalar().expect("tx.from too big")),
+                // word::Word::from(tx.caller_address.to_word()).map(Value::known),
+
+                //let caller_addrss = tx.caller_address.to_scalar();
+                word::Word::new([
+                    Value::known(tx.caller_address.to_scalar().expect("fx from")),
+                    Value::known(F::zero()),
+                ]),
             ),
             (
                 CalleeAddress,
@@ -1803,14 +1903,32 @@ impl<F: Field> TxCircuitConfig<F> {
                         keccak_input,
                     ),
                 }),
-                Value::known(
-                    tx.callee_address
-                        .unwrap_or(Address::zero())
-                        .to_scalar()
-                        .expect("tx.to too big"),
-                ),
+                // Value::known(
+                //     tx.callee_address
+                //         .unwrap_or(Address::zero())
+                //         .to_scalar()
+                //         .expect("tx.to too big"),
+                // ),
+                // word::Word::from(tx.callee_address.unwrap_or(Address::zero()).to_word())
+                //     .map(Value::known),
+                word::Word::new([
+                    Value::known(
+                        tx.callee_address
+                            .unwrap_or(Address::zero())
+                            .to_scalar()
+                            .expect("fx to"),
+                    ),
+                    Value::known(F::zero()),
+                ]),
+            ),
+            (
+                IsCreate,
+                None,
+                word::Word::new([
+                    Value::known(F::from(tx.is_create as u64)),
+                    Value::known(F::zero()),
+                ]),
             ),
-            (IsCreate, None, Value::known(F::from(tx.is_create as u64))),
             (
                 TxFieldTag::Value,
                 Some(RlpTableInputValue {
@@ -1819,7 +1937,8 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: tx.value.tag_length(),
                     be_bytes_rlc: rlc_be_bytes(&tx.value.to_be_bytes(), keccak_input),
                 }),
-                rlc_be_bytes(&tx.value.to_be_bytes(), evm_word),
+                //rlc_be_bytes(&tx.value.to_be_bytes(), evm_word),
+                word::Word::from(tx.value.to_word()).map(Value::known),
             ),
             (
                 CallDataRLC,
@@ -1829,17 +1948,29 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: tx.call_data.tag_length(),
                     be_bytes_rlc: rlc_be_bytes(&tx.call_data, keccak_input),
                 }),
-                rlc_be_bytes(&tx.call_data, keccak_input),
+                //rlc_be_bytes(&tx.call_data, keccak_input)
+                word::Word::new([
+                    rlc_be_bytes(&tx.call_data, keccak_input),
+                    Value::known(F::zero()),
+                ]),
             ),
             (
                 CallDataLength,
                 None,
-                Value::known(F::from(tx.call_data.len() as u64)),
+                //Value::known(F::from(tx.call_data.len() as u64)),
+                word::Word::new([
+                    Value::known(F::from(tx.call_data.len() as u64)),
+                    Value::known(F::zero()),
+                ]),
             ),
             (
                 CallDataGasCost,
                 None,
-                Value::known(F::from(tx.call_data_gas_cost)),
+                //Value::known(F::from(tx.call_data_gas_cost)),
+                word::Word::new([
+                    Value::known(F::from(tx.call_data_gas_cost)),
+                    Value::known(F::zero()),
+                ]),
             ),
             (
                 TxDataGasCost,
@@ -1849,7 +1980,11 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: 0,
                     be_bytes_rlc: zero_rlc,
                 }),
-                Value::known(F::from(tx.tx_data_gas_cost)),
+                //Value::known(F::from(tx.tx_data_gas_cost)),
+                word::Word::new([
+                    Value::known(F::from(tx.tx_data_gas_cost)),
+                    Value::known(F::zero()),
+                ]),
             ),
             (
                 ChainID,
@@ -1859,7 +1994,8 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: tx.chain_id.tag_length(),
                     be_bytes_rlc: rlc_be_bytes(&tx.chain_id.to_be_bytes(), keccak_input),
                 }),
-                Value::known(F::from(tx.chain_id)),
+                //Value::known(F::from(tx.chain_id)),
+                word::Word::new([Value::known(F::from(tx.chain_id)), Value::known(F::zero())]),
             ),
             (
                 SigV,
@@ -1869,7 +2005,8 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: tx.v.tag_length(),
                     be_bytes_rlc: rlc_be_bytes(&tx.v.to_be_bytes(), keccak_input),
                 }),
-                Value::known(F::from(tx.v)),
+                //Value::known(F::from(tx.v)),
+                word::Word::new([Value::known(F::from(tx.v)), Value::known(F::zero())]),
             ),
             (
                 SigR,
@@ -1879,7 +2016,13 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: tx.r.tag_length(),
                     be_bytes_rlc: rlc_be_bytes(&tx.r.to_be_bytes(), keccak_input),
                 }),
-                rlc_be_bytes(&tx.r.to_be_bytes(), evm_word),
+                //rlc_be_bytes(&tx.r.to_be_bytes(), evm_word),
+                //word::Word::from(tx.r.to_word()).map(Value::known),
+                word::Word::new([
+                    Value::known(unwrap_value(rlc_be_bytes(&tx.r.to_be_bytes(), evm_word))),
+                    Value::known(F::zero()),
+                    //F::zero(),
+                ]),
             ),
             (
                 SigS,
@@ -1889,7 +2032,17 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: tx.s.tag_length(),
                     be_bytes_rlc: rlc_be_bytes(&tx.s.to_be_bytes(), keccak_input),
                 }),
-                rlc_be_bytes(&tx.s.to_be_bytes(), evm_word),
+                //rlc_be_bytes(&tx.s.to_be_bytes(), evm_word),
+                //word::Word::from(tx.s.to_word()).map(Value::known),
+                // word::Word::new([
+                //     Value::known(rlc_be_bytes(&tx.s.to_be_bytes(), evm_word)),
+                //     Value::known(F::zero()),
+                // ]),
+                word::Word::new([
+                    Value::known(unwrap_value(rlc_be_bytes(&tx.s.to_be_bytes(), evm_word))),
+                    Value::known(F::zero()),
+                    //F::zero(),
+                ]),
             ),
             (
                 TxSignLength,
@@ -1899,7 +2052,11 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: rlp_sign_tag_length,
                     be_bytes_rlc: zero_rlc,
                 }),
-                Value::known(F::from(tx.rlp_unsigned.len() as u64)),
+                //Value::known(F::from(tx.rlp_unsigned.len() as u64)),
+                word::Word::new([
+                    Value::known(F::from(tx.rlp_unsigned.len() as u64)),
+                    Value::known(F::zero()),
+                ]),
             ),
             (
                 TxSignRLC,
@@ -1909,9 +2066,19 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: 0,
                     be_bytes_rlc: zero_rlc,
                 }),
-                rlc_be_bytes(&tx.rlp_unsigned, keccak_input),
+                //rlc_be_bytes(&tx.rlp_unsigned, keccak_input),
+                word::Word::new([
+                    rlc_be_bytes(&tx.rlp_unsigned, keccak_input),
+                    Value::known(F::zero()),
+                ]),
+            ),
+            //(TxSignHash, None, sign_hash_rlc),
+            (
+                TxSignHash,
+                None,
+                //word::Word::from(U256::from_big_endian(&sign_hash)).map(Value::known),
+                word::Word::new([sign_hash_rlc, Value::known(F::zero())]),
             ),
-            (TxSignHash, None, sign_hash_rlc),
             (
                 TxHashLength,
                 Some(RlpTableInputValue {
@@ -1920,7 +2087,11 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: get_rlp_len_tag_length(&tx.rlp_signed),
                     be_bytes_rlc: zero_rlc,
                 }),
-                Value::known(F::from(tx.rlp_signed.len() as u64)),
+                //Value::known(F::from(tx.rlp_signed.len() as u64)),
+                word::Word::new([
+                    Value::known(F::from(tx.rlp_signed.len() as u64)),
+                    Value::known(F::zero()),
+                ]),
             ),
             (
                 TxHashRLC,
@@ -1930,23 +2101,45 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_len: 0,
                     be_bytes_rlc: zero_rlc,
                 }),
-                rlc_be_bytes(&tx.rlp_signed, keccak_input),
+                //rlc_be_bytes(&tx.rlp_signed, keccak_input),
+                word::Word::new([
+                    rlc_be_bytes(&tx.rlp_signed, keccak_input),
+                    Value::known(F::zero()),
+                ]),
+            ),
+            //(TxFieldTag::TxHash, None, hash_rlc),
+            (
+                TxFieldTag::TxHash,
+                None,
+                //word::Word::from(U256::from_big_endian(&hash)).map(Value::known),
+                word::Word::new([hash_rlc, Value::known(F::zero())]),
             ),
-            (TxFieldTag::TxHash, None, hash_rlc),
             (
                 TxFieldTag::TxType,
                 None,
-                Value::known(F::from(tx.tx_type as u64)),
+                //Value::known(F::from(tx.tx_type as u64)),
+                word::Word::new([
+                    Value::known(F::from(tx.tx_type as u64)),
+                    Value::known(F::zero()),
+                ]),
             ),
             (
                 AccessListAddressesLen,
                 None,
-                Value::known(F::from(access_list_address_size)),
+                //Value::known(F::from(access_list_address_size)),
+                word::Word::new([
+                    Value::known(F::from(access_list_address_size)),
+                    Value::known(F::zero()),
+                ]),
             ),
             (
                 AccessListStorageKeysLen,
                 None,
-                Value::known(F::from(access_list_storage_key_size)),
+                //Value::known(F::from(access_list_storage_key_size)),
+                word::Word::new([
+                    Value::known(F::from(access_list_storage_key_size)),
+                    Value::known(F::zero()),
+                ]),
             ),
             (
                 AccessListRLC,
@@ -1957,17 +2150,34 @@ impl<F: Field> TxCircuitConfig<F> {
                     be_bytes_rlc: zero_rlc,
                 }),
                 // TODO: need to check if it's correct with RLP.
-                rlc_be_bytes(
-                    &tx.access_list
-                        .as_ref()
-                        .map(|access_list| access_list.rlp_bytes())
-                        .unwrap_or_default(),
-                    keccak_input,
-                ),
+                {
+                    let access_list_rlc = rlc_be_bytes(
+                        &tx.access_list
+                            .as_ref()
+                            .map(|access_list| access_list.rlp_bytes())
+                            .unwrap_or_default(),
+                        keccak_input,
+                    );
+
+                    word::Word::new([access_list_rlc, Value::known(F::zero())])
+                },
             ),
-            (BlockNumber, None, Value::known(F::from(tx.block_number))),
+            (
+                BlockNumber,
+                None,
+                word::Word::new([
+                    Value::known(F::from(tx.block_number)),
+                    Value::known(F::zero()),
+                ]),
+            ),
+            //Value::known(F::from(tx.block_number))),
         ];
 
+        // constructs two hashes' word
+        let sign_hash_word = word::Word::from(U256::from_big_endian(&sign_hash)).map(Value::known);
+        let tx_hash_word = word::Word::from(U256::from_big_endian(&hash)).map(Value::known);
+        let tx_value_evm_rlc = rlc_be_bytes(&tx.value.to_be_bytes(), evm_word);
+
         for (tx_tag, rlp_input, tx_value) in fixed_rows {
             let rlp_tag = rlp_input.clone().map_or(Null, |input| input.tag);
             let rlp_is_none = rlp_input.clone().map_or(false, |input| input.is_none);
@@ -2030,7 +2240,7 @@ impl<F: Field> TxCircuitConfig<F> {
                 ),
                 (
                     "sv_address",
-                    self.sv_address,
+                    self.sv_address, // not change to word
                     sign_data.get_addr().to_scalar().unwrap(),
                 ),
                 // tx_tag related indicator columns
@@ -2063,6 +2273,17 @@ impl<F: Field> TxCircuitConfig<F> {
                 let (col_anno, col, col_val) =
                     ("tx_value_rlc", self.tx_value_rlc, rlp_be_bytes_rlc);
                 region.assign_advice(|| col_anno, col, *offset, || col_val)?;
+                let value_evm_rlc = if tx_tag == TxFieldTag::Value {
+                    tx_value_evm_rlc
+                } else {
+                    tx_value.lo()
+                };
+                region.assign_advice(
+                    || "tx_value_evm_rlc",
+                    self.tx_value_evm_rlc,
+                    *offset,
+                    || value_evm_rlc,
+                )?;
             }
 
             // lookup conditions
@@ -2169,6 +2390,24 @@ impl<F: Field> TxCircuitConfig<F> {
                 F::from(tx.id as u64),
             )?;
 
+            let hash_word_assign = if tx_tag == TxFieldTag::TxSignLength {
+                sign_hash_word
+            } else if tx_tag == TxFieldTag::TxHashLength {
+                tx_hash_word
+            } else {
+                // for non TxSignLength & non TxHashLength tag, this word value won't lookup, hence
+                // all set zero limbs. word::Word::default() will panic as default
+                // limbs are none.
+                word::Word::new([F::zero(), F::zero()]).map(Value::known)
+            };
+
+            hash_word_assign.assign_advice(
+                region,
+                || "assign sign_hash_word",
+                self.tx_hash_word,
+                *offset,
+            )?;
+
             *offset += 1;
         }
         Ok(tx_value_cells)
@@ -2206,7 +2445,7 @@ impl<F: Field> TxCircuitConfig<F> {
                 tx_id_next,
                 CallData,
                 idx as u64,
-                Value::known(F::from(*byte as u64)),
+                word::Word::new([Value::known(F::from(*byte as u64)), Value::known(F::zero())]),
             )?;
 
             // 1st phase columns
@@ -2247,8 +2486,8 @@ impl<F: Field> TxCircuitConfig<F> {
         tx_id_next: usize,
         tag: TxFieldTag,
         index: u64,
-        value: Value<F>,
-    ) -> Result<AssignedCell<F, F>, Error> {
+        value: word::Word<Value<F>>,
+    ) -> Result<word::Word<AssignedCell<F, F>>, Error> {
         let (tx_type, tx_id) = if let Some(tx) = tx {
             (tx.tx_type, tx.id)
         } else {
@@ -2265,9 +2504,19 @@ impl<F: Field> TxCircuitConfig<F> {
         let tx_id_is_zero_chip = IsZeroChip::construct(self.tx_id_is_zero.clone());
         tx_id_is_zero_chip.assign(region, offset, Value::known(F::from(tx_id as u64)))?;
 
-        let value_is_zero_chip = IsZeroChip::construct(self.value_is_zero.clone());
-        value_is_zero_chip.assign(region, offset, value)?;
+        let value_word_zero =
+            unwrap_value(value.lo()) == F::zero() && unwrap_value(value.hi()) == F::zero();
+        let value_is_zero_lo_chip = IsZeroChip::construct(self.value_limb_is_zero[0].clone());
+        value_is_zero_lo_chip.assign(region, offset, value.lo())?;
+        let value_is_zero_hi_chip = IsZeroChip::construct(self.value_limb_is_zero[1].clone());
+        value_is_zero_hi_chip.assign(region, offset, value.hi())?;
 
+        region.assign_advice(
+            || "tx circuit: is_value_zero",
+            self.is_value_zero,
+            offset,
+            || Value::known(F::from(value_word_zero as u64)),
+        )?;
         let tx_id_unchanged_chip = IsEqualChip::construct(self.tx_id_unchanged.clone());
         tx_id_unchanged_chip.assign(
             region,
@@ -2299,10 +2548,12 @@ impl<F: Field> TxCircuitConfig<F> {
             region.assign_advice(|| col_anno, col, offset, || Value::known(col_val))?;
         }
         // 2nd phase columns
-        let tx_value_cell =
-            region.assign_advice(|| "tx_value", self.tx_table.value, offset, || value)?;
+        // let tx_value_cell =
+        //     region.assign_advice(|| "tx_value", self.tx_table.value, offset, || value)?;
 
-        Ok(tx_value_cell)
+        let tx_value_cells =
+            value.assign_advice(region, || "tx_value", self.tx_table.value, offset)?;
+        Ok(tx_value_cells)
     }
 
     fn assign_calldata_zeros(
@@ -2311,10 +2562,11 @@ impl<F: Field> TxCircuitConfig<F> {
         start: usize,
         end: usize,
     ) -> Result<(), Error> {
-        // let rlp_data = F::from( as u64);
         let tag = F::from(CallData as u64);
         let tx_id_is_zero_chip = IsZeroChip::construct(self.tx_id_is_zero.clone());
-        let value_is_zero_chip = IsZeroChip::construct(self.value_is_zero.clone());
+        let value_is_zero_lo_chip = IsZeroChip::construct(self.value_limb_is_zero[0].clone());
+        let value_is_zero_hi_chip = IsZeroChip::construct(self.value_limb_is_zero[1].clone());
+
         let tx_id_unchanged = IsEqualChip::construct(self.tx_id_unchanged.clone());
         let tag_chip = BinaryNumberChip::construct(self.tx_tag_bits);
 
@@ -2336,7 +2588,9 @@ impl<F: Field> TxCircuitConfig<F> {
             // no need to assign tx_id_is_zero_chip for real prover as tx_id = 0
             tx_id_is_zero_chip.assign(region, offset, Value::known(F::zero()))?;
             // no need to assign value_is_zero_chip for real prover as value = 0
-            value_is_zero_chip.assign(region, offset, Value::known(F::zero()))?;
+            value_is_zero_lo_chip.assign(region, offset, Value::known(F::zero()))?;
+            value_is_zero_hi_chip.assign(region, offset, Value::known(F::zero()))?;
+
             tx_id_unchanged.assign(
                 region,
                 offset,
@@ -2347,7 +2601,10 @@ impl<F: Field> TxCircuitConfig<F> {
             for (col, value) in [
                 (self.tx_table.tx_id, F::zero()),
                 (self.tx_table.index, F::zero()),
-                (self.tx_table.value, F::zero()),
+                (self.tx_table.value.lo(), F::zero()),
+                (self.tx_table.value.hi(), F::zero()),
+                // when value is zero, is_value_zero is true
+                (self.is_value_zero, F::one()),
                 (self.is_final, F::one()),
                 (self.is_calldata, F::one()),
                 (self.calldata_gas_cost_acc, F::zero()),
@@ -2405,7 +2662,8 @@ pub struct TxCircuit<F: Field> {
     /// Size
     pub size: usize,
     /// Tx value cells (exported for PI circuit)
-    pub value_cells: RefCell<Option<Vec<AssignedCell<F, F>>>>,
+    #[allow(clippy::type_complexity)]
+    pub value_cells: RefCell<Option<Vec<word::Word<AssignedCell<F, F>>>>>,
     _marker: PhantomData<F>,
 }
 
@@ -2581,12 +2839,11 @@ impl<F: Field> TxCircuit<F> {
         start_l1_queue_index: u64,
         sign_datas: Vec<SignData>,
         padding_txs: &[Transaction],
-    ) -> Result<Vec<AssignedCell<F, F>>, Error> {
+    ) -> Result<Vec<word::Word<AssignedCell<F, F>>>, Error> {
         layouter.assign_region(
             || "tx table aux",
             |mut region| {
                 let mut offset = 0;
-
                 let sigs = &sign_datas;
 
                 debug_assert_eq!(padding_txs.len() + self.txs.len(), sigs.len());
@@ -2779,7 +3036,6 @@ impl<F: Field> SubCircuit<F> for TxCircuit<F> {
         layouter: &mut impl Layouter<F>,
     ) -> Result<(), Error> {
         assert!(self.txs.len() <= self.max_txs);
-
         let padding_txs = (self.txs.len()..self.max_txs)
             .map(|i| {
                 let mut tx = Transaction::dummy(self.chain_id);
diff --git a/zkevm-circuits/src/tx_circuit/dev.rs b/zkevm-circuits/src/tx_circuit/dev.rs
index e17711710c..adb6abf556 100644
--- a/zkevm-circuits/src/tx_circuit/dev.rs
+++ b/zkevm-circuits/src/tx_circuit/dev.rs
@@ -6,9 +6,7 @@ pub use super::TxCircuit;
 
 use crate::{
     sig_circuit::{SigCircuit, SigCircuitConfig, SigCircuitConfigArgs},
-    table::{
-        BlockTable, KeccakTable, RlpFsmRlpTable as RlpTable, SigTable, TxTable, U16Table, U8Table,
-    },
+    table::{BlockTable, KeccakTable, RlpFsmRlpTable as RlpTable, SigTable, TxTable, UXTable},
     tx_circuit::{TxCircuitConfig, TxCircuitConfigArgs},
     util::{Challenges, SubCircuit, SubCircuitConfig},
     witness::Transaction,
@@ -32,9 +30,9 @@ pub struct TxCircuitTesterConfigArgs<F: Field> {
     /// SigTable
     pub sig_table: SigTable,
     /// u8 lookup table,
-    pub u8_table: U8Table,
+    pub u8_table: UXTable<8>,
     /// u16 lookup table,
-    pub u16_table: U16Table,
+    pub u16_table: UXTable<16>,
     /// Challenges
     pub challenges: Challenges<Expression<F>>,
 }
@@ -46,9 +44,9 @@ pub struct TxCircuitTesterConfig<F: Field> {
     // SigTable is assigned inside SigCircuit
     sig_config: SigCircuitConfig<F>,
     /// u16 lookup table,
-    pub u8_table: U8Table,
+    pub u8_table: UXTable<8>,
     /// u16 lookup table,
-    pub u16_table: U16Table,
+    pub u16_table: UXTable<16>,
 }
 
 impl<F: Field> SubCircuitConfig<F> for TxCircuitTesterConfig<F> {
@@ -168,8 +166,8 @@ impl<F: Field> Circuit<F> for TxCircuitTester<F> {
         let keccak_table = KeccakTable::construct(meta);
         let rlp_table = RlpTable::construct(meta);
         let sig_table = SigTable::construct(meta);
-        let u8_table = U8Table::construct(meta);
-        let u16_table = U16Table::construct(meta);
+        let u8_table = UXTable::construct(meta);
+        let u16_table = UXTable::construct(meta);
         let challenges = Challenges::construct(meta);
 
         let config = {
diff --git a/zkevm-circuits/src/witness/tx.rs b/zkevm-circuits/src/witness/tx.rs
index 5680194c1b..77f513df4d 100644
--- a/zkevm-circuits/src/witness/tx.rs
+++ b/zkevm-circuits/src/witness/tx.rs
@@ -1,7 +1,7 @@
 use crate::{
     evm_circuit::{step::ExecutionState, util::rlc},
     table::TxContextFieldTag,
-    util::{rlc_be_bytes, Challenges},
+    util::{rlc_be_bytes, word, Challenges},
     witness::{
         rlp_fsm::SmState,
         DataTable, Format,
@@ -158,11 +158,21 @@ impl Transaction {
     pub fn table_assignments_fixed<F: Field>(
         &self,
         challenges: Challenges<Value<F>>,
-    ) -> Vec<[Value<F>; 4]> {
+    ) -> Vec<[Value<F>; 5]> {
         let tx_hash_be_bytes = keccak256(&self.rlp_signed);
         let tx_sign_hash_be_bytes = keccak256(&self.rlp_unsigned);
         let (access_list_address_size, access_list_storage_key_size) =
             access_list_size(&self.access_list);
+        // let gas_price_word = word::Word::from(self.gas_price.to_word()).map(Value::known);
+        let value_word = word::Word::from(self.value.to_word()).map(Value::known);
+        // let tx_hash_word =
+        //     word::Word::from(Word::from_big_endian(&tx_hash_be_bytes)).map(Value::known);
+        // let tx_sign_hash_word =
+        //     word::Word::from(Word::from_big_endian(&tx_sign_hash_be_bytes)).map(Value::known);
+        // let caller_address_word = word::Word::from(self.caller_address).map(Value::known);
+        // let callee_address_word =
+        //     word::Word::from(self.callee_address.unwrap_or(Address::zero())).map(Value::known);
+        println!("Transaction table_assignments_fixed");
 
         let ret = vec![
             [
@@ -170,6 +180,7 @@ impl Transaction {
                 Value::known(F::from(TxContextFieldTag::Nonce as u64)),
                 Value::known(F::zero()),
                 Value::known(F::from(self.nonce)),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
@@ -178,18 +189,26 @@ impl Transaction {
                 challenges
                     .evm_word()
                     .map(|challenge| rlc::value(&self.gas_price.to_le_bytes(), challenge)),
+                Value::known(F::zero()),
+                // can not use word type as tx circuit use rlc value to lookup keccak table
+                // gas_price_word.lo(),
+                // gas_price_word.hi(),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::Gas as u64)),
                 Value::known(F::zero()),
                 Value::known(F::from(self.gas)),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::CallerAddress as u64)),
                 Value::known(F::zero()),
                 Value::known(self.caller_address.to_scalar().unwrap()),
+                Value::known(F::zero()),
+                // caller_address_word.lo(),
+                // caller_address_word.hi(),
             ],
             [
                 Value::known(F::from(self.id as u64)),
@@ -201,122 +220,152 @@ impl Transaction {
                         .to_scalar()
                         .unwrap(),
                 ),
+                Value::known(F::zero()),
+                // callee_address_word.lo(),
+                // callee_address_word.hi(),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::IsCreate as u64)),
                 Value::known(F::zero()),
                 Value::known(F::from(self.is_create as u64)),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::Value as u64)),
                 Value::known(F::zero()),
-                challenges
-                    .evm_word()
-                    .map(|challenge| rlc::value(&self.value.to_le_bytes(), challenge)),
+                // challenges
+                //     .evm_word()
+                //     .map(|challenge| rlc::value(&self.value.to_le_bytes(), challenge)),
+                value_word.lo(),
+                value_word.hi(),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::CallDataRLC as u64)),
                 Value::known(F::zero()),
                 rlc_be_bytes(&self.call_data, challenges.keccak_input()),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::CallDataLength as u64)),
                 Value::known(F::zero()),
                 Value::known(F::from(self.call_data_length as u64)),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::CallDataGasCost as u64)),
                 Value::known(F::zero()),
                 Value::known(F::from(self.call_data_gas_cost)),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::TxDataGasCost as u64)),
                 Value::known(F::zero()),
                 Value::known(F::from(self.tx_data_gas_cost)),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::ChainID as u64)),
                 Value::known(F::zero()),
                 Value::known(F::from(self.chain_id)),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::SigV as u64)),
                 Value::known(F::zero()),
                 Value::known(F::from(self.v)),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::SigR as u64)),
                 Value::known(F::zero()),
+                // TODO: check if change r to word hi lo ?
                 rlc_be_bytes(&self.r.to_be_bytes(), challenges.evm_word()),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::SigS as u64)),
                 Value::known(F::zero()),
+                // TODO: check if change s to word hi lo ?
                 rlc_be_bytes(&self.s.to_be_bytes(), challenges.evm_word()),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::TxSignLength as u64)),
                 Value::known(F::zero()),
                 Value::known(F::from(self.rlp_unsigned.len() as u64)),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::TxSignRLC as u64)),
                 Value::known(F::zero()),
                 rlc_be_bytes(&self.rlp_unsigned, challenges.keccak_input()),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::TxSignHash as u64)),
                 Value::known(F::zero()),
+                // TODO: check if change to word hi lo ?
                 rlc_be_bytes(&tx_sign_hash_be_bytes, challenges.evm_word()),
+                Value::known(F::zero()),
+                // tx_sign_hash_word.lo(),
+                // tx_sign_hash_word.hi(),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::TxHashLength as u64)),
                 Value::known(F::zero()),
                 Value::known(F::from(self.rlp_signed.len() as u64)),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::TxHashRLC as u64)),
                 Value::known(F::zero()),
                 rlc_be_bytes(&self.rlp_signed, challenges.keccak_input()),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::TxHash as u64)),
                 Value::known(F::zero()),
                 rlc_be_bytes(&tx_hash_be_bytes, challenges.evm_word()),
+                Value::known(F::zero()),
+                // tx_hash_word.lo(),
+                // tx_hash_word.hi(),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::TxType as u64)),
                 Value::known(F::zero()),
                 Value::known(F::from(self.tx_type as u64)),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::AccessListAddressesLen as u64)),
                 Value::known(F::zero()),
                 Value::known(F::from(access_list_address_size)),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::AccessListStorageKeysLen as u64)),
                 Value::known(F::zero()),
                 Value::known(F::from(access_list_storage_key_size)),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
@@ -331,12 +380,14 @@ impl Transaction {
                         .unwrap_or_default(),
                     challenges.keccak_input(),
                 ),
+                Value::known(F::zero()),
             ],
             [
                 Value::known(F::from(self.id as u64)),
                 Value::known(F::from(TxContextFieldTag::BlockNumber as u64)),
                 Value::known(F::zero()),
                 Value::known(F::from(self.block_number)),
+                Value::known(F::zero()),
             ],
         ];
 
@@ -347,7 +398,7 @@ impl Transaction {
     pub fn table_assignments_dyn<F: Field>(
         &self,
         _challenges: Challenges<Value<F>>,
-    ) -> Vec<[Value<F>; 4]> {
+    ) -> Vec<[Value<F>; 5]> {
         self.call_data
             .iter()
             .enumerate()
@@ -357,6 +408,7 @@ impl Transaction {
                     Value::known(F::from(TxContextFieldTag::CallData as u64)),
                     Value::known(F::from(idx as u64)),
                     Value::known(F::from(*byte as u64)),
+                    Value::known(F::zero()),
                 ]
             })
             .collect()