feat: Merkle tree list hashing

This commit is contained in:
Tyler Beckman 2024-10-28 17:42:42 -06:00
parent 27e5aaa777
commit d4f07b4f04
Signed by: Ty
GPG key ID: 2813440C772555A4
2 changed files with 37 additions and 0 deletions

View file

@ -1,5 +1,6 @@
{ {
"cSpell.words": [ "cSpell.words": [
"hasher",
"Merkle", "Merkle",
"Precertificate" "Precertificate"
], ],

View file

@ -1 +1,37 @@
use sha2::{Digest, Sha256};
use super::types::MerkleTreeLeaf;
pub enum MerkleTreeNode<'a> {
Leaf(MerkleTreeLeaf<'a>),
Intermediate(String)
}
/// Hashes a merkle leaf list. This takes in a slice of u8 slices, each
/// representing the binary form of a merkle tree leaf. This implementation is
/// not optimized for extra-long lists as its implementation is recursive,
/// however, the current-largest CT log as of 11/5/24 would theoretically only
/// go 32 levels deep.
pub fn hash_merkle_leaf_list(leaves: &[&[u8]]) -> [u8; 32] {
let mut hasher = Sha256::default();
// The hash of an empty list is the empty hash, no branch necessary
if leaves.len() == 1 {
// The hash of one element is 0x00 + the hash of its data
hasher.update([0x00u8]);
hasher.update(leaves[0]);
} else if leaves.len() > 1 {
// For n > 1, let k be the largest power of two smaller than n (i.e., k < n <=
// 2k)
// MTH(D[n]) = SHA-256(0x01 || MTH(D[0:k]) || MTH(D[k:n]))
// This can be calculated by taking log_2(n), flooring it, then taking 2
// to the power of it again
let k = 2usize.pow(leaves.len().ilog2());
hasher.update([0x01u8]);
hasher.update(hash_merkle_leaf_list(&leaves[0..k]));
hasher.update(hash_merkle_leaf_list(&leaves[k..leaves.len()]));
}
return hasher.finalize().into();
}