commonware_cryptography/sha256/
mod.rs1use crate::{Array, Error, Hasher};
24use bytes::{Buf, BufMut};
25use commonware_codec::{Codec, Error as CodecError, SizedCodec};
26use commonware_utils::hex;
27use rand::{CryptoRng, Rng};
28use sha2::{Digest as _, Sha256 as ISha256};
29use std::{
30 fmt::{Debug, Display},
31 ops::Deref,
32};
33
34const DIGEST_LENGTH: usize = 32;
35
36pub fn hash(message: &[u8]) -> Digest {
38 let array: [u8; DIGEST_LENGTH] = ISha256::digest(message).into();
39 Digest::from(array)
40}
41
42#[derive(Debug)]
44pub struct Sha256 {
45 hasher: ISha256,
46}
47
48impl Default for Sha256 {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54impl Clone for Sha256 {
55 fn clone(&self) -> Self {
56 Self::default()
58 }
59}
60
61impl Hasher for Sha256 {
62 type Digest = Digest;
63
64 fn new() -> Self {
65 Self {
66 hasher: ISha256::new(),
67 }
68 }
69
70 fn update(&mut self, message: &[u8]) {
71 self.hasher.update(message);
72 }
73
74 fn finalize(&mut self) -> Self::Digest {
75 let finalized = self.hasher.finalize_reset();
76 let array: [u8; DIGEST_LENGTH] = finalized.into();
77 Self::Digest::from(array)
78 }
79
80 fn reset(&mut self) {
81 self.hasher = ISha256::new();
82 }
83
84 fn random<R: Rng + CryptoRng>(rng: &mut R) -> Self::Digest {
85 let mut digest = [0u8; DIGEST_LENGTH];
86 rng.fill_bytes(&mut digest);
87 Self::Digest::from(digest)
88 }
89}
90
91#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
93#[repr(transparent)]
94pub struct Digest([u8; DIGEST_LENGTH]);
95
96impl Codec for Digest {
97 fn write(&self, buf: &mut impl BufMut) {
98 self.0.write(buf);
99 }
100
101 fn read(buf: &mut impl Buf) -> Result<Self, CodecError> {
102 Self::read_from(buf).map_err(|err| CodecError::Wrapped("Digest", err.into()))
103 }
104
105 fn len_encoded(&self) -> usize {
106 DIGEST_LENGTH
107 }
108}
109
110impl SizedCodec for Digest {
111 const LEN_ENCODED: usize = DIGEST_LENGTH;
112}
113
114impl Array for Digest {
115 type Error = Error;
116}
117
118impl From<[u8; DIGEST_LENGTH]> for Digest {
119 fn from(value: [u8; DIGEST_LENGTH]) -> Self {
120 Self(value)
121 }
122}
123
124impl TryFrom<&[u8]> for Digest {
125 type Error = Error;
126 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
127 if value.len() != DIGEST_LENGTH {
128 return Err(Error::InvalidDigestLength);
129 }
130 let array: [u8; DIGEST_LENGTH] =
131 value.try_into().map_err(|_| Error::InvalidDigestLength)?;
132 Ok(Self(array))
133 }
134}
135
136impl TryFrom<&Vec<u8>> for Digest {
137 type Error = Error;
138 fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
139 Self::try_from(value.as_slice())
140 }
141}
142
143impl TryFrom<Vec<u8>> for Digest {
144 type Error = Error;
145 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
146 if value.len() != DIGEST_LENGTH {
147 return Err(Error::InvalidDigestLength);
148 }
149
150 let boxed_slice = value.into_boxed_slice();
153 let boxed_array: Box<[u8; DIGEST_LENGTH]> = boxed_slice
154 .try_into()
155 .map_err(|_| Error::InvalidDigestLength)?;
156 Ok(Self(*boxed_array))
157 }
158}
159
160impl AsRef<[u8]> for Digest {
161 fn as_ref(&self) -> &[u8] {
162 &self.0
163 }
164}
165
166impl Deref for Digest {
167 type Target = [u8];
168 fn deref(&self) -> &[u8] {
169 &self.0
170 }
171}
172
173impl Debug for Digest {
174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175 write!(f, "{}", hex(&self.0))
176 }
177}
178
179impl Display for Digest {
180 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181 write!(f, "{}", hex(&self.0))
182 }
183}
184
185impl crate::Digest for Digest {}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 use commonware_utils::hex;
191
192 const HELLO_DIGEST: &str = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
193
194 #[test]
195 fn test_sha256() {
196 let msg = b"hello world";
197
198 let mut hasher = Sha256::new();
200 hasher.update(msg);
201 let digest = hasher.finalize();
202 assert!(Digest::try_from(digest.as_ref()).is_ok());
203 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
204
205 hasher.update(msg);
207 let digest = hasher.finalize();
208 assert!(Digest::try_from(digest.as_ref()).is_ok());
209 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
210
211 let hash = hash(msg);
213 assert_eq!(hex(hash.as_ref()), HELLO_DIGEST);
214 }
215
216 #[test]
217 fn test_sha256_len() {
218 assert_eq!(Digest::LEN_ENCODED, DIGEST_LENGTH);
219 }
220
221 #[test]
222 fn test_codec() {
223 let msg = b"hello world";
224 let mut hasher = Sha256::new();
225 hasher.update(msg);
226 let digest = hasher.finalize();
227
228 let encoded = digest.encode();
229 assert_eq!(encoded.len(), DIGEST_LENGTH);
230 assert_eq!(encoded, digest.as_ref());
231
232 let decoded = Digest::decode(encoded).unwrap();
233 assert_eq!(digest, decoded);
234 }
235}