mirror of
https://github.com/mii443/merkle.rs.git
synced 2025-08-22 16:05:30 +00:00
Port to ring. (#15)
This commit is contained in:
committed by
Frederic Jacobs
parent
e621241f2f
commit
4503258724
@ -14,7 +14,7 @@ homepage = "https://github.com/SpinResearch/merkle.rs"
|
|||||||
repository = "https://github.com/SpinResearch/merkle.rs"
|
repository = "https://github.com/SpinResearch/merkle.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rust-crypto = "^0.2.36"
|
ring = "0.6.0-alpha"
|
||||||
protobuf = { version = "^1.0.0", optional = true }
|
protobuf = { version = "^1.0.0", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@ -6,17 +6,20 @@ extern crate test;
|
|||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
|
||||||
extern crate merkle;
|
extern crate merkle;
|
||||||
extern crate crypto;
|
extern crate ring;
|
||||||
|
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
|
use ring::digest::{Algorithm, SHA512};
|
||||||
|
|
||||||
use merkle::MerkleTree;
|
use merkle::MerkleTree;
|
||||||
use crypto::sha3::Sha3;
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static digest: &'static Algorithm = &SHA512;
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_small_str_tree(b: &mut Bencher) {
|
fn bench_small_str_tree(b: &mut Bencher) {
|
||||||
let digest = Sha3::sha3_256();
|
|
||||||
let values = vec!["one", "two", "three", "four"];
|
let values = vec!["one", "two", "three", "four"];
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
@ -26,7 +29,6 @@ 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 digest = Sha3::sha3_256();
|
|
||||||
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()).unwrap();
|
||||||
|
|
||||||
@ -40,7 +42,6 @@ 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 digest = Sha3::sha3_256();
|
|
||||||
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()).unwrap();
|
||||||
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<_>>();
|
||||||
@ -54,7 +55,6 @@ fn bench_small_str_proof_check(b: &mut Bencher) {
|
|||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_big_rnd_tree(b: &mut Bencher) {
|
fn bench_big_rnd_tree(b: &mut Bencher) {
|
||||||
let digest = Sha3::sha3_256();
|
|
||||||
let mut values = vec![vec![0u8; 256]; 160];
|
let mut values = vec![vec![0u8; 256]; 160];
|
||||||
let mut rng = rand::IsaacRng::new_unseeded();
|
let mut rng = rand::IsaacRng::new_unseeded();
|
||||||
|
|
||||||
@ -69,7 +69,6 @@ fn bench_big_rnd_tree(b: &mut Bencher) {
|
|||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_big_rnd_proof_gen(b: &mut Bencher) {
|
fn bench_big_rnd_proof_gen(b: &mut Bencher) {
|
||||||
let digest = Sha3::sha3_256();
|
|
||||||
let mut values = vec![vec![0u8; 256]; 160];
|
let mut values = vec![vec![0u8; 256]; 160];
|
||||||
let mut rng = rand::IsaacRng::new_unseeded();
|
let mut rng = rand::IsaacRng::new_unseeded();
|
||||||
|
|
||||||
@ -89,7 +88,6 @@ fn bench_big_rnd_proof_gen(b: &mut Bencher) {
|
|||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_big_rnd_proof_check(b: &mut Bencher) {
|
fn bench_big_rnd_proof_check(b: &mut Bencher) {
|
||||||
let digest = Sha3::sha3_256();
|
|
||||||
let mut values = vec![vec![0u8; 256]; 160];
|
let mut values = vec![vec![0u8; 256]; 160];
|
||||||
let mut rng = rand::IsaacRng::new_unseeded();
|
let mut rng = rand::IsaacRng::new_unseeded();
|
||||||
|
|
||||||
|
30
src/hashutils.rs
Normal file
30
src/hashutils.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
use ring::digest::{ Algorithm, Context };
|
||||||
|
|
||||||
|
/// The sole purpose of this trait is to extend the standard
|
||||||
|
/// `ring::algo::Algorithm` type with a couple utility functions.
|
||||||
|
pub trait HashUtils {
|
||||||
|
|
||||||
|
/// Compute the hash the given byte array
|
||||||
|
fn hash_bytes(&'static self, bytes: &[u8]) -> Vec<u8>;
|
||||||
|
|
||||||
|
/// Compute the hash of the concatenation of `left` and `right`
|
||||||
|
fn combine_hashes(&'static self, left: &[u8], right: &[u8]) -> Vec<u8>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HashUtils for Algorithm {
|
||||||
|
|
||||||
|
fn hash_bytes(&'static self, bytes: &[u8]) -> Vec<u8> {
|
||||||
|
let mut context = Context::new(self);
|
||||||
|
context.update(bytes);
|
||||||
|
context.finish().as_ref().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn combine_hashes(&'static self, left: &[u8], right: &[u8]) -> Vec<u8> {
|
||||||
|
let mut context = Context::new(self);
|
||||||
|
let combined = [left, right].concat();
|
||||||
|
context.update(&combined);
|
||||||
|
context.finish().as_ref().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
//! *merkle* implements a Merkle Tree in Rust.
|
//! *merkle* implements a Merkle Tree in Rust.
|
||||||
|
|
||||||
extern crate crypto;
|
extern crate ring;
|
||||||
|
|
||||||
#[cfg(feature = "serialization-protobuf")]
|
#[cfg(feature = "serialization-protobuf")]
|
||||||
extern crate protobuf;
|
extern crate protobuf;
|
||||||
@ -19,7 +19,7 @@ pub use merkletree::MerkleTree;
|
|||||||
mod proof;
|
mod proof;
|
||||||
pub use proof::Proof;
|
pub use proof::Proof;
|
||||||
|
|
||||||
mod merkledigest;
|
mod hashutils;
|
||||||
|
|
||||||
mod tree;
|
mod tree;
|
||||||
|
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
use crypto::digest::Digest;
|
|
||||||
|
|
||||||
/// The sole purpose of this trait is to extend the standard
|
|
||||||
/// `crypto::digest::Digest` with a couple utility functions.
|
|
||||||
pub trait MerkleDigest {
|
|
||||||
|
|
||||||
/// Compute the hash the given byte array
|
|
||||||
fn hash_bytes(&mut self, bytes: &[u8]) -> Vec<u8>;
|
|
||||||
|
|
||||||
/// Compute the hash of the concatenation of `left` and `right`
|
|
||||||
fn combine_hashes(&mut self, left: &[u8], right: &[u8]) -> Vec<u8>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <D> MerkleDigest for D where D: Digest {
|
|
||||||
|
|
||||||
fn hash_bytes(&mut self, bytes: &[u8]) -> Vec<u8> {
|
|
||||||
let mut hash = vec![0; self.output_bytes()];
|
|
||||||
|
|
||||||
self.reset();
|
|
||||||
self.input(bytes);
|
|
||||||
self.result(&mut hash);
|
|
||||||
self.reset();
|
|
||||||
|
|
||||||
hash
|
|
||||||
}
|
|
||||||
|
|
||||||
fn combine_hashes(&mut self, left: &[u8], right: &[u8]) -> Vec<u8> {
|
|
||||||
let mut hash = vec![0; self.output_bytes()];
|
|
||||||
|
|
||||||
self.reset();
|
|
||||||
self.input(left);
|
|
||||||
self.input(right);
|
|
||||||
self.result(&mut hash);
|
|
||||||
self.reset();
|
|
||||||
|
|
||||||
hash
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +1,19 @@
|
|||||||
|
|
||||||
use crypto::digest::Digest;
|
use ring::digest::Algorithm;
|
||||||
|
|
||||||
use tree::Tree;
|
use tree::Tree;
|
||||||
use merkledigest::MerkleDigest;
|
use hashutils::HashUtils;
|
||||||
|
|
||||||
use proof::{ Proof, Lemma };
|
use proof::{ Proof, Lemma };
|
||||||
|
|
||||||
/// A Merkle tree is a binary tree, with values of type `T` at the leafs,
|
/// A Merkle tree is a binary tree, with values of type `T` at the leafs,
|
||||||
/// and where every node holds the hash of the concatenation of the hashes of
|
/// and where every node holds the hash of the concatenation of the hashes of
|
||||||
/// its children nodes.
|
/// its children nodes.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct MerkleTree<D, T> {
|
pub struct MerkleTree<T> {
|
||||||
/// The hashing function used by this Merkle tree
|
|
||||||
digest: D,
|
/// The hashing algorithm used by this Merkle tree
|
||||||
|
pub algorithm: &'static Algorithm,
|
||||||
|
|
||||||
/// The root of the inner binary tree
|
/// The root of the inner binary tree
|
||||||
root: Tree<T>,
|
root: Tree<T>,
|
||||||
@ -24,11 +25,11 @@ pub struct MerkleTree<D, T> {
|
|||||||
count: usize
|
count: usize
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <D, T> MerkleTree<D, T> where D: Digest + Clone, T: Into<Vec<u8>> + Clone {
|
impl <T> MerkleTree<T> where T: Into<Vec<u8>> + Clone {
|
||||||
|
|
||||||
/// 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(mut digest: D, values: Vec<T>) -> Option<Self> {
|
pub fn from_vec(algo: &'static Algorithm, values: Vec<T>) -> Option<Self> {
|
||||||
if values.is_empty() {
|
if values.is_empty() {
|
||||||
return None
|
return None
|
||||||
}
|
}
|
||||||
@ -38,7 +39,7 @@ impl <D, T> MerkleTree<D, T> where D: Digest + Clone, T: Into<Vec<u8>> + Clone {
|
|||||||
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(&mut digest, v);
|
let leaf = Tree::make_leaf(algo, v);
|
||||||
cur.push(leaf);
|
cur.push(leaf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ impl <D, T> MerkleTree<D, T> where D: Digest + Clone, T: Into<Vec<u8>> + Clone {
|
|||||||
let left = cur.remove(0);
|
let left = cur.remove(0);
|
||||||
let right = cur.remove(0);
|
let right = cur.remove(0);
|
||||||
|
|
||||||
let combined_hash = digest.combine_hashes(
|
let combined_hash = algo.combine_hashes(
|
||||||
left.hash(),
|
left.hash(),
|
||||||
right.hash()
|
right.hash()
|
||||||
);
|
);
|
||||||
@ -77,18 +78,13 @@ impl <D, T> MerkleTree<D, T> where D: Digest + Clone, T: Into<Vec<u8>> + Clone {
|
|||||||
let root = cur.remove(0);
|
let root = cur.remove(0);
|
||||||
|
|
||||||
Some(MerkleTree {
|
Some(MerkleTree {
|
||||||
digest: digest,
|
algorithm: algo,
|
||||||
root: root,
|
root: root,
|
||||||
height: height,
|
height: height,
|
||||||
count: count
|
count: count
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the hash function used in this Merkle tree
|
|
||||||
pub fn digest(&self) -> &D {
|
|
||||||
&self.digest
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the root hash of Merkle tree
|
/// Returns the root hash of Merkle tree
|
||||||
pub fn root_hash(&self) -> &Vec<u8> {
|
pub fn root_hash(&self) -> &Vec<u8> {
|
||||||
self.root.hash()
|
self.root.hash()
|
||||||
@ -106,13 +102,12 @@ impl <D, T> MerkleTree<D, T> where D: Digest + Clone, T: Into<Vec<u8>> + Clone {
|
|||||||
|
|
||||||
/// Generate an inclusion proof for the given value.
|
/// Generate an inclusion proof for the given value.
|
||||||
/// Returns `None` if the given value is not found in the tree.
|
/// Returns `None` if the given value is not found in the tree.
|
||||||
pub fn gen_proof(&self, value: T) -> Option<Proof<D, T>> {
|
pub fn gen_proof(&self, value: T) -> Option<Proof<T>> {
|
||||||
let mut digest = self.digest.clone();
|
|
||||||
let root_hash = self.root_hash().clone();
|
let root_hash = self.root_hash().clone();
|
||||||
let node_hash = digest.hash_bytes(&value.clone().into());
|
let node_hash = self.algorithm.hash_bytes(&value.clone().into());
|
||||||
|
|
||||||
Lemma::new(&self.root, &node_hash).map(|lemma|
|
Lemma::new(&self.root, &node_hash).map(|lemma|
|
||||||
Proof::new(digest, root_hash, lemma, value)
|
Proof::new(self.algorithm, root_hash, lemma, value)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
38
src/proof.rs
38
src/proof.rs
@ -1,16 +1,16 @@
|
|||||||
|
|
||||||
use crypto::digest::Digest;
|
use ring::digest::Algorithm;
|
||||||
|
|
||||||
use tree::Tree;
|
use tree::Tree;
|
||||||
use merkledigest::MerkleDigest;
|
use hashutils::HashUtils;
|
||||||
|
|
||||||
/// An inclusion proof represent the fact that a `value` is a member
|
/// An inclusion proof represent the fact that a `value` is a member
|
||||||
/// of a `MerkleTree` with root hash `root_hash`, and hash function `digest`.
|
/// of a `MerkleTree` with root hash `root_hash`, and hash function `digest`.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Proof<D, T> {
|
pub struct Proof<T> {
|
||||||
|
|
||||||
/// The hash function used in the original `MerkleTree`
|
/// The hashing algorithm used in the original `MerkleTree`
|
||||||
pub digest: D,
|
pub algorithm: &'static Algorithm,
|
||||||
|
|
||||||
/// The hash of the root of the original `MerkleTree`
|
/// The hash of the root of the original `MerkleTree`
|
||||||
pub root_hash: Vec<u8>,
|
pub root_hash: Vec<u8>,
|
||||||
@ -22,12 +22,12 @@ pub struct Proof<D, T> {
|
|||||||
pub value: T
|
pub value: T
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <D, T> Proof<D, T> {
|
impl <T> Proof<T> {
|
||||||
|
|
||||||
/// Constructs a new `Proof`
|
/// Constructs a new `Proof`
|
||||||
pub fn new(digest: D, root_hash: Vec<u8>, lemma: Lemma, value: T) -> Self {
|
pub fn new(algo: &'static Algorithm, root_hash: Vec<u8>, lemma: Lemma, value: T) -> Self {
|
||||||
Proof {
|
Proof {
|
||||||
digest: digest,
|
algorithm: algo,
|
||||||
root_hash: root_hash,
|
root_hash: root_hash,
|
||||||
lemma: lemma,
|
lemma: lemma,
|
||||||
value: value
|
value: value
|
||||||
@ -36,15 +36,15 @@ impl <D, T> Proof<D, T> {
|
|||||||
|
|
||||||
/// Checks whether this inclusion proof is well-formed,
|
/// Checks whether this inclusion proof is well-formed,
|
||||||
/// and whether its root hash matches the given `root_hash`.
|
/// and whether its root hash matches the given `root_hash`.
|
||||||
pub fn validate(&self, root_hash: &[u8]) -> bool where D: Digest + Clone {
|
pub fn validate(&self, root_hash: &[u8]) -> bool {
|
||||||
if self.root_hash != root_hash || self.lemma.node_hash != root_hash {
|
if self.root_hash != root_hash || self.lemma.node_hash != root_hash {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
self.validate_lemma(&self.lemma, &mut self.digest.clone())
|
self.validate_lemma(&self.lemma)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_lemma(&self, lemma: &Lemma, digest: &mut D) -> bool where D: Digest {
|
fn validate_lemma(&self, lemma: &Lemma) -> bool {
|
||||||
match lemma.sub_lemma {
|
match lemma.sub_lemma {
|
||||||
|
|
||||||
None =>
|
None =>
|
||||||
@ -56,13 +56,13 @@ impl <D, T> Proof<D, T> {
|
|||||||
false,
|
false,
|
||||||
|
|
||||||
Some(Positioned::Left(ref hash)) => {
|
Some(Positioned::Left(ref hash)) => {
|
||||||
let hashes_match = digest.combine_hashes(hash, &sub.node_hash) == lemma.node_hash;
|
let hashes_match = self.algorithm.combine_hashes(hash, &sub.node_hash) == lemma.node_hash;
|
||||||
hashes_match && self.validate_lemma(sub, digest)
|
hashes_match && self.validate_lemma(sub)
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Positioned::Right(ref hash)) => {
|
Some(Positioned::Right(ref hash)) => {
|
||||||
let hashes_match = digest.combine_hashes(&sub.node_hash, hash) == lemma.node_hash;
|
let hashes_match = self.algorithm.combine_hashes(&sub.node_hash, hash) == lemma.node_hash;
|
||||||
hashes_match && self.validate_lemma(sub, digest)
|
hashes_match && self.validate_lemma(sub)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -85,7 +85,9 @@ pub struct Lemma {
|
|||||||
impl 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> where T: Into<Vec<u8>> + Clone {
|
pub fn new<T>(tree: &Tree<T>, needle: &[u8]) -> Option<Lemma>
|
||||||
|
where T: Into<Vec<u8>> + Clone {
|
||||||
|
|
||||||
match *tree {
|
match *tree {
|
||||||
Tree::Leaf { ref hash, .. } =>
|
Tree::Leaf { ref hash, .. } =>
|
||||||
Lemma::new_leaf_proof(hash, needle),
|
Lemma::new_leaf_proof(hash, needle),
|
||||||
@ -107,7 +109,9 @@ impl Lemma {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_tree_proof<T>(hash: &[u8], needle: &[u8], left: &Tree<T>, right: &Tree<T>) -> Option<Lemma> where T: Into<Vec<u8>> + Clone {
|
fn new_tree_proof<T>(hash: &[u8], needle: &[u8], left: &Tree<T>, right: &Tree<T>) -> Option<Lemma>
|
||||||
|
where T: Into<Vec<u8>> + Clone {
|
||||||
|
|
||||||
Lemma::new(left, needle)
|
Lemma::new(left, needle)
|
||||||
.map(|lemma| {
|
.map(|lemma| {
|
||||||
let right_hash = right.hash().clone();
|
let right_hash = right.hash().clone();
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
mod proof;
|
mod proof;
|
||||||
|
|
||||||
|
use ring::digest::Algorithm;
|
||||||
|
|
||||||
use proof::{ Proof, Lemma, Positioned };
|
use proof::{ Proof, Lemma, Positioned };
|
||||||
pub use self::proof::{ ProofProto, LemmaProto };
|
pub use self::proof::{ ProofProto, LemmaProto };
|
||||||
|
|
||||||
@ -8,13 +10,13 @@ use protobuf::Message;
|
|||||||
use protobuf::error::ProtobufResult;
|
use protobuf::error::ProtobufResult;
|
||||||
use protobuf::core::parse_from_bytes;
|
use protobuf::core::parse_from_bytes;
|
||||||
|
|
||||||
impl <D, T> Proof<D, T> {
|
impl <T> Proof<T> {
|
||||||
|
|
||||||
/// Constructs a `Proof` struct from its Protobuf representation.
|
/// Constructs a `Proof` struct from its Protobuf representation.
|
||||||
pub fn from_protobuf(digest: D, proto: ProofProto) -> Option<Self>
|
pub fn from_protobuf(algorithm: &'static Algorithm, proto: ProofProto) -> Option<Self>
|
||||||
where T: From<Vec<u8>>
|
where T: From<Vec<u8>>
|
||||||
{
|
{
|
||||||
proto.into_proof(digest)
|
proto.into_proof(algorithm)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encode this `Proof` to its Protobuf representation.
|
/// Encode this `Proof` to its Protobuf representation.
|
||||||
@ -25,10 +27,10 @@ impl <D, T> Proof<D, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a `Proof` from its Protobuf binary representation.
|
/// Parse a `Proof` from its Protobuf binary representation.
|
||||||
pub fn parse_from_bytes(bytes: &[u8], digest: D) -> ProtobufResult<Option<Proof<D, T>>>
|
pub fn parse_from_bytes(bytes: &[u8], algorithm: &'static Algorithm) -> ProtobufResult<Option<Self>>
|
||||||
where T: From<Vec<u8>>
|
where T: From<Vec<u8>>
|
||||||
{
|
{
|
||||||
parse_from_bytes::<ProofProto>(bytes).map(|proto| proto.into_proof(digest))
|
parse_from_bytes::<ProofProto>(bytes).map(|proto| proto.into_proof(algorithm))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serialize this `Proof` with Protobuf.
|
/// Serialize this `Proof` with Protobuf.
|
||||||
@ -40,7 +42,7 @@ impl <D, T> Proof<D, T> {
|
|||||||
|
|
||||||
impl ProofProto {
|
impl ProofProto {
|
||||||
|
|
||||||
pub fn from_proof<D, T>(proof: Proof<D, T>) -> Self
|
pub fn from_proof<T>(proof: Proof<T>) -> Self
|
||||||
where T: Into<Vec<u8>>
|
where T: Into<Vec<u8>>
|
||||||
{
|
{
|
||||||
let mut proto = Self::new();
|
let mut proto = Self::new();
|
||||||
@ -56,7 +58,7 @@ impl ProofProto {
|
|||||||
proto
|
proto
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_proof<D, T>(mut self, digest: D) -> Option<Proof<D, T>>
|
pub fn into_proof<T>(mut self, algorithm: &'static Algorithm) -> Option<Proof<T>>
|
||||||
where T: From<Vec<u8>>
|
where T: From<Vec<u8>>
|
||||||
{
|
{
|
||||||
if !self.has_root_hash() || !self.has_lemma() {
|
if !self.has_root_hash() || !self.has_lemma() {
|
||||||
@ -65,7 +67,7 @@ impl ProofProto {
|
|||||||
|
|
||||||
self.take_lemma().into_lemma().map(|lemma| {
|
self.take_lemma().into_lemma().map(|lemma| {
|
||||||
Proof::new(
|
Proof::new(
|
||||||
digest,
|
algorithm,
|
||||||
self.take_root_hash(),
|
self.take_root_hash(),
|
||||||
lemma,
|
lemma,
|
||||||
self.take_value().into()
|
self.take_value().into()
|
||||||
|
64
src/tests.rs
64
src/tests.rs
@ -1,16 +1,17 @@
|
|||||||
|
|
||||||
#![cfg(test)]
|
#![cfg(test)]
|
||||||
|
|
||||||
use crypto::sha3::Sha3;
|
use ring::digest::{ Algorithm, SHA512 };
|
||||||
|
|
||||||
use merkletree::MerkleTree;
|
use merkletree::MerkleTree;
|
||||||
use merkledigest::MerkleDigest;
|
use hashutils::HashUtils;
|
||||||
use proof::Positioned;
|
use proof::Positioned;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static digest: &'static Algorithm = &SHA512;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_str_vec() {
|
fn test_from_str_vec() {
|
||||||
let mut digest = Sha3::sha3_256();
|
|
||||||
|
|
||||||
let values = vec!["one", "two", "three", "four"];
|
let values = vec!["one", "two", "three", "four"];
|
||||||
|
|
||||||
let hashes = vec![
|
let hashes = vec![
|
||||||
@ -21,7 +22,7 @@ fn test_from_str_vec() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
let count = values.len();
|
let count = values.len();
|
||||||
let tree = MerkleTree::from_vec(Sha3::sha3_256(), values).unwrap();
|
let tree = MerkleTree::from_vec(digest, values).unwrap();
|
||||||
|
|
||||||
let h01 = digest.combine_hashes(&hashes[0], &hashes[1]);
|
let h01 = digest.combine_hashes(&hashes[0], &hashes[1]);
|
||||||
let h23 = digest.combine_hashes(&hashes[2], &hashes[3]);
|
let h23 = digest.combine_hashes(&hashes[2], &hashes[3]);
|
||||||
@ -38,16 +39,15 @@ fn test_from_str_vec() {
|
|||||||
#[should_panic]
|
#[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(Sha3::sha3_256(), values).unwrap();
|
MerkleTree::from_vec(digest, values).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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(Sha3::sha3_256(), values).unwrap();
|
let tree = MerkleTree::from_vec(digest, values).unwrap();
|
||||||
|
|
||||||
let mut d = Sha3::sha3_256();
|
let root_hash = &digest.hash_bytes(&"hello, world".as_bytes());
|
||||||
let root_hash = &d.hash_bytes(&"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,19 +58,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(Sha3::sha3_256(), values).unwrap();
|
let tree = MerkleTree::from_vec(digest, values).unwrap();
|
||||||
|
|
||||||
let mut d = Sha3::sha3_256();
|
|
||||||
|
|
||||||
let hashes = vec![
|
let hashes = vec![
|
||||||
d.hash_bytes(&vec![1]),
|
digest.hash_bytes(&vec![1]),
|
||||||
d.hash_bytes(&vec![2]),
|
digest.hash_bytes(&vec![2]),
|
||||||
d.hash_bytes(&vec![3])
|
digest.hash_bytes(&vec![3])
|
||||||
];
|
];
|
||||||
|
|
||||||
let h01 = &d.combine_hashes(&hashes[0], &hashes[1]);
|
let h01 = &digest.combine_hashes(&hashes[0], &hashes[1]);
|
||||||
let h2 = &hashes[2];
|
let h2 = &hashes[2];
|
||||||
let root_hash = &d.combine_hashes(h01, h2);
|
let root_hash = &digest.combine_hashes(h01, h2);
|
||||||
|
|
||||||
assert_eq!(tree.count(), 3);
|
assert_eq!(tree.count(), 3);
|
||||||
assert_eq!(tree.height(), 2);
|
assert_eq!(tree.height(), 2);
|
||||||
@ -80,22 +78,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(Sha3::sha3_256(), values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
||||||
|
|
||||||
let mut d = Sha3::sha3_256();
|
let hashes = values.iter().map(|v| digest.hash_bytes(v)).collect::<Vec<_>>();
|
||||||
|
|
||||||
let hashes = values.iter().map(|v| d.hash_bytes(v)).collect::<Vec<_>>();
|
let h01 = digest.combine_hashes(&hashes[0], &hashes[1]);
|
||||||
|
let h23 = digest.combine_hashes(&hashes[2], &hashes[3]);
|
||||||
let h01 = &d.combine_hashes(&hashes[0], &hashes[1]);
|
let h45 = digest.combine_hashes(&hashes[4], &hashes[5]);
|
||||||
let h23 = &d.combine_hashes(&hashes[2], &hashes[3]);
|
let h67 = digest.combine_hashes(&hashes[6], &hashes[7]);
|
||||||
let h45 = &d.combine_hashes(&hashes[4], &hashes[5]);
|
|
||||||
let h67 = &d.combine_hashes(&hashes[6], &hashes[7]);
|
|
||||||
let h8 = &hashes[8];
|
let h8 = &hashes[8];
|
||||||
let h0123 = &d.combine_hashes(h01, h23);
|
let h0123 = digest.combine_hashes(&h01, &h23);
|
||||||
let h4567 = &d.combine_hashes(h45, h67);
|
let h4567 = digest.combine_hashes(&h45, &h67);
|
||||||
let h1to7 = &d.combine_hashes(h0123, h4567);
|
let h1to7 = digest.combine_hashes(&h0123, &h4567);
|
||||||
|
|
||||||
let root_hash = &d.combine_hashes(h1to7, h8);
|
let root_hash = &digest.combine_hashes(&h1to7, &h8);
|
||||||
|
|
||||||
assert_eq!(tree.count(), 9);
|
assert_eq!(tree.count(), 9);
|
||||||
assert_eq!(tree.height(), 4);
|
assert_eq!(tree.height(), 4);
|
||||||
@ -105,7 +101,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(Sha3::sha3_256(), values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
||||||
let root_hash = tree.root_hash();
|
let root_hash = tree.root_hash();
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
@ -119,7 +115,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(Sha3::sha3_256(), values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
||||||
let root_hash = tree.root_hash();
|
let root_hash = tree.root_hash();
|
||||||
|
|
||||||
let value = "Rusty";
|
let value = "Rusty";
|
||||||
@ -133,10 +129,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(Sha3::sha3_256(), values1.clone()).unwrap();
|
let tree1 = MerkleTree::from_vec(digest, values1.clone()).unwrap();
|
||||||
|
|
||||||
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(Sha3::sha3_256(), values2.clone()).unwrap();
|
let tree2 = MerkleTree::from_vec(digest, values2.clone()).unwrap();
|
||||||
|
|
||||||
let root_hash = tree2.root_hash();
|
let root_hash = tree2.root_hash();
|
||||||
|
|
||||||
@ -151,7 +147,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(Sha3::sha3_256(), values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
||||||
let root_hash = tree.root_hash();
|
let root_hash = tree.root_hash();
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crypto::digest::Digest;
|
|
||||||
|
|
||||||
use merkledigest::MerkleDigest;
|
use ring::digest::Algorithm;
|
||||||
|
|
||||||
|
use hashutils::HashUtils;
|
||||||
|
|
||||||
pub use proof::{
|
pub use proof::{
|
||||||
Proof,
|
Proof,
|
||||||
@ -34,8 +35,8 @@ impl <T> Tree<T> where T: Into<Vec<u8>> + Clone {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new leaf
|
/// Create a new leaf
|
||||||
pub fn make_leaf<D: Digest>(digest: &mut D, value: T) -> Tree<T> {
|
pub fn make_leaf(algo: &'static Algorithm, value: T) -> Tree<T> {
|
||||||
let hash = digest.hash_bytes(&value.clone().into());
|
let hash = algo.hash_bytes(&value.clone().into());
|
||||||
Tree::new(hash, value)
|
Tree::new(hash, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,24 +1,27 @@
|
|||||||
|
|
||||||
#![cfg(feature="serialization-protobuf")]
|
#![cfg(feature="serialization-protobuf")]
|
||||||
|
|
||||||
extern crate crypto;
|
extern crate ring;
|
||||||
extern crate merkle;
|
extern crate merkle;
|
||||||
extern crate protobuf;
|
extern crate protobuf;
|
||||||
|
|
||||||
use crypto::sha3::Sha3;
|
use ring::digest::{ Algorithm, SHA512 };
|
||||||
|
|
||||||
use merkle::{ MerkleTree, Proof };
|
use merkle::{ MerkleTree, Proof };
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static digest: &'static Algorithm = &SHA512;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_protobuf_inverse() {
|
fn test_protobuf_inverse() {
|
||||||
let digest = Sha3::sha3_256();
|
|
||||||
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.clone(), values.clone()).unwrap();
|
let tree = MerkleTree::from_vec(digest, values.clone()).unwrap();
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
let proof = tree.gen_proof(value).unwrap();
|
let proof = tree.gen_proof(value).unwrap();
|
||||||
let bytes = proof.clone().write_to_bytes().unwrap();
|
let bytes = proof.clone().write_to_bytes().unwrap();
|
||||||
let res = Proof::<Sha3, Vec<u8>>::parse_from_bytes(&bytes, digest).unwrap().unwrap();
|
let res = Proof::<Vec<u8>>::parse_from_bytes(&bytes, digest).unwrap().unwrap();
|
||||||
|
|
||||||
assert_eq!(proof.root_hash, res.root_hash);
|
assert_eq!(proof.root_hash, res.root_hash);
|
||||||
assert_eq!(proof.value, res.value);
|
assert_eq!(proof.value, res.value);
|
||||||
|
Reference in New Issue
Block a user