commonware_cryptography/sha256/
mod.rs

1//! SHA-256 implementation of the `Hasher` trait.
2//!
3//! This implementation uses the `sha2` crate to generate SHA-256 digests.
4//!
5//! # Example
6//! ```rust
7//! use commonware_cryptography::{Hasher, Sha256};
8//!
9//! // Create a new SHA-256 hasher
10//! let mut hasher = Sha256::new();
11//!
12//! // Update the hasher with some messages
13//! hasher.update(b"hello,");
14//! hasher.update(b"world!");
15//!
16//! // Finalize the hasher to get the digest
17//! let digest = hasher.finalize();
18//!
19//! // Print the digest
20//! println!("digest: {:?}", digest);
21//! ```
22
23use crate::{Array, Error, Hasher};
24use commonware_utils::{hex, SizedSerialize};
25use rand::{CryptoRng, Rng};
26use sha2::{Digest as _, Sha256 as ISha256};
27use std::{
28    fmt::{Debug, Display},
29    ops::Deref,
30};
31
32const DIGEST_LENGTH: usize = 32;
33
34/// Generate a SHA-256 digest from a message.
35pub fn hash(message: &[u8]) -> Digest {
36    let array: [u8; DIGEST_LENGTH] = ISha256::digest(message).into();
37    Digest::from(array)
38}
39
40/// SHA-256 hasher.
41#[derive(Debug)]
42pub struct Sha256 {
43    hasher: ISha256,
44}
45
46impl Default for Sha256 {
47    fn default() -> Self {
48        Self::new()
49    }
50}
51
52impl Clone for Sha256 {
53    fn clone(&self) -> Self {
54        // We manually implement `Clone` to avoid cloning the hasher state.
55        Self::default()
56    }
57}
58
59impl Hasher for Sha256 {
60    type Digest = Digest;
61
62    fn new() -> Self {
63        Self {
64            hasher: ISha256::new(),
65        }
66    }
67
68    fn update(&mut self, message: &[u8]) {
69        self.hasher.update(message);
70    }
71
72    fn finalize(&mut self) -> Self::Digest {
73        let finalized = self.hasher.finalize_reset();
74        let array: [u8; DIGEST_LENGTH] = finalized.into();
75        Self::Digest::from(array)
76    }
77
78    fn reset(&mut self) {
79        self.hasher = ISha256::new();
80    }
81
82    fn random<R: Rng + CryptoRng>(rng: &mut R) -> Self::Digest {
83        let mut digest = [0u8; DIGEST_LENGTH];
84        rng.fill_bytes(&mut digest);
85        Self::Digest::from(digest)
86    }
87}
88
89/// Digest of a SHA-256 hashing operation.
90#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
91#[repr(transparent)]
92pub struct Digest([u8; DIGEST_LENGTH]);
93
94impl Array for Digest {}
95
96impl SizedSerialize for Digest {
97    const SERIALIZED_LEN: usize = DIGEST_LENGTH;
98}
99
100impl From<[u8; DIGEST_LENGTH]> for Digest {
101    fn from(value: [u8; DIGEST_LENGTH]) -> Self {
102        Self(value)
103    }
104}
105
106impl TryFrom<&[u8]> for Digest {
107    type Error = Error;
108    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
109        if value.len() != DIGEST_LENGTH {
110            return Err(Error::InvalidDigestLength);
111        }
112        let array: [u8; DIGEST_LENGTH] =
113            value.try_into().map_err(|_| Error::InvalidDigestLength)?;
114        Ok(Self(array))
115    }
116}
117
118impl TryFrom<&Vec<u8>> for Digest {
119    type Error = Error;
120    fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
121        Self::try_from(value.as_slice())
122    }
123}
124
125impl TryFrom<Vec<u8>> for Digest {
126    type Error = Error;
127    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
128        if value.len() != DIGEST_LENGTH {
129            return Err(Error::InvalidDigestLength);
130        }
131
132        // If the length is correct, we can safely convert the vector into a boxed slice without
133        // any copies.
134        let boxed_slice = value.into_boxed_slice();
135        let boxed_array: Box<[u8; DIGEST_LENGTH]> = boxed_slice
136            .try_into()
137            .map_err(|_| Error::InvalidDigestLength)?;
138        Ok(Self(*boxed_array))
139    }
140}
141
142impl AsRef<[u8]> for Digest {
143    fn as_ref(&self) -> &[u8] {
144        &self.0
145    }
146}
147
148impl Deref for Digest {
149    type Target = [u8];
150    fn deref(&self) -> &[u8] {
151        &self.0
152    }
153}
154
155impl Debug for Digest {
156    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157        write!(f, "{}", hex(&self.0))
158    }
159}
160
161impl Display for Digest {
162    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163        write!(f, "{}", hex(&self.0))
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170    use commonware_utils::hex;
171
172    const HELLO_DIGEST: &str = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
173
174    #[test]
175    fn test_sha256() {
176        let msg = b"hello world";
177
178        // Generate initial hash
179        let mut hasher = Sha256::new();
180        hasher.update(msg);
181        let digest = hasher.finalize();
182        assert!(Digest::try_from(digest.as_ref()).is_ok());
183        assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
184
185        // Reuse hasher
186        hasher.update(msg);
187        let digest = hasher.finalize();
188        assert!(Digest::try_from(digest.as_ref()).is_ok());
189        assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
190
191        // Test simple hasher
192        let hash = hash(msg);
193        assert_eq!(hex(hash.as_ref()), HELLO_DIGEST);
194    }
195
196    #[test]
197    fn test_sha256_len() {
198        assert_eq!(Digest::SERIALIZED_LEN, DIGEST_LENGTH);
199    }
200}