Skip to content

Commit

Permalink
5.7(cont) Words64TryIntoU256LE Does Not Automatically Pad Input
Browse files Browse the repository at this point in the history
  • Loading branch information
tiagofneto committed Oct 31, 2023
1 parent 8c74f18 commit 97aad21
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 29 deletions.
30 changes: 9 additions & 21 deletions src/data_structures/eth_mpt.cairo
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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');
}
Expand Down Expand Up @@ -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')
}
Expand Down Expand Up @@ -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')
}
}
Expand Down
7 changes: 1 addition & 6 deletions src/data_structures/tests/test_eth_mpt.cairo
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -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;
};
},
Expand Down
52 changes: 50 additions & 2 deletions src/utils/types/tests/test_words64.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
41 changes: 41 additions & 0 deletions src/utils/types/words64.cairo
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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<u256, felt252> {
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...
Expand Down

0 comments on commit 97aad21

Please sign in to comment.