diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index e5daf05..9fdfb7b 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -49,3 +49,4 @@ jobs: with: fail_ci_if_error: true token: ${{ secrets.CODECOV_TOKEN }} + informational: true diff --git a/tree_hash/Cargo.toml b/tree_hash/Cargo.toml index e3a8ca9..5debd90 100644 --- a/tree_hash/Cargo.toml +++ b/tree_hash/Cargo.toml @@ -11,15 +11,15 @@ keywords = ["ethereum"] categories = ["cryptography::cryptocurrencies"] [dependencies] -ethereum-types = "0.14.1" -ethereum_hashing = "0.6.0" +alloy-primitives = "0.7.0" +ethereum_hashing = "0.7.0" smallvec = "1.6.1" [dev-dependencies] rand = "0.8.5" tree_hash_derive = { path = "../tree_hash_derive", version = "0.6.0" } -ethereum_ssz = "0.5" -ethereum_ssz_derive = "0.5" +ethereum_ssz = "0.6" +ethereum_ssz_derive = "0.6" [features] -arbitrary = ["ethereum-types/arbitrary"] +arbitrary = ["alloy-primitives/arbitrary"] diff --git a/tree_hash/src/impls.rs b/tree_hash/src/impls.rs index 277aedf..53d28f4 100644 --- a/tree_hash/src/impls.rs +++ b/tree_hash/src/impls.rs @@ -1,5 +1,5 @@ use super::*; -use ethereum_types::{H160, H256, U128, U256}; +use alloy_primitives::{Address, B256, U128, U256}; use std::sync::Arc; fn int_to_hash256(int: u64) -> Hash256 { @@ -109,9 +109,7 @@ impl TreeHash for U128 { } fn tree_hash_packed_encoding(&self) -> PackedEncoding { - let mut result = [0; 16]; - self.to_little_endian(&mut result); - PackedEncoding::from_slice(&result) + PackedEncoding::from_slice(&self.to_le_bytes::<{ Self::BYTES }>()) } fn tree_hash_packing_factor() -> usize { @@ -119,9 +117,7 @@ impl TreeHash for U128 { } fn tree_hash_root(&self) -> Hash256 { - let mut result = [0; HASHSIZE]; - self.to_little_endian(&mut result[0..16]); - Hash256::from_slice(&result) + Hash256::right_padding_from(&self.to_le_bytes::<{ Self::BYTES }>()) } } @@ -131,9 +127,7 @@ impl TreeHash for U256 { } fn tree_hash_packed_encoding(&self) -> PackedEncoding { - let mut result = [0; 32]; - self.to_little_endian(&mut result); - PackedEncoding::from_slice(&result) + PackedEncoding::from(self.to_le_bytes::<{ Self::BYTES }>()) } fn tree_hash_packing_factor() -> usize { @@ -141,20 +135,18 @@ impl TreeHash for U256 { } fn tree_hash_root(&self) -> Hash256 { - let mut result = [0; 32]; - self.to_little_endian(&mut result[..]); - Hash256::from_slice(&result) + Hash256::from(self.to_le_bytes::<{ Self::BYTES }>()) } } -impl TreeHash for H160 { +impl TreeHash for Address { fn tree_hash_type() -> TreeHashType { TreeHashType::Vector } fn tree_hash_packed_encoding(&self) -> PackedEncoding { let mut result = [0; 32]; - result[0..20].copy_from_slice(self.as_bytes()); + result[0..20].copy_from_slice(self.as_slice()); PackedEncoding::from_slice(&result) } @@ -164,18 +156,18 @@ impl TreeHash for H160 { fn tree_hash_root(&self) -> Hash256 { let mut result = [0; 32]; - result[0..20].copy_from_slice(self.as_bytes()); + result[0..20].copy_from_slice(self.as_slice()); Hash256::from_slice(&result) } } -impl TreeHash for H256 { +impl TreeHash for B256 { fn tree_hash_type() -> TreeHashType { TreeHashType::Vector } fn tree_hash_packed_encoding(&self) -> PackedEncoding { - PackedEncoding::from_slice(self.as_bytes()) + PackedEncoding::from_slice(self.as_slice()) } fn tree_hash_packing_factor() -> usize { @@ -216,8 +208,8 @@ mod test { let false_bytes: Vec = vec![0; 32]; - assert_eq!(true.tree_hash_root().as_bytes(), true_bytes.as_slice()); - assert_eq!(false.tree_hash_root().as_bytes(), false_bytes.as_slice()); + assert_eq!(true.tree_hash_root().as_slice(), true_bytes.as_slice()); + assert_eq!(false.tree_hash_root().as_slice(), false_bytes.as_slice()); } #[test] @@ -229,16 +221,16 @@ mod test { #[test] fn int_to_bytes() { - assert_eq!(int_to_hash256(0).as_bytes(), &[0; 32]); + assert_eq!(int_to_hash256(0).as_slice(), &[0; 32]); assert_eq!( - int_to_hash256(1).as_bytes(), + int_to_hash256(1).as_slice(), &[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ); assert_eq!( - int_to_hash256(u64::max_value()).as_bytes(), + int_to_hash256(u64::max_value()).as_slice(), &[ 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 diff --git a/tree_hash/src/lib.rs b/tree_hash/src/lib.rs index 2c0a5c5..18567e4 100644 --- a/tree_hash/src/lib.rs +++ b/tree_hash/src/lib.rs @@ -16,7 +16,7 @@ pub const MERKLE_HASH_CHUNK: usize = 2 * BYTES_PER_CHUNK; pub const MAX_UNION_SELECTOR: u8 = 127; pub const SMALLVEC_SIZE: usize = 32; -pub type Hash256 = ethereum_types::H256; +pub type Hash256 = alloy_primitives::B256; pub type PackedEncoding = SmallVec<[u8; SMALLVEC_SIZE]>; /// Convenience method for `MerkleHasher` which also provides some fast-paths for small trees. @@ -30,7 +30,7 @@ pub fn merkle_root(bytes: &[u8], minimum_leaf_count: usize) -> Hash256 { if leaves == 0 { // If there are no bytes then the hash is always zero. - Hash256::zero() + Hash256::ZERO } else if leaves == 1 { // If there is only one leaf, the hash is always those leaf bytes padded out to 32-bytes. let mut hash = [0; HASHSIZE]; @@ -64,7 +64,7 @@ pub fn mix_in_length(root: &Hash256, length: usize) -> Hash256 { let mut length_bytes = [0; BYTES_PER_CHUNK]; length_bytes[0..usize_len].copy_from_slice(&length.to_le_bytes()); - Hash256::from_slice(ðereum_hashing::hash32_concat(root.as_bytes(), &length_bytes)[..]) + Hash256::from_slice(ðereum_hashing::hash32_concat(root.as_slice(), &length_bytes)[..]) } /// Returns `Some(root)` created by hashing `root` and `selector`, if `selector <= @@ -88,7 +88,7 @@ pub fn mix_in_selector(root: &Hash256, selector: u8) -> Option { let mut chunk = [0; BYTES_PER_CHUNK]; chunk[0] = selector; - let root = ethereum_hashing::hash32_concat(root.as_bytes(), &chunk); + let root = ethereum_hashing::hash32_concat(root.as_slice(), &chunk); Some(Hash256::from_slice(&root)) } @@ -201,7 +201,7 @@ mod test { }; assert_eq!( - mix_in_length(&Hash256::from_slice(&[42; BYTES_PER_CHUNK]), 42).as_bytes(), + mix_in_length(&Hash256::from_slice(&[42; BYTES_PER_CHUNK]), 42).as_slice(), &hash[..] ); } diff --git a/tree_hash/src/merkle_hasher.rs b/tree_hash/src/merkle_hasher.rs index c188ba5..3ea841d 100644 --- a/tree_hash/src/merkle_hasher.rs +++ b/tree_hash/src/merkle_hasher.rs @@ -280,7 +280,7 @@ impl MerkleHasher { } else if self.next_leaf == 1 { // The next_leaf can only be 1 if the tree has a depth of one. If have been no // leaves supplied, assume a root of zero. - break Ok(Hash256::zero()); + break Ok(Hash256::ZERO); } else { // The only scenario where there are (a) no half nodes and (b) a tree of depth // two or more is where no leaves have been supplied at all. @@ -359,6 +359,8 @@ impl MerkleHasher { #[cfg(test)] mod test { + use alloy_primitives::U256; + use super::*; use crate::merkleize_padded; @@ -376,7 +378,7 @@ mod test { fn compare_with_reference(leaves: &[Hash256], depth: usize) { let reference_bytes = leaves .iter() - .flat_map(|hash| hash.as_bytes()) + .flat_map(|hash| hash.as_slice()) .copied() .collect::>(); @@ -385,7 +387,7 @@ mod test { let merklizer_root_32_bytes = { let mut m = MerkleHasher::with_depth(depth); for leaf in leaves.iter() { - m.write(leaf.as_bytes()).expect("should process leaf"); + m.write(leaf.as_slice()).expect("should process leaf"); } m.finish().expect("should finish") }; @@ -426,7 +428,7 @@ mod test { /// of leaves and a depth. fn compare_reference_with_len(leaves: u64, depth: usize) { let leaves = (0..leaves) - .map(Hash256::from_low_u64_be) + .map(|leaf| Hash256::from(U256::from(leaf))) .collect::>(); compare_with_reference(&leaves, depth) } @@ -435,13 +437,13 @@ mod test { /// results. fn compare_new_with_leaf_count(num_leaves: u64, depth: usize) { let leaves = (0..num_leaves) - .map(Hash256::from_low_u64_be) + .map(|leaf| Hash256::from(U256::from(leaf))) .collect::>(); let from_depth = { let mut m = MerkleHasher::with_depth(depth); for leaf in leaves.iter() { - m.write(leaf.as_bytes()).expect("should process leaf"); + m.write(leaf.as_slice()).expect("should process leaf"); } m.finish() }; @@ -449,7 +451,7 @@ mod test { let from_num_leaves = { let mut m = MerkleHasher::with_leaves(num_leaves as usize); for leaf in leaves.iter() { - m.process_leaf(leaf.as_bytes()) + m.process_leaf(leaf.as_slice()) .expect("should process leaf"); } m.finish() @@ -495,7 +497,7 @@ mod test { #[test] fn with_0_leaves() { let hasher = MerkleHasher::with_leaves(0); - assert_eq!(hasher.finish().unwrap(), Hash256::zero()); + assert_eq!(hasher.finish().unwrap(), Hash256::ZERO); } #[test] diff --git a/tree_hash/src/merkleize_padded.rs b/tree_hash/src/merkleize_padded.rs index 007155e..74d92bc 100644 --- a/tree_hash/src/merkleize_padded.rs +++ b/tree_hash/src/merkleize_padded.rs @@ -280,7 +280,7 @@ mod test { let input = vec![0; 10 * BYTES_PER_CHUNK]; let min_nodes = 2usize.pow(ZERO_HASHES_MAX_INDEX as u32); assert_eq!( - merkleize_padded(&input, min_nodes).as_bytes(), + merkleize_padded(&input, min_nodes).as_slice(), get_zero_hash(ZERO_HASHES_MAX_INDEX) ); } diff --git a/tree_hash/tests/tests.rs b/tree_hash/tests/tests.rs index b831614..348a185 100644 --- a/tree_hash/tests/tests.rs +++ b/tree_hash/tests/tests.rs @@ -1,3 +1,4 @@ +use alloy_primitives::{Address, U128, U160, U256}; use ssz_derive::Encode; use tree_hash::{Hash256, MerkleHasher, PackedEncoding, TreeHash, BYTES_PER_CHUNK}; use tree_hash_derive::TreeHash; @@ -44,7 +45,7 @@ fn mix_in_selector(a: Hash256, selector: u8) -> Hash256 { let mut b = [0; 32]; b[0] = selector; - Hash256::from_slice(ðereum_hashing::hash32_concat(a.as_bytes(), &b)) + Hash256::from_slice(ðereum_hashing::hash32_concat(a.as_slice(), &b)) } fn u8_hash_concat(v1: u8, v2: u8) -> Hash256 { @@ -126,3 +127,52 @@ fn variable_union() { mix_in_selector(u8_hash_concat(2, 1), 1) ); } + +/// Test that the packed encodings for different types are equal. +#[test] +fn packed_encoding_example() { + let val = 0xfff0eee0ddd0ccc0bbb0aaa099908880_u128; + let canonical = U256::from(val).tree_hash_packed_encoding(); + let encodings = [ + (0x8880_u16.tree_hash_packed_encoding(), 0), + (0x9990_u16.tree_hash_packed_encoding(), 2), + (0xaaa0_u16.tree_hash_packed_encoding(), 4), + (0xbbb0_u16.tree_hash_packed_encoding(), 6), + (0xccc0_u16.tree_hash_packed_encoding(), 8), + (0xddd0_u16.tree_hash_packed_encoding(), 10), + (0xeee0_u16.tree_hash_packed_encoding(), 12), + (0xfff0_u16.tree_hash_packed_encoding(), 14), + (U128::from(val).tree_hash_packed_encoding(), 0), + (U128::from(0).tree_hash_packed_encoding(), 16), + ( + Hash256::from_slice(U256::from(val).as_le_slice()).tree_hash_packed_encoding(), + 0, + ), + ( + Hash256::from_slice(U256::from(val).as_le_slice()) + .tree_hash_root() + .0 + .into(), + 0, + ), + (U256::from(val).tree_hash_root().0.into(), 0), + ( + Address::from(U160::from(val).to_le_bytes::<20>()) + .tree_hash_root() + .0 + .into(), + 0, + ), + ( + Address::from(U160::from(val).to_le_bytes::<20>()).tree_hash_packed_encoding(), + 0, + ), + ]; + for (i, (encoding, offset)) in encodings.into_iter().enumerate() { + assert_eq!( + &encoding[..], + &canonical[offset..offset + encoding.len()], + "encoding {i} is wrong" + ); + } +} diff --git a/tree_hash_derive/src/lib.rs b/tree_hash_derive/src/lib.rs index 4c4529d..9e920cd 100644 --- a/tree_hash_derive/src/lib.rs +++ b/tree_hash_derive/src/lib.rs @@ -132,7 +132,7 @@ fn tree_hash_derive_struct(item: &DeriveInput, struct_data: &DataStruct) -> Toke let mut hasher = tree_hash::MerkleHasher::with_leaves(#num_leaves); #( - hasher.write(self.#idents.tree_hash_root().as_bytes()) + hasher.write(self.#idents.tree_hash_root().as_slice()) .expect("tree hash derive should not apply too many leaves"); )*