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