use std::marker::PhantomData; /// Models a keyed hash function using an associated function (i.e. without `&self` receiver). pub trait KeyedHash { /// The error type used to signal what went wrong. type Error; /// Performs a keyed hash using `key` and `data` and writes the output to `out` fn keyed_hash( key: &[u8; KEY_LEN], data: &[u8], out: &mut [u8; HASH_LEN], ) -> Result<(), Self::Error>; } /// Models a keyed hash function using a method (i.e. with a `&self` receiver). /// /// This makes type inference easier, but also requires having a [`KeyedHashInstance`] value, /// instead of just the [`KeyedHash`] type. pub trait KeyedHashInstance { /// The error type used to signal what went wrong. type Error; /// Performs a keyed hash using `key` and `data` and writes the output to `out` fn keyed_hash( &self, key: &[u8; KEY_LEN], data: &[u8], out: &mut [u8; HASH_LEN], ) -> Result<(), Self::Error>; } /// This is a helper to allow for type parameter inference when calling functions /// that need a [KeyedHash]. /// /// Really just binds the [KeyedHash] trait to a dummy variable, so the type of this dummy variable /// can be used for type inference. Less typing work. #[derive(Debug, PartialEq, Eq)] pub struct InferKeyedHash where Static: KeyedHash, { pub _phantom_keyed_hasher: PhantomData<*const Static>, } impl InferKeyedHash where Static: KeyedHash, { pub const KEY_LEN: usize = KEY_LEN; pub const HASH_LEN: usize = HASH_LEN; pub const fn new() -> Self { Self { _phantom_keyed_hasher: PhantomData, } } /// This just forwards to [KeyedHash::keyed_hash] of the type parameter `Static` fn keyed_hash_internal<'a>( &self, key: &'a [u8; KEY_LEN], data: &'a [u8], out: &mut [u8; HASH_LEN], ) -> Result<(), Static::Error> { Static::keyed_hash(key, data, out) } /// Returns the key length of the keyed hash function. pub const fn key_len(self) -> usize { Self::KEY_LEN } /// Returns the hash length of the keyed hash function. pub const fn hash_len(self) -> usize { Self::HASH_LEN } } impl> KeyedHashInstance for InferKeyedHash { type Error = Static::Error; fn keyed_hash( &self, key: &[u8; KEY_LEN], data: &[u8], out: &mut [u8; HASH_LEN], ) -> Result<(), Static::Error> { self.keyed_hash_internal(key, data, out) } } // Helper traits ///////////////////////////////////////////// impl Default for InferKeyedHash where Static: KeyedHash, { fn default() -> Self { Self::new() } } impl Clone for InferKeyedHash where Static: KeyedHash, { fn clone(&self) -> Self { *self } } impl Copy for InferKeyedHash where Static: KeyedHash, { } use rosenpass_to::{with_destination, To}; /// Extends the [`KeyedHash`] trait with a [`To`]-flavoured function. pub trait KeyedHashTo: KeyedHash { fn keyed_hash_to( key: &[u8; KEY_LEN], data: &[u8], ) -> impl To<[u8; HASH_LEN], Result<(), Self::Error>> { with_destination(|out| Self::keyed_hash(key, data, out)) } } impl> KeyedHashTo for T { } /// Extends the [`KeyedHashInstance`] trait with a [`To`]-flavoured function. pub trait KeyedHashInstanceTo: KeyedHashInstance { fn keyed_hash_to( &self, key: &[u8; KEY_LEN], data: &[u8], ) -> impl To<[u8; HASH_LEN], Result<(), Self::Error>> { with_destination(|out| self.keyed_hash(key, data, out)) } } impl> KeyedHashInstanceTo for T { }