Skip to content
This repository was archived by the owner on Apr 18, 2025. It is now read-only.

Commit dfc787e

Browse files
naureAurélien Nicolas
andauthored
memory_opt_opcodes: constraints for MLOAD/MSTORE/MSTORE8/CALLDATALOAD (#533)
* memory_opt_opcodes: constraints for MLOAD/MSTORE/MSTORE8 * memory_opt_opcodes: refactor all memory alignment logic into a gadget * memory_opt_opcodes: connect calldata and memory values * memory_opt_opcodes: switch to BE-order to match current copy circuit --------- Co-authored-by: Aurélien Nicolas <info@nau.re>
1 parent 1224c0f commit dfc787e

File tree

10 files changed

+481
-206
lines changed

10 files changed

+481
-206
lines changed

bus-mapping/src/circuit_input_builder/input_state_ref.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ impl<'a> CircuitInputStateRef<'a> {
279279
step: &mut ExecStep,
280280
address: MemoryAddress, //Caution: make sure this address = slot passing
281281
value: Word,
282+
// TODO: take value_prev as parameter.
282283
) -> Result<(), Error> {
283284
let call_id = self.call()?.call_id;
284285
self.push_op(step, RW::WRITE, MemoryWordOp::new(call_id, address, value));

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ impl Opcode for Calldataload {
106106
word_right_bytes
107107
.clone_from_slice(&memory.0[(slot + 32) as usize..(slot + 64) as usize]);
108108

109-
let addr_right_Word = Word::from_little_endian(&word_right_bytes);
109+
let addr_right_Word = Word::from_big_endian(&word_right_bytes);
110110

111111
state.push_op(
112112
&mut exec_step,

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

Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -28,57 +28,35 @@ impl Opcode for Mload {
2828
// Manage first stack read at latest stack position
2929
state.stack_read(&mut exec_step, stack_position, stack_value_read)?;
3030

31-
// Read the memory
32-
let mut mem_read_addr: MemoryAddress = stack_value_read.try_into()?;
33-
// Accesses to memory that hasn't been initialized are valid, and return
34-
// 0.
31+
// Read the memory value from the next step of the trace.
3532
let mem_read_value = geth_steps[1].stack.last()?;
3633

37-
// TODO: get two memory words (slot, slot + 32) at address if offset != 0, otherwise get one
38-
// word at slot.
39-
let mut memory = state.call_ctx_mut()?.memory.clone();
40-
println!("before mload memory length is {}", memory.0.len());
41-
4234
let offset = stack_value_read.as_u64();
43-
// expand to offset + 64 to enusre addr_right_Word without out of boundary
44-
let minimal_length = offset + 64;
45-
46-
memory.extend_at_least(minimal_length as usize);
47-
4835
let shift = offset % 32;
4936
let slot = offset - shift;
50-
println!(
51-
"minimal_length {} , slot {}, shift {}, memory_length {}",
52-
minimal_length,
53-
slot,
54-
shift,
55-
memory.0.len()
56-
);
37+
println!("shift {}, slot {}", shift, slot);
5738

58-
let mut slot_bytes: [u8; 32] = [0; 32];
59-
slot_bytes.clone_from_slice(&memory.0[(slot as usize)..(slot as usize + 32)]);
39+
let (left_word, right_word) = {
40+
// Get the memory chunk that contains the word, starting at an aligned slot address.
41+
let slots_content = state.call_ctx()?.memory.read_chunk(slot.into(), 64.into());
6042

61-
let addr_left_Word = Word::from_big_endian(&slot_bytes);
62-
// TODO: edge case: if shift = 0, skip to read right word ?
63-
let mut word_right_bytes: [u8; 32] = [0; 32];
64-
slot_bytes.clone_from_slice(&memory.0[(slot + 32) as usize..(slot + 64) as usize]);
65-
66-
let addr_right_Word = Word::from_little_endian(&word_right_bytes);
43+
(
44+
Word::from_big_endian(&slots_content[..32]),
45+
Word::from_big_endian(&slots_content[32..64]),
46+
)
47+
};
6748

6849
// First stack write
69-
//
7050
state.stack_write(&mut exec_step, stack_position, mem_read_value)?;
7151

72-
// First mem read -> 32 MemoryOp generated.
73-
state.memory_read_word(&mut exec_step, slot.into(), addr_left_Word)?;
74-
state.memory_read_word(&mut exec_step, (slot + 32).into(), addr_right_Word)?;
52+
state.memory_read_word(&mut exec_step, slot.into(), left_word)?;
53+
state.memory_read_word(&mut exec_step, (slot + 32).into(), right_word)?;
7554

76-
// reconstruction
77-
// "minimal_length - 32" subtract 32 as actual expansion size
55+
// Expand memory if needed.
7856
state
7957
.call_ctx_mut()?
8058
.memory
81-
.extend_at_least((minimal_length - 32) as usize);
59+
.extend_at_least((offset + 32) as usize);
8260

8361
Ok(vec![exec_step])
8462
}

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

Lines changed: 31 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -30,102 +30,57 @@ impl<const IS_MSTORE8: bool> Opcode for Mstore<IS_MSTORE8> {
3030
let value_pos = geth_step.stack.nth_last_filled(1);
3131
state.stack_read(&mut exec_step, value_pos, value)?;
3232

33-
// First mem write -> 32 MemoryOp generated.
34-
let offset_addr: MemoryAddress = offset.try_into()?;
35-
// TODO: get two memory words (slot, slot + 32) at address if offset != 0, otherwise get one
36-
// word at slot.
37-
38-
let mut memory = state.call_ctx_mut()?.memory.clone();
39-
// expand memory size + 64 as slot
40-
let minimal_length = offset_addr.0
41-
+ if IS_MSTORE8 {
42-
1
43-
} else {
44-
64 /* 32 */
45-
};
46-
println!(
47-
"minimal_length {} , IS_MSTORE8 {}, memory_length {}, value {}",
48-
minimal_length,
49-
IS_MSTORE8,
50-
memory.0.len(),
51-
value
52-
);
53-
54-
memory.extend_at_least(minimal_length);
55-
56-
let offset_u64 = offset.as_u64();
33+
let offset_u64 = offset.as_u64() as usize;
5734
let shift = offset_u64 % 32;
5835
let slot = offset_u64 - shift;
5936
println!("shift {}, slot {}", shift, slot);
60-
// reconstruct memory with value
61-
match IS_MSTORE8 {
62-
true => {
63-
//let bytes= *value.to_le_bytes().to_vec();
64-
let val = *value.to_le_bytes().first().unwrap();
65-
let word_v8 = Word::from(val as u64);
66-
memory.0[offset_u64 as usize] = val;
67-
}
68-
false => {
69-
let bytes = value.to_be_bytes();
70-
memory[offset_u64 as usize..offset_u64 as usize + 32].copy_from_slice(&bytes);
71-
}
72-
}
7337

74-
// after memory construction, we can get slot_Word(left_Word), right_word to fill buss
75-
// mapping.
76-
let mut slot_bytes: [u8; 32] = [0; 32];
77-
let mut addr_left_Word = Word::zero();
38+
let (left_word, right_word) = {
39+
// Get the memory chunk that contains the word, starting at an aligned slot address.
40+
let mut slots_content = state.call_ctx()?.memory.read_chunk(slot.into(), 64.into());
41+
42+
// reconstruct memory with value
43+
match IS_MSTORE8 {
44+
true => {
45+
let val = *value.to_le_bytes().first().unwrap();
46+
slots_content[shift] = val;
47+
}
48+
false => {
49+
let bytes = value.to_be_bytes();
50+
slots_content[shift..shift + 32].copy_from_slice(&bytes);
51+
}
52+
}
7853

79-
if IS_MSTORE8 {
80-
let byte = *value.to_le_bytes().first().unwrap();
81-
addr_left_Word = Word::from(byte as u64);
82-
} else {
83-
slot_bytes.clone_from_slice(&memory.0[(slot as usize)..(slot as usize + 32)]);
84-
addr_left_Word = Word::from_big_endian(&slot_bytes);
85-
}
54+
// after memory construction, we can get the left and right words to fill bus mapping.
55+
(
56+
Word::from_big_endian(&slots_content[..32]),
57+
Word::from_big_endian(&slots_content[32..64]),
58+
)
59+
};
8660

87-
// TODO: edge case: if shift = 0, no need to right word
88-
let mut word_right_bytes: [u8; 32] = [0; 32];
89-
let cur_memory_size = memory.0.len();
90-
// when is_msotre8, skip word_right as mstore8 only affect one word.
61+
// memory write left word for mstore8 and mstore.
62+
state.memory_write_word(&mut exec_step, slot.into(), left_word)?;
9163

92-
// construct right word
93-
let addr_right_Word = Word::from_big_endian(&word_right_bytes);
64+
if !IS_MSTORE8 {
65+
// memory write right word for mstore
66+
state.memory_write_word(&mut exec_step, (slot + 32).into(), right_word)?;
9467

95-
// address = 100, slot = 96 shift = 4
96-
// value = address + 32 = 132
97-
// left word = slot ( 96...96+32 bytes) slot = 128...128+32 word(fill 0)
98-
match IS_MSTORE8 {
99-
true => {
100-
// memory write operation for mstore8
101-
state.memory_write_word(&mut exec_step, slot.into(), addr_left_Word)?;
102-
}
103-
false => {
104-
// lookup left word
105-
state.memory_write_word(&mut exec_step, slot.into(), addr_left_Word)?;
106-
// look up right word
107-
state.memory_write_word(&mut exec_step, (slot + 32).into(), addr_right_Word)?;
108-
}
68+
// TODO: edge case: if shift = 0, we could skip the right word?
10969
}
11070

11171
// reconstruction
112-
let offset = geth_step.stack.nth_last(0)?;
113-
let value = geth_step.stack.nth_last(1)?;
114-
let offset_addr: MemoryAddress = offset.try_into()?;
11572

116-
let minimal_length = offset_addr.0 + if IS_MSTORE8 { 1 } else { 32 };
73+
let minimal_length = offset_u64 + if IS_MSTORE8 { 1 } else { 32 };
11774
state.call_ctx_mut()?.memory.extend_at_least(minimal_length);
11875

119-
let mem_starts = offset_addr.0;
120-
12176
match IS_MSTORE8 {
12277
true => {
12378
let val = *value.to_le_bytes().first().unwrap();
124-
state.call_ctx_mut()?.memory.0[mem_starts] = val;
79+
state.call_ctx_mut()?.memory.0[offset_u64] = val;
12580
}
12681
false => {
12782
let bytes = value.to_be_bytes();
128-
state.call_ctx_mut()?.memory[mem_starts..mem_starts + 32].copy_from_slice(&bytes);
83+
state.call_ctx_mut()?.memory[offset_u64..offset_u64 + 32].copy_from_slice(&bytes);
12984
}
13085
}
13186

0 commit comments

Comments
 (0)