libcrux_traits/digest/
slice.rs

1//! This module contains the trait and related errors for hashers that take slices as
2//! arguments and write the results to mutable slices.
3
4use super::arrayref;
5
6/// A trait for oneshot hashing, where the output is written to a provided slice.
7pub trait Hash {
8    /// Writes the digest for the given input byte slice, into `digest` in immediate mode.
9    fn hash(digest: &mut [u8], payload: &[u8]) -> Result<usize, HashError>;
10}
11
12/// A trait for incremental hashing, where the output is written to a provided slice.
13pub trait DigestIncremental: super::DigestIncrementalBase {
14    /// Writes the digest into `digest`.
15    ///
16    /// Note that the digest state can be continued to be used, to extend the digest.
17    fn finish(state: &mut Self::IncrementalState, digest: &mut [u8]) -> Result<usize, FinishError>;
18}
19
20/// Error indicating that finalizing failed.
21#[derive(Debug, PartialEq)]
22pub enum FinishError {
23    /// The length of the provided digest buffer is invalid.
24    InvalidDigestLength,
25    /// Unknown error.
26    Unknown,
27}
28
29impl core::fmt::Display for FinishError {
30    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
31        let text = match self {
32            FinishError::InvalidDigestLength => {
33                "the length of the provided digest buffer is invalid"
34            }
35            FinishError::Unknown => "indicates an unknown error",
36        };
37
38        f.write_str(text)
39    }
40}
41
42/// Error indicating that hashing failed.
43#[derive(Debug, PartialEq)]
44pub enum HashError {
45    /// The length of the provided digest buffer is invalid.
46    InvalidDigestLength,
47    /// The length of the provided payload is invalid.
48    InvalidPayloadLength,
49    /// Indicates an unknown error.
50    Unknown,
51}
52
53impl core::fmt::Display for HashError {
54    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55        let text = match self {
56            HashError::InvalidDigestLength => "the length of the provided digest buffer is invalid",
57            HashError::InvalidPayloadLength => "the length of the provided payload is invalid",
58            HashError::Unknown => "indicates an unknown error",
59        };
60
61        f.write_str(text)
62    }
63}
64
65#[cfg(feature = "error-in-core")]
66mod error_in_core {
67
68    impl core::error::Error for super::HashError {}
69    impl core::error::Error for super::FinishError {}
70}
71
72impl From<arrayref::HashError> for HashError {
73    fn from(e: arrayref::HashError) -> Self {
74        match e {
75            arrayref::HashError::InvalidPayloadLength => Self::InvalidPayloadLength,
76            arrayref::HashError::Unknown => Self::Unknown,
77        }
78    }
79}
80
81#[macro_export]
82/// Implements [`Hash`] for any [`arrayref::Hash`].
83macro_rules! impl_hash_trait {
84    ($type:ty => $len:expr) => {
85        impl $crate::digest::slice::Hash for $type {
86            fn hash(
87                digest: &mut [u8],
88                payload: &[u8],
89            ) -> Result<usize, $crate::digest::slice::HashError> {
90                let digest: &mut [u8; $len] = digest
91                    .try_into()
92                    .map_err(|_| $crate::digest::slice::HashError::InvalidDigestLength)?;
93                <Self as $crate::digest::arrayref::Hash<$len>>::hash(digest, payload)
94                    .map(|_| $len)
95                    .map_err($crate::digest::slice::HashError::from)
96            }
97        }
98    };
99}
100
101#[macro_export]
102/// Implements [`DigestIncremental`] for any [`arrayref::DigestIncremental`].
103macro_rules! impl_digest_incremental_trait {
104    ($type:ty => $incremental_state:ty, $len:expr) => {
105        impl $crate::digest::slice::DigestIncremental for $type {
106            fn finish(
107                state: &mut Self::IncrementalState,
108                digest: &mut [u8],
109            ) -> Result<usize, $crate::digest::slice::FinishError> {
110                let digest: &mut [u8; $len] = digest
111                    .try_into()
112                    .map_err(|_| $crate::digest::slice::FinishError::InvalidDigestLength)?;
113                <Self as $crate::digest::arrayref::DigestIncremental<$len>>::finish(state, digest);
114
115                Ok($len)
116            }
117        }
118    };
119}
120
121pub use impl_digest_incremental_trait;
122pub use impl_hash_trait;