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};
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([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 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 std::fmt::Formatter<'_>) -> std::fmt::Result {
148 write!(f, "{}", hex(&self.0))
149 }
150}
151
152impl Display for Digest {
153 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154 write!(f, "{}", hex(&self.0))
155 }
156}
157
158impl crate::Digest for Digest {
159 fn random<R: Rng + CryptoRng>(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 = 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}