Skip to content

Commit

Permalink
add from_bytes for conversions from [u8; 32]
Browse files Browse the repository at this point in the history
The function is `const`, so it is fundamentally different from the
`From` trait implementation by allowing compile-time instantiation of a
`Hash`.
  • Loading branch information
ureeves authored and oconnor663 committed May 1, 2023
1 parent ce48d79 commit 8176a22
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 8 deletions.
22 changes: 14 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,20 +176,21 @@ fn counter_high(counter: u64) -> u32 {
/// An output of the default size, 32 bytes, which provides constant-time
/// equality checking.
///
/// `Hash` implements [`From`] and [`Into`] for `[u8; 32]`, and it provides an
/// explicit [`as_bytes`] method returning `&[u8; 32]`. However, byte arrays
/// and slices don't provide constant-time equality checking, which is often a
/// security requirement in software that handles private data. `Hash` doesn't
/// implement [`Deref`] or [`AsRef`], to avoid situations where a type
/// conversion happens implicitly and the constant-time property is
/// accidentally lost.
/// `Hash` implements [`From`] and [`Into`] for `[u8; 32]`, and it provides
/// explicit [`from_bytes`], and [`as_bytes`] for conversions between itself
/// and `[u8; 32]`. However, byte arrays and slices don't provide constant-time
/// equality checking, which is often a security requirement in software that
/// handles private data. `Hash` doesn't implement [`Deref`] or [`AsRef`], to
/// avoid situations where a type conversion happens implicitly and the
/// constant-time property is accidentally lost.
///
/// `Hash` provides the [`to_hex`] and [`from_hex`] methods for converting to
/// and from hexadecimal. It also implements [`Display`] and [`FromStr`].
///
/// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
/// [`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html
/// [`as_bytes`]: #method.as_bytes
/// [`from_bytes`]: #method.from_bytes
/// [`Deref`]: https://doc.rust-lang.org/stable/std/ops/trait.Deref.html
/// [`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html
/// [`to_hex`]: #method.to_hex
Expand All @@ -208,6 +209,11 @@ impl Hash {
&self.0
}

/// Create a `Hash` from its raw bytes representation.
pub const fn from_bytes(bytes: [u8; OUT_LEN]) -> Self {
Self(bytes)
}

/// Encode a `Hash` in lowercase hexadecimal.
///
/// The returned [`ArrayString`] is a fixed size and doesn't allocate memory
Expand Down Expand Up @@ -259,7 +265,7 @@ impl Hash {
impl From<[u8; OUT_LEN]> for Hash {
#[inline]
fn from(bytes: [u8; OUT_LEN]) -> Self {
Self(bytes)
Self::from_bytes(bytes)
}
}

Expand Down
25 changes: 25 additions & 0 deletions src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,3 +603,28 @@ fn test_issue_206_windows_sse2() {
assert_eq!(crate::Hasher::new().update(input).finalize(), expected_hash);
}
}

#[test]
fn test_hash_conversions() {
let bytes1 = [42; 32];
let hash1: crate::Hash = bytes1.into();
let bytes2: [u8; 32] = hash1.into();
assert_eq!(bytes1, bytes2);

let bytes3 = *hash1.as_bytes();
assert_eq!(bytes1, bytes3);

let hash2 = crate::Hash::from_bytes(bytes1);
assert_eq!(hash1, hash2);

let hex = hash1.to_hex();
let hash3 = crate::Hash::from_hex(hex.as_bytes()).unwrap();
assert_eq!(hash1, hash3);
}

#[test]
const fn test_hash_const_conversions() {
let bytes = [42; 32];
let hash = crate::Hash::from_bytes(bytes);
_ = hash.as_bytes();
}

0 comments on commit 8176a22

Please sign in to comment.