From ccc4202de3df228754b21b1c8cab1e5899c1b6e3 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Wed, 3 Aug 2022 22:54:17 -0700 Subject: [PATCH] Packing memory operations --- evm/src/cpu/kernel/aggregator.rs | 2 + evm/src/cpu/kernel/asm/memory/packing.asm | 45 +++++++++++++++++++++++ evm/src/cpu/kernel/interpreter.rs | 16 +++++++- evm/src/cpu/kernel/tests/mod.rs | 1 + evm/src/cpu/kernel/tests/packing.rs | 29 +++++++++++++++ 5 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 evm/src/cpu/kernel/asm/memory/packing.asm create mode 100644 evm/src/cpu/kernel/tests/packing.rs diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 4c8a1173..5f28d89b 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -25,6 +25,8 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/halt.asm"), include_str!("asm/memory/core.asm"), include_str!("asm/memory/memcpy.asm"), + include_str!("asm/memory/metadata.asm"), + include_str!("asm/memory/packing.asm"), include_str!("asm/memory/txn_fields.asm"), include_str!("asm/rlp/encode.asm"), include_str!("asm/rlp/decode.asm"), diff --git a/evm/src/cpu/kernel/asm/memory/packing.asm b/evm/src/cpu/kernel/asm/memory/packing.asm new file mode 100644 index 00000000..35bc673e --- /dev/null +++ b/evm/src/cpu/kernel/asm/memory/packing.asm @@ -0,0 +1,45 @@ +// Methods for encoding integers as bytes in memory, as well as the reverse, +// decoding bytes as integers. All big-endian. + +global mload_packing: + // stack: context, segment, offset, len, retdest + // TODO + // stack: value + +global mstore_unpacking: + // stack: context, segment, offset, value, len, retdest + // We will enumerate i in (32 - len)..32. + // That way BYTE(i, value) will give us the bytes we want. + DUP5 // len + PUSH 32 + SUB + +mstore_unpacking_loop: + // stack: i, context, segment, offset, value, len, retdest + // If i == 32, finish. + DUP1 + %eq_const(32) + %jumpi(mstore_unpacking_finish) + + // stack: i, context, segment, offset, value, len, retdest + DUP5 // value + DUP2 // i + BYTE + // stack: value[i], i, context, segment, offset, value, len, retdest + DUP5 DUP5 DUP5 // context, segment, offset + // stack: context, segment, offset, value[i], i, context, segment, offset, value, len, retdest + MSTORE_GENERAL + // stack: i, context, segment, offset, value, len, retdest + + // Increment offset. + SWAP3 %add_const(1) SWAP3 + // Increment i. + %add_const(1) + + %jump(mstore_unpacking_loop) + +mstore_unpacking_finish: + // stack: i, context, segment, offset, value, len, retdest + %pop6 + // stack: retdest + JUMP diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 6a5b794f..5d1938e5 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -196,7 +196,7 @@ impl<'a> Interpreter<'a> { 0x17 => self.run_or(), // "OR", 0x18 => self.run_xor(), // "XOR", 0x19 => self.run_not(), // "NOT", - 0x1a => todo!(), // "BYTE", + 0x1a => self.run_byte(), // "BYTE", 0x1b => self.run_shl(), // "SHL", 0x1c => todo!(), // "SHR", 0x1d => todo!(), // "SAR", @@ -380,6 +380,20 @@ impl<'a> Interpreter<'a> { self.push(!x); } + fn run_byte(&mut self) { + dbg!("byte"); + let i = self.pop(); + let x = self.pop(); + let result = if i > 32.into() { + 0 + } else { + let mut bytes = [0; 32]; + x.to_big_endian(&mut bytes); + bytes[i.as_usize()] + }; + self.push(result.into()); + } + fn run_shl(&mut self) { let shift = self.pop(); let x = self.pop(); diff --git a/evm/src/cpu/kernel/tests/mod.rs b/evm/src/cpu/kernel/tests/mod.rs index ab92c5a0..1396f9f2 100644 --- a/evm/src/cpu/kernel/tests/mod.rs +++ b/evm/src/cpu/kernel/tests/mod.rs @@ -1,6 +1,7 @@ mod curve_ops; mod ecrecover; mod exp; +mod packing; mod rlp; mod transaction_parsing; diff --git a/evm/src/cpu/kernel/tests/packing.rs b/evm/src/cpu/kernel/tests/packing.rs new file mode 100644 index 00000000..44b9242d --- /dev/null +++ b/evm/src/cpu/kernel/tests/packing.rs @@ -0,0 +1,29 @@ +use anyhow::Result; + +use crate::cpu::kernel::aggregator::KERNEL; +use crate::cpu::kernel::interpreter::Interpreter; +use crate::memory::segments::Segment; + +#[test] +fn test_mstore_unpacking() -> Result<()> { + let mstore_unpacking = KERNEL.global_labels["mstore_unpacking"]; + + let retdest = 0xDEADBEEFu32.into(); + let len = 4.into(); + let value = 0xABCD1234u32.into(); + let offset = 0.into(); + let segment = (Segment::TxnData as u32).into(); + let context = 0.into(); + let initial_stack = vec![retdest, len, value, offset, segment, context]; + + let mut interpreter = Interpreter::new_with_kernel(mstore_unpacking, initial_stack); + + interpreter.run()?; + assert_eq!(interpreter.stack(), vec![]); + assert_eq!( + &interpreter.get_txn_data(), + &[0xAB.into(), 0xCD.into(), 0x12.into(), 0x34.into()] + ); + + Ok(()) +}