Merge rust-bitcoin/rust-bitcoin#1761: Feature (hashes): Add from_bytes_ref and from_bytes_mut to all Hash types

91863c8a78 Feature (hashes): Add from_bytes_ref and from_bytes_mut to all Hash types (junderw)

Pull request description:

  Closes #1756

  I added tests to one of the Hash types, let me know if this seems reasonable as a test and I'll add it for all the other Hash types.

ACKs for top commit:
  apoelstra:
    ACK 91863c8a78
  tcharding:
    ACK 91863c8a78

Tree-SHA512: e1fc278eab4c13b04462636d424b05c599d8f75d76ac8c50cff195085af5ab71aee8a74386d58a457a7ab528226ff4686b3fd0c0019530835709ac1c9577281e
This commit is contained in:
Andrew Poelstra 2023-03-29 14:08:56 +00:00
commit 0c48c6b009
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
2 changed files with 29 additions and 1 deletions

View File

@ -84,6 +84,20 @@ macro_rules! hash_trait_impls {
pub fn backward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHex { 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()) 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),*> { impl<$($gen: $gent),*> str::FromStr for Hash<$($gen),*> {

View File

@ -405,6 +405,8 @@ mod tests {
#[test] #[test]
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
fn test() { fn test() {
use std::convert::TryFrom;
use crate::{ripemd160, Hash, HashEngine}; use crate::{ripemd160, Hash, HashEngine};
#[derive(Clone)] #[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 // Hash through high-level API, check hex encoding/decoding
let hash = ripemd160::Hash::hash(test.input.as_bytes()); let hash = ripemd160::Hash::hash(test.input.as_bytes());
assert_eq!(hash, test.output_str.parse::<ripemd160::Hash>().expect("parse hex")); assert_eq!(hash, test.output_str.parse::<ripemd160::Hash>().expect("parse hex"));
assert_eq!(&hash[..], &test.output[..]); assert_eq!(&hash[..], &test.output[..]);
assert_eq!(&hash.to_string(), &test.output_str); 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 // Hash through engine, checking that we can input byte by byte
let mut engine = ripemd160::Hash::engine(); let mut engine = ripemd160::Hash::engine();