mirror of
https://github.com/mii443/merkle.rs.git
synced 2025-08-23 00:15:31 +00:00
split into files
This commit is contained in:
155
src/lib.rs
155
src/lib.rs
@ -2,154 +2,19 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
pub extern crate crypto;
|
pub extern crate crypto;
|
||||||
|
|
||||||
use crypto::digest::Digest;
|
use crypto::digest::Digest;
|
||||||
|
|
||||||
pub trait Hashable {
|
mod tree;
|
||||||
fn to_bytes(&self) -> Vec<u8>;
|
pub use tree::{
|
||||||
}
|
Tree,
|
||||||
|
Hashable,
|
||||||
|
MerkleDigest,
|
||||||
|
};
|
||||||
|
|
||||||
pub trait MerkleDigest {
|
mod merkletree;
|
||||||
fn hash_bytes(&mut self, bytes: &Vec<u8>) -> Vec<u8>;
|
pub use merkletree::{
|
||||||
fn combine_hashes(&mut self, left: &Vec<u8>, right: &Vec<u8>) -> Vec<u8>;
|
MerkleTree
|
||||||
}
|
};
|
||||||
|
|
||||||
impl <D> MerkleDigest for D where D: Digest {
|
|
||||||
|
|
||||||
fn hash_bytes(&mut self, bytes: &Vec<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: &Vec<u8>, right: &Vec<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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Tree<T> {
|
|
||||||
Leaf {
|
|
||||||
hash: Vec<u8>,
|
|
||||||
value: T
|
|
||||||
},
|
|
||||||
|
|
||||||
Node {
|
|
||||||
hash: Vec<u8>,
|
|
||||||
left: Box<Tree<T>>,
|
|
||||||
right: Box<Tree<T>>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <T> Tree<T> where T: Hashable {
|
|
||||||
|
|
||||||
fn new(hash: Vec<u8>, value: T) -> Self {
|
|
||||||
Tree::Leaf {
|
|
||||||
hash: hash,
|
|
||||||
value: value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_hash(&self) -> &Vec<u8> {
|
|
||||||
match *self {
|
|
||||||
Tree::Leaf { ref hash, value: _ } => hash,
|
|
||||||
Tree::Node { ref hash, left: _, right: _ } => hash
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_leaf<D, T>(digest: &mut D, value: T) -> Tree<T> where D: Digest, T: Hashable {
|
|
||||||
let hash = digest.hash_bytes(&value.to_bytes());
|
|
||||||
Tree::new(hash, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MerkleTree<D, T> {
|
|
||||||
digest: D,
|
|
||||||
tree: Tree<T>,
|
|
||||||
height: usize,
|
|
||||||
count: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl <D, T> MerkleTree<D, T> where D: Digest, T: Hashable {
|
|
||||||
|
|
||||||
pub fn from_vec(mut digest: D, values: Vec<T>) -> Self {
|
|
||||||
if values.is_empty() {
|
|
||||||
panic!("Cannot build a Merkle tree from an empty vector.");
|
|
||||||
}
|
|
||||||
|
|
||||||
let count = values.len();
|
|
||||||
let mut height = 0;
|
|
||||||
if count == 1 {
|
|
||||||
height = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut cur = Vec::with_capacity(count);
|
|
||||||
|
|
||||||
for v in values.into_iter().rev() {
|
|
||||||
let leaf = make_leaf(&mut digest, v);
|
|
||||||
cur.push(leaf);
|
|
||||||
}
|
|
||||||
|
|
||||||
cur.reverse();
|
|
||||||
|
|
||||||
while cur.len() > 1 {
|
|
||||||
let mut next = Vec::new();
|
|
||||||
while cur.len() > 0 {
|
|
||||||
if cur.len() == 1 {
|
|
||||||
next.push(cur.remove(0));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
let left = cur.remove(0);
|
|
||||||
let right = cur.remove(0);
|
|
||||||
|
|
||||||
let combined_hash = digest.combine_hashes(
|
|
||||||
left.get_hash(),
|
|
||||||
right.get_hash()
|
|
||||||
);
|
|
||||||
|
|
||||||
let node = Tree::Node {
|
|
||||||
hash: combined_hash,
|
|
||||||
left: Box::new(left),
|
|
||||||
right: Box::new(right)
|
|
||||||
};
|
|
||||||
|
|
||||||
next.push(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
height = height + 1;
|
|
||||||
cur = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(cur.len() == 1);
|
|
||||||
|
|
||||||
let tree = cur.remove(0);
|
|
||||||
|
|
||||||
MerkleTree {
|
|
||||||
digest: digest,
|
|
||||||
tree: tree,
|
|
||||||
height: height,
|
|
||||||
count: count
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn root_hash(&self) -> &Vec<u8> {
|
|
||||||
self.tree.get_hash()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
83
src/merkletree.rs
Normal file
83
src/merkletree.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
extern crate crypto;
|
||||||
|
use crypto::digest::Digest;
|
||||||
|
|
||||||
|
pub use tree::{
|
||||||
|
Tree,
|
||||||
|
Hashable,
|
||||||
|
MerkleDigest,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct MerkleTree<D, T> {
|
||||||
|
digest: D,
|
||||||
|
tree: Tree<T>,
|
||||||
|
pub height: usize,
|
||||||
|
pub count: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <D, T> MerkleTree<D, T> where D: Digest, T: Hashable {
|
||||||
|
|
||||||
|
pub fn from_vec(mut digest: D, values: Vec<T>) -> Self {
|
||||||
|
if values.is_empty() {
|
||||||
|
panic!("Cannot build a Merkle tree from an empty vector.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let count = values.len();
|
||||||
|
let mut height = 0;
|
||||||
|
if count == 1 {
|
||||||
|
height = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut cur = Vec::with_capacity(count);
|
||||||
|
|
||||||
|
for v in values.into_iter().rev() {
|
||||||
|
let leaf = Tree::make_leaf(&mut digest, v);
|
||||||
|
cur.push(leaf);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur.reverse();
|
||||||
|
|
||||||
|
while cur.len() > 1 {
|
||||||
|
let mut next = Vec::new();
|
||||||
|
while cur.len() > 0 {
|
||||||
|
if cur.len() == 1 {
|
||||||
|
next.push(cur.remove(0));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let left = cur.remove(0);
|
||||||
|
let right = cur.remove(0);
|
||||||
|
|
||||||
|
let combined_hash = digest.combine_hashes(
|
||||||
|
left.get_hash(),
|
||||||
|
right.get_hash()
|
||||||
|
);
|
||||||
|
|
||||||
|
let node = Tree::Node {
|
||||||
|
hash: combined_hash,
|
||||||
|
left: Box::new(left),
|
||||||
|
right: Box::new(right)
|
||||||
|
};
|
||||||
|
|
||||||
|
next.push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
height = height + 1;
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(cur.len() == 1);
|
||||||
|
|
||||||
|
let tree = cur.remove(0);
|
||||||
|
|
||||||
|
MerkleTree {
|
||||||
|
digest: digest,
|
||||||
|
tree: tree,
|
||||||
|
height: height,
|
||||||
|
count: count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn root_hash(&self) -> &Vec<u8> {
|
||||||
|
self.tree.get_hash()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
11
src/tests.rs
11
src/tests.rs
@ -3,9 +3,14 @@
|
|||||||
|
|
||||||
use crypto::sha3::Sha3;
|
use crypto::sha3::Sha3;
|
||||||
|
|
||||||
use MerkleTree;
|
use tree::{
|
||||||
use MerkleDigest;
|
Hashable,
|
||||||
use Hashable;
|
MerkleDigest,
|
||||||
|
};
|
||||||
|
|
||||||
|
use merkletree::{
|
||||||
|
MerkleTree
|
||||||
|
};
|
||||||
|
|
||||||
impl Hashable for String {
|
impl Hashable for String {
|
||||||
fn to_bytes(&self) -> Vec<u8> {
|
fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
72
src/tree.rs
Normal file
72
src/tree.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
extern crate crypto;
|
||||||
|
use crypto::digest::Digest;
|
||||||
|
|
||||||
|
pub trait Hashable {
|
||||||
|
fn to_bytes(&self) -> Vec<u8>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Tree<T> {
|
||||||
|
Leaf {
|
||||||
|
hash: Vec<u8>,
|
||||||
|
value: T
|
||||||
|
},
|
||||||
|
|
||||||
|
Node {
|
||||||
|
hash: Vec<u8>,
|
||||||
|
left: Box<Tree<T>>,
|
||||||
|
right: Box<Tree<T>>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <T> Tree<T> where T: Hashable {
|
||||||
|
|
||||||
|
pub fn new(hash: Vec<u8>, value: T) -> Self {
|
||||||
|
Tree::Leaf {
|
||||||
|
hash: hash,
|
||||||
|
value: value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_hash(&self) -> &Vec<u8> {
|
||||||
|
match *self {
|
||||||
|
Tree::Leaf { ref hash, value: _ } => hash,
|
||||||
|
Tree::Node { ref hash, left: _, right: _ } => hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn make_leaf<D: Digest>(digest: &mut D, value: T) -> Tree<T> {
|
||||||
|
let hash = digest.hash_bytes(&value.to_bytes());
|
||||||
|
Tree::new(hash, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MerkleDigest {
|
||||||
|
fn hash_bytes(&mut self, bytes: &Vec<u8>) -> Vec<u8>;
|
||||||
|
fn combine_hashes(&mut self, left: &Vec<u8>, right: &Vec<u8>) -> Vec<u8>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <D> MerkleDigest for D where D: Digest {
|
||||||
|
|
||||||
|
fn hash_bytes(&mut self, bytes: &Vec<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: &Vec<u8>, right: &Vec<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
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user