use crate::Hasher; pub(super) fn hmac(key : K, data : M) -> T::Output where T : Hasher, T::Output : AsRef<[u8]>, K : Iterator + Clone, M : Iterator, { let key_len = key.clone().count(); let key = if key_len > 64 { KeyOrHash::from_hash(T::hash(&key.collect::>())) } else { KeyOrHash::from_key(key) }; let key = key.chain(std::iter::repeat(0)); //if key[i] does not exist, use 0 instead. let mut inner_pad = [0u8;64]; let mut outer_pad = [0u8;64]; let pads = inner_pad.iter_mut().zip(outer_pad.iter_mut()); for ((i,o),k) in pads.zip(key) { *i = k ^ 0x36; *o = k ^ 0x5C; } let hash = T::hash(&inner_pad.iter().copied().chain(data).collect::>()); T::hash(&outer_pad.iter().chain(hash.as_ref().iter()).copied().collect::>()) } enum KeyOrHash, H: AsRef<[u8]>> { Key(K), Hash{ hash : H, idx : usize } } impl, H: AsRef<[u8]>> KeyOrHash{ fn from_key(key : K) -> Self { Self::Key(key) } fn from_hash(hash : H) -> Self { Self::Hash { hash, idx: 0 } } } impl, H: AsRef<[u8]>> Iterator for KeyOrHash{ type Item = u8; fn next(&mut self) -> Option { match self { KeyOrHash::Key(k) => k.next(), KeyOrHash::Hash { hash: owned, idx } => { *idx += 1; owned.as_ref().get(*idx-1).copied() }, } } }