Skip to content

Commit

Permalink
load word to bytes
Browse files Browse the repository at this point in the history
  • Loading branch information
lordshashank committed Sep 28, 2024
1 parent d4a7873 commit e17ecd9
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 114 deletions.
9 changes: 6 additions & 3 deletions crates/evm/src/instructions/environmental_information.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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};


Expand Down Expand Up @@ -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
Expand Down
27 changes: 17 additions & 10 deletions crates/evm/src/instructions/system_operations.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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};


Expand All @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand Down
23 changes: 20 additions & 3 deletions crates/evm/src/memory.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -307,7 +308,10 @@ pub(crate) impl InternalMemoryMethods of InternalMemoryTrait {
let nonzero_mask_f: NonZero<u256> = 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();
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down
28 changes: 18 additions & 10 deletions crates/evm/src/precompiles/ec_operations/ec_add.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) },
Expand Down
22 changes: 14 additions & 8 deletions crates/evm/src/precompiles/ec_operations/ec_mul.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) },
Expand Down
80 changes: 0 additions & 80 deletions crates/utils/src/helpers.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -120,34 +120,6 @@ pub fn split_word_128(value: u256, ref dst: Array<u8>) {
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<u8>) -> 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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit e17ecd9

Please sign in to comment.