-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
365d2a3
commit 451a04f
Showing
10 changed files
with
170 additions
and
93 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
use sha2::{Digest, Sha256}; | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq)] | ||
pub struct Hash([u8; 32]); | ||
|
||
impl Hash { | ||
pub fn new(data: &[u8]) -> Self { | ||
let mut hasher = Sha256::new(); | ||
hasher.update(data); | ||
Hash(hasher.finalize().into()) | ||
} | ||
|
||
pub fn as_bytes(&self) -> &[u8; 32] { | ||
&self.0 | ||
} | ||
|
||
pub fn as_hex(&self) -> String { | ||
self.0.iter().map(|b| format!("{:02x}", b)).collect() | ||
} | ||
|
||
pub fn combine(left: &Hash, right: &Hash) -> Self { | ||
let mut combined_data = Vec::with_capacity(64); | ||
combined_data.extend_from_slice(left.as_bytes()); | ||
combined_data.extend_from_slice(right.as_bytes()); | ||
Self::new(&combined_data) | ||
} | ||
|
||
pub fn empty() -> Self { | ||
Hash([0u8; 32]) | ||
} | ||
|
||
pub fn from_hex(hex: &str) -> Result<Self, Box<dyn std::error::Error>> { | ||
if hex.len() != 64 { | ||
// Each byte is represented by 2 hex characters, so 32 bytes = 64 hex chars | ||
return Err("invalid hex string length: expected 64 characters".into()); | ||
} | ||
|
||
let mut hash = [0u8; 32]; | ||
for i in 0..32 { | ||
let byte = u8::from_str_radix(&hex[i * 2..i * 2 + 2], 16) | ||
.map_err(|e| format!("failed to parse hex byte at position {}: {}", i, e))?; | ||
hash[i] = byte; | ||
} | ||
|
||
Ok(Hash::new(&hash)) | ||
} | ||
} | ||
|
||
mod test { | ||
#[test] | ||
fn test_hash() { | ||
let data = b"hello world"; | ||
let hash = crate::hash::Hash::new(data); | ||
assert_eq!( | ||
hash.as_hex(), | ||
"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
pub mod hash; | ||
pub mod merkle_proof; | ||
pub mod merkle_tree; | ||
pub mod node; | ||
pub mod solidity; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
use crate::{hash::Hash, node::Node}; | ||
|
||
#[derive(Debug)] | ||
pub struct MerkleProof { | ||
proof: Vec<Hash>, | ||
} | ||
|
||
impl MerkleProof { | ||
pub fn new(proof: Vec<Hash>) -> Self { | ||
MerkleProof { proof } | ||
} | ||
|
||
pub fn verify(&self, root: Node<T>) -> Result<bool, Box<dyn std::error::Error>> { | ||
Ok(true) // todo: implement | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use crate::node::Node; | ||
use crate::hash::Hash; | ||
|
||
pub struct MerkleTree<T> | ||
where | ||
T: Clone + AsRef<[u8]>, | ||
{ | ||
root: Node<T>, | ||
leaves: Vec<Node<T>>, | ||
} | ||
|
||
impl<T> MerkleTree<T> | ||
where | ||
T: Clone + AsRef<[u8]>, | ||
{ | ||
// pub fn new() | ||
} | ||
|
||
|
Empty file.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
use crate::hash::Hash; | ||
|
||
/// Represents a node in a Merkle Tree. | ||
#[derive(Debug, Clone)] | ||
pub struct Node<T> | ||
where | ||
T: AsRef<[u8]> + Clone, | ||
{ | ||
hash: Hash, // Hash of the node | ||
is_leaf: bool, // Is this node a leaf? | ||
data: Option<T>, // Data for leaf nodes | ||
} | ||
|
||
impl<T> Node<T> | ||
where | ||
T: AsRef<[u8]> + Clone, | ||
{ | ||
/// Create a new leaf node from the given data. | ||
pub fn new(data: Option<T>) -> Self { | ||
let is_leaf = data.is_some(); | ||
let hash = if let Some(ref value) = data { | ||
Hash::new(value.as_ref()) | ||
} else { | ||
Hash::empty() | ||
}; | ||
|
||
Node { | ||
hash, | ||
is_leaf, | ||
data, | ||
} | ||
} | ||
|
||
/// Combine two child nodes to create a new parent node. | ||
pub fn new_from_children(left: &Node<T>, right: &Node<T>) -> Self { | ||
let combined_hash = Hash::combine(&left.hash, &right.hash); | ||
|
||
Node { | ||
hash: combined_hash, | ||
is_leaf: false, | ||
data: None, | ||
} | ||
} | ||
|
||
/// Retrieve the hash of the node. | ||
pub fn hash(&self) -> &Hash { | ||
&self.hash | ||
} | ||
|
||
/// Check if the node is a leaf. | ||
pub fn is_leaf(&self) -> bool { | ||
self.is_leaf | ||
} | ||
|
||
/// Retrieve the data (if any). | ||
pub fn data(&self) -> Option<T> { | ||
self.data.clone() | ||
} | ||
} | ||
|
||
|
||
mod tests { | ||
#[test] | ||
fn test_node() { | ||
let data = b"hello world"; | ||
let node = crate::node::Node::new(Some(data)); | ||
assert_eq!(node.is_leaf(), true); | ||
assert_eq!(node.data(), Some(data)); | ||
} | ||
} |