mirror of
https://github.com/mii443/merkle.rs.git
synced 2025-08-22 16:05:30 +00:00
Separate the leafs hash domain from the internal nodes' one (#22)
* Separate the leafs hash domain from the internal nodes' one. This change prevents an internal node from having the same hash as a leaf, and thus from potentially ending up with two different trees with the same root hash. Close #20 * Align with the CT spec, and allows building a tree from an empty dataset. Fixes #20. Prepares #24.
This commit is contained in:
committed by
Frederic Jacobs
parent
bebbcde461
commit
bce59c9f39
@ -30,7 +30,7 @@ fn bench_small_str_tree(b: &mut Bencher) {
|
|||||||
#[bench]
|
#[bench]
|
||||||
fn bench_small_str_proof_gen(b: &mut Bencher) {
|
fn bench_small_str_proof_gen(b: &mut Bencher) {
|
||||||
let values = vec!["one", "two", "three", "four"];
|
let values = vec!["one", "two", "three", "four"];
|
||||||
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
for value in &values {
|
for value in &values {
|
||||||
@ -43,7 +43,7 @@ fn bench_small_str_proof_gen(b: &mut Bencher) {
|
|||||||
#[bench]
|
#[bench]
|
||||||
fn bench_small_str_proof_check(b: &mut Bencher) {
|
fn bench_small_str_proof_check(b: &mut Bencher) {
|
||||||
let values = vec!["one", "two", "three", "four"];
|
let values = vec!["one", "two", "three", "four"];
|
||||||
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
let proofs = values.iter().map(|v| tree.gen_proof(v).unwrap()).collect::<Vec<_>>();
|
let proofs = values.iter().map(|v| tree.gen_proof(v).unwrap()).collect::<Vec<_>>();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
@ -63,7 +63,8 @@ fn bench_big_rnd_tree(b: &mut Bencher) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
MerkleTree::from_vec(digest, values.clone()).unwrap()
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
|
test::black_box(tree)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +77,7 @@ fn bench_big_rnd_proof_gen(b: &mut Bencher) {
|
|||||||
rng.fill_bytes(&mut v);
|
rng.fill_bytes(&mut v);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
for value in &values {
|
for value in &values {
|
||||||
@ -95,8 +96,10 @@ fn bench_big_rnd_proof_check(b: &mut Bencher) {
|
|||||||
rng.fill_bytes(&mut v);
|
rng.fill_bytes(&mut v);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
let proofs = values.into_iter().map(|v| tree.gen_proof(v).unwrap()).collect::<Vec<_>>();
|
let proofs = values.into_iter()
|
||||||
|
.map(|v| tree.gen_proof(v).unwrap())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
for proof in &proofs {
|
for proof in &proofs {
|
||||||
@ -114,7 +117,7 @@ fn bench_big_rnd_iter(b: &mut Bencher) {
|
|||||||
rng.fill_bytes(&mut v);
|
rng.fill_bytes(&mut v);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
for value in &tree {
|
for value in &tree {
|
||||||
|
@ -1,27 +1,38 @@
|
|||||||
|
|
||||||
use ring::digest::{ Algorithm, Context, digest, Digest };
|
use ring::digest::{ Algorithm, Context, Digest, digest };
|
||||||
|
|
||||||
/// The sole purpose of this trait is to extend the standard
|
/// The sole purpose of this trait is to extend the standard
|
||||||
/// `ring::algo::Algorithm` type with a couple utility functions.
|
/// `ring::algo::Algorithm` type with a couple utility functions.
|
||||||
pub trait HashUtils {
|
pub trait HashUtils {
|
||||||
|
|
||||||
/// Compute the hash the given byte array
|
/// Compute the hash of the empty string
|
||||||
fn hash_bytes(&'static self, bytes: &AsRef<[u8]>) -> Digest;
|
fn hash_empty(&'static self) -> Digest;
|
||||||
|
|
||||||
|
/// Compute the hash of the given leaf
|
||||||
|
fn hash_leaf(&'static self, bytes: &AsRef<[u8]>) -> Digest;
|
||||||
|
|
||||||
/// Compute the hash of the concatenation of `left` and `right`.
|
/// Compute the hash of the concatenation of `left` and `right`.
|
||||||
// XXX: This is overly generic temporarily to make refactoring easier.
|
// XXX: This is overly generic temporarily to make refactoring easier.
|
||||||
// TODO: Give `left` and `right` type &Digest.
|
// TODO: Give `left` and `right` type &Digest.
|
||||||
fn combine_hashes(&'static self, left: &AsRef<[u8]>, right: &AsRef<[u8]>) -> Digest;
|
fn hash_nodes(&'static self, left: &AsRef<[u8]>, right: &AsRef<[u8]>) -> Digest;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HashUtils for Algorithm {
|
impl HashUtils for Algorithm {
|
||||||
|
|
||||||
fn hash_bytes(&'static self, bytes: &AsRef<[u8]>) -> Digest {
|
fn hash_empty(&'static self) -> Digest {
|
||||||
digest(self, bytes.as_ref())
|
digest(self, &[])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn combine_hashes(&'static self, left: &AsRef<[u8]>, right: &AsRef<[u8]>) -> Digest {
|
fn hash_leaf(&'static self, leaf: &AsRef<[u8]>) -> Digest {
|
||||||
let mut ctx = Context::new(self);
|
let mut ctx = Context::new(self);
|
||||||
|
ctx.update(&[0x00]);
|
||||||
|
ctx.update(leaf.as_ref());
|
||||||
|
ctx.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash_nodes(&'static self, left: &AsRef<[u8]>, right: &AsRef<[u8]>) -> Digest {
|
||||||
|
let mut ctx = Context::new(self);
|
||||||
|
ctx.update(&[0x01]);
|
||||||
ctx.update(left.as_ref());
|
ctx.update(left.as_ref());
|
||||||
ctx.update(right.as_ref());
|
ctx.update(right.as_ref());
|
||||||
ctx.finish()
|
ctx.finish()
|
||||||
|
@ -28,11 +28,16 @@ impl <T> MerkleTree<T> {
|
|||||||
|
|
||||||
/// Constructs a Merkle Tree from a vector of data blocks.
|
/// Constructs a Merkle Tree from a vector of data blocks.
|
||||||
/// Returns `None` if `values` is empty.
|
/// Returns `None` if `values` is empty.
|
||||||
pub fn from_vec(algorithm: &'static Algorithm, values: Vec<T>) -> Option<Self>
|
pub fn from_vec(algorithm: &'static Algorithm, values: Vec<T>) -> Self
|
||||||
where T: AsRef<[u8]> {
|
where T: AsRef<[u8]> {
|
||||||
|
|
||||||
if values.is_empty() {
|
if values.is_empty() {
|
||||||
return None
|
return MerkleTree {
|
||||||
|
algorithm: algorithm,
|
||||||
|
root: Tree::empty(algorithm.hash_empty()),
|
||||||
|
height: 0,
|
||||||
|
count: 0
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let count = values.len();
|
let count = values.len();
|
||||||
@ -40,7 +45,7 @@ impl <T> MerkleTree<T> {
|
|||||||
let mut cur = Vec::with_capacity(count);
|
let mut cur = Vec::with_capacity(count);
|
||||||
|
|
||||||
for v in values {
|
for v in values {
|
||||||
let leaf = Tree::make_leaf(algorithm, v);
|
let leaf = Tree::new_leaf(algorithm, v);
|
||||||
cur.push(leaf);
|
cur.push(leaf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +59,7 @@ impl <T> MerkleTree<T> {
|
|||||||
let left = cur.remove(0);
|
let left = cur.remove(0);
|
||||||
let right = cur.remove(0);
|
let right = cur.remove(0);
|
||||||
|
|
||||||
let combined_hash = algorithm.combine_hashes(
|
let combined_hash = algorithm.hash_nodes(
|
||||||
left.hash(),
|
left.hash(),
|
||||||
right.hash()
|
right.hash()
|
||||||
);
|
);
|
||||||
@ -74,16 +79,16 @@ impl <T> MerkleTree<T> {
|
|||||||
cur = next;
|
cur = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(cur.len() == 1);
|
debug_assert!(cur.len() == 1);
|
||||||
|
|
||||||
let root = cur.remove(0);
|
let root = cur.remove(0);
|
||||||
|
|
||||||
Some(MerkleTree {
|
MerkleTree {
|
||||||
algorithm: algorithm,
|
algorithm: algorithm,
|
||||||
root: root,
|
root: root,
|
||||||
height: height,
|
height: height,
|
||||||
count: count
|
count: count
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the root hash of Merkle tree
|
/// Returns the root hash of Merkle tree
|
||||||
@ -107,9 +112,9 @@ impl <T> MerkleTree<T> {
|
|||||||
where T: AsRef<[u8]> {
|
where T: AsRef<[u8]> {
|
||||||
|
|
||||||
let root_hash = self.root_hash().clone();
|
let root_hash = self.root_hash().clone();
|
||||||
let node_hash = self.algorithm.hash_bytes(&value.as_ref());
|
let leaf_hash = self.algorithm.hash_leaf(&value.as_ref());
|
||||||
|
|
||||||
Lemma::new(&self.root, node_hash.as_ref()).map(|lemma|
|
Lemma::new(&self.root, leaf_hash.as_ref()).map(|lemma|
|
||||||
Proof::new(self.algorithm, root_hash, lemma, value)
|
Proof::new(self.algorithm, root_hash, lemma, value)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -56,13 +56,13 @@ impl <T> Proof<T> {
|
|||||||
false,
|
false,
|
||||||
|
|
||||||
Some(Positioned::Left(ref hash)) => {
|
Some(Positioned::Left(ref hash)) => {
|
||||||
let combined = self.algorithm.combine_hashes(hash, &sub.node_hash);
|
let combined = self.algorithm.hash_nodes(hash, &sub.node_hash);
|
||||||
let hashes_match = combined.as_ref() == lemma.node_hash.as_slice();
|
let hashes_match = combined.as_ref() == lemma.node_hash.as_slice();
|
||||||
hashes_match && self.validate_lemma(sub)
|
hashes_match && self.validate_lemma(sub)
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Positioned::Right(ref hash)) => {
|
Some(Positioned::Right(ref hash)) => {
|
||||||
let combined = self.algorithm.combine_hashes(&sub.node_hash, hash);
|
let combined = self.algorithm.hash_nodes(&sub.node_hash, hash);
|
||||||
let hashes_match = combined.as_ref() == lemma.node_hash.as_slice();
|
let hashes_match = combined.as_ref() == lemma.node_hash.as_slice();
|
||||||
hashes_match && self.validate_lemma(sub)
|
hashes_match && self.validate_lemma(sub)
|
||||||
}
|
}
|
||||||
@ -91,6 +91,9 @@ impl Lemma {
|
|||||||
where T: AsRef<[u8]> {
|
where T: AsRef<[u8]> {
|
||||||
|
|
||||||
match *tree {
|
match *tree {
|
||||||
|
Tree::Empty {.. } =>
|
||||||
|
None,
|
||||||
|
|
||||||
Tree::Leaf { ref hash, .. } =>
|
Tree::Leaf { ref hash, .. } =>
|
||||||
Lemma::new_leaf_proof(hash, needle),
|
Lemma::new_leaf_proof(hash, needle),
|
||||||
|
|
||||||
|
77
src/tests.rs
77
src/tests.rs
@ -15,19 +15,19 @@ fn test_from_str_vec() {
|
|||||||
let values = vec!["one", "two", "three", "four"];
|
let values = vec!["one", "two", "three", "four"];
|
||||||
|
|
||||||
let hashes = vec![
|
let hashes = vec![
|
||||||
digest.hash_bytes(&values[0].as_bytes()),
|
digest.hash_leaf(&values[0].as_bytes()),
|
||||||
digest.hash_bytes(&values[1].as_bytes()),
|
digest.hash_leaf(&values[1].as_bytes()),
|
||||||
digest.hash_bytes(&values[2].as_bytes()),
|
digest.hash_leaf(&values[2].as_bytes()),
|
||||||
digest.hash_bytes(&values[3].as_bytes())
|
digest.hash_leaf(&values[3].as_bytes())
|
||||||
];
|
];
|
||||||
|
|
||||||
let count = values.len();
|
let count = values.len();
|
||||||
let tree = MerkleTree::from_vec(digest, values).unwrap();
|
let tree = MerkleTree::from_vec(digest, values);
|
||||||
|
|
||||||
let h01 = digest.combine_hashes(&hashes[0], &hashes[1]);
|
let h01 = digest.hash_nodes(&hashes[0], &hashes[1]);
|
||||||
let h23 = digest.combine_hashes(&hashes[2], &hashes[3]);
|
let h23 = digest.hash_nodes(&hashes[2], &hashes[3]);
|
||||||
|
|
||||||
let root_hash = digest.combine_hashes(&h01, &h23);
|
let root_hash = digest.hash_nodes(&h01, &h23);
|
||||||
|
|
||||||
assert_eq!(tree.count(), count);
|
assert_eq!(tree.count(), count);
|
||||||
assert_eq!(tree.height(), 2);
|
assert_eq!(tree.height(), 2);
|
||||||
@ -36,18 +36,21 @@ fn test_from_str_vec() {
|
|||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
|
||||||
fn test_from_vec_empty() {
|
fn test_from_vec_empty() {
|
||||||
let values: Vec<Vec<u8>> = vec![];
|
let values: Vec<Vec<u8>> = vec![];
|
||||||
MerkleTree::from_vec(digest, values).unwrap();
|
let tree = MerkleTree::from_vec(digest, values);
|
||||||
|
let empty_hash: Vec<u8> = digest.hash_empty().as_ref().into();
|
||||||
|
let root_hash= tree.root_hash().clone();
|
||||||
|
|
||||||
|
assert_eq!(root_hash, empty_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_vec1() {
|
fn test_from_vec1() {
|
||||||
let values = vec!["hello, world".to_string()];
|
let values = vec!["hello, world".to_string()];
|
||||||
let tree = MerkleTree::from_vec(digest, values).unwrap();
|
let tree = MerkleTree::from_vec(digest, values);
|
||||||
|
|
||||||
let root_hash = &digest.hash_bytes(&"hello, world".as_bytes());
|
let root_hash = &digest.hash_leaf(&"hello, world".as_bytes());
|
||||||
|
|
||||||
assert_eq!(tree.count(), 1);
|
assert_eq!(tree.count(), 1);
|
||||||
assert_eq!(tree.height(), 0);
|
assert_eq!(tree.height(), 0);
|
||||||
@ -58,17 +61,17 @@ fn test_from_vec1() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_from_vec3() {
|
fn test_from_vec3() {
|
||||||
let values = vec![vec![1], vec![2], vec![3]];
|
let values = vec![vec![1], vec![2], vec![3]];
|
||||||
let tree = MerkleTree::from_vec(digest, values).unwrap();
|
let tree = MerkleTree::from_vec(digest, values);
|
||||||
|
|
||||||
let hashes = vec![
|
let hashes = vec![
|
||||||
digest.hash_bytes(&vec![1]),
|
digest.hash_leaf(&vec![1]),
|
||||||
digest.hash_bytes(&vec![2]),
|
digest.hash_leaf(&vec![2]),
|
||||||
digest.hash_bytes(&vec![3])
|
digest.hash_leaf(&vec![3])
|
||||||
];
|
];
|
||||||
|
|
||||||
let h01 = digest.combine_hashes(&hashes[0], &hashes[1]);
|
let h01 = digest.hash_nodes(&hashes[0], &hashes[1]);
|
||||||
let h2 = &hashes[2];
|
let h2 = &hashes[2];
|
||||||
let root_hash = &digest.combine_hashes(&h01, h2);
|
let root_hash = &digest.hash_nodes(&h01, h2);
|
||||||
|
|
||||||
assert_eq!(tree.count(), 3);
|
assert_eq!(tree.count(), 3);
|
||||||
assert_eq!(tree.height(), 2);
|
assert_eq!(tree.height(), 2);
|
||||||
@ -78,20 +81,20 @@ fn test_from_vec3() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_from_vec9() {
|
fn test_from_vec9() {
|
||||||
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
||||||
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
|
|
||||||
let hashes = values.iter().map(|v| digest.hash_bytes(v)).collect::<Vec<_>>();
|
let hashes = values.iter().map(|v| digest.hash_leaf(v)).collect::<Vec<_>>();
|
||||||
|
|
||||||
let h01 = digest.combine_hashes(&hashes[0], &hashes[1]);
|
let h01 = digest.hash_nodes(&hashes[0], &hashes[1]);
|
||||||
let h23 = digest.combine_hashes(&hashes[2], &hashes[3]);
|
let h23 = digest.hash_nodes(&hashes[2], &hashes[3]);
|
||||||
let h45 = digest.combine_hashes(&hashes[4], &hashes[5]);
|
let h45 = digest.hash_nodes(&hashes[4], &hashes[5]);
|
||||||
let h67 = digest.combine_hashes(&hashes[6], &hashes[7]);
|
let h67 = digest.hash_nodes(&hashes[6], &hashes[7]);
|
||||||
let h8 = &hashes[8];
|
let h8 = &hashes[8];
|
||||||
let h0123 = digest.combine_hashes(&h01, &h23);
|
let h0123 = digest.hash_nodes(&h01, &h23);
|
||||||
let h4567 = digest.combine_hashes(&h45, &h67);
|
let h4567 = digest.hash_nodes(&h45, &h67);
|
||||||
let h1to7 = digest.combine_hashes(&h0123, &h4567);
|
let h1to7 = digest.hash_nodes(&h0123, &h4567);
|
||||||
|
|
||||||
let root_hash = &digest.combine_hashes(&h1to7, h8);
|
let root_hash = &digest.hash_nodes(&h1to7, h8);
|
||||||
|
|
||||||
assert_eq!(tree.count(), 9);
|
assert_eq!(tree.count(), 9);
|
||||||
assert_eq!(tree.height(), 4);
|
assert_eq!(tree.height(), 4);
|
||||||
@ -101,7 +104,7 @@ fn test_from_vec9() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_valid_proof() {
|
fn test_valid_proof() {
|
||||||
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
||||||
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
let root_hash = tree.root_hash();
|
let root_hash = tree.root_hash();
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
@ -115,7 +118,7 @@ fn test_valid_proof() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_valid_proof_str() {
|
fn test_valid_proof_str() {
|
||||||
let values = vec!["Hello", "my", "name", "is", "Rusty"];
|
let values = vec!["Hello", "my", "name", "is", "Rusty"];
|
||||||
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
let root_hash = tree.root_hash();
|
let root_hash = tree.root_hash();
|
||||||
|
|
||||||
let value = "Rusty";
|
let value = "Rusty";
|
||||||
@ -129,10 +132,10 @@ fn test_valid_proof_str() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_wrong_proof() {
|
fn test_wrong_proof() {
|
||||||
let values1 = vec![vec![1], vec![2], vec![3], vec![4]];
|
let values1 = vec![vec![1], vec![2], vec![3], vec![4]];
|
||||||
let tree1 = MerkleTree::from_vec(digest, values1.clone()).unwrap();
|
let tree1 = MerkleTree::from_vec(digest, values1.clone());
|
||||||
|
|
||||||
let values2 = vec![vec![4], vec![5], vec![6], vec![7]];
|
let values2 = vec![vec![4], vec![5], vec![6], vec![7]];
|
||||||
let tree2 = MerkleTree::from_vec(digest, values2.clone()).unwrap();
|
let tree2 = MerkleTree::from_vec(digest, values2.clone());
|
||||||
|
|
||||||
let root_hash = tree2.root_hash();
|
let root_hash = tree2.root_hash();
|
||||||
|
|
||||||
@ -147,7 +150,7 @@ fn test_wrong_proof() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_mutate_proof_first_lemma() {
|
fn test_mutate_proof_first_lemma() {
|
||||||
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
||||||
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
let root_hash = tree.root_hash();
|
let root_hash = tree.root_hash();
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
@ -177,7 +180,7 @@ fn test_mutate_proof_first_lemma() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_tree_iter() {
|
fn test_tree_iter() {
|
||||||
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
||||||
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
let iter = tree.iter().map(|x| x.clone()).collect::<Vec<_>>();
|
let iter = tree.iter().map(|x| x.clone()).collect::<Vec<_>>();
|
||||||
|
|
||||||
assert_eq!(values, iter);
|
assert_eq!(values, iter);
|
||||||
@ -186,7 +189,7 @@ fn test_tree_iter() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_tree_into_iter() {
|
fn test_tree_into_iter() {
|
||||||
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
||||||
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
let iter = tree.into_iter().map(|x| x.clone()).collect::<Vec<_>>();
|
let iter = tree.into_iter().map(|x| x.clone()).collect::<Vec<_>>();
|
||||||
|
|
||||||
assert_eq!(values, iter);
|
assert_eq!(values, iter);
|
||||||
@ -195,7 +198,7 @@ fn test_tree_into_iter() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_tree_into_iter_loop() {
|
fn test_tree_into_iter_loop() {
|
||||||
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
||||||
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
|
|
||||||
let mut collected = Vec::new();
|
let mut collected = Vec::new();
|
||||||
|
|
||||||
@ -209,7 +212,7 @@ fn test_tree_into_iter_loop() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_tree_into_iter_loop_borrow() {
|
fn test_tree_into_iter_loop_borrow() {
|
||||||
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
||||||
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
|
|
||||||
let mut collected = Vec::new();
|
let mut collected = Vec::new();
|
||||||
|
|
||||||
|
30
src/tree.rs
30
src/tree.rs
@ -12,6 +12,10 @@ pub use proof::{
|
|||||||
/// Binary Tree where leaves hold a stand-alone value.
|
/// Binary Tree where leaves hold a stand-alone value.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Tree<T> {
|
pub enum Tree<T> {
|
||||||
|
Empty {
|
||||||
|
hash: Vec<u8>
|
||||||
|
},
|
||||||
|
|
||||||
Leaf {
|
Leaf {
|
||||||
hash: Vec<u8>,
|
hash: Vec<u8>,
|
||||||
value: T
|
value: T
|
||||||
@ -26,6 +30,13 @@ pub enum Tree<T> {
|
|||||||
|
|
||||||
impl <T> Tree<T> {
|
impl <T> Tree<T> {
|
||||||
|
|
||||||
|
/// Create an empty tree
|
||||||
|
pub fn empty(hash: Digest) -> Self {
|
||||||
|
Tree::Empty {
|
||||||
|
hash: hash.as_ref().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new tree
|
/// Create a new tree
|
||||||
pub fn new(hash: Digest, value: T) -> Self {
|
pub fn new(hash: Digest, value: T) -> Self {
|
||||||
Tree::Leaf {
|
Tree::Leaf {
|
||||||
@ -35,18 +46,19 @@ impl <T> Tree<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new leaf
|
/// Create a new leaf
|
||||||
pub fn make_leaf(algo: &'static Algorithm, value: T) -> Tree<T>
|
pub fn new_leaf(algo: &'static Algorithm, value: T) -> Tree<T>
|
||||||
where T: AsRef<[u8]> {
|
where T: AsRef<[u8]> {
|
||||||
|
|
||||||
let hash = algo.hash_bytes(&value.as_ref());
|
let hash = algo.hash_leaf(&value.as_ref());
|
||||||
Tree::new(hash, value)
|
Tree::new(hash, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a hash from the tree.
|
/// Returns a hash from the tree.
|
||||||
pub fn hash(&self) -> &Vec<u8> {
|
pub fn hash(&self) -> &Vec<u8> {
|
||||||
match *self {
|
match *self {
|
||||||
Tree::Leaf { ref hash, .. } | Tree::Node { ref hash, .. } =>
|
Tree::Empty { ref hash } => hash,
|
||||||
hash
|
Tree::Leaf { ref hash, .. } => hash,
|
||||||
|
Tree::Node { ref hash, .. } => hash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +93,11 @@ impl <'a, T> LeavesIterator<'a, T> {
|
|||||||
fn add_left(&mut self, mut tree: &'a Tree<T>) {
|
fn add_left(&mut self, mut tree: &'a Tree<T>) {
|
||||||
loop {
|
loop {
|
||||||
match *tree {
|
match *tree {
|
||||||
|
Tree::Empty { .. } => {
|
||||||
|
self.current_value = None;
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
|
||||||
Tree::Node { ref left, ref right, .. } => {
|
Tree::Node { ref left, ref right, .. } => {
|
||||||
self.right_nodes.push(right);
|
self.right_nodes.push(right);
|
||||||
tree = left;
|
tree = left;
|
||||||
@ -135,6 +152,11 @@ impl <T> LeavesIntoIterator<T> {
|
|||||||
fn add_left(&mut self, mut tree: Tree<T>) {
|
fn add_left(&mut self, mut tree: Tree<T>) {
|
||||||
loop {
|
loop {
|
||||||
match tree {
|
match tree {
|
||||||
|
Tree::Empty { .. } => {
|
||||||
|
self.current_value = None;
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
|
||||||
Tree::Node { left, right, .. } => {
|
Tree::Node { left, right, .. } => {
|
||||||
self.right_nodes.push(*right);
|
self.right_nodes.push(*right);
|
||||||
tree = *left;
|
tree = *left;
|
||||||
|
@ -16,7 +16,7 @@ static digest: &'static Algorithm = &SHA512;
|
|||||||
fn test_protobuf_inverse() {
|
fn test_protobuf_inverse() {
|
||||||
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
let values = (1..10).map(|x| vec![x]).collect::<Vec<_>>();
|
||||||
|
|
||||||
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone());
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
let proof = tree.gen_proof(value).unwrap();
|
let proof = tree.gen_proof(value).unwrap();
|
||||||
|
Reference in New Issue
Block a user