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 fn update(&mut self, message: &[u8]) -> &mut Self {
68 self.hasher.update(message);
69 self
70 }
71
72 fn finalize(&mut self) -> Self::Digest {
73 let finalized = self.hasher.finalize_reset();
74 let array: [u8; DIGEST_LENGTH] = finalized.into();
75 Self::Digest::from(array)
76 }
77
78 fn reset(&mut self) -> &mut Self {
79 self.hasher = ISha256::new();
80 self
81 }
82}
83
84#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
86#[repr(transparent)]
87pub struct Digest(pub [u8; DIGEST_LENGTH]);
88
89#[cfg(feature = "arbitrary")]
90impl<'a> arbitrary::Arbitrary<'a> for Digest {
91 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
92 let len = u.int_in_range(0..=256)?;
94 let data = u.bytes(len)?;
95 Ok(Sha256::hash(data))
96 }
97}
98
99impl Write for Digest {
100 fn write(&self, buf: &mut impl BufMut) {
101 self.0.write(buf);
102 }
103}
104
105impl Read for Digest {
106 type Cfg = ();
107
108 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
109 let array = <[u8; DIGEST_LENGTH]>::read(buf)?;
110 Ok(Self(array))
111 }
112}
113
114impl FixedSize for Digest {
115 const SIZE: usize = DIGEST_LENGTH;
116}
117
118impl Span for Digest {}
119
120impl Array for Digest {}
121
122impl From<[u8; DIGEST_LENGTH]> for Digest {
123 fn from(value: [u8; DIGEST_LENGTH]) -> Self {
124 Self(value)
125 }
126}
127
128impl AsRef<[u8]> for Digest {
129 fn as_ref(&self) -> &[u8] {
130 &self.0
131 }
132}
133
134impl Deref for Digest {
135 type Target = [u8];
136 fn deref(&self) -> &[u8] {
137 &self.0
138 }
139}
140
141impl Debug for Digest {
142 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
143 write!(f, "{}", hex(&self.0))
144 }
145}
146
147impl Display for Digest {
148 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
149 write!(f, "{}", hex(&self.0))
150 }
151}
152
153impl crate::Digest for Digest {
154 const EMPTY: Self = Self([0u8; DIGEST_LENGTH]);
155}
156
157impl Random for Digest {
158 fn random(mut rng: impl CryptoRngCore) -> Self {
159 let mut array = [0u8; DIGEST_LENGTH];
160 rng.fill_bytes(&mut array);
161 Self(array)
162 }
163}
164
165impl Zeroize for Digest {
166 fn zeroize(&mut self) {
167 self.0.zeroize();
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174 use commonware_codec::{DecodeExt, Encode};
175 use commonware_utils::hex;
176
177 const HELLO_DIGEST: [u8; DIGEST_LENGTH] =
178 hex!("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!(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!(digest.as_ref(), HELLO_DIGEST);
196
197 let hash = Sha256::hash(msg);
199 assert_eq!(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_codec() {
209 let msg = b"hello world";
210 let mut hasher = Sha256::new();
211 hasher.update(msg);
212 let digest = hasher.finalize();
213
214 let encoded = digest.encode();
215 assert_eq!(encoded.len(), DIGEST_LENGTH);
216 assert_eq!(encoded, digest.as_ref());
217
218 let decoded = Digest::decode(encoded).unwrap();
219 assert_eq!(digest, decoded);
220 }
221
222 #[cfg(feature = "arbitrary")]
223 mod conformance {
224 use super::*;
225 use commonware_codec::conformance::CodecConformance;
226
227 commonware_conformance::conformance_tests! {
228 CodecConformance<Digest>,
229 }
230 }
231}