earthbucks_lib 0.8.5

EarthBucks library for data structures and algorithms
Documentation
use crate::hash::double_blake3_hash;
use std::sync::Arc;

pub struct MerkleNode {
    left: Option<Arc<MerkleNode>>,
    right: Option<Arc<MerkleNode>>,
    data: Vec<u8>,
}

impl MerkleNode {
    pub fn new(
        left: Option<Arc<MerkleNode>>,
        right: Option<Arc<MerkleNode>>,
        data: Vec<u8>,
    ) -> Self {
        MerkleNode { left, right, data }
    }

    pub fn hash(&self) -> Vec<u8> {
        match (&self.left, &self.right) {
            (Some(left), Some(right)) => {
                double_blake3_hash(&[left.hash(), right.hash()].concat()).to_vec()
            }

            (Some(left), None) => double_blake3_hash(&[left.hash(), left.hash()].concat()).to_vec(),
            (None, Some(right)) => {
                double_blake3_hash(&[right.hash(), right.hash()].concat()).to_vec()
            }
            (None, None) => self.data.clone(),
        }
    }

    pub fn from_bufs(mut datas: Vec<Vec<u8>>) -> Arc<MerkleNode> {
        match datas.len() {
            0 => panic!("Cannot create MerkleNode from empty array"),
            1 => Arc::new(MerkleNode::new(None, None, datas[0].clone())),
            2 => {
                let left = Arc::new(MerkleNode::new(None, None, datas[0].clone()));
                let right = Arc::new(MerkleNode::new(None, None, datas[1].clone()));
                Arc::new(MerkleNode::new(
                    Some(left.clone()),
                    Some(right.clone()),
                    double_blake3_hash(&[left.hash(), right.hash()].concat()).to_vec(),
                ))
            }
            _ => {
                while datas.len() & (datas.len() - 1) != 0 {
                    datas.push(datas[datas.len() - 1].clone());
                }
                let (left_datas, right_datas) = datas.split_at(datas.len() / 2);
                let left = MerkleNode::from_bufs(left_datas.to_vec());
                let right = MerkleNode::from_bufs(right_datas.to_vec());
                Arc::new(MerkleNode::new(
                    Some(left.clone()),
                    Some(right.clone()),
                    double_blake3_hash(&[left.hash(), right.hash()].concat()).to_vec(),
                ))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn from_bufs_1_data() {
        let data = double_blake3_hash("data1".as_bytes()).to_vec();
        let root = MerkleNode::from_bufs(vec![data]);
        let hex = hex::encode(root.hash());
        assert_eq!(
            hex,
            "689ce4d2c5a083571f0a1b1d8d4bb9a5b5494aba2c98eb606c1d265681ac5244"
        );
    }

    #[test]
    fn from_bufs_2_datas() {
        let data1 = double_blake3_hash("data1".as_bytes()).to_vec();
        let data2 = double_blake3_hash("data2".as_bytes()).to_vec();

        let data = vec![data1, data2];
        let root = MerkleNode::from_bufs(data);
        let hex = hex::encode(root.hash());
        assert_eq!(
            hex,
            "fdc77b5c255818023a45501e5a5ce7f2e0ea275546cad26df121d4b8f17d8cde"
        );
    }

    #[test]
    fn from_bufs_4_datas() {
        let data1 = double_blake3_hash("data1".as_bytes()).to_vec();
        let data2 = double_blake3_hash("data2".as_bytes()).to_vec();
        let data3 = double_blake3_hash("data3".as_bytes()).to_vec();
        let data4 = double_blake3_hash("data4".as_bytes()).to_vec();

        let data = vec![data1, data2, data3, data4];
        let root = MerkleNode::from_bufs(data);
        let hex = hex::encode(root.hash());
        assert_eq!(
            hex,
            "a3344f480b6c8102dd11ad1b686aa2b890b8455bd5343f66b33d392b05b4f187"
        );
    }
}