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, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
91#[repr(transparent)]
92pub struct Digest([u8; DIGEST_LENGTH]);
93
94impl Array for Digest {
95    type Error = Error;
96}
97
98impl SizedSerialize for Digest {
99    const SERIALIZED_LEN: usize = DIGEST_LENGTH;
100}
101
102impl From<[u8; DIGEST_LENGTH]> for Digest {
103    fn from(value: [u8; DIGEST_LENGTH]) -> Self {
104        Self(value)
105    }
106}
107
108impl TryFrom<&[u8]> for Digest {
109    type Error = Error;
110    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
111        if value.len() != DIGEST_LENGTH {
112            return Err(Error::InvalidDigestLength);
113        }
114        let array: [u8; DIGEST_LENGTH] =
115            value.try_into().map_err(|_| Error::InvalidDigestLength)?;
116        Ok(Self(array))
117    }
118}
119
120impl TryFrom<&Vec<u8>> for Digest {
121    type Error = Error;
122    fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
123        Self::try_from(value.as_slice())
124    }
125}
126
127impl TryFrom<Vec<u8>> for Digest {
128    type Error = Error;
129    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
130        if value.len() != DIGEST_LENGTH {
131            return Err(Error::InvalidDigestLength);
132        }
133
134        // If the length is correct, we can safely convert the vector into a boxed slice without
135        // any copies.
136        let boxed_slice = value.into_boxed_slice();
137        let boxed_array: Box<[u8; DIGEST_LENGTH]> = boxed_slice
138            .try_into()
139            .map_err(|_| Error::InvalidDigestLength)?;
140        Ok(Self(*boxed_array))
141    }
142}
143
144impl AsRef<[u8]> for Digest {
145    fn as_ref(&self) -> &[u8] {
146        &self.0
147    }
148}
149
150impl Deref for Digest {
151    type Target = [u8];
152    fn deref(&self) -> &[u8] {
153        &self.0
154    }
155}
156
157impl Debug for Digest {
158    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159        write!(f, "{}", hex(&self.0))
160    }
161}
162
163impl Display for Digest {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        write!(f, "{}", hex(&self.0))
166    }
167}
168
169impl crate::Digest for Digest {}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174    use commonware_utils::hex;
175
176    const HELLO_DIGEST: &str = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
177
178    #[test]
179    fn test_sha256() {
180        let msg = b"hello world";
181
182        // Generate initial hash
183        let mut hasher = Sha256::new();
184        hasher.update(msg);
185        let digest = hasher.finalize();
186        assert!(Digest::try_from(digest.as_ref()).is_ok());
187        assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
188
189        // Reuse hasher
190        hasher.update(msg);
191        let digest = hasher.finalize();
192        assert!(Digest::try_from(digest.as_ref()).is_ok());
193        assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
194
195        // Test simple hasher
196        let hash = hash(msg);
197        assert_eq!(hex(hash.as_ref()), HELLO_DIGEST);
198    }
199
200    #[test]
201    fn test_sha256_len() {
202        assert_eq!(Digest::SERIALIZED_LEN, DIGEST_LENGTH);
203    }
204}