diff --git a/Cargo.lock b/Cargo.lock index d8568bf685e..3256db6e14c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12879,7 +12879,9 @@ dependencies = [ "apollo_config", "async-recursion", "async-trait", + "blake2", "derive_more", + "digest 0.10.7", "ethnum", "expect-test", "hex", diff --git a/crates/starknet_committer/Cargo.toml b/crates/starknet_committer/Cargo.toml index 906ede3d156..4de6c991c6f 100644 --- a/crates/starknet_committer/Cargo.toml +++ b/crates/starknet_committer/Cargo.toml @@ -7,12 +7,15 @@ license.workspace = true description = "Computes and manages Starknet state." [features] +os_input = ["dep:blake2", "dep:digest"] testing = ["starknet_patricia/testing"] [dependencies] apollo_config.workspace = true async-trait.workspace = true +blake2 = { workspace = true, optional = true } derive_more = { workspace = true, features = ["as_ref", "from", "into"] } +digest = { workspace = true, optional = true } ethnum.workspace = true pretty_assertions.workspace = true rand.workspace = true diff --git a/crates/starknet_committer/src/db/serde_db_utils.rs b/crates/starknet_committer/src/db/serde_db_utils.rs index 67babb06e9d..613ef870d60 100644 --- a/crates/starknet_committer/src/db/serde_db_utils.rs +++ b/crates/starknet_committer/src/db/serde_db_utils.rs @@ -1,8 +1,17 @@ +#[cfg(feature = "os_input")] +use blake2::Blake2s256; +#[cfg(feature = "os_input")] +use digest::Digest; use serde::{Deserialize, Serialize}; use starknet_api::block::BlockNumber; +#[cfg(feature = "os_input")] +use starknet_patricia::patricia_merkle_tree::types::NodeIndex; use starknet_patricia_storage::storage_trait::DbValue; use starknet_types_core::felt::Felt; +#[cfg(feature = "os_input")] +use crate::patricia_merkle_tree::tree::SortedLeavesRequest; + #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Hash, Serialize)] pub struct DbBlockNumber(pub BlockNumber); @@ -23,3 +32,51 @@ pub fn serialize_felt_no_packing(felt: Felt) -> DbValue { pub fn deserialize_felt_no_packing(value: &DbValue) -> Felt { Felt::from_bytes_be_slice(&value.0) } + +/// BLAKE2s-256 digest over a deterministic encoding of [`SortedLeavesRequest`]. +/// +/// The hashed payload is a concatenation length-prefixed big-endian 32-byte +/// [`NodeIndex`] values (`idx.0.to_be_bytes()`), in this order: +/// +/// 1. Classes trie — `len(classes_sorted)` then each class leaf index (already sorted). +/// 2. Contracts trie — `len(contracts_sorted)` then each contract leaf index (already sorted). +/// 3. Storage tries — `len(storage_sorted)` then, for each contract index in ascending order: the +/// contract index, `len(storage slot indices)` for that contract, then each storage slot index +/// (already sorted within the contract). +#[cfg(feature = "os_input")] +pub fn accessed_keys_digest(sorted: &SortedLeavesRequest<'_>) -> [u8; 32] { + let mut payload = Vec::new(); + + let class = sorted.class_sorted.get_indices(); + payload.extend_from_slice(&encode_usize(class.len())); + for idx in class { + payload.extend_from_slice(&idx.0.to_be_bytes()); + } + + let contract = sorted.contract_sorted.get_indices(); + payload.extend_from_slice(&encode_usize(contract.len())); + for idx in contract { + payload.extend_from_slice(&idx.0.to_be_bytes()); + } + + let mut contract_indices: Vec = sorted.storage_sorted.keys().copied().collect(); + contract_indices.sort_unstable(); + + payload.extend_from_slice(&encode_usize(contract_indices.len())); + for contract_idx in contract_indices { + let sorted_slots = sorted.storage_sorted.get(&contract_idx).unwrap(); + payload.extend_from_slice(&contract_idx.0.to_be_bytes()); + let slot_indices = sorted_slots.get_indices(); + payload.extend_from_slice(&encode_usize(slot_indices.len())); + for slot in slot_indices { + payload.extend_from_slice(&slot.0.to_be_bytes()); + } + } + + Blake2s256::digest(&payload).into() +} + +#[cfg(feature = "os_input")] +fn encode_usize(n: usize) -> [u8; 8] { + u64::try_from(n).expect("accessed leaf count exceeds u64::MAX").to_be_bytes() +} diff --git a/crates/starknet_committer/src/patricia_merkle_tree/tree.rs b/crates/starknet_committer/src/patricia_merkle_tree/tree.rs index f43c2624281..dcfade54499 100644 --- a/crates/starknet_committer/src/patricia_merkle_tree/tree.rs +++ b/crates/starknet_committer/src/patricia_merkle_tree/tree.rs @@ -63,6 +63,7 @@ pub struct LeavesRequest { pub struct SortedLeavesRequest<'a> { pub class_sorted: SortedLeafIndices<'a>, pub contract_sorted: SortedLeafIndices<'a>, + // TODO(Ariel): use BTreeMap here and in fetch_all_patricia_paths. pub storage_sorted: HashMap>, }