use std::collections::HashMap;
pub type IMTNode = String;
pub type IMTHashFunction = fn(Vec<IMTNode>) -> IMTNode;
#[derive(Debug)]
pub struct LeanIMT {
size: usize,
depth: usize,
side_nodes: HashMap<usize, IMTNode>,
leaves: HashMap<IMTNode, usize>,
hash: IMTHashFunction,
}
impl LeanIMT {
pub fn new(hash: IMTHashFunction) -> Self {
LeanIMT {
size: 0,
depth: 0,
side_nodes: HashMap::new(),
leaves: HashMap::new(),
hash,
}
}
pub fn insert(&mut self, leaf: IMTNode) -> Result<IMTNode, &'static str> {
if self.leaves.contains_key(&leaf) {
return Err("Leaf already exists");
}
if leaf == "0" {
return Err("Leaf cannot be zero");
}
let mut index = self.size;
let mut tree_depth = self.depth;
if (1 << tree_depth) < index + 1 {
tree_depth += 1;
self.depth = tree_depth;
}
let mut node = leaf.clone();
for level in 0..tree_depth {
if ((index >> level) & 1) == 1 {
let side_node = self
.side_nodes
.get(&level)
.cloned()
.expect("No side node at this level");
node = (self.hash)(vec![side_node, node]);
} else {
self.side_nodes.insert(level, node.clone());
break;
}
}
index += 1;
self.size = index;
self.side_nodes.insert(tree_depth, node.clone());
self.leaves.insert(leaf, index);
Ok(node)
}
pub fn insert_many(&mut self, leaves: Vec<IMTNode>) -> Result<IMTNode, &'static str> {
for leaf in &leaves {
if self.leaves.contains_key(leaf) {
return Err("Leaf already exists");
}
if leaf == "0" {
return Err("Leaf cannot be zero");
}
}
let mut current_level_new_nodes = leaves.clone();
let tree_size = self.size;
let mut tree_depth = self.depth;
while (1 << tree_depth) < tree_size + leaves.len() {
tree_depth += 1;
}
self.depth = tree_depth;
let mut current_level_start_index = tree_size;
let mut current_level_size = tree_size + leaves.len();
let mut next_level_start_index = current_level_start_index >> 1;
let mut next_level_size = ((current_level_size - 1) >> 1) + 1;
for level in 0..tree_depth {
let number_of_new_nodes = next_level_size - next_level_start_index;
let mut next_level_new_nodes = Vec::with_capacity(number_of_new_nodes);
for i in 0..number_of_new_nodes {
let left_index = (i + next_level_start_index) * 2 - current_level_start_index;
let right_index = left_index + 1;
let left_node = if left_index < current_level_new_nodes.len() {
current_level_new_nodes[left_index].clone()
} else {
self.side_nodes.get(&level).cloned().unwrap_or("0".to_string())
};
let right_node = if right_index < current_level_new_nodes.len() {
current_level_new_nodes[right_index].clone()
} else {
"0".to_string()
};
let parent_node = if right_node != "0" {
(self.hash)(vec![left_node.clone(), right_node])
} else {
left_node.clone()
};
next_level_new_nodes.push(parent_node);
}
if current_level_size & 1 == 1 {
self.side_nodes
.insert(level, current_level_new_nodes.last().cloned().unwrap());
} else if current_level_new_nodes.len() > 1 {
self.side_nodes.insert(
level,
current_level_new_nodes
.get(current_level_new_nodes.len() - 2)
.cloned()
.unwrap(),
);
}
current_level_start_index = next_level_start_index;
next_level_start_index >>= 1;
current_level_new_nodes = next_level_new_nodes;
current_level_size = next_level_size;
next_level_size = ((next_level_size - 1) >> 1) + 1;
}
self.size = tree_size + leaves.len();
self.side_nodes
.insert(tree_depth, current_level_new_nodes[0].clone());
for (i, leaf) in leaves.iter().enumerate() {
self.leaves.insert(leaf.clone(), tree_size + i + 1);
}
Ok(current_level_new_nodes[0].clone())
}
pub fn update(
&mut self,
old_leaf: &IMTNode,
new_leaf: IMTNode,
sibling_nodes: &[IMTNode],
) -> Result<IMTNode, &'static str> {
if !self.leaves.contains_key(old_leaf) {
return Err("Leaf does not exist");
}
if self.leaves.contains_key(&new_leaf) && new_leaf != "0" {
return Err("New leaf already exists");
}
let index = self.index_of(old_leaf)?;
let mut node = new_leaf.clone();
let mut old_root = old_leaf.clone();
let last_index = self.size - 1;
let mut i = 0;
let tree_depth = self.depth;
for level in 0..tree_depth {
if ((index >> level) & 1) == 1 {
let sibling_node = sibling_nodes
.get(i)
.cloned()
.ok_or("Not enough sibling nodes")?;
node = (self.hash)(vec![sibling_node.clone(), node]);
old_root = (self.hash)(vec![sibling_node, old_root]);
i += 1;
} else {
if (index >> level) != (last_index >> level) {
let sibling_node = sibling_nodes
.get(i)
.cloned()
.ok_or("Not enough sibling nodes")?;
node = (self.hash)(vec![node, sibling_node.clone()]);
old_root = (self.hash)(vec![old_root, sibling_node]);
i += 1;
} else {
self.side_nodes.insert(level, node.clone());
}
}
}
if Some(old_root) != self.root() {
return Err("Wrong sibling nodes");
}
self.side_nodes.insert(tree_depth, node.clone());
if new_leaf != "0" {
let leaf_index = *self.leaves.get(old_leaf).unwrap();
self.leaves.insert(new_leaf.clone(), leaf_index);
}
self.leaves.remove(old_leaf);
Ok(node)
}
pub fn remove(&mut self, old_leaf: &IMTNode, sibling_nodes: &[IMTNode]) -> Result<IMTNode, &'static str> {
self.update(old_leaf, "0".to_string(), sibling_nodes)
}
pub fn has(&self, leaf: &IMTNode) -> bool {
self.leaves.contains_key(leaf)
}
pub fn index_of(&self, leaf: &IMTNode) -> Result<usize, &'static str> {
self.leaves
.get(leaf)
.map(|&index| index - 1)
.ok_or("Leaf does not exist")
}
pub fn root(&self) -> Option<IMTNode> {
self.side_nodes.get(&self.depth).cloned()
}
pub fn get_size(&self) -> usize {
self.size
}
pub fn get_depth(&self) -> usize {
self.depth
}
pub fn get_side_nodes(&self) -> HashMap<usize, IMTNode> {
self.side_nodes.clone()
}
pub fn get_leaves(&self) -> HashMap<IMTNode, usize> {
self.leaves.clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn simple_hash_function(nodes: Vec<String>) -> String {
nodes.join(",")
}
#[test]
fn test_new_lean_imt() {
let hash: IMTHashFunction = simple_hash_function;
let imt = LeanIMT::new(hash);
assert_eq!(imt.size, 0);
assert_eq!(imt.depth, 0);
assert!(imt.root().is_none());
}
#[test]
fn test_insert() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
assert!(imt.insert("leaf1".to_string()).is_ok());
assert_eq!(imt.size, 1);
assert_eq!(imt.depth, 0);
assert!(imt.has(&"leaf1".to_string()));
assert_eq!(imt.root().unwrap(), "leaf1".to_string());
}
#[test]
fn test_insert_many() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
let leaves = vec!["leaf1".to_string(), "leaf2".to_string(), "leaf3".to_string()];
assert!(imt.insert_many(leaves.clone()).is_ok());
assert_eq!(imt.size, 3);
assert_eq!(imt.depth, 2);
for leaf in &leaves {
assert!(imt.has(leaf));
}
let expected_root = simple_hash_function(vec![
simple_hash_function(vec![
leaves[0].clone(),
leaves[1].clone(),
]),
leaves[2].clone(),
]);
assert_eq!(imt.root().unwrap(), expected_root);
}
#[test]
fn test_insert_duplicate_leaf() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
imt.insert("leaf1".to_string()).unwrap();
let result = imt.insert("leaf1".to_string());
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Leaf already exists");
}
#[test]
fn test_insert_many_with_duplicate_leaf() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
imt.insert("leaf1".to_string()).unwrap();
let leaves = vec!["leaf2".to_string(), "leaf1".to_string()];
let result = imt.insert_many(leaves);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Leaf already exists");
}
#[test]
fn test_update() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
imt.insert("leaf1".to_string()).unwrap();
let sibling_nodes = vec![];
assert!(imt
.update(
&"leaf1".to_string(),
"new_leaf1".to_string(),
&sibling_nodes
)
.is_ok());
assert!(imt.has(&"new_leaf1".to_string()));
assert!(!imt.has(&"leaf1".to_string()));
assert_eq!(imt.root().unwrap(), "new_leaf1".to_string());
}
#[test]
fn test_update_nonexistent_leaf() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
let sibling_nodes = vec![];
let result = imt.update(
&"nonexistent_leaf".to_string(),
"new_leaf".to_string(),
&sibling_nodes,
);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Leaf does not exist");
}
#[test]
fn test_remove() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
imt.insert("leaf1".to_string()).unwrap();
let sibling_nodes = vec![];
assert!(imt.remove(&"leaf1".to_string(), &sibling_nodes).is_ok());
assert!(!imt.has(&"leaf1".to_string()));
assert_eq!(imt.root().unwrap(), "0".to_string());
}
#[test]
fn test_remove_nonexistent_leaf() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
let sibling_nodes = vec![];
let result = imt.remove(&"nonexistent_leaf".to_string(), &sibling_nodes);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Leaf does not exist");
}
#[test]
fn test_has_and_index_of() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
assert!(!imt.has(&"leaf1".to_string()));
assert!(imt.index_of(&"leaf1".to_string()).is_err());
imt.insert("leaf1".to_string()).unwrap();
assert!(imt.has(&"leaf1".to_string()));
assert_eq!(imt.index_of(&"leaf1".to_string()).unwrap(), 0);
}
#[test]
fn test_root_after_operations() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
assert!(imt.root().is_none());
imt.insert("leaf1".to_string()).unwrap();
let root_after_leaf1 = imt.root().unwrap();
imt.insert("leaf2".to_string()).unwrap();
let root_after_leaf2 = imt.root().unwrap();
assert_ne!(root_after_leaf1, root_after_leaf2);
let sibling_nodes = vec!["leaf2".to_string()];
imt.remove(&"leaf1".to_string(), &sibling_nodes).unwrap();
let root_after_removal = imt.root().unwrap();
assert_eq!(root_after_removal, "0,leaf2".to_string());
let sibling_nodes = vec!["0".to_string()];
imt.update(
&"leaf2".to_string(),
"leaf3".to_string(),
&sibling_nodes,
)
.unwrap();
let root_after_update = imt.root().unwrap();
assert_eq!(root_after_update, "0,leaf3".to_string());
}
#[test]
fn test_tree_consistency() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
imt.insert("leaf1".to_string()).unwrap();
imt.insert("leaf2".to_string()).unwrap();
imt.insert("leaf3".to_string()).unwrap();
imt.insert("leaf4".to_string()).unwrap();
let root_before = imt.root().unwrap();
let sibling_nodes = vec!["leaf1".to_string(), simple_hash_function(vec![
"leaf3".to_string(),
"leaf4".to_string(),
])];
imt.update(
&"leaf2".to_string(),
"leaf2_updated".to_string(),
&sibling_nodes,
)
.unwrap();
let root_after = imt.root().unwrap();
assert_ne!(root_before, root_after);
let sibling_nodes = vec!["leaf4".to_string(), simple_hash_function(vec![
"leaf1".to_string(),
"leaf2_updated".to_string(),
])];
imt.remove(&"leaf3".to_string(), &sibling_nodes).unwrap();
let root_after_removal = imt.root().unwrap();
assert_ne!(root_after, root_after_removal);
assert!(imt.has(&"leaf1".to_string()));
assert!(imt.has(&"leaf2_updated".to_string()));
assert!(!imt.has(&"leaf2".to_string()));
assert!(!imt.has(&"leaf3".to_string()));
assert!(imt.has(&"leaf4".to_string()));
}
#[test]
fn test_large_number_of_leaves() {
let hash: IMTHashFunction = |nodes: Vec<String>| {
format!("H({})", nodes.join("+"))
};
let mut imt = LeanIMT::new(hash);
let leaves: Vec<_> = (1..=100).map(|i| format!("leaf{}", i)).collect();
assert!(imt.insert_many(leaves.clone()).is_ok());
assert_eq!(imt.size, 100);
for leaf in &leaves {
assert!(imt.has(leaf));
}
let expected_depth = (100 as f64).log2().ceil() as usize;
assert_eq!(imt.depth, expected_depth);
}
#[test]
fn test_insertion_after_removal() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
imt.insert("leaf1".to_string()).unwrap();
imt.insert("leaf2".to_string()).unwrap();
let sibling_nodes = vec!["leaf2".to_string()];
imt.remove(&"leaf1".to_string(), &sibling_nodes).unwrap();
assert!(imt.insert("leaf3".to_string()).is_ok());
assert!(!imt.has(&"leaf1".to_string()));
assert!(imt.has(&"leaf2".to_string()));
assert!(imt.has(&"leaf3".to_string()));
}
#[test]
fn test_tree_after_all_leaves_removed() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
imt.insert("leaf1".to_string()).unwrap();
imt.insert("leaf2".to_string()).unwrap();
let sibling_nodes = vec!["leaf2".to_string()];
imt.remove(&"leaf1".to_string(), &sibling_nodes).unwrap();
let sibling_nodes = vec!["0".to_string()];
imt.remove(&"leaf2".to_string(), &sibling_nodes).unwrap();
assert_eq!(imt.size, 2);
assert_eq!(imt.depth, 1);
assert_eq!(imt.root().unwrap(), "0,0".to_string());
assert!(!imt.has(&"leaf1".to_string()));
assert!(!imt.has(&"leaf2".to_string()));
}
#[test]
fn test_insert_after_tree_becomes_empty() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
imt.insert("leaf1".to_string()).unwrap();
let sibling_nodes = vec![];
imt.remove(&"leaf1".to_string(), &sibling_nodes).unwrap();
assert!(imt.insert("leaf2".to_string()).is_ok());
assert!(imt.has(&"leaf2".to_string()));
assert_eq!(imt.root().unwrap(), "0,leaf2".to_string());
}
#[test]
fn test_insertion_causes_depth_increase() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
imt.insert("leaf1".to_string()).unwrap();
assert_eq!(imt.depth, 0);
imt.insert("leaf2".to_string()).unwrap();
assert_eq!(imt.depth, 1);
imt.insert("leaf3".to_string()).unwrap();
assert_eq!(imt.depth, 2);
imt.insert("leaf4".to_string()).unwrap();
assert_eq!(imt.depth, 2);
imt.insert("leaf5".to_string()).unwrap();
assert_eq!(imt.depth, 3);
}
#[test]
fn test_invalid_sibling_nodes_on_update() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
imt.insert("leaf1".to_string()).unwrap();
imt.insert("leaf2".to_string()).unwrap();
let sibling_nodes = vec!["wrong_sibling".to_string()];
let result = imt.update(
&"leaf1".to_string(),
"leaf1_updated".to_string(),
&sibling_nodes,
);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Wrong sibling nodes");
}
#[test]
fn test_invalid_sibling_nodes_on_remove() {
let hash: IMTHashFunction = simple_hash_function;
let mut imt = LeanIMT::new(hash);
imt.insert("leaf1".to_string()).unwrap();
imt.insert("leaf2".to_string()).unwrap();
let sibling_nodes = vec!["wrong_sibling".to_string()];
let result = imt.remove(&"leaf1".to_string(), &sibling_nodes);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "Wrong sibling nodes");
}
}