From 97aad214ad4fb32576eb0f183d09c24f0bad969d Mon Sep 17 00:00:00 2001 From: tiagofneto Date: Tue, 31 Oct 2023 11:15:07 +0600 Subject: [PATCH] 5.7(cont) Words64TryIntoU256LE Does Not Automatically Pad Input --- src/data_structures/eth_mpt.cairo | 30 ++++------- src/data_structures/tests/test_eth_mpt.cairo | 7 +-- src/utils/types/tests/test_words64.cairo | 52 +++++++++++++++++++- src/utils/types/words64.cairo | 41 +++++++++++++++ 4 files changed, 101 insertions(+), 29 deletions(-) diff --git a/src/data_structures/eth_mpt.cairo b/src/data_structures/eth_mpt.cairo index 655bea2..dbcf957 100644 --- a/src/data_structures/eth_mpt.cairo +++ b/src/data_structures/eth_mpt.cairo @@ -1,7 +1,7 @@ use cairo_lib::hashing::keccak::keccak_cairo_words64; use cairo_lib::encoding::rlp::{RLPItem, rlp_decode, rlp_decode_list_lazy}; use cairo_lib::utils::types::byte::{Byte, ByteTrait}; -use cairo_lib::utils::bitwise::{right_shift, left_shift, reverse_endianness_u256}; +use cairo_lib::utils::bitwise::{right_shift, left_shift}; use cairo_lib::utils::types::words64::{Words64, Words64Trait}; use cairo_lib::utils::math::pow; @@ -113,8 +113,8 @@ impl MPTImpl of MPTTrait { if current_hash_words.len() == 0 { 0 } else { - match current_hash_words.as_u256_be(32) { - Result::Ok(h) => reverse_endianness_u256(h), + match current_hash_words.as_u256_le(32) { + Result::Ok(h) => h, Result::Err(_) => { break Result::Err('Invalid hash'); } @@ -272,26 +272,16 @@ impl MPTImpl of MPTTrait { let n_nibbles = (first_len * 2) - 1; if prefix == 0 { - match second.as_u256_be(32) { + match second.as_u256_le(32) { Result::Ok(n) => Result::Ok( - ( - MPTNode::Extension( - (first, reverse_endianness_u256(n), 2, n_nibbles - 1) - ), - rlp_byte_len - ) + (MPTNode::Extension((first, n, 2, n_nibbles - 1)), rlp_byte_len) ), Result::Err(_) => Result::Err('Invalid next node') } } else if prefix == 1 { - match second.as_u256_be(32) { + match second.as_u256_le(32) { Result::Ok(n) => Result::Ok( - ( - MPTNode::Extension( - (first, reverse_endianness_u256(n), 1, n_nibbles) - ), - rlp_byte_len - ) + (MPTNode::Extension((first, n, 1, n_nibbles)), rlp_byte_len) ), Result::Err(_) => Result::Err('Invalid next node') } @@ -320,10 +310,8 @@ impl MPTImpl of MPTTrait { RLPItem::Bytes(_) => Result::Err('Invalid RLP for node'), RLPItem::List(l) => { let (hash_words, _) = *l.at(0); - match hash_words.as_u256_be(32) { - Result::Ok(h) => Result::Ok( - (MPTNode::LazyBranch(reverse_endianness_u256(h)), rlp_byte_len) - ), + match hash_words.as_u256_le(32) { + Result::Ok(h) => Result::Ok((MPTNode::LazyBranch(h), rlp_byte_len)), Result::Err(_) => Result::Err('Invalid hash') } } diff --git a/src/data_structures/tests/test_eth_mpt.cairo b/src/data_structures/tests/test_eth_mpt.cairo index ff1e06d..42556d5 100644 --- a/src/data_structures/tests/test_eth_mpt.cairo +++ b/src/data_structures/tests/test_eth_mpt.cairo @@ -1,6 +1,5 @@ use cairo_lib::data_structures::eth_mpt::{MPTNode, MPTTrait}; use cairo_lib::utils::types::words64::{Words64, Words64Trait}; -use cairo_lib::utils::bitwise::reverse_endianness_u256; #[test] #[available_gas(9999999999)] @@ -108,11 +107,7 @@ fn test_decode_rlp_node_branch() { if i >= hashes.len() { break (); } - assert( - reverse_endianness_u256((*hashes.at(i)).as_u256_be(32).unwrap()) == *expected - .at(i), - 'Wrong hash' - ); + assert((*hashes.at(i)).as_u256_le(32).unwrap() == *expected.at(i), 'Wrong hash'); i += 1; }; }, diff --git a/src/utils/types/tests/test_words64.cairo b/src/utils/types/tests/test_words64.cairo index 9618d34..d0ee0a1 100644 --- a/src/utils/types/tests/test_words64.cairo +++ b/src/utils/types/tests/test_words64.cairo @@ -70,12 +70,60 @@ fn test_as_u256_be_not_full() { #[test] #[available_gas(99999999)] fn test_as_u256_be_not_full_start() { - let words = array![0x2e8b632605e20000, 0x480829ebcee54bc4, 0xb6f2392a].span(); + let words = array![0x008b632605e20000, 0x480829ebcee54bc4, 0xb6f2392a].span(); - let expected = 0xe20526638b2ec44be5ceeb2908482a39f2b6; + let expected = 0xe20526638b00c44be5ceeb2908482a39f2b6; assert(words.as_u256_be(20).unwrap() == expected, 'Wrong value'); } +#[test] +#[available_gas(99999999)] +fn test_as_u256_be_not_full_end() { + let words = array![0x2e8b632605e20000, 0x480829ebcee54bc4, 0xb6f2392a].span(); + + let expected = 0x0000e20526638b2ec44be5ceeb2908482a39f2b600; + assert(words.as_u256_be(21).unwrap() == expected, 'Wrong value'); +} + +#[test] +#[available_gas(99999999)] +fn test_as_u256_le_full() { + let words = array![ + 0x2e8b632605e21673, 0x480829ebcee54bc4, 0xb6f239256ff310f9, 0x09898da43a5d35f4, + ] + .span(); + + let expected = 0x09898DA43A5D35F4B6F239256FF310F9480829EBCEE54BC42E8B632605E21673; + assert(words.as_u256_le(32).unwrap() == expected, 'Wrong value'); +} + +#[test] +#[available_gas(99999999)] +fn test_as_u256_le_not_full() { + let words = array![0x2e8b632605e21673, 0x480829ebcee54bc4, 0xb6f2392a].span(); + + let expected: u256 = 0xB6F2392A480829EBCEE54BC42E8B632605E21673000000000000000000000000; + assert(words.as_u256_le(20).unwrap() == expected, 'Wrong value'); +} + +#[test] +#[available_gas(99999999)] +fn test_as_u256_le_not_full_start() { + let words = array![0x008b632605e20000, 0x480829ebcee54bc4, 0xb6f2392a].span(); + + let expected = 0xB6F2392A480829EBCEE54BC4008B632605E20000000000000000000000000000; + assert(words.as_u256_le(20).unwrap() == expected, 'Wrong value'); +} + +#[test] +#[available_gas(99999999)] +fn test_as_u256_le_not_full_end() { + let words = array![0x008b632605e20000, 0x480829ebcee54bc4, 0xb6f2392a].span(); + + let expected: u256 = 0x00B6F2392A480829EBCEE54BC4008B632605E200000000000000000000000000; + assert(words.as_u256_le(21).unwrap() == expected, 'Wrong value'); +} + #[test] #[available_gas(99999999)] fn test_reverse_endianness_u64() { diff --git a/src/utils/types/words64.cairo b/src/utils/types/words64.cairo index 8c4d39b..23ef8f1 100644 --- a/src/utils/types/words64.cairo +++ b/src/utils/types/words64.cairo @@ -1,4 +1,5 @@ use cairo_lib::utils::bitwise::left_shift; +use cairo_lib::utils::math::pow; // @notice Represents a span of 64 bit words // @dev In many cases it's expected that the words are in little endian, but the overall order is big endian @@ -56,6 +57,46 @@ impl Words64Impl of Words64Trait { } } + // @notice Converts little endian 64 bit words to a little endian u256 + // @param bytes_used The number of bytes used + // @return The little endian u256 representation of the words + fn as_u256_le(self: Words64, bytes_used: usize) -> Result { + let len = self.len(); + + if len > 4 { + return Result::Err('Too many words'); + } + + if len == 0 || bytes_used == 0 { + return Result::Ok(0); + } + + let mut len_last_word = bytes_used % 8; + if len_last_word == 0 { + len_last_word = 8; + } + + let mut output: u256 = 0; + + let word_pow2 = 0x10000000000000000; // 2 ** 64 + let mut current_pow2: u256 = pow(2, (32 - bytes_used.into()) * 8); + + let mut i = 0; + loop { + if i == len { + break Result::Ok(output); + } + + output = output | ((*self.at(i)).into() * current_pow2); + + if i < len - 1 { + current_pow2 = current_pow2 * word_pow2; + } + + i += 1; + } + } + // @notice Slices 64 bit little endian words from a starting byte and a length // @param start The starting byte // The starting byte is counted from the left. Example: 0xabcdef -> byte 0 is 0xab, byte 1 is 0xcd...