commonware_cryptography/sha256/
mod.rs1use crate::Hasher;
24#[cfg(not(feature = "std"))]
25use alloc::vec;
26use bytes::{Buf, BufMut};
27use commonware_codec::{DecodeExt, Error as CodecError, FixedSize, Read, ReadExt, Write};
28use commonware_utils::{hex, Array, Span};
29use core::{
30 fmt::{Debug, Display},
31 ops::Deref,
32};
33use rand_core::CryptoRngCore;
34use sha2::{Digest as _, Sha256 as ISha256};
35use zeroize::Zeroize;
36
37pub type CoreSha256 = ISha256;
39
40const DIGEST_LENGTH: usize = 32;
41
42#[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 Self::default()
58 }
59}
60
61impl Sha256 {
62 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]) -> &mut Self {
79 self.hasher.update(message);
80 self
81 }
82
83 fn finalize(&mut self) -> Self::Digest {
84 let finalized = self.hasher.finalize_reset();
85 let array: [u8; DIGEST_LENGTH] = finalized.into();
86 Self::Digest::from(array)
87 }
88
89 fn reset(&mut self) -> &mut Self {
90 self.hasher = ISha256::new();
91 self
92 }
93
94 fn empty() -> Self::Digest {
95 Self::new().finalize()
96 }
97}
98
99#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
101#[repr(transparent)]
102pub struct Digest(pub [u8; DIGEST_LENGTH]);
103
104impl Write for Digest {
105 fn write(&self, buf: &mut impl BufMut) {
106 self.0.write(buf);
107 }
108}
109
110impl Read for Digest {
111 type Cfg = ();
112
113 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
114 let array = <[u8; DIGEST_LENGTH]>::read(buf)?;
115 Ok(Self(array))
116 }
117}
118
119impl FixedSize for Digest {
120 const SIZE: usize = DIGEST_LENGTH;
121}
122
123impl Span for Digest {}
124
125impl Array for Digest {}
126
127impl From<[u8; DIGEST_LENGTH]> for Digest {
128 fn from(value: [u8; DIGEST_LENGTH]) -> Self {
129 Self(value)
130 }
131}
132
133impl AsRef<[u8]> for Digest {
134 fn as_ref(&self) -> &[u8] {
135 &self.0
136 }
137}
138
139impl Deref for Digest {
140 type Target = [u8];
141 fn deref(&self) -> &[u8] {
142 &self.0
143 }
144}
145
146impl Debug for Digest {
147 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
148 write!(f, "{}", hex(&self.0))
149 }
150}
151
152impl Display for Digest {
153 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
154 write!(f, "{}", hex(&self.0))
155 }
156}
157
158impl crate::Digest for Digest {
159 fn random<R: CryptoRngCore>(rng: &mut R) -> Self {
160 let mut array = [0u8; DIGEST_LENGTH];
161 rng.fill_bytes(&mut array);
162 Self(array)
163 }
164}
165
166impl Zeroize for Digest {
167 fn zeroize(&mut self) {
168 self.0.zeroize();
169 }
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175 use commonware_codec::{DecodeExt, Encode};
176 use commonware_utils::hex;
177
178 const HELLO_DIGEST: &str = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
179
180 #[test]
181 fn test_sha256() {
182 let msg = b"hello world";
183
184 let mut hasher = Sha256::new();
186 hasher.update(msg);
187 let digest = hasher.finalize();
188 assert!(Digest::decode(digest.as_ref()).is_ok());
189 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
190
191 hasher.update(msg);
193 let digest = hasher.finalize();
194 assert!(Digest::decode(digest.as_ref()).is_ok());
195 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
196
197 let hash = Sha256::hash(msg);
199 assert_eq!(hex(hash.as_ref()), HELLO_DIGEST);
200 }
201
202 #[test]
203 fn test_sha256_len() {
204 assert_eq!(Digest::SIZE, DIGEST_LENGTH);
205 }
206
207 #[test]
208 fn test_hash_empty() {
209 let digest1 = Sha256::empty();
210 let digest2 = Sha256::empty();
211
212 assert_eq!(digest1, digest2);
213 }
214
215 #[test]
216 fn test_sha256_empty() {
217 let empty_digest = Sha256::empty();
218
219 let expected_bytes = [
222 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f,
223 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b,
224 0x78, 0x52, 0xb8, 0x55,
225 ];
226 let expected_digest = Digest::from(expected_bytes);
227
228 assert_eq!(empty_digest, expected_digest);
229 }
230
231 #[test]
232 fn test_codec() {
233 let msg = b"hello world";
234 let mut hasher = Sha256::new();
235 hasher.update(msg);
236 let digest = hasher.finalize();
237
238 let encoded = digest.encode();
239 assert_eq!(encoded.len(), DIGEST_LENGTH);
240 assert_eq!(encoded, digest.as_ref());
241
242 let decoded = Digest::decode(encoded).unwrap();
243 assert_eq!(digest, decoded);
244 }
245}