mirror of
https://github.com/mii443/merkle.rs.git
synced 2025-08-22 16:05:30 +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)]
|
||||
|
||||
pub extern crate crypto;
|
||||
|
||||
use crypto::digest::Digest;
|
||||
|
||||
pub trait Hashable {
|
||||
fn to_bytes(&self) -> Vec<u8>;
|
||||
}
|
||||
mod tree;
|
||||
pub use tree::{
|
||||
Tree,
|
||||
Hashable,
|
||||
MerkleDigest,
|
||||
};
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
}
|
||||
mod merkletree;
|
||||
pub use merkletree::{
|
||||
MerkleTree
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
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 MerkleTree;
|
||||
use MerkleDigest;
|
||||
use Hashable;
|
||||
use tree::{
|
||||
Hashable,
|
||||
MerkleDigest,
|
||||
};
|
||||
|
||||
use merkletree::{
|
||||
MerkleTree
|
||||
};
|
||||
|
||||
impl Hashable for String {
|
||||
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