use crate::{config::*, utils::util::hash_n_subhashes, types::*};
use plonky2::plonk::config::GenericHashOut;
use serde::{Deserialize, Serialize};
use crate::custom_serializer::base64;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Node {
#[serde(serialize_with = "base64::serialize_option", deserialize_with = "base64::deserialize_option")]
hash: Option<Vec<u8>>,
children: Option<Vec<Node>>,
}
impl Node {
pub fn new(hash: Option<Vec<u8>>) -> Self {
Node {
hash,
children: None,
}
}
pub fn hash(&self) -> &Option<Vec<u8>> {
&self.hash
}
pub fn set_hash(&mut self, hash: Vec<u8>) {
self.hash = Some(hash);
}
pub fn set_children(&mut self, children: Vec<Node>) {
self.children = Some(children);
}
fn collect_nodes_at_depth_mut<'a>(
&'a mut self,
target_depth: usize,
result: &mut Vec<&'a mut Node>,
current_depth: usize,
) {
if current_depth == target_depth {
result.push(self);
} else if current_depth < target_depth {
if let Some(ref mut children) = self.children {
for child in children {
child.collect_nodes_at_depth_mut(target_depth, result, current_depth + 1);
}
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MerkleTree {
pub root: Node,
pub depth: usize,
}
impl MerkleTree {
pub fn new_from_leafs(leafs: Vec<Node>, depth: usize, batch: bool) -> Self {
let mut nodes = Vec::new();
let mut padded_nodes = Vec::new();
let chunks = if batch {
leafs.chunks(BATCH_SIZE)
} else {
leafs.chunks(RECURSIVE_SIZE)
};
if chunks.len() % RECURSIVE_SIZE != 0 {
let padding_size = RECURSIVE_SIZE - (chunks.len() % RECURSIVE_SIZE);
for _ in 0..padding_size {
padded_nodes.push(Node::new(None));
}
}
for chunk in chunks {
let mut node = Node::new(None);
node.set_children(chunk.to_vec());
nodes.push(node);
}
if nodes.len() == 1 && !batch {
Self {
root: nodes[0].clone(),
depth: depth + 1, }
} else {
nodes.extend(padded_nodes);
Self::new_from_leafs(nodes, depth + 1, false)
}
}
pub fn get_nodes_from_depth(&mut self, depth: usize) -> Vec<&mut Node> {
let mut result = Vec::new();
self.root.collect_nodes_at_depth_mut(depth, &mut result, 1);
result
}
pub fn get_merkle_tree_exclude_leaves(&self) -> MerkleTree {
let mut new_tree = self.clone();
let nodes = new_tree.get_nodes_from_depth(self.depth - 1);
for node in nodes {
node.children = None;
}
new_tree.depth -= 1;
new_tree
}
pub fn get_nth_leaf_path(&self, n: usize) -> Option<Vec<usize>> {
let mut start_position = 0;
let mut node_leafs;
let mut current_node = &self.root;
let mut path = Vec::new();
for current_depth in 1..self.depth {
node_leafs = RECURSIVE_SIZE.pow(self.depth as u32 - current_depth as u32 - 1) * BATCH_SIZE;
let index = (n - start_position) / node_leafs;
current_node = ¤t_node.children.as_ref().unwrap()[index];
start_position += index * node_leafs;
path.push(index);
}
let leaf_index = n - start_position;
path.push(leaf_index);
if path.len() == self.depth {
return Some(path);
}
None
}
fn verify_recursive(root_node: &Node) -> bool{
if root_node.children.is_none() {
return true;
}
if let Some(ref children) = root_node.children {
for child in children {
Self::verify_recursive(child);
}
}
if root_node.hash.is_none() {
return false
}
let children_hashes = root_node.children.as_ref().unwrap().iter()
.filter_map(|child| child.hash.clone())
.collect::<Vec<_>>();
let hash = hash_n_subhashes::<F, D>(&children_hashes).to_bytes();
if root_node.hash.as_ref().unwrap() != &hash {
return false
}
true
}
pub fn verify(&self) -> bool {
Self::verify_recursive(&self.root)
}
pub fn prove_inclusion(&self, path: Vec<usize>) -> MerkleProof {
let mut merkle_proof: Option<MerkleProof> = None;
let mut current_node = &self.root;
for i in 0..path.len()-1 {
let index = path[i+1];
let nodes = current_node.children.as_ref().unwrap();
let hashes = nodes.iter().map(|node| node.hash.clone().unwrap()).collect::<Vec<_>>();
let left_hashes_temp = hashes[0..index].to_vec();
let right_hashes_temp = hashes[index + 1..].to_vec();
current_node = &nodes[index];
if merkle_proof.is_none() {
merkle_proof = Some(MerkleProof {
left_hashes: left_hashes_temp,
right_hashes: right_hashes_temp,
parent_hashes: None,
});
} else {
merkle_proof = Some(MerkleProof {
left_hashes: left_hashes_temp,
right_hashes: right_hashes_temp,
parent_hashes: Some(Box::new(merkle_proof.unwrap())),
});
}
}
merkle_proof.unwrap()
}
}