use digest::FixedOutput;
use crate::digest::{
crypto_common::BlockSizeUser,
generic_array::typenum::{PartialDiv, U32, Unsigned},
};
pub trait Tag: Sized {
fn tag(self, tag: &[u8]) -> Self {
self.tag_vectored(core::iter::once(tag))
}
fn tag_vectored<'a>(self, tag_components: impl Iterator<Item = &'a [u8]> + Clone) -> Self;
}
impl<H: BlockSizeUser + FixedOutput + Default + Clone> Tag for H
where
<H as BlockSizeUser>::BlockSize: PartialDiv<H::OutputSize>,
<<H as BlockSizeUser>::BlockSize as PartialDiv<H::OutputSize>>::Output: Unsigned,
{
fn tag_vectored<'a>(mut self, tag_components: impl Iterator<Item = &'a [u8]> + Clone) -> Self {
let hashed_tag = {
let mut hash = H::default();
for component in tag_components {
hash.update(component);
}
hash.finalize_fixed()
};
let fill_block =
<<H::BlockSize as PartialDiv<H::OutputSize>>::Output as Unsigned>::to_usize();
for _ in 0..fill_block {
self.update(&hashed_tag[..]);
}
self
}
}
pub trait HashInto {
fn hash_into(self, hash: &mut impl digest::Update);
}
impl HashInto for u8 {
fn hash_into(self, hash: &mut impl digest::Update) {
hash.update(&[self])
}
}
impl<T: HashInto + Clone> HashInto for &T {
fn hash_into(self, hash: &mut impl digest::Update) {
self.clone().hash_into(hash)
}
}
impl<'a, T> HashInto for &'a [T]
where
&'a T: HashInto,
{
fn hash_into(self, hash: &mut impl digest::Update) {
for item in self {
item.hash_into(hash)
}
}
}
impl HashInto for &str {
fn hash_into(self, hash: &mut impl digest::Update) {
hash.update(self.as_bytes())
}
}
impl<T: HashInto, const N: usize> HashInto for [T; N] {
fn hash_into(self, hash: &mut impl digest::Update) {
for item in self {
item.hash_into(hash)
}
}
}
#[cfg(feature = "alloc")]
impl<K: HashInto, V: HashInto> HashInto for alloc::collections::BTreeMap<K, V> {
fn hash_into(self, hash: &mut impl digest::Update) {
for (key, value) in self {
key.hash_into(hash);
value.hash_into(hash);
}
}
}
#[cfg(feature = "alloc")]
impl<T: HashInto + Ord> HashInto for alloc::collections::BTreeSet<T> {
fn hash_into(self, hash: &mut impl digest::Update) {
for item in self {
item.hash_into(hash)
}
}
}
pub trait HashAdd {
#[must_use]
fn add<HI: HashInto>(self, data: HI) -> Self;
#[must_use]
fn ds(self, domain_separator: &'static str) -> Self
where
Self: Sized,
{
self.add(domain_separator.len() as u8).add(domain_separator)
}
#[must_use]
fn ds_vectored(self, separators: &[&'static str]) -> Self
where
Self: Sized,
{
let total_len: usize = separators.iter().map(|sep| sep.len()).sum();
self.add(total_len as u8).add(separators)
}
}
impl<D: digest::Update> HashAdd for D {
fn add<HI: HashInto>(mut self, data: HI) -> Self {
data.hash_into(&mut self);
self
}
}
pub trait Hash32: digest::FixedOutput<OutputSize = U32> + Clone + Default + Tag {}
impl<H> Hash32 for H where H: digest::FixedOutput<OutputSize = U32> + Clone + Default + Tag {}