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.
This commit is contained in:
Martin Habovstiak 2024-08-30 05:49:52 +02:00
parent 1058cbb9f8
commit 94c0614bda
4 changed files with 19 additions and 5 deletions

View File

@ -135,7 +135,6 @@ impl<T: GeneralHash> GeneralHash for Hmac<T> {
impl<T: GeneralHash> Hash for Hmac<T> { impl<T: GeneralHash> Hash for Hmac<T> {
type Bytes = T::Bytes; type Bytes = T::Bytes;
const LEN: usize = T::LEN;
fn from_slice(sl: &[u8]) -> Result<Hmac<T>, FromSliceError> { T::from_slice(sl).map(Hmac) } fn from_slice(sl: &[u8]) -> Result<Hmac<T>, FromSliceError> { T::from_slice(sl).map(Hmac) }

View File

@ -108,7 +108,6 @@ macro_rules! hash_trait_impls {
impl<$($gen: $gent),*> crate::Hash for Hash<$($gen),*> { impl<$($gen: $gent),*> crate::Hash for Hash<$($gen),*> {
type Bytes = [u8; $bits / 8]; type Bytes = [u8; $bits / 8];
const LEN: usize = $bits / 8;
const DISPLAY_BACKWARD: bool = $reverse; const DISPLAY_BACKWARD: bool = $reverse;
fn from_slice(sl: &[u8]) -> $crate::_export::_core::result::Result<Hash<$($gen),*>, $crate::FromSliceError> { fn from_slice(sl: &[u8]) -> $crate::_export::_core::result::Result<Hash<$($gen),*>, $crate::FromSliceError> {

View File

@ -274,10 +274,10 @@ pub trait Hash:
+ convert::AsRef<[u8]> + convert::AsRef<[u8]>
{ {
/// The byte array that represents the hash internally. /// The byte array that represents the hash internally.
type Bytes: hex::FromHex + Copy; type Bytes: hex::FromHex + Copy + IsByteArray /* <LEN={Self::LEN}> is still unsupported by Rust */;
/// Length of the hash, in bytes. /// Length of the hash, in bytes.
const LEN: usize; const LEN: usize = Self::Bytes::LEN;
/// Copies a byte slice into a hash object. /// Copies a byte slice into a hash object.
fn from_slice(sl: &[u8]) -> Result<Self, FromSliceError>; fn from_slice(sl: &[u8]) -> Result<Self, FromSliceError>;
@ -297,6 +297,23 @@ pub trait Hash:
fn from_byte_array(bytes: Self::Bytes) -> Self; 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<const N: usize> IsByteArray for [u8; N] {
const LEN: usize = N;
}
mod sealed {
#[doc(hidden)]
pub trait IsByteArray { }
impl<const N: usize> IsByteArray for [u8; N] { }
}
/// Attempted to create a hash from an invalid length slice. /// Attempted to create a hash from an invalid length slice.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct FromSliceError { pub struct FromSliceError {

View File

@ -231,7 +231,6 @@ macro_rules! hash_newtype {
impl $crate::Hash for $newtype { impl $crate::Hash for $newtype {
type Bytes = <$hash as $crate::Hash>::Bytes; 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)*])*); const DISPLAY_BACKWARD: bool = $crate::hash_newtype_get_direction!($hash, $(#[$($type_attrs)*])*);
#[inline] #[inline]