Merge pull request #120 from zcash/imt-witness-non-empty-tree

incrementalmerkletree: Check `IncrementalWitness` at construction
This commit is contained in:
Kris Nuttycombe 2024-11-24 08:53:26 -07:00 committed by GitHub
commit b05d9863db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 27 additions and 14 deletions

View File

@ -7,6 +7,11 @@ and this project adheres to Rust's notion of
## Unreleased ## Unreleased
### Changed
- `incrementalmerkletree::witness`:
- `IncrementalWitness::{from_tree, from_parts}` now return `Option<Self>`
(returning `None` if a witness cannot be constructed).
## [0.7.0] - 2024-09-25 ## [0.7.0] - 2024-09-25
### Changed ### Changed

View File

@ -25,7 +25,7 @@ use crate::{
/// ///
/// tree.append(TestNode(0)); /// tree.append(TestNode(0));
/// tree.append(TestNode(1)); /// tree.append(TestNode(1));
/// let mut witness = IncrementalWitness::from_tree(tree.clone()); /// let mut witness = IncrementalWitness::from_tree(tree.clone()).expect("tree is not empty");
/// assert_eq!(witness.witnessed_position(), Position::from(1)); /// assert_eq!(witness.witnessed_position(), Position::from(1));
/// assert_eq!(tree.root(), witness.root()); /// assert_eq!(tree.root(), witness.root());
/// ///
@ -45,30 +45,38 @@ pub struct IncrementalWitness<H, const DEPTH: u8> {
impl<H, const DEPTH: u8> IncrementalWitness<H, DEPTH> { impl<H, const DEPTH: u8> IncrementalWitness<H, DEPTH> {
/// Creates an `IncrementalWitness` for the most recent commitment added to the given /// Creates an `IncrementalWitness` for the most recent commitment added to the given
/// [`CommitmentTree`]. /// [`CommitmentTree`].
pub fn from_tree(tree: CommitmentTree<H, DEPTH>) -> Self { ///
IncrementalWitness { /// Returns `None` if `tree` is empty (and thus there is no position to witness).
pub fn from_tree(tree: CommitmentTree<H, DEPTH>) -> Option<Self> {
(!tree.is_empty()).then(|| IncrementalWitness {
tree, tree,
filled: vec![], filled: vec![],
cursor_depth: 0, cursor_depth: 0,
cursor: None, cursor: None,
} })
} }
/// Constructs an `IncrementalWitness` from its parts.
///
/// Returns `None` if the parts do not form a valid witness, for example if `tree` is
/// empty (and thus there is no position to witness).
pub fn from_parts( pub fn from_parts(
tree: CommitmentTree<H, DEPTH>, tree: CommitmentTree<H, DEPTH>,
filled: Vec<H>, filled: Vec<H>,
cursor: Option<CommitmentTree<H, DEPTH>>, cursor: Option<CommitmentTree<H, DEPTH>>,
) -> Self { ) -> Option<Self> {
let mut witness = IncrementalWitness { (!tree.is_empty()).then(|| {
tree, let mut witness = IncrementalWitness {
filled, tree,
cursor_depth: 0, filled,
cursor, cursor_depth: 0,
}; cursor,
};
witness.cursor_depth = witness.next_depth(); witness.cursor_depth = witness.next_depth();
witness witness
})
} }
pub fn tree(&self) -> &CommitmentTree<H, DEPTH> { pub fn tree(&self) -> &CommitmentTree<H, DEPTH> {
@ -248,7 +256,7 @@ mod tests {
for c in 'a'..'h' { for c in 'a'..'h' {
base_tree.append(c.to_string()).unwrap(); base_tree.append(c.to_string()).unwrap();
} }
let mut witness = IncrementalWitness::from_tree(base_tree); let mut witness = IncrementalWitness::from_tree(base_tree).unwrap();
for c in 'h'..'z' { for c in 'h'..'z' {
witness.append(c.to_string()).unwrap(); witness.append(c.to_string()).unwrap();
} }