@@ -12,9 +12,10 @@ use crate::{
12
12
} ,
13
13
is_precompiled,
14
14
math_gadget:: {
15
- ContractCreateGadget , IsEqualWordGadget , IsZeroWordGadget , RangeCheckGadget ,
15
+ ContractCreateGadget , IsEqualWordGadget , IsZeroGadget , IsZeroWordGadget ,
16
+ RangeCheckGadget ,
16
17
} ,
17
- not, or,
18
+ not, or, rlc ,
18
19
tx:: { BeginTxHelperGadget , TxDataGadget } ,
19
20
AccountAddress , CachedRegion , Cell , StepRws ,
20
21
} ,
@@ -45,6 +46,9 @@ pub(crate) struct BeginTxGadget<F> {
45
46
code_hash : WordLoHiCell < F > ,
46
47
is_empty_code_hash : IsEqualWordGadget < F , WordLoHi < Expression < F > > , WordLoHi < Expression < F > > > ,
47
48
caller_nonce_hash_bytes : Word32Cell < F > ,
49
+ calldata_length : Cell < F > ,
50
+ calldata_length_is_zero : IsZeroGadget < F > ,
51
+ calldata_rlc : Cell < F > ,
48
52
create : ContractCreateGadget < F , false > ,
49
53
callee_not_exists : IsZeroWordGadget < F , WordLoHiCell < F > > ,
50
54
is_caller_callee_equal : Cell < F > ,
@@ -184,6 +188,9 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
184
188
) ;
185
189
186
190
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 ( ) ;
187
194
let create = ContractCreateGadget :: construct ( cb) ;
188
195
cb. require_equal_word (
189
196
"tx caller address equivalence" ,
@@ -216,23 +223,36 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
216
223
caller_nonce_hash_bytes. to_word ( ) ,
217
224
) ;
218
225
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 ( ) ) ,
232
231
) ;
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
+ } ) ;
233
253
cb. keccak_table_lookup (
234
- rlc_acc . expr ( ) ,
235
- length . expr ( ) ,
254
+ calldata_rlc . expr ( ) ,
255
+ calldata_length . expr ( ) ,
236
256
cb. curr . state . code_hash . to_word ( ) ,
237
257
) ;
238
258
@@ -454,6 +474,9 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
454
474
code_hash,
455
475
is_empty_code_hash,
456
476
caller_nonce_hash_bytes,
477
+ calldata_length,
478
+ calldata_length_is_zero,
479
+ calldata_rlc,
457
480
create,
458
481
callee_not_exists,
459
482
is_caller_callee_equal,
@@ -554,6 +577,18 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
554
577
offset,
555
578
U256 :: from_big_endian ( & untrimmed_contract_addr) ,
556
579
) ?;
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) ?;
557
592
self . create . assign (
558
593
region,
559
594
offset,
0 commit comments