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

memory_opt_opcodes: constraints for MLOAD/MSTORE/MSTORE8/CALLDATALOAD #533

Merged
merged 6 commits into from
Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bus-mapping/src/circuit_input_builder/input_state_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ impl<'a> CircuitInputStateRef<'a> {
step: &mut ExecStep,
address: MemoryAddress, //Caution: make sure this address = slot passing
value: Word,
// TODO: take value_prev as parameter.
) -> Result<(), Error> {
let call_id = self.call()?.call_id;
self.push_op(step, RW::WRITE, MemoryWordOp::new(call_id, address, value));
Expand Down
2 changes: 1 addition & 1 deletion bus-mapping/src/evm/opcodes/calldataload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl Opcode for Calldataload {
word_right_bytes
.clone_from_slice(&memory.0[(slot + 32) as usize..(slot + 64) as usize]);

let addr_right_Word = Word::from_little_endian(&word_right_bytes);
let addr_right_Word = Word::from_big_endian(&word_right_bytes);

state.push_op(
&mut exec_step,
Expand Down
50 changes: 14 additions & 36 deletions bus-mapping/src/evm/opcodes/mload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,57 +28,35 @@ impl Opcode for Mload {
// Manage first stack read at latest stack position
state.stack_read(&mut exec_step, stack_position, stack_value_read)?;

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

// TODO: get two memory words (slot, slot + 32) at address if offset != 0, otherwise get one
// word at slot.
let mut memory = state.call_ctx_mut()?.memory.clone();
println!("before mload memory length is {}", memory.0.len());

let offset = stack_value_read.as_u64();
// expand to offset + 64 to enusre addr_right_Word without out of boundary
let minimal_length = offset + 64;

memory.extend_at_least(minimal_length as usize);

let shift = offset % 32;
let slot = offset - shift;
println!(
"minimal_length {} , slot {}, shift {}, memory_length {}",
minimal_length,
slot,
shift,
memory.0.len()
);
println!("shift {}, slot {}", shift, slot);

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

let addr_left_Word = Word::from_big_endian(&slot_bytes);
// TODO: edge case: if shift = 0, skip to read right word ?
let mut word_right_bytes: [u8; 32] = [0; 32];
slot_bytes.clone_from_slice(&memory.0[(slot + 32) as usize..(slot + 64) as usize]);

let addr_right_Word = Word::from_little_endian(&word_right_bytes);
(
Word::from_big_endian(&slots_content[..32]),
Word::from_big_endian(&slots_content[32..64]),
)
};

// First stack write
//
state.stack_write(&mut exec_step, stack_position, mem_read_value)?;

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

// reconstruction
// "minimal_length - 32" subtract 32 as actual expansion size
// Expand memory if needed.
state
.call_ctx_mut()?
.memory
.extend_at_least((minimal_length - 32) as usize);
.extend_at_least((offset + 32) as usize);

Ok(vec![exec_step])
}
Expand Down
107 changes: 31 additions & 76 deletions bus-mapping/src/evm/opcodes/mstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,102 +30,57 @@ impl<const IS_MSTORE8: bool> Opcode for Mstore<IS_MSTORE8> {
let value_pos = geth_step.stack.nth_last_filled(1);
state.stack_read(&mut exec_step, value_pos, value)?;

// First mem write -> 32 MemoryOp generated.
let offset_addr: MemoryAddress = offset.try_into()?;
// TODO: get two memory words (slot, slot + 32) at address if offset != 0, otherwise get one
// word at slot.

let mut memory = state.call_ctx_mut()?.memory.clone();
// expand memory size + 64 as slot
let minimal_length = offset_addr.0
+ if IS_MSTORE8 {
1
} else {
64 /* 32 */
};
println!(
"minimal_length {} , IS_MSTORE8 {}, memory_length {}, value {}",
minimal_length,
IS_MSTORE8,
memory.0.len(),
value
);

memory.extend_at_least(minimal_length);

let offset_u64 = offset.as_u64();
let offset_u64 = offset.as_u64() as usize;
let shift = offset_u64 % 32;
let slot = offset_u64 - shift;
println!("shift {}, slot {}", shift, slot);
// reconstruct memory with value
match IS_MSTORE8 {
true => {
//let bytes= *value.to_le_bytes().to_vec();
let val = *value.to_le_bytes().first().unwrap();
let word_v8 = Word::from(val as u64);
memory.0[offset_u64 as usize] = val;
}
false => {
let bytes = value.to_be_bytes();
memory[offset_u64 as usize..offset_u64 as usize + 32].copy_from_slice(&bytes);
}
}

// after memory construction, we can get slot_Word(left_Word), right_word to fill buss
// mapping.
let mut slot_bytes: [u8; 32] = [0; 32];
let mut addr_left_Word = Word::zero();
let (left_word, right_word) = {
// Get the memory chunk that contains the word, starting at an aligned slot address.
let mut slots_content = state.call_ctx()?.memory.read_chunk(slot.into(), 64.into());

// reconstruct memory with value
match IS_MSTORE8 {
true => {
let val = *value.to_le_bytes().first().unwrap();
slots_content[shift] = val;
}
false => {
let bytes = value.to_be_bytes();
slots_content[shift..shift + 32].copy_from_slice(&bytes);
}
}

if IS_MSTORE8 {
let byte = *value.to_le_bytes().first().unwrap();
addr_left_Word = Word::from(byte as u64);
} else {
slot_bytes.clone_from_slice(&memory.0[(slot as usize)..(slot as usize + 32)]);
addr_left_Word = Word::from_big_endian(&slot_bytes);
}
// after memory construction, we can get the left and right words to fill bus mapping.
(
Word::from_big_endian(&slots_content[..32]),
Word::from_big_endian(&slots_content[32..64]),
)
};

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

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

// address = 100, slot = 96 shift = 4
// value = address + 32 = 132
// left word = slot ( 96...96+32 bytes) slot = 128...128+32 word(fill 0)
match IS_MSTORE8 {
true => {
// memory write operation for mstore8
state.memory_write_word(&mut exec_step, slot.into(), addr_left_Word)?;
}
false => {
// lookup left word
state.memory_write_word(&mut exec_step, slot.into(), addr_left_Word)?;
// look up right word
state.memory_write_word(&mut exec_step, (slot + 32).into(), addr_right_Word)?;
}
// TODO: edge case: if shift = 0, we could skip the right word?
}

// reconstruction
let offset = geth_step.stack.nth_last(0)?;
let value = geth_step.stack.nth_last(1)?;
let offset_addr: MemoryAddress = offset.try_into()?;

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

let mem_starts = offset_addr.0;

match IS_MSTORE8 {
true => {
let val = *value.to_le_bytes().first().unwrap();
state.call_ctx_mut()?.memory.0[mem_starts] = val;
state.call_ctx_mut()?.memory.0[offset_u64] = val;
}
false => {
let bytes = value.to_be_bytes();
state.call_ctx_mut()?.memory[mem_starts..mem_starts + 32].copy_from_slice(&bytes);
state.call_ctx_mut()?.memory[offset_u64..offset_u64 + 32].copy_from_slice(&bytes);
}
}

Expand Down
Loading