From e17ecd94ea7f56c60c2b4fe737ea714992215be0 Mon Sep 17 00:00:00 2001 From: lordforever Date: Sat, 28 Sep 2024 19:18:05 +0530 Subject: [PATCH] load word to bytes --- .../environmental_information.cairo | 9 ++- .../src/instructions/system_operations.cairo | 27 ++++--- crates/evm/src/memory.cairo | 23 +++++- .../precompiles/ec_operations/ec_add.cairo | 28 ++++--- .../precompiles/ec_operations/ec_mul.cairo | 22 +++-- crates/utils/src/helpers.cairo | 80 ------------------- 6 files changed, 75 insertions(+), 114 deletions(-) diff --git a/crates/evm/src/instructions/environmental_information.cairo b/crates/evm/src/instructions/environmental_information.cairo index 2661198f..bc991b30 100644 --- a/crates/evm/src/instructions/environmental_information.cairo +++ b/crates/evm/src/instructions/environmental_information.cairo @@ -8,8 +8,9 @@ use crate::model::vm::{VM, VMTrait}; use crate::model::{AddressTrait}; use crate::stack::StackTrait; use crate::state::StateTrait; -use utils::helpers::{ceil32, load_word}; +use utils::helpers::{ceil32}; use utils::set::SetTrait; +use utils::traits::bytes::FromBytes; use utils::traits::{EthAddressIntoU256}; @@ -85,8 +86,10 @@ pub impl EnvironmentInformationImpl of EnvironmentInformationTrait { let bytes_len = core::cmp::min(32, calldata_len - offset); let sliced = calldata.slice(offset, bytes_len); - // Fill data to load with bytes in calldata - let mut data_to_load: u256 = load_word(bytes_len, sliced); + // Use from_be_bytes_partial to load the data + let mut data_to_load: u256 = sliced + .from_be_bytes_partial() + .expect('Failed to parse calldata'); // Fill the rest of the data to load with zeros // TODO: optimize once we have dw-based exponentiation diff --git a/crates/evm/src/instructions/system_operations.cairo b/crates/evm/src/instructions/system_operations.cairo index c15f55bf..936a338d 100644 --- a/crates/evm/src/instructions/system_operations.cairo +++ b/crates/evm/src/instructions/system_operations.cairo @@ -388,7 +388,8 @@ mod tests { use utils::constants::EMPTY_KECCAK; use utils::helpers::compute_starknet_address; use utils::helpers::load_word; - use utils::traits::bytes::U8SpanExTrait; + use utils::traits::bytes::{U8SpanExTrait, FromBytes}; + use utils::traits::{EthAddressIntoU256}; @@ -403,10 +404,11 @@ mod tests { vm.stack.push(32).expect('push failed'); vm.stack.push(0).expect('push failed'); - assert(vm.exec_return().is_ok(), 'Exec return failed'); - - // Then - assert(1000 == load_word(32, vm.return_data()), 'Wrong return_data'); + let return_data = vm.return_data(); + let parsed_return_data: u256 = return_data + .from_be_bytes_partial() + .expect('Failed to parse return data'); + assert(1000 == parsed_return_data, 'Wrong return_data'); assert(!vm.is_running(), 'vm should be stopped'); assert_eq!(vm.error, false); } @@ -424,8 +426,11 @@ mod tests { vm.stack.push(0).expect('push failed'); assert(vm.exec_revert().is_ok(), 'Exec revert failed'); - // Then - assert(1000 == load_word(32, vm.return_data()), 'Wrong return_data'); + let return_data = vm.return_data(); + let parsed_return_data: u256 = return_data + .from_be_bytes_partial() + .expect('Failed to parse return data'); + assert(1000 == parsed_return_data, 'Wrong return_data'); assert(!vm.is_running(), 'vm should be stopped'); assert_eq!(vm.error, true); } @@ -442,9 +447,11 @@ mod tests { vm.stack.push(32).expect('push failed'); vm.stack.push(1).expect('push failed'); assert(vm.exec_return().is_ok(), 'Exec return failed'); - - // Then - assert(256 == load_word(32, vm.return_data()), 'Wrong return_data'); + let return_data = vm.return_data(); + let parsed_return_data: u256 = return_data + .from_be_bytes_partial() + .expect('Failed to parse return data'); + assert(1000 == parsed_return_data, 'Wrong return_data'); assert(!vm.is_running(), 'vm should be stopped'); assert_eq!(vm.error, false); } diff --git a/crates/evm/src/memory.cairo b/crates/evm/src/memory.cairo index b24ec7ca..98945d76 100644 --- a/crates/evm/src/memory.cairo +++ b/crates/evm/src/memory.cairo @@ -6,6 +6,7 @@ use utils::constants::{ POW_2_72, POW_2_80, POW_2_88, POW_2_96, POW_2_104, POW_2_112, POW_2_120, POW_256_16 }; use utils::traits::array::ArrayExtTrait; +use utils::traits::bytes::FromBytes; use utils::{helpers, math::Bitshift}; #[derive(Destruct, Default)] @@ -307,7 +308,10 @@ pub(crate) impl InternalMemoryMethods of InternalMemoryTrait { let nonzero_mask_f: NonZero = mask_f.try_into().unwrap(); let (word_high, word_low) = DivRem::div_rem(word.into(), nonzero_mask_i); let (_, word_low_l) = DivRem::div_rem(word_low, nonzero_mask_f); - let bytes_as_word = helpers::load_word(elements.len(), elements); + let bytes_as_word: u128 = elements + .slice(0, elements.len()) + .from_be_bytes_partial() + .expect('Failed to parse word_low'); let new_w: u128 = (word_high * mask_i + bytes_as_word.into() * mask_f + word_low_l) .try_into() .unwrap(); @@ -545,7 +549,16 @@ pub(crate) impl InternalMemoryMethods of InternalMemoryTrait { ) { let word = self.items.get(chunk_index.into()); let word_high = (word.into() / start_mask); - let word_low = helpers::load_word(16 - start_offset_in_chunk, elements); + + // Calculate the number of bytes to read + let bytes_to_read = 16 - start_offset_in_chunk; + + // Slice the elements and convert to u128 using from_be_bytes_partial + let word_low: u128 = elements + .slice(0, bytes_to_read) + .from_be_bytes_partial() + .expect('Failed to parse word_low'); + let new_word: u128 = (word_high * start_mask + word_low.into()).try_into().unwrap(); self.items.insert(chunk_index.into(), new_word); } @@ -579,7 +592,11 @@ pub(crate) impl InternalMemoryMethods of InternalMemoryTrait { let word = self.items.get(chunk_index.into()); let word_low = (word.into() % end_mask); - let low_bytes = helpers::load_word(end_offset_in_chunk, elements); + // Convert the elements to u128 using from_be_bytes_partial + let low_bytes: u128 = elements + .slice(0, end_offset_in_chunk) + .from_be_bytes_partial() + .expect('Failed to parse low_bytes'); let new_word: u128 = (low_bytes.into() * end_mask + word_low).try_into().unwrap(); self.items.insert(chunk_index.into(), new_word); } diff --git a/crates/evm/src/precompiles/ec_operations/ec_add.cairo b/crates/evm/src/precompiles/ec_operations/ec_add.cairo index fe167792..91e08cb3 100644 --- a/crates/evm/src/precompiles/ec_operations/ec_add.cairo +++ b/crates/evm/src/precompiles/ec_operations/ec_add.cairo @@ -13,8 +13,8 @@ use crate::precompiles::ec_operations::{ eq_mod_p, eq_neg_mod_p, is_on_curve, double_ec_point_unchecked, BN254_PRIME_LIMBS, BN254_PRIME }; use garaga::core::circuit::AddInputResultTrait2; -use utils::helpers::{load_word}; -use utils::traits::bytes::{ToBytes, U8SpanExTrait}; +// use utils::helpers::{load_word}; +use utils::traits::bytes::{ToBytes, U8SpanExTrait, FromBytes}; const BASE_COST: u64 = 150; @@ -31,17 +31,25 @@ pub impl EcAdd of Precompile { // Pad the input to 128 bytes to avoid out-of-bounds accesses let mut input = input.pad_right_with_zeroes(128); - let x1_bytes = *(input.multi_pop_front::<32>().unwrap()); - let x1: u256 = load_word(U256_BYTES_LEN, x1_bytes.unbox().span()); + let x1: u256 = match input.slice(0, 32).from_be_bytes() { + Option::Some(x1) => x1, + Option::None => { return Result::Ok((gas, [].span())); } + }; - let y1_bytes = *(input.multi_pop_front::<32>().unwrap()); - let y1: u256 = load_word(U256_BYTES_LEN, y1_bytes.unbox().span()); + let y1: u256 = match input.slice(32, 32).from_be_bytes() { + Option::Some(y1) => y1, + Option::None => { return Result::Ok((gas, [].span())); } + }; - let x2_bytes = *(input.multi_pop_front::<32>().unwrap()); - let x2: u256 = load_word(U256_BYTES_LEN, x2_bytes.unbox().span()); + let x2: u256 = match input.slice(64, 32).from_be_bytes() { + Option::Some(x2) => x2, + Option::None => { return Result::Ok((gas, [].span())); } + }; - let y2_bytes = *(input.multi_pop_front::<32>().unwrap()); - let y2: u256 = load_word(U256_BYTES_LEN, y2_bytes.unbox().span()); + let y2: u256 = match input.slice(96, 32).from_be_bytes() { + Option::Some(y2) => y2, + Option::None => { return Result::Ok((gas, [].span())); } + }; let (x, y) = match ec_add(x1, y1, x2, y2) { Option::Some((x, y)) => { (x, y) }, diff --git a/crates/evm/src/precompiles/ec_operations/ec_mul.cairo b/crates/evm/src/precompiles/ec_operations/ec_mul.cairo index 6c94d7d9..fb714191 100644 --- a/crates/evm/src/precompiles/ec_operations/ec_mul.cairo +++ b/crates/evm/src/precompiles/ec_operations/ec_mul.cairo @@ -6,8 +6,8 @@ use crate::errors::EVMError; use crate::precompiles::Precompile; use crate::precompiles::ec_operations::ec_add::ec_safe_add; use crate::precompiles::ec_operations::{is_on_curve, double_ec_point_unchecked, BN254_PRIME}; -use utils::helpers::{load_word}; -use utils::traits::bytes::{ToBytes, U8SpanExTrait}; +// use utils::helpers::{load_word}; +use utils::traits::bytes::{ToBytes, U8SpanExTrait, FromBytes}; const BASE_COST: u64 = 6000; const U256_BYTES_LEN: usize = 32; @@ -23,14 +23,20 @@ pub impl EcMul of Precompile { // Pad the input to 128 bytes to avoid out-of-bounds accesses let mut input = input.pad_right_with_zeroes(96); - let x1_bytes = *(input.multi_pop_front::<32>().unwrap()); - let x1: u256 = load_word(U256_BYTES_LEN, x1_bytes.unbox().span()); + let x1: u256 = match input.slice(0, 32).from_be_bytes() { + Option::Some(x1) => x1, + Option::None => { return Result::Ok((gas, [].span())); } + }; - let y1_bytes = *(input.multi_pop_front::<32>().unwrap()); - let y1: u256 = load_word(U256_BYTES_LEN, y1_bytes.unbox().span()); + let y1: u256 = match input.slice(32, 32).from_be_bytes() { + Option::Some(y1) => y1, + Option::None => { return Result::Ok((gas, [].span())); } + }; - let s_bytes = *(input.multi_pop_front::<32>().unwrap()); - let s: u256 = load_word(U256_BYTES_LEN, s_bytes.unbox().span()); + let s: u256 = match input.slice(64, 32).from_be_bytes() { + Option::Some(s) => s, + Option::None => { return Result::Ok((gas, [].span())); } + }; let (x, y) = match ec_mul(x1, y1, s) { Option::Some((x, y)) => { (x, y) }, diff --git a/crates/utils/src/helpers.cairo b/crates/utils/src/helpers.cairo index d10b7ad6..fa1e6b17 100644 --- a/crates/utils/src/helpers.cairo +++ b/crates/utils/src/helpers.cairo @@ -120,34 +120,6 @@ pub fn split_word_128(value: u256, ref dst: Array) { split_word(value, 16, ref dst) } - -/// Loads a sequence of bytes into a single u256 in big-endian order. -/// -/// # Arguments -/// * `len` - The number of bytes to load. -/// * `words` - The span of bytes to load. -/// -/// # Returns -/// A `u256` value representing the loaded bytes in big-endian order. -pub fn load_word(mut len: usize, words: Span) -> u256 { - if len == 0 { - return 0; - } - - let mut current: u256 = 0; - let mut counter = 0; - - while len != 0 { - let loaded: u8 = *words[counter]; - let tmp = current * 256; - current = tmp + loaded.into(); - len -= 1; - counter += 1; - }; - - current -} - /// Converts a u256 to a bytes array represented by an array of u8 values in big-endian order. /// /// # Arguments @@ -236,58 +208,6 @@ mod tests { assert(1 == *bytes_array[30], 'wrong conversion'); } - #[test] - fn test_load_word() { - // No bytes to load - let res0 = helpers::load_word(0, ArrayTrait::new().span()); - assert(0 == res0, 'res0: wrong load'); - - // Single bytes value - let mut arr1 = ArrayTrait::new(); - arr1.append(0x01); - let res1 = helpers::load_word(1, arr1.span()); - assert(1 == res1, 'res1: wrong load'); - - let mut arr2 = ArrayTrait::new(); - arr2.append(0xff); - let res2 = helpers::load_word(1, arr2.span()); - assert(255 == res2, 'res2: wrong load'); - - // Two byte values - let mut arr3 = ArrayTrait::new(); - arr3.append(0x01); - arr3.append(0x00); - let res3 = helpers::load_word(2, arr3.span()); - assert(256 == res3, 'res3: wrong load'); - - let mut arr4 = ArrayTrait::new(); - arr4.append(0xff); - arr4.append(0xff); - let res4 = helpers::load_word(2, arr4.span()); - assert(65535 == res4, 'res4: wrong load'); - - // Four byte values - let mut arr5 = ArrayTrait::new(); - arr5.append(0xff); - arr5.append(0xff); - arr5.append(0xff); - arr5.append(0xff); - let res5 = helpers::load_word(4, arr5.span()); - assert(4294967295 == res5, 'res5: wrong load'); - - // 16 bytes values - let mut arr6 = ArrayTrait::new(); - arr6.append(0xff); - let mut counter: u128 = 0; - while counter < 15 { - arr6.append(0xff); - counter += 1; - }; - let res6 = helpers::load_word(16, arr6.span()); - assert(340282366920938463463374607431768211455 == res6, 'res6: wrong load'); - } - - #[test] fn test_split_word_le() { // Test with 0 value and 0 len