@@ -12,9 +12,10 @@ use crate::{
1212 } ,
1313 is_precompiled,
1414 math_gadget:: {
15- ContractCreateGadget , IsEqualWordGadget , IsZeroWordGadget , RangeCheckGadget ,
15+ ContractCreateGadget , IsEqualWordGadget , IsZeroGadget , IsZeroWordGadget ,
16+ RangeCheckGadget ,
1617 } ,
17- not, or,
18+ not, or, rlc ,
1819 tx:: { BeginTxHelperGadget , TxDataGadget } ,
1920 AccountAddress , CachedRegion , Cell , StepRws ,
2021 } ,
@@ -45,6 +46,9 @@ pub(crate) struct BeginTxGadget<F> {
4546 code_hash : WordLoHiCell < F > ,
4647 is_empty_code_hash : IsEqualWordGadget < F , WordLoHi < Expression < F > > , WordLoHi < Expression < F > > > ,
4748 caller_nonce_hash_bytes : Word32Cell < F > ,
49+ calldata_length : Cell < F > ,
50+ calldata_length_is_zero : IsZeroGadget < F > ,
51+ calldata_rlc : Cell < F > ,
4852 create : ContractCreateGadget < F , false > ,
4953 callee_not_exists : IsZeroWordGadget < F , WordLoHiCell < F > > ,
5054 is_caller_callee_equal : Cell < F > ,
@@ -184,6 +188,9 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
184188 ) ;
185189
186190 let caller_nonce_hash_bytes = cb. query_word32 ( ) ;
191+ let calldata_length = cb. query_cell ( ) ;
192+ let calldata_length_is_zero = cb. is_zero ( calldata_length. expr ( ) ) ;
193+ let calldata_rlc = cb. query_cell_phase2 ( ) ;
187194 let create = ContractCreateGadget :: construct ( cb) ;
188195 cb. require_equal_word (
189196 "tx caller address equivalence" ,
@@ -216,23 +223,36 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
216223 caller_nonce_hash_bytes. to_word ( ) ,
217224 ) ;
218225
219- let length = cb. tx_context ( tx_id. expr ( ) , TxContextFieldTag :: CallDataLength , None ) ;
220- let rlc_acc = cb. query_cell_phase2 ( ) ;
221- cb. copy_table_lookup (
222- WordLoHi :: from_lo_unchecked ( tx_id. expr ( ) ) ,
223- CopyDataType :: TxCalldata . expr ( ) ,
224- WordLoHi :: zero ( ) ,
225- CopyDataType :: RlcAcc . expr ( ) ,
226- 0 . expr ( ) ,
227- length. expr ( ) ,
228- 0 . expr ( ) ,
229- length. expr ( ) ,
230- rlc_acc. expr ( ) ,
231- 0 . expr ( ) ,
226+ cb. tx_context_lookup (
227+ tx_id. expr ( ) ,
228+ TxContextFieldTag :: CallDataLength ,
229+ None ,
230+ WordLoHi :: from_lo_unchecked ( calldata_length. expr ( ) ) ,
232231 ) ;
232+ // If calldata_length > 0 we use the copy circuit to calculate the calldata_rlc for the
233+ // keccack input.
234+ cb. condition ( not:: expr ( calldata_length_is_zero. expr ( ) ) , |cb| {
235+ cb. copy_table_lookup (
236+ WordLoHi :: from_lo_unchecked ( tx_id. expr ( ) ) ,
237+ CopyDataType :: TxCalldata . expr ( ) ,
238+ WordLoHi :: zero ( ) ,
239+ CopyDataType :: RlcAcc . expr ( ) ,
240+ 0 . expr ( ) ,
241+ calldata_length. expr ( ) ,
242+ 0 . expr ( ) ,
243+ calldata_length. expr ( ) ,
244+ calldata_rlc. expr ( ) ,
245+ 0 . expr ( ) ,
246+ )
247+ } ) ;
248+ // If calldata_length == 0, the copy circuit will not contain any entry, so we skip the
249+ // lookup and instead force calldata_rlc to be 0 for the keccack input.
250+ cb. condition ( calldata_length_is_zero. expr ( ) , |cb| {
251+ cb. require_equal ( "calldata_rlc = 0" , calldata_rlc. expr ( ) , 0 . expr ( ) ) ;
252+ } ) ;
233253 cb. keccak_table_lookup (
234- rlc_acc . expr ( ) ,
235- length . expr ( ) ,
254+ calldata_rlc . expr ( ) ,
255+ calldata_length . expr ( ) ,
236256 cb. curr . state . code_hash . to_word ( ) ,
237257 ) ;
238258
@@ -454,6 +474,9 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
454474 code_hash,
455475 is_empty_code_hash,
456476 caller_nonce_hash_bytes,
477+ calldata_length,
478+ calldata_length_is_zero,
479+ calldata_rlc,
457480 create,
458481 callee_not_exists,
459482 is_caller_callee_equal,
@@ -554,6 +577,18 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
554577 offset,
555578 U256 :: from_big_endian ( & untrimmed_contract_addr) ,
556579 ) ?;
580+ self . calldata_length . assign (
581+ region,
582+ offset,
583+ Value :: known ( F :: from ( tx. call_data . len ( ) as u64 ) ) ,
584+ ) ?;
585+ self . calldata_length_is_zero
586+ . assign ( region, offset, F :: from ( tx. call_data . len ( ) as u64 ) ) ?;
587+ let calldata_rlc = region
588+ . challenges ( )
589+ . keccak_input ( )
590+ . map ( |randomness| rlc:: value ( tx. call_data . iter ( ) . rev ( ) , randomness) ) ;
591+ self . calldata_rlc . assign ( region, offset, calldata_rlc) ?;
557592 self . create . assign (
558593 region,
559594 offset,
0 commit comments