Skip to content
This repository was archived by the owner on Jul 5, 2024. It is now read-only.

Commit 2291146

Browse files
committed
fix: add missing copy event, keccak input, cell assignments, calldata.len=0 case
1 parent 496829a commit 2291146

File tree

3 files changed

+80
-19
lines changed

3 files changed

+80
-19
lines changed

bus-mapping/src/circuit_input_builder/block.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ pub struct Block {
8484
pub block_steps: BlockSteps,
8585
/// Copy events in this block.
8686
pub copy_events: Vec<CopyEvent>,
87-
/// Inputs to the SHA3 opcode
87+
/// Inputs to the SHA3 opcode as well as data hashed during the EVM execution like init code
88+
/// and address creation inputs.
8889
pub sha3_inputs: Vec<Vec<u8>>,
8990
/// Exponentiation events in the block.
9091
pub exp_events: Vec<ExpEvent>,

bus-mapping/src/evm/opcodes/begin_end_tx.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use super::TxExecSteps;
22
use crate::{
3-
circuit_input_builder::{Call, CircuitInputStateRef, ExecState, ExecStep},
3+
circuit_input_builder::{
4+
Call, CircuitInputStateRef, CopyDataType, CopyEvent, ExecState, ExecStep, NumberOrHash,
5+
},
46
operation::{AccountField, AccountOp, CallContextField, TxReceiptField, TxRefundOp, RW},
57
state_db::CodeDB,
68
Error,
@@ -148,6 +150,29 @@ fn gen_begin_tx_steps(state: &mut CircuitInputStateRef) -> Result<ExecStep, Erro
148150
stream.append(&nonce_prev);
149151
stream.out().to_vec()
150152
});
153+
// We also hash the call_data as it will be used as init code, and the
154+
// call_context.code_hash needs to be checked against the hash of this call_data.
155+
state.block.sha3_inputs.push(state.tx.call_data.to_vec());
156+
157+
// Append the copy for the CopyCircuit to calculate RLC(call_data) for the keccack lookup
158+
if state.tx.call_data.len() > 0 {
159+
state.push_copy(
160+
&mut exec_step,
161+
CopyEvent {
162+
src_addr: 0,
163+
src_addr_end: state.tx.call_data.len() as u64,
164+
src_type: CopyDataType::TxCalldata,
165+
src_id: NumberOrHash::Number(state.tx.id as usize),
166+
dst_addr: 0,
167+
dst_type: CopyDataType::RlcAcc,
168+
dst_id: NumberOrHash::Number(0),
169+
log_id: None,
170+
rw_counter_start: state.block_ctx.rwc,
171+
bytes: state.tx.call_data.iter().map(|b| (*b, false)).collect(),
172+
},
173+
);
174+
}
175+
dbg!((state.tx.id, state.tx.call_data.len(), &state.tx.call_data));
151176
}
152177

153178
// There are 4 branches from here.

zkevm-circuits/src/evm_circuit/execution/begin_tx.rs

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)