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::Hasher;
24use bytes::{Buf, BufMut};
25use commonware_codec::{DecodeExt, Error as CodecError, FixedSize, Read, ReadExt, Write};
26use commonware_utils::{hex, Array};
27use rand::{CryptoRng, Rng};
28use sha2::{Digest as _, Sha256 as ISha256};
29use std::{
30    fmt::{Debug, Display},
31    ops::Deref,
32};
33
34const DIGEST_LENGTH: usize = 32;
35
36/// Generate a SHA-256 digest from a message.
37pub fn hash(message: &[u8]) -> Digest {
38    let array: [u8; DIGEST_LENGTH] = ISha256::digest(message).into();
39    Digest::from(array)
40}
41
42/// SHA-256 hasher.
43#[derive(Debug)]
44pub struct Sha256 {
45    hasher: ISha256,
46}
47
48impl Default for Sha256 {
49    fn default() -> Self {
50        Self::new()
51    }
52}
53
54impl Clone for Sha256 {
55    fn clone(&self) -> Self {
56        // We manually implement `Clone` to avoid cloning the hasher state.
57        Self::default()
58    }
59}
60
61impl Sha256 {
62    /// Convenience function for testing that creates an easily recognizable digest by repeating a
63    /// single byte.
64    pub fn fill(b: u8) -> <Self as Hasher>::Digest {
65        <Self as Hasher>::Digest::decode(vec![b; DIGEST_LENGTH].as_ref()).unwrap()
66    }
67}
68
69impl Hasher for Sha256 {
70    type Digest = Digest;
71
72    fn new() -> Self {
73        Self {
74            hasher: ISha256::new(),
75        }
76    }
77
78    fn update(&mut self, message: &[u8]) {
79        self.hasher.update(message);
80    }
81
82    fn finalize(&mut self) -> Self::Digest {
83        let finalized = self.hasher.finalize_reset();
84        let array: [u8; DIGEST_LENGTH] = finalized.into();
85        Self::Digest::from(array)
86    }
87
88    fn reset(&mut self) {
89        self.hasher = ISha256::new();
90    }
91}
92
93/// Digest of a SHA-256 hashing operation.
94#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
95#[repr(transparent)]
96pub struct Digest([u8; DIGEST_LENGTH]);
97
98impl Write for Digest {
99    fn write(&self, buf: &mut impl BufMut) {
100        self.0.write(buf);
101    }
102}
103
104impl Read for Digest {
105    type Cfg = ();
106
107    fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
108        let array = <[u8; DIGEST_LENGTH]>::read(buf)?;
109        Ok(Self(array))
110    }
111}
112
113impl FixedSize for Digest {
114    const SIZE: usize = DIGEST_LENGTH;
115}
116
117impl Array for Digest {}
118
119impl From<[u8; DIGEST_LENGTH]> for Digest {
120    fn from(value: [u8; DIGEST_LENGTH]) -> Self {
121        Self(value)
122    }
123}
124
125impl AsRef<[u8]> for Digest {
126    fn as_ref(&self) -> &[u8] {
127        &self.0
128    }
129}
130
131impl Deref for Digest {
132    type Target = [u8];
133    fn deref(&self) -> &[u8] {
134        &self.0
135    }
136}
137
138impl Debug for Digest {
139    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140        write!(f, "{}", hex(&self.0))
141    }
142}
143
144impl Display for Digest {
145    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146        write!(f, "{}", hex(&self.0))
147    }
148}
149
150impl crate::Digest for Digest {
151    fn random<R: Rng + CryptoRng>(rng: &mut R) -> Self {
152        let mut array = [0u8; DIGEST_LENGTH];
153        rng.fill_bytes(&mut array);
154        Self(array)
155    }
156}
157
158#[cfg(test)]
159mod tests {
160    use super::*;
161    use commonware_codec::{DecodeExt, Encode};
162    use commonware_utils::hex;
163
164    const HELLO_DIGEST: &str = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
165
166    #[test]
167    fn test_sha256() {
168        let msg = b"hello world";
169
170        // Generate initial hash
171        let mut hasher = Sha256::new();
172        hasher.update(msg);
173        let digest = hasher.finalize();
174        assert!(Digest::decode(digest.as_ref()).is_ok());
175        assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
176
177        // Reuse hasher
178        hasher.update(msg);
179        let digest = hasher.finalize();
180        assert!(Digest::decode(digest.as_ref()).is_ok());
181        assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
182
183        // Test simple hasher
184        let hash = hash(msg);
185        assert_eq!(hex(hash.as_ref()), HELLO_DIGEST);
186    }
187
188    #[test]
189    fn test_sha256_len() {
190        assert_eq!(Digest::SIZE, DIGEST_LENGTH);
191    }
192
193    #[test]
194    fn test_codec() {
195        let msg = b"hello world";
196        let mut hasher = Sha256::new();
197        hasher.update(msg);
198        let digest = hasher.finalize();
199
200        let encoded = digest.encode();
201        assert_eq!(encoded.len(), DIGEST_LENGTH);
202        assert_eq!(encoded, digest.as_ref());
203
204        let decoded = Digest::decode(encoded).unwrap();
205        assert_eq!(digest, decoded);
206    }
207}