diff --git a/crates/committer/src/hash/types.rs b/crates/committer/src/hash/types.rs index f64744b1..db4ab7e5 100644 --- a/crates/committer/src/hash/types.rs +++ b/crates/committer/src/hash/types.rs @@ -6,7 +6,7 @@ use crate::types::Felt; pub(crate) struct HashInputPair(pub Felt, pub Felt); #[allow(dead_code)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub(crate) struct HashOutput(pub Felt); #[allow(dead_code)] diff --git a/crates/committer/src/patricia_merkle_tree/filled_node.rs b/crates/committer/src/patricia_merkle_tree/filled_node.rs index e82d2693..e8329d67 100644 --- a/crates/committer/src/patricia_merkle_tree/filled_node.rs +++ b/crates/committer/src/patricia_merkle_tree/filled_node.rs @@ -23,8 +23,8 @@ pub(crate) enum NodeData { #[allow(dead_code)] pub(crate) struct BinaryData { - left_hash: HashOutput, - right_hash: HashOutput, + pub(crate) left_hash: HashOutput, + pub(crate) right_hash: HashOutput, } #[allow(dead_code)] diff --git a/crates/committer/src/patricia_merkle_tree/test_utils.rs b/crates/committer/src/patricia_merkle_tree/test_utils.rs deleted file mode 100644 index 2a9144d5..00000000 --- a/crates/committer/src/patricia_merkle_tree/test_utils.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::{ - hash::types::{HashOutput, PedersenHashFunction}, - patricia_merkle_tree::filled_node::{LeafData, NodeData}, -}; - -use super::TreeHashFunction; - -pub(crate) struct MockTreeHashFunctionImpl; - -/// Mock implementation of TreeHashFunction for testing purposes. -impl TreeHashFunction for MockTreeHashFunctionImpl { - fn compute_node_hash(node_data: NodeData) -> HashOutput { - match node_data { - NodeData::Binary(_) => todo!(), - NodeData::Edge(_) => todo!(), - NodeData::Leaf(leaf_data) => match leaf_data { - LeafData::StorageValue(_) => todo!(), - LeafData::CompiledClassHash(compiled_class_hash) => { - HashOutput(compiled_class_hash.0) - } - LeafData::StateTreeTuple { .. } => { - todo!() - } - }, - } - } -} diff --git a/crates/committer/src/patricia_merkle_tree/types.rs b/crates/committer/src/patricia_merkle_tree/types.rs index c720648c..8a7a2a64 100644 --- a/crates/committer/src/patricia_merkle_tree/types.rs +++ b/crates/committer/src/patricia_merkle_tree/types.rs @@ -1,10 +1,9 @@ -use crate::hash::types::{HashFunction, HashOutput}; -use crate::patricia_merkle_tree::filled_node::NodeData; +use std::marker::PhantomData; + +use crate::hash::types::{HashFunction, HashInputPair, HashOutput}; +use crate::patricia_merkle_tree::filled_node::{BinaryData, LeafData, NodeData}; use crate::types::Felt; -#[cfg(test)] -#[path = "test_utils.rs"] -mod test_utils; #[cfg(test)] #[path = "types_test.rs"] pub mod types_test; @@ -14,6 +13,39 @@ pub(crate) trait TreeHashFunction { fn compute_node_hash(node_data: NodeData) -> HashOutput; } +pub(crate) struct TreeHashFunctionImpl { + _hash_function: PhantomData, +} + +/// Implementation of TreeHashFunction. +// TODO(Aner, 11/4/25): Implement the function for LeafData::StorageValue and LeafData::StateTreeTuple +// TODO(Aner, 11/4/24): Verify the correctness of the implementation. +impl TreeHashFunction for TreeHashFunctionImpl { + fn compute_node_hash(node_data: NodeData) -> HashOutput { + match node_data { + NodeData::Binary(BinaryData { + left_hash, + right_hash, + }) => H::compute_hash(HashInputPair(left_hash.0, right_hash.0)), + NodeData::Edge(EdgeData { + bottom_hash: hash_output, + path_to_bottom: PathToBottom { path, length }, + }) => HashOutput( + H::compute_hash(HashInputPair(hash_output.0, path.0)).0 + Felt::from(length.0), + ), + NodeData::Leaf(leaf_data) => match leaf_data { + LeafData::StorageValue(_) => todo!(), + LeafData::CompiledClassHash(compiled_class_hash) => { + HashOutput(compiled_class_hash.0) + } + LeafData::StateTreeTuple { .. } => { + todo!() + } + }, + } + } +} + #[allow(dead_code)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub(crate) struct NodeIndex(pub Felt); diff --git a/crates/committer/src/patricia_merkle_tree/types_test.rs b/crates/committer/src/patricia_merkle_tree/types_test.rs index 621d1055..4d910551 100644 --- a/crates/committer/src/patricia_merkle_tree/types_test.rs +++ b/crates/committer/src/patricia_merkle_tree/types_test.rs @@ -1,4 +1,9 @@ -use crate::patricia_merkle_tree::types::{EdgePath, EdgePathLength, NodeIndex, PathToBottom}; +use crate::hash::types::{HashFunction, HashInputPair, HashOutput, PedersenHashFunction}; +use crate::patricia_merkle_tree::filled_node::{BinaryData, NodeData}; +use crate::patricia_merkle_tree::types::TreeHashFunction; +use crate::patricia_merkle_tree::types::{ + EdgePath, EdgePathLength, NodeIndex, PathToBottom, TreeHashFunctionImpl, +}; use crate::types::Felt; use rstest::rstest; #[rstest] @@ -22,3 +27,53 @@ fn test_compute_bottom_index( let expected = NodeIndex(Felt::from(expected)); assert_eq!(bottom_index, expected); } + +#[rstest] +#[case(Felt::ONE, Felt::TWO, Felt::from_hex("0x5bb9440e27889a364bcb678b1f679ecd1347acdedcbf36e83494f857cc58026").unwrap())] +#[case(Felt::from(0xBE_u128), Felt::from(0xA0BEE_u128), Felt::from_hex("0x4e8f149d7d5adb77a8c85b631a3acb6fb9aa5ecb06ea4ec105753629243e380").unwrap())] +#[case(Felt::from(0x1234_u128), Felt::from(0xABCD_u128), Felt::from_hex("0x615bb8d47888d2987ad0c63fc06e9e771930986a4dd8adc55617febfcf3639e").unwrap())] +fn test_tree_hash_function_impl_binary_node( + #[case] left_hash: Felt, + #[case] right_hash: Felt, + #[case] expected_hash: Felt, +) { + let hash_output = TreeHashFunctionImpl::::compute_node_hash( + NodeData::Binary(BinaryData { + left_hash: HashOutput(left_hash), + right_hash: HashOutput(right_hash), + }), + ); + assert_eq!( + hash_output, + PedersenHashFunction::compute_hash(HashInputPair(left_hash, right_hash)) + ); + assert_eq!(hash_output, HashOutput(expected_hash)); +} + +#[rstest] +#[case(Felt::ONE, Felt::TWO, 3, Felt::from_hex("0x5bb9440e27889a364bcb678b1f679ecd1347acdedcbf36e83494f857cc58029").unwrap())] +#[case(Felt::from(0xBE_u128), Felt::from(0xA0BEE_u128), 0xBB, Felt::from_hex("0x4e8f149d7d5adb77a8c85b631a3acb6fb9aa5ecb06ea4ec105753629243e43b").unwrap())] +#[case(Felt::from(0x1234ABCD_u128),Felt::from(42_u128),6, Felt::from_hex("0x1d937094c09b5f8e26a662d21911871e3cbc6858d55cc49af9848ea6fed4e9").unwrap())] +fn test_tree_hash_function_impl_edge_node( + #[case] bottom_hash: Felt, + #[case] edge_path: Felt, + #[case] length: u8, + #[case] expected_hash: Felt, +) { + use crate::patricia_merkle_tree::types::EdgeData; + + let hash_output = + TreeHashFunctionImpl::::compute_node_hash(NodeData::Edge(EdgeData { + bottom_hash: HashOutput(bottom_hash), + path_to_bottom: PathToBottom { + path: EdgePath(edge_path), + length: EdgePathLength(length), + }, + })); + let direct_hash_computation = HashOutput( + PedersenHashFunction::compute_hash(HashInputPair(bottom_hash, edge_path)).0 + + Felt::from(length), + ); + assert_eq!(hash_output, HashOutput(expected_hash)); + assert_eq!(hash_output, direct_hash_computation); +} diff --git a/crates/committer/src/types.rs b/crates/committer/src/types.rs index 6f1de664..9e6e88b4 100644 --- a/crates/committer/src/types.rs +++ b/crates/committer/src/types.rs @@ -1,19 +1,23 @@ -use starknet_types_core::felt::Felt as StarknetTypesFelt; +use starknet_types_core::felt::{Felt as StarknetTypesFelt, FromStrError}; #[derive(Eq, PartialEq, Clone, Copy, Debug, Default, Hash, derive_more::Add)] pub(crate) struct Felt(StarknetTypesFelt); -impl From for Felt { - fn from(felt: StarknetTypesFelt) -> Self { - Self(felt) - } -} - -impl From for Felt { - fn from(value: u128) -> Self { - Self(value.into()) - } +#[macro_export] +macro_rules! impl_from { + ($to:ty, $from:ty, $($other_from: ty),+) => { + $crate::impl_from!($to, $from); + $crate::impl_from!($to $(, $other_from)*); + }; + ($to:ty, $from:ty) => { + impl From<$from> for $to { + fn from(value: $from) -> Self { + Self(value.into()) + } + } + }; } +impl_from!(Felt, StarknetTypesFelt, u128, u8); impl From for StarknetTypesFelt { fn from(felt: Felt) -> Self { @@ -39,4 +43,9 @@ impl Felt { pub fn pow(&self, exponent: impl Into) -> Self { Self(self.0.pow(exponent.into())) } + + /// Parse a hex-encoded number into `Felt`. + pub fn from_hex(hex_string: &str) -> Result { + Ok(StarknetTypesFelt::from_hex(hex_string)?.into()) + } }