use super::{ BTreeMap, BTreeSet, InnerNodeInfo, MerkleError, MerklePath, NodeIndex, Rpo256, RpoDigest, ValuePath, Vec, Word, EMPTY_WORD, }; use crate::utils::{ format, string::String, vec, word_to_hex, ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, }; use core::fmt; #[cfg(test)] mod tests; // CONSTANTS // ================================================================================================ /// Index of the root node. const ROOT_INDEX: NodeIndex = NodeIndex::root(); /// An RpoDigest consisting of 4 ZERO elements. const EMPTY_DIGEST: RpoDigest = RpoDigest::new(EMPTY_WORD); // PARTIAL MERKLE TREE // ================================================================================================ /// A partial Merkle tree with NodeIndex keys and 4-element RpoDigest leaf values. Partial Merkle /// Tree allows to create Merkle Tree by providing Merkle paths of different lengths. /// /// The root of the tree is recomputed on each new leaf update. #[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct PartialMerkleTree { max_depth: u8, nodes: BTreeMap, leaves: BTreeSet, } impl Default for PartialMerkleTree { fn default() -> Self { Self::new() } } impl PartialMerkleTree { // CONSTANTS // -------------------------------------------------------------------------------------------- /// Minimum supported depth. pub const MIN_DEPTH: u8 = 1; /// Maximum supported depth. pub const MAX_DEPTH: u8 = 64; // CONSTRUCTORS // -------------------------------------------------------------------------------------------- /// Returns a new empty [PartialMerkleTree]. pub fn new() -> Self { PartialMerkleTree { max_depth: 0, nodes: BTreeMap::new(), leaves: BTreeSet::new(), } } /// Appends the provided paths iterator into the set. /// /// Analogous to [Self::add_path]. pub fn with_paths(paths: I) -> Result where I: IntoIterator, { // create an empty tree let tree = PartialMerkleTree::new(); paths.into_iter().try_fold(tree, |mut tree, (index, value, path)| { tree.add_path(index, value, path)?; Ok(tree) }) } /// Returns a new [PartialMerkleTree] instantiated with leaves map as specified by the provided /// entries. /// /// # Errors /// Returns an error if: /// - If the depth is 0 or is greater than 64. /// - The number of entries exceeds the maximum tree capacity, that is 2^{depth}. /// - The provided entries contain an insufficient set of nodes. pub fn with_leaves(entries: R) -> Result where R: IntoIterator, I: Iterator + ExactSizeIterator, { let mut layers: BTreeMap> = BTreeMap::new(); let mut leaves = BTreeSet::new(); let mut nodes = BTreeMap::new(); // add data to the leaves and nodes maps and also fill layers map, where the key is the // depth of the node and value is its index. for (node_index, hash) in entries.into_iter() { leaves.insert(node_index); nodes.insert(node_index, hash); layers .entry(node_index.depth()) .and_modify(|layer_vec| layer_vec.push(node_index.value())) .or_insert(vec![node_index.value()]); } // check if the number of leaves can be accommodated by the tree's depth; we use a min // depth of 63 because we consider passing in a vector of size 2^64 infeasible. let max = (1_u64 << 63) as usize; if layers.len() > max { return Err(MerkleError::InvalidNumEntries(max, layers.len())); } // Get maximum depth let max_depth = *layers.keys().next_back().unwrap_or(&0); // fill layers without nodes with empty vector for depth in 0..max_depth { layers.entry(depth).or_default(); } let mut layer_iter = layers.into_values().rev(); let mut parent_layer = layer_iter.next().unwrap(); let mut current_layer; for depth in (1..max_depth + 1).rev() { // set current_layer = parent_layer and parent_layer = layer_iter.next() current_layer = layer_iter.next().unwrap(); core::mem::swap(&mut current_layer, &mut parent_layer); for index_value in current_layer { // get the parent node index let parent_node = NodeIndex::new(depth - 1, index_value / 2)?; // Check if the parent hash was already calculated. In about half of the cases, we // don't need to do anything. if !parent_layer.contains(&parent_node.value()) { // create current node index let index = NodeIndex::new(depth, index_value)?; // get hash of the current node let node = nodes.get(&index).ok_or(MerkleError::NodeNotInSet(index))?; // get hash of the sibling node let sibling = nodes .get(&index.sibling()) .ok_or(MerkleError::NodeNotInSet(index.sibling()))?; // get parent hash let parent = Rpo256::merge(&index.build_node(*node, *sibling)); // add index value of the calculated node to the parents layer parent_layer.push(parent_node.value()); // add index and hash to the nodes map nodes.insert(parent_node, parent); } } } Ok(PartialMerkleTree { max_depth, nodes, leaves, }) } // PUBLIC ACCESSORS // -------------------------------------------------------------------------------------------- /// Returns the root of this Merkle tree. pub fn root(&self) -> RpoDigest { self.nodes.get(&ROOT_INDEX).cloned().unwrap_or(EMPTY_DIGEST) } /// Returns the depth of this Merkle tree. pub fn max_depth(&self) -> u8 { self.max_depth } /// Returns a node at the specified NodeIndex. /// /// # Errors /// Returns an error if the specified NodeIndex is not contained in the nodes map. pub fn get_node(&self, index: NodeIndex) -> Result { self.nodes.get(&index).ok_or(MerkleError::NodeNotInSet(index)).map(|hash| *hash) } /// Returns true if provided index contains in the leaves set, false otherwise. pub fn is_leaf(&self, index: NodeIndex) -> bool { self.leaves.contains(&index) } /// Returns a vector of paths from every leaf to the root. pub fn to_paths(&self) -> Vec<(NodeIndex, ValuePath)> { let mut paths = Vec::new(); self.leaves.iter().for_each(|&leaf| { paths.push(( leaf, ValuePath { value: self.get_node(leaf).expect("Failed to get leaf node"), path: self.get_path(leaf).expect("Failed to get path"), }, )); }); paths } /// Returns a Merkle path from the node at the specified index to the root. /// /// The node itself is not included in the path. /// /// # Errors /// Returns an error if: /// - the specified index has depth set to 0 or the depth is greater than the depth of this /// Merkle tree. /// - the specified index is not contained in the nodes map. pub fn get_path(&self, mut index: NodeIndex) -> Result { if index.is_root() { return Err(MerkleError::DepthTooSmall(index.depth())); } else if index.depth() > self.max_depth() { return Err(MerkleError::DepthTooBig(index.depth() as u64)); } if !self.nodes.contains_key(&index) { return Err(MerkleError::NodeNotInSet(index)); } let mut path = Vec::new(); for _ in 0..index.depth() { let sibling_index = index.sibling(); index.move_up(); let sibling = self.nodes.get(&sibling_index).cloned().expect("Sibling node not in the map"); path.push(sibling); } Ok(MerklePath::new(path)) } // ITERATORS // -------------------------------------------------------------------------------------------- /// Returns an iterator over the leaves of this [PartialMerkleTree]. pub fn leaves(&self) -> impl Iterator + '_ { self.leaves.iter().map(|&leaf| { ( leaf, self.get_node(leaf) .unwrap_or_else(|_| panic!("Leaf with {leaf} is not in the nodes map")), ) }) } /// Returns an iterator over the inner nodes of this Merkle tree. pub fn inner_nodes(&self) -> impl Iterator + '_ { let inner_nodes = self.nodes.iter().filter(|(index, _)| !self.leaves.contains(index)); inner_nodes.map(|(index, digest)| { let left_hash = self.nodes.get(&index.left_child()).expect("Failed to get left child hash"); let right_hash = self.nodes.get(&index.right_child()).expect("Failed to get right child hash"); InnerNodeInfo { value: *digest, left: *left_hash, right: *right_hash, } }) } // STATE MUTATORS // -------------------------------------------------------------------------------------------- /// Adds the nodes of the specified Merkle path to this [PartialMerkleTree]. The `index_value` /// and `value` parameters specify the leaf node at which the path starts. /// /// # Errors /// Returns an error if: /// - The depth of the specified node_index is greater than 64 or smaller than 1. /// - The specified path is not consistent with other paths in the set (i.e., resolves to a /// different root). pub fn add_path( &mut self, index_value: u64, value: RpoDigest, path: MerklePath, ) -> Result<(), MerkleError> { let index_value = NodeIndex::new(path.len() as u8, index_value)?; Self::check_depth(index_value.depth())?; self.update_depth(index_value.depth()); // add provided node and its sibling to the leaves set self.leaves.insert(index_value); let sibling_node_index = index_value.sibling(); self.leaves.insert(sibling_node_index); // add provided node and its sibling to the nodes map self.nodes.insert(index_value, value); self.nodes.insert(sibling_node_index, path[0]); // traverse to the root, updating the nodes let mut index_value = index_value; let node = Rpo256::merge(&index_value.build_node(value, path[0])); let root = path.iter().skip(1).copied().fold(node, |node, hash| { index_value.move_up(); // insert calculated node to the nodes map self.nodes.insert(index_value, node); // if the calculated node was a leaf, remove it from leaves set. self.leaves.remove(&index_value); let sibling_node = index_value.sibling(); // Insert node from Merkle path to the nodes map. This sibling node becomes a leaf only // if it is a new node (it wasn't in nodes map). // Node can be in 3 states: internal node, leaf of the tree and not a tree node at all. // - Internal node can only stay in this state -- addition of a new path can't make it // a leaf or remove it from the tree. // - Leaf node can stay in the same state (remain a leaf) or can become an internal // node. In the first case we don't need to do anything, and the second case is handled // by the call of `self.leaves.remove(&index_value);` // - New node can be a calculated node or a "sibling" node from a Merkle Path: // --- Calculated node, obviously, never can be a leaf. // --- Sibling node can be only a leaf, because otherwise it is not a new node. if self.nodes.insert(sibling_node, hash).is_none() { self.leaves.insert(sibling_node); } Rpo256::merge(&index_value.build_node(node, hash)) }); // if the path set is empty (the root is all ZEROs), set the root to the root of the added // path; otherwise, the root of the added path must be identical to the current root if self.root() == EMPTY_DIGEST { self.nodes.insert(ROOT_INDEX, root); } else if self.root() != root { return Err(MerkleError::ConflictingRoots([self.root(), root].to_vec())); } Ok(()) } /// Updates value of the leaf at the specified index returning the old leaf value. /// By default the specified index is assumed to belong to the deepest layer. If the considered /// node does not belong to the tree, the first node on the way to the root will be changed. /// /// By default the specified index is assumed to belong to the deepest layer. If the considered /// node does not belong to the tree, the first node on the way to the root will be changed. /// /// This also recomputes all hashes between the leaf and the root, updating the root itself. /// /// # Errors /// Returns an error if: /// - The specified index is greater than the maximum number of nodes on the deepest layer. pub fn update_leaf(&mut self, index: u64, value: Word) -> Result { let mut node_index = NodeIndex::new(self.max_depth(), index)?; // proceed to the leaf for _ in 0..node_index.depth() { if !self.leaves.contains(&node_index) { node_index.move_up(); } } // add node value to the nodes Map let old_value = self .nodes .insert(node_index, value.into()) .ok_or(MerkleError::NodeNotInSet(node_index))?; // if the old value and new value are the same, there is nothing to update if value == *old_value { return Ok(old_value); } let mut value = value.into(); for _ in 0..node_index.depth() { let sibling = self.nodes.get(&node_index.sibling()).expect("sibling should exist"); value = Rpo256::merge(&node_index.build_node(value, *sibling)); node_index.move_up(); self.nodes.insert(node_index, value); } Ok(old_value) } // UTILITY FUNCTIONS // -------------------------------------------------------------------------------------------- /// Utility to visualize a [PartialMerkleTree] in text. pub fn print(&self) -> Result { let indent = " "; let mut s = String::new(); s.push_str("root: "); s.push_str(&word_to_hex(&self.root())?); s.push('\n'); for d in 1..=self.max_depth() { let entries = 2u64.pow(d.into()); for i in 0..entries { let index = NodeIndex::new(d, i).expect("The index must always be valid"); let node = self.get_node(index); let node = match node { Err(_) => continue, Ok(node) => node, }; for _ in 0..d { s.push_str(indent); } s.push_str(&format!("({}, {}): ", index.depth(), index.value())); s.push_str(&word_to_hex(&node)?); s.push('\n'); } } Ok(s) } // HELPER METHODS // -------------------------------------------------------------------------------------------- /// Updates depth value with the maximum of current and provided depth. fn update_depth(&mut self, new_depth: u8) { self.max_depth = new_depth.max(self.max_depth); } /// Returns an error if the depth is 0 or is greater than 64. fn check_depth(depth: u8) -> Result<(), MerkleError> { // validate the range of the depth. if depth < Self::MIN_DEPTH { return Err(MerkleError::DepthTooSmall(depth)); } else if Self::MAX_DEPTH < depth { return Err(MerkleError::DepthTooBig(depth as u64)); } Ok(()) } } // SERIALIZATION // ================================================================================================ impl Serializable for PartialMerkleTree { fn write_into(&self, target: &mut W) { // write leaf nodes target.write_u64(self.leaves.len() as u64); for leaf_index in self.leaves.iter() { leaf_index.write_into(target); self.get_node(*leaf_index).expect("Leaf hash not found").write_into(target); } } } impl Deserializable for PartialMerkleTree { fn read_from(source: &mut R) -> Result { let leaves_len = source.read_u64()? as usize; let mut leaf_nodes = Vec::with_capacity(leaves_len); // add leaf nodes to the vector for _ in 0..leaves_len { let index = NodeIndex::read_from(source)?; let hash = RpoDigest::read_from(source)?; leaf_nodes.push((index, hash)); } let pmt = PartialMerkleTree::with_leaves(leaf_nodes).map_err(|_| { DeserializationError::InvalidValue("Invalid data for PartialMerkleTree creation".into()) })?; Ok(pmt) } }