Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ matrix:
- libdw-dev
- binutils-dev
- libiberty-dev
- zlib1g-dev
- zlib1g-dev

- env: NAME='clippy'
rust: nightly-2018-07-22
before_script:
- rustup component add clippy-preview
script:
- cargo clippy --all -- -D clippy
- cargo clippy --all --all-features -- -D clippy

env:
global:
Expand Down
10 changes: 10 additions & 0 deletions src/merkletree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,16 @@ impl<T> MerkleTree<T> {
.map(|lemma| Proof::new(self.algorithm, root_hash, lemma, value))
}

/// Generate an inclusion proof for the `n`-th leaf value.
pub fn gen_nth_proof(&self, n: usize) -> Option<Proof<T>>
where
T: Hashable + Clone,
{
let root_hash = self.root_hash().clone();
Lemma::new_by_index(&self.root, n, self.count)
.map(|(lemma, value)| Proof::new(self.algorithm, root_hash, lemma, value.clone()))
}

/// Creates an `Iterator` over the values contained in this Merkle tree.
pub fn iter(&self) -> LeavesIterator<T> {
self.root.iter()
Expand Down
85 changes: 82 additions & 3 deletions src/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ mod algorithm_serde {
}
}

#[cfg(test)]
mod test {
use super::*;
use ring::digest::{
Expand All @@ -74,13 +75,13 @@ mod algorithm_serde {
fn test_serialize_known_algorithms() {
extern crate serde_json;

for alg in [SHA1, SHA256, SHA384, SHA512, SHA512_256].iter() {
for alg in &[SHA1, SHA256, SHA384, SHA512, SHA512_256] {
let mut serializer = serde_json::Serializer::with_formatter(
vec![],
serde_json::ser::PrettyFormatter::new(),
);

let _ = serialize(alg, &mut serializer).expect(&format!("{:?}", alg));
serialize(alg, &mut serializer).expect(&format!("{:?}", alg));
let alg_ = deserialize(&mut serde_json::Deserializer::from_slice(
&serializer.into_inner()[..],
)).expect(&format!("{:?}", alg));
Expand Down Expand Up @@ -153,6 +154,15 @@ impl<T> Proof<T> {

self.lemma.validate(self.algorithm)
}

/// Returns the index of this proof's value, given the total number of items in the tree.
///
/// # Panics
///
/// Panics if the proof is malformed. Call `validate` first.
pub fn index(&self, count: usize) -> usize {
self.lemma.index(count)
}
}

/// A `Lemma` holds the hash of a node, the hash of its sibling node,
Expand All @@ -170,7 +180,8 @@ pub struct Lemma {
}

impl Lemma {
/// Attempts to generate a proof that the a value with hash `needle` is a member of the given `tree`.
/// Attempts to generate a proof that the a value with hash `needle` is a
/// member of the given `tree`.
pub fn new<T>(tree: &Tree<T>, needle: &[u8]) -> Option<Lemma> {
match *tree {
Tree::Empty { .. } => None,
Expand All @@ -185,6 +196,74 @@ impl Lemma {
}
}

/// 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
/// `tree`. If `idx >= count`, `None` is returned. Otherwise it returns
/// 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 {
return None;
}
match *tree {
Tree::Empty { .. } => None,

Tree::Leaf {
ref hash,
ref value,
..
} => {
if count != 1 {
return None;
}
let lemma = Lemma {
node_hash: hash.clone(),
sibling_hash: None,
sub_lemma: None,
};
Some((lemma, value))
}

Tree::Node {
ref hash,
ref left,
ref 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)
})
}
}
}

/// Returns the index of this lemma's value, given the total number of items in the tree.
///
/// # Panics
///
/// Panics if the lemma is malformed. Call `validate_lemma` first.
pub fn index(&self, count: usize) -> usize {
let left_count = count.next_power_of_two() / 2;
match (self.sub_lemma.as_ref(), self.sibling_hash.as_ref()) {
(None, None) => 0,
(Some(l), Some(&Positioned::Left(_))) => left_count + l.index(count - left_count),
(Some(l), Some(&Positioned::Right(_))) => l.index(left_count),
(None, Some(_)) | (Some(_), None) => panic!("malformed lemma"),
}
}

fn new_leaf_proof(hash: &[u8], needle: &[u8]) -> Option<Lemma> {
if *hash == *needle {
Some(Lemma {
Expand Down
22 changes: 21 additions & 1 deletion src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,26 @@ fn test_wrong_proof() {
}
}

#[test]
fn test_nth_proof() {
// Calculation depends on the total count. Try a few numbers: odd, even, powers of two...
for &count in &[1, 2, 3, 10, 15, 16, 17, 22] {
let values = (1..(count + 1)).map(|x| vec![x as u8]).collect::<Vec<_>>();
let tree = MerkleTree::from_vec(digest, values.clone());
let root_hash = tree.root_hash();

for i in 0..count {
let proof = tree.gen_nth_proof(i).expect("gen proof by index");
assert_eq!(vec![i as u8 + 1], proof.value);
assert!(proof.validate(&root_hash));
assert_eq!(i, proof.index(tree.count()));
}

assert!(tree.gen_nth_proof(count).is_none());
assert!(tree.gen_nth_proof(count + 1000).is_none());
}
}

#[test]
fn test_mutate_proof_first_lemma() {
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
Expand Down Expand Up @@ -189,7 +209,7 @@ fn test_tree_iter() {
fn test_tree_into_iter() {
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
let tree = MerkleTree::from_vec(digest, values.clone());
let iter = tree.iter().cloned().collect::<Vec<_>>();
let iter = tree.into_iter().collect::<Vec<_>>();

assert_eq!(values, iter);
}
Expand Down
4 changes: 2 additions & 2 deletions tests/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ pub struct PublicKey {
impl PublicKey {
pub fn new(zero_values: Vec<u8>, one_values: Vec<u8>) -> Self {
PublicKey {
zero_values: zero_values,
one_values: one_values,
zero_values,
one_values,
}
}

Expand Down