Skip to main content

rootchain_crypto/
hashing.rs

1use blake3::Hasher;
2use rootchain_core::types::{BlockHeader, Hash, Transaction};
3
4pub fn hash_bytes(data: &[u8]) -> Hash {
5    Hash::from_bytes(blake3::hash(data).into())
6}
7
8pub fn hash_block_header(header: &BlockHeader) -> Hash {
9    let mut hasher = Hasher::new();
10    hasher.update(&header.height.to_le_bytes());
11    hasher.update(&header.prev_hash.0);
12    hasher.update(&header.merkle_root.0);
13    hasher.update(&header.state_root.0);
14    hasher.update(&header.proposer.0);
15    hasher.update(&header.timestamp.to_le_bytes());
16    Hash::from_bytes(hasher.finalize().into())
17}
18pub fn hash_transaction(tx: &Transaction) -> Hash {
19    let mut hasher = Hasher::new();
20    let tx_type_u8 = match tx.tx_type {
21        rootchain_core::types::TransactionType::Transfer => 0u8,
22        rootchain_core::types::TransactionType::Governance => 1u8,
23        rootchain_core::types::TransactionType::ContractDeploy => 2u8,
24        rootchain_core::types::TransactionType::ContractCall => 3u8,
25        rootchain_core::types::TransactionType::SubmitEquivocationProof => 4u8,
26    };
27    hasher.update(&[tx_type_u8]);
28    hasher.update(&tx.from.0);
29    hasher.update(&tx.to.0);
30    hasher.update(&tx.amount.to_le_bytes());
31    hasher.update(&tx.fee.to_le_bytes());
32    hasher.update(&tx.nonce.to_le_bytes());
33    hasher.update(&tx.payload);
34    Hash::from_bytes(hasher.finalize().into())
35}
36
37pub fn compute_merkle_root(tx_hashes: &[Hash]) -> Hash {
38    if tx_hashes.is_empty() {
39        return Hash::zero();
40    }
41
42    let mut current_level = tx_hashes.to_vec();
43    while current_level.len() > 1 {
44        let mut next_level = Vec::with_capacity(current_level.len().div_ceil(2));
45        for chunk in current_level.chunks(2) {
46            let mut hasher = Hasher::new();
47            if chunk.len() == 2 {
48                hasher.update(&chunk[0].0);
49                hasher.update(&chunk[1].0);
50            } else {
51                hasher.update(&chunk[0].0);
52                hasher.update(&chunk[0].0); // duplicate last odd element
53            }
54            next_level.push(Hash::from_bytes(hasher.finalize().into()));
55        }
56        current_level = next_level;
57    }
58    current_level[0]
59}