From 94c0614bda8bca6077e76fbdd1414e32119a02d5 Mon Sep 17 00:00:00 2001 From: Martin Habovstiak Date: Fri, 30 Aug 2024 05:49:52 +0200 Subject: [PATCH] Enforce that `Hash::Bytes` is an array In the future we would like to guarantee the correctness of `LEN` which is currently not entirely possible, so this at least adds a sealed trait enforcing the `Bytes` type to be an array. Consumers concerned about the validity of the length can access the `LEN` constant on `Bytes` instead to get the correct length of the array. --- hashes/src/hmac.rs | 1 - hashes/src/internal_macros.rs | 1 - hashes/src/lib.rs | 21 +++++++++++++++++++-- hashes/src/util.rs | 1 - 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/hashes/src/hmac.rs b/hashes/src/hmac.rs index 7b8c1a401..9de980d04 100644 --- a/hashes/src/hmac.rs +++ b/hashes/src/hmac.rs @@ -135,7 +135,6 @@ impl GeneralHash for Hmac { impl Hash for Hmac { type Bytes = T::Bytes; - const LEN: usize = T::LEN; fn from_slice(sl: &[u8]) -> Result, FromSliceError> { T::from_slice(sl).map(Hmac) } diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs index a105a66c3..3e362d23f 100644 --- a/hashes/src/internal_macros.rs +++ b/hashes/src/internal_macros.rs @@ -108,7 +108,6 @@ macro_rules! hash_trait_impls { impl<$($gen: $gent),*> crate::Hash for Hash<$($gen),*> { type Bytes = [u8; $bits / 8]; - const LEN: usize = $bits / 8; const DISPLAY_BACKWARD: bool = $reverse; fn from_slice(sl: &[u8]) -> $crate::_export::_core::result::Result, $crate::FromSliceError> { diff --git a/hashes/src/lib.rs b/hashes/src/lib.rs index 897f97b8f..df2be7556 100644 --- a/hashes/src/lib.rs +++ b/hashes/src/lib.rs @@ -274,10 +274,10 @@ pub trait Hash: + convert::AsRef<[u8]> { /// The byte array that represents the hash internally. - type Bytes: hex::FromHex + Copy; + type Bytes: hex::FromHex + Copy + IsByteArray /* is still unsupported by Rust */; /// Length of the hash, in bytes. - const LEN: usize; + const LEN: usize = Self::Bytes::LEN; /// Copies a byte slice into a hash object. fn from_slice(sl: &[u8]) -> Result; @@ -297,6 +297,23 @@ pub trait Hash: fn from_byte_array(bytes: Self::Bytes) -> Self; } +/// Ensures that a type is an array. +pub trait IsByteArray: AsRef<[u8]> + sealed::IsByteArray { + /// The length of the array. + const LEN: usize; +} + +impl IsByteArray for [u8; N] { + const LEN: usize = N; +} + +mod sealed { + #[doc(hidden)] + pub trait IsByteArray { } + + impl IsByteArray for [u8; N] { } +} + /// Attempted to create a hash from an invalid length slice. #[derive(Debug, Clone, PartialEq, Eq)] pub struct FromSliceError { diff --git a/hashes/src/util.rs b/hashes/src/util.rs index 58d08d9f1..2956415d6 100644 --- a/hashes/src/util.rs +++ b/hashes/src/util.rs @@ -231,7 +231,6 @@ macro_rules! hash_newtype { impl $crate::Hash for $newtype { type Bytes = <$hash as $crate::Hash>::Bytes; - const LEN: usize = <$hash as $crate::Hash>::LEN; const DISPLAY_BACKWARD: bool = $crate::hash_newtype_get_direction!($hash, $(#[$($type_attrs)*])*); #[inline]