-
Notifications
You must be signed in to change notification settings - Fork 305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add compile time conversions from & into [u8; 32]
#299
Conversation
I hesitate in changing |
Making As far as a |
Let me know your thoughts about this approach: diff --git a/src/lib.rs b/src/lib.rs
index b3621c1..18dfd03 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -176,19 +176,19 @@ 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 also the `const`
+/// functions [`new`] and [`as_bytes`]. 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
+/// [`new`]: #method.new
/// [`as_bytes`]: #method.as_bytes
/// [`Deref`]: https://doc.rust-lang.org/stable/std/ops/trait.Deref.html
/// [`AsRef`]: https://doc.rust-lang.org/std/convert/trait.AsRef.html
@@ -200,11 +200,19 @@ fn counter_high(counter: u64) -> u32 {
pub struct Hash([u8; OUT_LEN]);
impl Hash {
+ /// Create a new `Hash` from 32 bytes.
+ /// constant-time equality checking, so if you need to compare hashes,
+ /// prefer the `Hash` type.
+ #[inline]
+ pub const fn new(bytes: [u8; OUT_LEN]) -> Self {
+ Self(bytes)
+ }
+
/// The raw bytes of the `Hash`. Note that byte arrays don't provide
/// constant-time equality checking, so if you need to compare hashes,
/// prefer the `Hash` type.
#[inline]
- pub fn as_bytes(&self) -> &[u8; OUT_LEN] {
+ pub const fn as_bytes(&self) -> &[u8; OUT_LEN] {
&self.0
}
diff --git a/src/test.rs b/src/test.rs
index 4b6272c..1d9b9aa 100644
--- a/src/test.rs
+++ b/src/test.rs
@@ -603,3 +603,25 @@ fn test_issue_206_windows_sse2() {
assert_eq!(crate::Hasher::new().update(input).finalize(), expected_hash);
}
}
+
+#[test]
+fn test_hash_conversions() {
+ let bytes1 = [99; 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::new(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 = [99; 32];
+ let hash = crate::Hash::new(bytes);
+ _ = hash.as_bytes();
+} |
fae490c
to
a133dad
Compare
The function is `const`, so it is fundamentally different from the `From` trait implementation by allowing compile-time instantiation of a `Hash`.
a133dad
to
9054123
Compare
I'm not very opinionated on it tbh, but a |
I think you're right. Landing this as-is. |
Let me know if you need this to get released sooner rather than later? I might like to take one last look at the API at release time before we commit to it forever :) |
It is useful to be able to convert from
Hash
into[u8; 32]
and vice-versa at compile time.