use crate::HashAlg;
use crate::multihash::MultihashDigest;
use malt::{Log, TreeHasher};
use std::collections::BTreeMap;
#[derive(Clone, Debug)]
pub struct CyphrHasher {
alg: HashAlg,
}
impl CyphrHasher {
pub fn new(alg: HashAlg) -> Self {
Self { alg }
}
}
impl TreeHasher for CyphrHasher {
type Digest = Vec<u8>;
fn leaf(&self, data: &[u8]) -> Self::Digest {
let mut prefix_data = Vec::with_capacity(1 + data.len());
prefix_data.push(0x00);
prefix_data.extend_from_slice(data);
crate::state::hash_bytes(self.alg, &prefix_data).to_vec()
}
fn node(&self, left: &Self::Digest, right: &Self::Digest) -> Self::Digest {
let mut d = Vec::with_capacity(1 + left.len() + right.len());
d.push(0x01);
d.extend_from_slice(left);
d.extend_from_slice(right);
crate::state::hash_bytes(self.alg, &d).to_vec()
}
fn empty(&self) -> Self::Digest {
crate::state::hash_bytes(self.alg, b"").to_vec()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CommitRoot(pub MultihashDigest);
impl CommitRoot {
pub fn as_multihash(&self) -> &MultihashDigest {
&self.0
}
}
pub type CommitLog = Log<CyphrHasher>;
pub type CommitTrees = BTreeMap<HashAlg, CommitLog>;
pub fn commit_root_from_trees(trees: &CommitTrees) -> crate::error::Result<CommitRoot> {
let mut variants = BTreeMap::new();
for (&alg, log) in trees {
variants.insert(alg, log.root().into_boxed_slice());
}
let md = MultihashDigest::new(variants)?;
Ok(CommitRoot(md))
}
pub fn compute_cr(trs: &[&MultihashDigest], algs: &[HashAlg]) -> crate::error::Result<CommitRoot> {
let mut trees = CommitTrees::new();
for &alg in algs {
let mut log = Log::new(CyphrHasher::new(alg));
for tr in trs {
let bytes = tr.get_or_err(alg)?;
log.append(bytes);
}
trees.insert(alg, log);
}
commit_root_from_trees(&trees)
}