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_math::algebra::Random;
29use commonware_utils::{hex, Array, Span};
30use core::{
31 fmt::{Debug, Display},
32 ops::Deref,
33};
34use rand_core::CryptoRngCore;
35use sha2::{Digest as _, Sha256 as ISha256};
36use zeroize::Zeroize;
37
38pub type CoreSha256 = ISha256;
40
41const DIGEST_LENGTH: usize = 32;
42
43#[derive(Debug, Default)]
45pub struct Sha256 {
46 hasher: ISha256,
47}
48
49impl Clone for Sha256 {
50 fn clone(&self) -> Self {
51 Self::default()
53 }
54}
55
56impl Sha256 {
57 pub fn fill(b: u8) -> <Self as Hasher>::Digest {
60 <Self as Hasher>::Digest::decode(vec![b; DIGEST_LENGTH].as_ref()).unwrap()
61 }
62}
63
64impl Hasher for Sha256 {
65 type Digest = Digest;
66
67 const EMPTY: Self::Digest = Digest(hex!(
68 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
69 ));
70
71 fn update(&mut self, message: &[u8]) -> &mut Self {
72 self.hasher.update(message);
73 self
74 }
75
76 fn finalize(&mut self) -> Self::Digest {
77 let finalized = self.hasher.finalize_reset();
78 let array: [u8; DIGEST_LENGTH] = finalized.into();
79 Self::Digest::from(array)
80 }
81
82 fn reset(&mut self) -> &mut Self {
83 self.hasher = ISha256::new();
84 self
85 }
86}
87
88#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
90#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
91#[repr(transparent)]
92pub struct Digest(pub [u8; DIGEST_LENGTH]);
93
94impl Write for Digest {
95 fn write(&self, buf: &mut impl BufMut) {
96 self.0.write(buf);
97 }
98}
99
100impl Read for Digest {
101 type Cfg = ();
102
103 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
104 let array = <[u8; DIGEST_LENGTH]>::read(buf)?;
105 Ok(Self(array))
106 }
107}
108
109impl FixedSize for Digest {
110 const SIZE: usize = DIGEST_LENGTH;
111}
112
113impl Span for Digest {}
114
115impl Array for Digest {}
116
117impl From<[u8; DIGEST_LENGTH]> for Digest {
118 fn from(value: [u8; DIGEST_LENGTH]) -> Self {
119 Self(value)
120 }
121}
122
123impl AsRef<[u8]> for Digest {
124 fn as_ref(&self) -> &[u8] {
125 &self.0
126 }
127}
128
129impl Deref for Digest {
130 type Target = [u8];
131 fn deref(&self) -> &[u8] {
132 &self.0
133 }
134}
135
136impl Debug for Digest {
137 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
138 write!(f, "{}", hex(&self.0))
139 }
140}
141
142impl Display for Digest {
143 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
144 write!(f, "{}", hex(&self.0))
145 }
146}
147
148impl crate::Digest for Digest {}
149
150impl Random for Digest {
151 fn random(mut rng: impl CryptoRngCore) -> Self {
152 let mut array = [0u8; DIGEST_LENGTH];
153 rng.fill_bytes(&mut array);
154 Self(array)
155 }
156}
157
158impl Zeroize for Digest {
159 fn zeroize(&mut self) {
160 self.0.zeroize();
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167 use commonware_codec::{DecodeExt, Encode};
168 use commonware_utils::hex;
169
170 const HELLO_DIGEST: [u8; DIGEST_LENGTH] =
171 hex!("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9");
172
173 #[test]
174 fn test_sha256() {
175 let msg = b"hello world";
176
177 let mut hasher = Sha256::new();
179 hasher.update(msg);
180 let digest = hasher.finalize();
181 assert!(Digest::decode(digest.as_ref()).is_ok());
182 assert_eq!(digest.as_ref(), HELLO_DIGEST);
183
184 hasher.update(msg);
186 let digest = hasher.finalize();
187 assert!(Digest::decode(digest.as_ref()).is_ok());
188 assert_eq!(digest.as_ref(), HELLO_DIGEST);
189
190 let hash = Sha256::hash(msg);
192 assert_eq!(hash.as_ref(), HELLO_DIGEST);
193 }
194
195 #[test]
196 fn test_sha256_len() {
197 assert_eq!(Digest::SIZE, DIGEST_LENGTH);
198 }
199
200 #[test]
201 fn test_sha256_empty() {
202 let empty_digest = Sha256::EMPTY;
203 let expected_digest = Sha256::new().finalize();
204
205 assert_eq!(empty_digest, expected_digest);
206 }
207
208 #[test]
209 fn test_codec() {
210 let msg = b"hello world";
211 let mut hasher = Sha256::new();
212 hasher.update(msg);
213 let digest = hasher.finalize();
214
215 let encoded = digest.encode();
216 assert_eq!(encoded.len(), DIGEST_LENGTH);
217 assert_eq!(encoded, digest.as_ref());
218
219 let decoded = Digest::decode(encoded).unwrap();
220 assert_eq!(digest, decoded);
221 }
222
223 #[cfg(feature = "arbitrary")]
224 mod conformance {
225 use super::*;
226 use commonware_codec::conformance::CodecConformance;
227
228 commonware_conformance::conformance_tests! {
229 CodecConformance<Digest>,
230 }
231 }
232}