Traverse tree only once for proof generation.

This commit is contained in:
Andreas Fackler
2018-06-11 10:10:32 +02:00
committed by Romain Ruetschi
parent 205853656b
commit 4f60edafcd
4 changed files with 34 additions and 71 deletions

View File

@ -166,14 +166,8 @@ impl<T> MerkleTree<T> {
T: Hashable + Clone, T: Hashable + Clone,
{ {
let root_hash = self.root_hash().clone(); let root_hash = self.root_hash().clone();
let value = if let Some(value) = self.root.nth_leaf(n, self.count) {
value
} else {
return None;
};
Lemma::new_by_index(&self.root, n, self.count) Lemma::new_by_index(&self.root, n, self.count)
.map(|lemma| Proof::new(self.algorithm, root_hash, lemma, value.clone())) .map(|(lemma, value)| Proof::new(self.algorithm, root_hash, lemma, value.clone()))
} }
/// Creates an `Iterator` over the values contained in this Merkle tree. /// Creates an `Iterator` over the values contained in this Merkle tree.

View File

@ -194,30 +194,54 @@ impl Lemma {
/// Attempts to generate a proof that the `idx`-th leaf is a member of /// Attempts to generate a proof that the `idx`-th leaf is a member of
/// the given tree. The `count` must equal the number of leaves in the /// the given tree. The `count` must equal the number of leaves in the
/// `tree`. If `idx >= count`, `None` is returned. /// `tree`. If `idx >= count`, `None` is returned. Otherwise it returns
pub fn new_by_index<T>(tree: &Tree<T>, idx: usize, count: usize) -> Option<Lemma> { /// the new `Lemma` and the `idx`-th value.
pub fn new_by_index<T>(tree: &Tree<T>, idx: usize, count: usize) -> Option<(Lemma, &T)> {
if idx >= count { if idx >= count {
return None; return None;
} }
match *tree { match *tree {
Tree::Empty { .. } => None, Tree::Empty { .. } => None,
Tree::Leaf { ref hash, .. } => { Tree::Leaf {
ref hash,
ref value,
..
} => {
if count != 1 { if count != 1 {
return None; return None;
} }
Some(Lemma { let lemma = Lemma {
node_hash: hash.clone(), node_hash: hash.clone(),
sibling_hash: None, sibling_hash: None,
sub_lemma: None, sub_lemma: None,
}) };
Some((lemma, value))
} }
Tree::Node { Tree::Node {
ref hash, ref hash,
ref left, ref left,
ref right, ref right,
} => Lemma::new_tree_proof_by_index(hash, idx, count, left, right), } => {
let left_count = count.next_power_of_two() / 2;
let (sub_lem_val, sibling_hash);
if idx < left_count {
sub_lem_val = Lemma::new_by_index(left, idx, left_count);
sibling_hash = Positioned::Right(right.hash().clone());
} else {
sub_lem_val = Lemma::new_by_index(right, idx - left_count, count - left_count);
sibling_hash = Positioned::Left(left.hash().clone());
}
sub_lem_val.map(|(sub_lemma, value)| {
let lemma = Lemma {
node_hash: hash.clone(),
sibling_hash: Some(sibling_hash),
sub_lemma: Some(Box::new(sub_lemma)),
};
(lemma, value)
})
}
} }
} }
@ -293,35 +317,6 @@ impl Lemma {
}, },
} }
} }
fn new_tree_proof_by_index<T>(
hash: &[u8],
idx: usize,
count: usize,
left: &Tree<T>,
right: &Tree<T>,
) -> Option<Lemma> {
let left_count = count.next_power_of_two() / 2;
Lemma::new_by_index(left, idx, left_count)
.map(|lemma| {
let right_hash = right.hash().clone();
let sub_lemma = Some(Positioned::Right(right_hash));
(lemma, sub_lemma)
})
.or_else(|| {
let sub_lemma = Lemma::new_by_index(right, idx - left_count, count - left_count);
sub_lemma.map(|lemma| {
let left_hash = left.hash().clone();
let sub_lemma = Some(Positioned::Left(left_hash));
(lemma, sub_lemma)
})
})
.map(|(sub_lemma, sibling_hash)| Lemma {
node_hash: hash.into(),
sibling_hash,
sub_lemma: Some(Box::new(sub_lemma)),
})
}
} }
/// Tags a value so that we know from which branch of a `Tree` (if any) it was found. /// Tags a value so that we know from which branch of a `Tree` (if any) it was found.

View File

@ -164,6 +164,9 @@ fn test_nth_proof() {
assert!(proof.validate(&root_hash)); assert!(proof.validate(&root_hash));
assert_eq!(i, proof.index(tree.count())); assert_eq!(i, proof.index(tree.count()));
} }
assert!(tree.gen_nth_proof(count).is_none());
assert!(tree.gen_nth_proof(count + 1000).is_none());
} }
} }

View File

@ -61,35 +61,6 @@ impl<T> Tree<T> {
pub fn iter(&self) -> LeavesIterator<T> { pub fn iter(&self) -> LeavesIterator<T> {
LeavesIterator::new(self) LeavesIterator::new(self)
} }
/// Returns the `n`-th leaf value, given the total `count`.
pub fn nth_leaf(&self, n: usize, count: usize) -> Option<&T> {
if n >= count {
return None;
}
let left_count = count.next_power_of_two() >> 1;
match *self {
Tree::Empty { .. } => None,
Tree::Leaf { ref value, .. } => {
if n == 0 {
Some(value)
} else {
None
}
}
Tree::Node {
ref left,
ref right,
..
} => {
if n < left_count {
left.nth_leaf(n, left_count)
} else {
right.nth_leaf(n - left_count, count - left_count)
}
}
}
}
} }
/// An borrowing iterator over the leaves of a `Tree`. /// An borrowing iterator over the leaves of a `Tree`.