smt: refactor MerklePath logic
Computation of the correct node indices to get is moved to `NodeIndex::proof_indices()`, and getting a node's index based on its parent is generalized into `SparseMerkleTree::get_hash()`.
This commit is contained in:
parent
78672585f1
commit
91aac69b8e
2 changed files with 69 additions and 18 deletions
|
@ -164,6 +164,18 @@ impl NodeIndex {
|
|||
self.depth = self.depth.saturating_sub(delta);
|
||||
self.value >>= delta as u32;
|
||||
}
|
||||
|
||||
// ITERATORS
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
/// Return an iterator of the indices required for a Merkle proof of inclusion of a node at
|
||||
/// `self`.
|
||||
///
|
||||
/// This is *exclusive* on both ends: neither `self` nor the root index are included in the
|
||||
/// returned iterator.
|
||||
pub fn proof_indices(&self) -> impl ExactSizeIterator<Item = NodeIndex> + use<> {
|
||||
ProofIter { next_index: self.sibling() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for NodeIndex {
|
||||
|
@ -188,6 +200,39 @@ impl Deserializable for NodeIndex {
|
|||
}
|
||||
}
|
||||
|
||||
/// Implementation for [`NodeIndex::proof_indices()`].
|
||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
struct ProofIter {
|
||||
next_index: NodeIndex,
|
||||
}
|
||||
|
||||
impl Iterator for ProofIter {
|
||||
type Item = NodeIndex;
|
||||
|
||||
fn next(&mut self) -> Option<NodeIndex> {
|
||||
if self.next_index.is_root() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let index = self.next_index;
|
||||
self.next_index = index.parent().sibling();
|
||||
|
||||
Some(index)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let remaining = ExactSizeIterator::len(self);
|
||||
|
||||
(remaining, Some(remaining))
|
||||
}
|
||||
}
|
||||
|
||||
impl ExactSizeIterator for ProofIter {
|
||||
fn len(&self) -> usize {
|
||||
self.next_index.depth() as usize
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use assert_matches::assert_matches;
|
||||
|
|
|
@ -79,28 +79,34 @@ pub(crate) trait SparseMerkleTree<const DEPTH: u8> {
|
|||
// PROVIDED METHODS
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
/// Returns a [MerklePath] to the specified key.
|
||||
///
|
||||
/// Mostly this is an implementation detail of [`Self::open()`].
|
||||
fn get_path(&self, key: &Self::Key) -> MerklePath {
|
||||
let index = NodeIndex::from(Self::key_to_leaf_index(key));
|
||||
index.proof_indices().map(|index| self.get_hash(index)).collect()
|
||||
}
|
||||
|
||||
/// Get the hash of a node at an arbitrary index, including the root or leaf hashes.
|
||||
///
|
||||
/// The root index simply returns [`Self::root()`]. Other hashes are retrieved by calling
|
||||
/// [`Self::get_inner_node()`] on the parent, and returning the respective child hash.
|
||||
fn get_hash(&self, index: NodeIndex) -> RpoDigest {
|
||||
if index.is_root() {
|
||||
return self.root();
|
||||
}
|
||||
|
||||
let InnerNode { left, right } = self.get_inner_node(index.parent());
|
||||
|
||||
let index_is_right = index.is_value_odd();
|
||||
if index_is_right { right } else { left }
|
||||
}
|
||||
|
||||
/// Returns an opening of the leaf associated with `key`. Conceptually, an opening is a Merkle
|
||||
/// path to the leaf, as well as the leaf itself.
|
||||
fn open(&self, key: &Self::Key) -> Self::Opening {
|
||||
let leaf = self.get_leaf(key);
|
||||
|
||||
let mut index: NodeIndex = {
|
||||
let leaf_index: LeafIndex<DEPTH> = Self::key_to_leaf_index(key);
|
||||
leaf_index.into()
|
||||
};
|
||||
|
||||
let merkle_path = {
|
||||
let mut path = Vec::with_capacity(index.depth() as usize);
|
||||
for _ in 0..index.depth() {
|
||||
let is_right = index.is_value_odd();
|
||||
index.move_up();
|
||||
let InnerNode { left, right } = self.get_inner_node(index);
|
||||
let value = if is_right { left } else { right };
|
||||
path.push(value);
|
||||
}
|
||||
|
||||
MerklePath::new(path)
|
||||
};
|
||||
let merkle_path = self.get_path(key);
|
||||
|
||||
Self::path_and_leaf_to_opening(merkle_path, leaf)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue