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, Default)]
44pub struct Sha256 {
45 hasher: ISha256,
46}
47
48impl Clone for Sha256 {
49 fn clone(&self) -> Self {
50 Self::default()
52 }
53}
54
55impl Sha256 {
56 pub fn fill(b: u8) -> <Self as Hasher>::Digest {
59 <Self as Hasher>::Digest::decode(vec![b; DIGEST_LENGTH].as_ref()).unwrap()
60 }
61}
62
63impl Hasher for Sha256 {
64 type Digest = Digest;
65
66 fn update(&mut self, message: &[u8]) -> &mut Self {
67 self.hasher.update(message);
68 self
69 }
70
71 fn finalize(&mut self) -> Self::Digest {
72 let finalized = self.hasher.finalize_reset();
73 let array: [u8; DIGEST_LENGTH] = finalized.into();
74 Self::Digest::from(array)
75 }
76
77 fn reset(&mut self) -> &mut Self {
78 self.hasher = ISha256::new();
79 self
80 }
81
82 fn empty() -> Self::Digest {
83 Self::new().finalize()
84 }
85}
86
87#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
89#[repr(transparent)]
90pub struct Digest(pub [u8; DIGEST_LENGTH]);
91
92impl Write for Digest {
93 fn write(&self, buf: &mut impl BufMut) {
94 self.0.write(buf);
95 }
96}
97
98impl Read for Digest {
99 type Cfg = ();
100
101 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
102 let array = <[u8; DIGEST_LENGTH]>::read(buf)?;
103 Ok(Self(array))
104 }
105}
106
107impl FixedSize for Digest {
108 const SIZE: usize = DIGEST_LENGTH;
109}
110
111impl Span for Digest {}
112
113impl Array for Digest {}
114
115impl From<[u8; DIGEST_LENGTH]> for Digest {
116 fn from(value: [u8; DIGEST_LENGTH]) -> Self {
117 Self(value)
118 }
119}
120
121impl AsRef<[u8]> for Digest {
122 fn as_ref(&self) -> &[u8] {
123 &self.0
124 }
125}
126
127impl Deref for Digest {
128 type Target = [u8];
129 fn deref(&self) -> &[u8] {
130 &self.0
131 }
132}
133
134impl Debug for Digest {
135 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
136 write!(f, "{}", hex(&self.0))
137 }
138}
139
140impl Display for Digest {
141 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
142 write!(f, "{}", hex(&self.0))
143 }
144}
145
146impl crate::Digest for Digest {
147 fn random<R: CryptoRngCore>(rng: &mut R) -> Self {
148 let mut array = [0u8; DIGEST_LENGTH];
149 rng.fill_bytes(&mut array);
150 Self(array)
151 }
152}
153
154impl Zeroize for Digest {
155 fn zeroize(&mut self) {
156 self.0.zeroize();
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163 use commonware_codec::{DecodeExt, Encode};
164 use commonware_utils::hex;
165
166 const HELLO_DIGEST: &str = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
167
168 #[test]
169 fn test_sha256() {
170 let msg = b"hello world";
171
172 let mut hasher = Sha256::new();
174 hasher.update(msg);
175 let digest = hasher.finalize();
176 assert!(Digest::decode(digest.as_ref()).is_ok());
177 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
178
179 hasher.update(msg);
181 let digest = hasher.finalize();
182 assert!(Digest::decode(digest.as_ref()).is_ok());
183 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
184
185 let hash = Sha256::hash(msg);
187 assert_eq!(hex(hash.as_ref()), HELLO_DIGEST);
188 }
189
190 #[test]
191 fn test_sha256_len() {
192 assert_eq!(Digest::SIZE, DIGEST_LENGTH);
193 }
194
195 #[test]
196 fn test_hash_empty() {
197 let digest1 = Sha256::empty();
198 let digest2 = Sha256::empty();
199
200 assert_eq!(digest1, digest2);
201 }
202
203 #[test]
204 fn test_sha256_empty() {
205 let empty_digest = Sha256::empty();
206
207 let expected_bytes = [
210 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f,
211 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b,
212 0x78, 0x52, 0xb8, 0x55,
213 ];
214 let expected_digest = Digest::from(expected_bytes);
215
216 assert_eq!(empty_digest, expected_digest);
217 }
218
219 #[test]
220 fn test_codec() {
221 let msg = b"hello world";
222 let mut hasher = Sha256::new();
223 hasher.update(msg);
224 let digest = hasher.finalize();
225
226 let encoded = digest.encode();
227 assert_eq!(encoded.len(), DIGEST_LENGTH);
228 assert_eq!(encoded, digest.as_ref());
229
230 let decoded = Digest::decode(encoded).unwrap();
231 assert_eq!(digest, decoded);
232 }
233}