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