use hmac::{Hmac, Mac, digest::FixedOutput};
use sha2::Sha256;
type HmacSha256 = Hmac<Sha256>;
pub(crate) struct HmacMsg<P>
where
P: AsRef<[u8]>,
{
chain: Vec<Vec<P>>,
}
impl<P> HmacMsg<P>
where
P: AsRef<[u8]>,
{
pub(crate) fn new(data: Vec<P>) -> Self {
Self { chain: vec![data] }
}
pub(crate) fn segment(&mut self, data: P) -> &mut Self {
self.chain.push(vec![data]);
self
}
#[allow(unused)]
fn segment_vec(&mut self, data: Vec<P>) -> &mut Self {
self.chain.push(data);
self
}
pub(crate) fn finalize_fixed(&self) -> Vec<u8> {
let res: Option<Vec<u8>> = self.chain.iter().fold(None, |acc, segment| {
let mut iter = segment.iter();
let mut hmac = match acc {
None => {
let f = iter.next().unwrap();
HmacSha256::new_from_slice(f.as_ref())
}
Some(prev) => HmacSha256::new_from_slice(prev.as_ref()),
}
.unwrap();
iter.for_each(|p| hmac.update(p.as_ref()));
let v = hmac.finalize_fixed().to_vec();
Some(v)
});
res.unwrap()
}
}