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_formatting::Hex;
29use commonware_math::algebra::Random;
30use commonware_utils::{Array, Span};
31use core::{
32 fmt::{Debug, Display},
33 ops::Deref,
34};
35use rand_core::CryptoRngCore;
36use sha2::{Digest as _, Sha256 as ISha256};
37use zeroize::Zeroize;
38
39pub type CoreSha256 = ISha256;
41
42const DIGEST_LENGTH: usize = 32;
43
44#[derive(Debug, Default)]
46pub struct Sha256 {
47 hasher: ISha256,
48}
49
50impl Clone for Sha256 {
51 fn clone(&self) -> Self {
52 Self::default()
54 }
55}
56
57impl Sha256 {
58 pub fn fill(b: u8) -> <Self as Hasher>::Digest {
61 <Self as Hasher>::Digest::decode(vec![b; DIGEST_LENGTH].as_ref()).unwrap()
62 }
63}
64
65impl Hasher for Sha256 {
66 type Digest = Digest;
67
68 fn update(&mut self, message: &[u8]) -> &mut Self {
69 self.hasher.update(message);
70 self
71 }
72
73 fn finalize(&mut self) -> Self::Digest {
74 let finalized = self.hasher.finalize_reset();
75 let array: [u8; DIGEST_LENGTH] = finalized.into();
76 Self::Digest::from(array)
77 }
78
79 fn reset(&mut self) -> &mut Self {
80 self.hasher = ISha256::new();
81 self
82 }
83}
84
85#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
87#[repr(transparent)]
88pub struct Digest(pub [u8; DIGEST_LENGTH]);
89
90#[cfg(feature = "arbitrary")]
91impl<'a> arbitrary::Arbitrary<'a> for Digest {
92 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
93 let len = u.int_in_range(0..=256)?;
95 let data = u.bytes(len)?;
96 Ok(Sha256::hash(data))
97 }
98}
99
100impl Write for Digest {
101 fn write(&self, buf: &mut impl BufMut) {
102 self.0.write(buf);
103 }
104}
105
106impl Read for Digest {
107 type Cfg = ();
108
109 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
110 let array = <[u8; DIGEST_LENGTH]>::read(buf)?;
111 Ok(Self(array))
112 }
113}
114
115impl FixedSize for Digest {
116 const SIZE: usize = DIGEST_LENGTH;
117}
118
119impl Span for Digest {}
120
121impl Array for Digest {}
122
123impl From<[u8; DIGEST_LENGTH]> for Digest {
124 fn from(value: [u8; DIGEST_LENGTH]) -> Self {
125 Self(value)
126 }
127}
128
129impl AsRef<[u8]> for Digest {
130 fn as_ref(&self) -> &[u8] {
131 &self.0
132 }
133}
134
135impl Deref for Digest {
136 type Target = [u8];
137 fn deref(&self) -> &[u8] {
138 &self.0
139 }
140}
141
142impl Debug for Digest {
143 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
144 write!(f, "{}", Hex(&self.0))
145 }
146}
147
148impl Display for Digest {
149 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
150 write!(f, "{}", Hex(&self.0))
151 }
152}
153
154impl crate::Digest for Digest {
155 const EMPTY: Self = Self([0u8; DIGEST_LENGTH]);
156}
157
158impl Random for Digest {
159 fn random(mut rng: impl CryptoRngCore) -> 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
177 const HELLO_DIGEST: [u8; DIGEST_LENGTH] = commonware_formatting::hex!(
178 "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
179 );
180
181 #[test]
182 fn test_sha256() {
183 let msg = b"hello world";
184
185 let mut hasher = Sha256::new();
187 hasher.update(msg);
188 let digest = hasher.finalize();
189 assert!(Digest::decode(digest.as_ref()).is_ok());
190 assert_eq!(digest.as_ref(), HELLO_DIGEST);
191
192 hasher.update(msg);
194 let digest = hasher.finalize();
195 assert!(Digest::decode(digest.as_ref()).is_ok());
196 assert_eq!(digest.as_ref(), HELLO_DIGEST);
197
198 let hash = Sha256::hash(msg);
200 assert_eq!(hash.as_ref(), HELLO_DIGEST);
201 }
202
203 #[test]
204 fn test_sha256_len() {
205 assert_eq!(Digest::SIZE, DIGEST_LENGTH);
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}