diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs index 7c4af89b..5bd5aff2 100644 --- a/hashes/src/internal_macros.rs +++ b/hashes/src/internal_macros.rs @@ -84,6 +84,20 @@ macro_rules! hash_trait_impls { pub fn backward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHex { internals::hex::display::DisplayArray::<_, [u8; $bits / 8 * 2]>::new(self.0.iter().rev()) } + + /// Zero cost conversion between a fixed length byte array shared reference and + /// a shared reference to this Hash type. + pub fn from_bytes_ref(bytes: &[u8; $bits / 8]) -> &Self { + // Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8] + unsafe { &*(bytes as *const _ as *const Self) } + } + + /// Zero cost conversion between a fixed length byte array exclusive reference and + /// an exclusive reference to this Hash type. + pub fn from_bytes_mut(bytes: &mut [u8; $bits / 8]) -> &mut Self { + // Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8] + unsafe { &mut *(bytes as *mut _ as *mut Self) } + } } impl<$($gen: $gent),*> str::FromStr for Hash<$($gen),*> { diff --git a/hashes/src/ripemd160.rs b/hashes/src/ripemd160.rs index 5661e28d..2d4dc68d 100644 --- a/hashes/src/ripemd160.rs +++ b/hashes/src/ripemd160.rs @@ -405,6 +405,8 @@ mod tests { #[test] #[cfg(feature = "alloc")] fn test() { + use std::convert::TryFrom; + use crate::{ripemd160, Hash, HashEngine}; #[derive(Clone)] @@ -465,12 +467,24 @@ mod tests { }, ]; - for test in tests { + for mut test in tests { // Hash through high-level API, check hex encoding/decoding let hash = ripemd160::Hash::hash(test.input.as_bytes()); assert_eq!(hash, test.output_str.parse::().expect("parse hex")); assert_eq!(&hash[..], &test.output[..]); assert_eq!(&hash.to_string(), &test.output_str); + assert_eq!( + ripemd160::Hash::from_bytes_ref( + <&[u8; 20]>::try_from(&*test.output).expect("known length") + ), + &hash + ); + assert_eq!( + ripemd160::Hash::from_bytes_mut( + <&mut [u8; 20]>::try_from(&mut *test.output).expect("known length") + ), + &hash + ); // Hash through engine, checking that we can input byte by byte let mut engine = ripemd160::Hash::engine();