@@ -12,21 +12,22 @@ 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,
18
+ not, rlc ,
18
19
tx:: { BeginTxHelperGadget , TxDataGadget } ,
19
20
AccountAddress , CachedRegion , Cell , StepRws ,
20
21
} ,
21
22
witness:: { Block , Call , ExecStep , Transaction } ,
22
23
} ,
23
- table:: { AccountFieldTag , BlockContextFieldTag , CallContextFieldTag } ,
24
+ table:: { AccountFieldTag , BlockContextFieldTag , CallContextFieldTag , TxContextFieldTag } ,
24
25
util:: {
25
26
word:: { Word32Cell , WordExpr , WordLoHi , WordLoHiCell } ,
26
27
Expr ,
27
28
} ,
28
29
} ;
29
- use bus_mapping:: state_db:: CodeDB ;
30
+ use bus_mapping:: { circuit_input_builder :: CopyDataType , state_db:: CodeDB } ;
30
31
use eth_types:: { evm_types:: PRECOMPILE_COUNT , keccak256, Field , OpsIdentity , ToWord , U256 } ;
31
32
use halo2_proofs:: {
32
33
circuit:: Value ,
@@ -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 > ,
@@ -183,12 +187,23 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
183
187
) ;
184
188
185
189
let caller_nonce_hash_bytes = cb. query_word32 ( ) ;
190
+ let calldata_length = cb. query_cell ( ) ;
191
+ let calldata_length_is_zero = cb. is_zero ( calldata_length. expr ( ) ) ;
192
+ let calldata_rlc = cb. query_cell_phase2 ( ) ;
186
193
let create = ContractCreateGadget :: construct ( cb) ;
187
194
cb. require_equal_word (
188
195
"tx caller address equivalence" ,
189
196
tx. caller_address . to_word ( ) ,
190
197
create. caller_address ( ) ,
191
198
) ;
199
+
200
+ cb. require_equal (
201
+ "tx nonce equivalence" ,
202
+ tx. nonce . expr ( ) ,
203
+ create. caller_nonce ( ) ,
204
+ ) ;
205
+
206
+ // 1. Handle contract creation transaction.
192
207
cb. condition ( tx. is_create . expr ( ) , |cb| {
193
208
cb. require_equal_word (
194
209
"call callee address equivalence" ,
@@ -201,21 +216,45 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
201
216
)
202
217
. to_word ( ) ,
203
218
) ;
204
- } ) ;
205
- cb. require_equal (
206
- "tx nonce equivalence" ,
207
- tx. nonce . expr ( ) ,
208
- create. caller_nonce ( ) ,
209
- ) ;
210
-
211
- // 1. Handle contract creation transaction.
212
- cb. condition ( tx. is_create . expr ( ) , |cb| {
213
219
cb. keccak_table_lookup (
214
220
create. input_rlc ( cb) ,
215
221
create. input_length ( ) ,
216
222
caller_nonce_hash_bytes. to_word ( ) ,
217
223
) ;
218
224
225
+ cb. tx_context_lookup (
226
+ tx_id. expr ( ) ,
227
+ TxContextFieldTag :: CallDataLength ,
228
+ None ,
229
+ WordLoHi :: from_lo_unchecked ( calldata_length. expr ( ) ) ,
230
+ ) ;
231
+ // If calldata_length > 0 we use the copy circuit to calculate the calldata_rlc for the
232
+ // keccack input.
233
+ cb. condition ( not:: expr ( calldata_length_is_zero. expr ( ) ) , |cb| {
234
+ cb. copy_table_lookup (
235
+ WordLoHi :: from_lo_unchecked ( tx_id. expr ( ) ) ,
236
+ CopyDataType :: TxCalldata . expr ( ) ,
237
+ WordLoHi :: zero ( ) ,
238
+ CopyDataType :: RlcAcc . expr ( ) ,
239
+ 0 . expr ( ) ,
240
+ calldata_length. expr ( ) ,
241
+ 0 . expr ( ) ,
242
+ calldata_length. expr ( ) ,
243
+ calldata_rlc. expr ( ) ,
244
+ 0 . expr ( ) ,
245
+ )
246
+ } ) ;
247
+ // If calldata_length == 0, the copy circuit will not contain any entry, so we skip the
248
+ // lookup and instead force calldata_rlc to be 0 for the keccack input.
249
+ cb. condition ( calldata_length_is_zero. expr ( ) , |cb| {
250
+ cb. require_equal ( "calldata_rlc = 0" , calldata_rlc. expr ( ) , 0 . expr ( ) ) ;
251
+ } ) ;
252
+ cb. keccak_table_lookup (
253
+ calldata_rlc. expr ( ) ,
254
+ calldata_length. expr ( ) ,
255
+ cb. curr . state . code_hash . to_word ( ) ,
256
+ ) ;
257
+
219
258
cb. account_write (
220
259
call_callee_address. to_word ( ) ,
221
260
AccountFieldTag :: Nonce ,
@@ -434,6 +473,9 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
434
473
code_hash,
435
474
is_empty_code_hash,
436
475
caller_nonce_hash_bytes,
476
+ calldata_length,
477
+ calldata_length_is_zero,
478
+ calldata_rlc,
437
479
create,
438
480
callee_not_exists,
439
481
is_caller_callee_equal,
@@ -522,6 +564,18 @@ impl<F: Field> ExecutionGadget<F> for BeginTxGadget<F> {
522
564
offset,
523
565
U256 :: from_big_endian ( & untrimmed_contract_addr) ,
524
566
) ?;
567
+ self . calldata_length . assign (
568
+ region,
569
+ offset,
570
+ Value :: known ( F :: from ( tx. call_data . len ( ) as u64 ) ) ,
571
+ ) ?;
572
+ self . calldata_length_is_zero
573
+ . assign ( region, offset, F :: from ( tx. call_data . len ( ) as u64 ) ) ?;
574
+ let calldata_rlc = region
575
+ . challenges ( )
576
+ . keccak_input ( )
577
+ . map ( |randomness| rlc:: value ( tx. call_data . iter ( ) . rev ( ) , randomness) ) ;
578
+ self . calldata_rlc . assign ( region, offset, calldata_rlc) ?;
525
579
self . create . assign (
526
580
region,
527
581
offset,
0 commit comments