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.depth = self.depth.saturating_sub(delta);
|
||||||
self.value >>= delta as u32;
|
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 {
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use assert_matches::assert_matches;
|
use assert_matches::assert_matches;
|
||||||
|
|
|
@ -79,28 +79,34 @@ pub(crate) trait SparseMerkleTree<const DEPTH: u8> {
|
||||||
// PROVIDED METHODS
|
// 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
|
/// 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.
|
/// path to the leaf, as well as the leaf itself.
|
||||||
fn open(&self, key: &Self::Key) -> Self::Opening {
|
fn open(&self, key: &Self::Key) -> Self::Opening {
|
||||||
let leaf = self.get_leaf(key);
|
let leaf = self.get_leaf(key);
|
||||||
|
let merkle_path = self.get_path(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)
|
|
||||||
};
|
|
||||||
|
|
||||||
Self::path_and_leaf_to_opening(merkle_path, leaf)
|
Self::path_and_leaf_to_opening(merkle_path, leaf)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue