commonware_cryptography/sha256/
mod.rs1use crate::Hasher;
24use bytes::{Buf, BufMut};
25use commonware_codec::{DecodeExt, Error as CodecError, FixedSize, Read, ReadExt, Write};
26use commonware_utils::{hex, Array};
27use rand::{CryptoRng, Rng};
28use sha2::{Digest as _, Sha256 as ISha256};
29use std::{
30 fmt::{Debug, Display},
31 ops::Deref,
32};
33use zeroize::Zeroize;
34
35pub type CoreSha256 = ISha256;
37
38const DIGEST_LENGTH: usize = 32;
39
40pub fn hash(message: &[u8]) -> Digest {
42 let array: [u8; DIGEST_LENGTH] = ISha256::digest(message).into();
43 Digest::from(array)
44}
45
46#[derive(Debug)]
48pub struct Sha256 {
49 hasher: ISha256,
50}
51
52impl Default for Sha256 {
53 fn default() -> Self {
54 Self::new()
55 }
56}
57
58impl Clone for Sha256 {
59 fn clone(&self) -> Self {
60 Self::default()
62 }
63}
64
65impl Sha256 {
66 pub fn fill(b: u8) -> <Self as Hasher>::Digest {
69 <Self as Hasher>::Digest::decode(vec![b; DIGEST_LENGTH].as_ref()).unwrap()
70 }
71}
72
73impl Hasher for Sha256 {
74 type Digest = Digest;
75
76 fn new() -> Self {
77 Self {
78 hasher: ISha256::new(),
79 }
80 }
81
82 fn update(&mut self, message: &[u8]) {
83 self.hasher.update(message);
84 }
85
86 fn finalize(&mut self) -> Self::Digest {
87 let finalized = self.hasher.finalize_reset();
88 let array: [u8; DIGEST_LENGTH] = finalized.into();
89 Self::Digest::from(array)
90 }
91
92 fn reset(&mut self) {
93 self.hasher = ISha256::new();
94 }
95}
96
97#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
99#[repr(transparent)]
100pub struct Digest([u8; DIGEST_LENGTH]);
101
102impl Write for Digest {
103 fn write(&self, buf: &mut impl BufMut) {
104 self.0.write(buf);
105 }
106}
107
108impl Read for Digest {
109 type Cfg = ();
110
111 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
112 let array = <[u8; DIGEST_LENGTH]>::read(buf)?;
113 Ok(Self(array))
114 }
115}
116
117impl FixedSize for Digest {
118 const SIZE: usize = DIGEST_LENGTH;
119}
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 std::fmt::Formatter<'_>) -> std::fmt::Result {
144 write!(f, "{}", hex(&self.0))
145 }
146}
147
148impl Display for Digest {
149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150 write!(f, "{}", hex(&self.0))
151 }
152}
153
154impl crate::Digest for Digest {
155 fn random<R: Rng + CryptoRng>(rng: &mut R) -> Self {
156 let mut array = [0u8; DIGEST_LENGTH];
157 rng.fill_bytes(&mut array);
158 Self(array)
159 }
160}
161
162impl Zeroize for Digest {
163 fn zeroize(&mut self) {
164 self.0.zeroize();
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171 use commonware_codec::{DecodeExt, Encode};
172 use commonware_utils::hex;
173
174 const HELLO_DIGEST: &str = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
175
176 #[test]
177 fn test_sha256() {
178 let msg = b"hello world";
179
180 let mut hasher = Sha256::new();
182 hasher.update(msg);
183 let digest = hasher.finalize();
184 assert!(Digest::decode(digest.as_ref()).is_ok());
185 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
186
187 hasher.update(msg);
189 let digest = hasher.finalize();
190 assert!(Digest::decode(digest.as_ref()).is_ok());
191 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
192
193 let hash = hash(msg);
195 assert_eq!(hex(hash.as_ref()), HELLO_DIGEST);
196 }
197
198 #[test]
199 fn test_sha256_len() {
200 assert_eq!(Digest::SIZE, DIGEST_LENGTH);
201 }
202
203 #[test]
204 fn test_codec() {
205 let msg = b"hello world";
206 let mut hasher = Sha256::new();
207 hasher.update(msg);
208 let digest = hasher.finalize();
209
210 let encoded = digest.encode();
211 assert_eq!(encoded.len(), DIGEST_LENGTH);
212 assert_eq!(encoded, digest.as_ref());
213
214 let decoded = Digest::decode(encoded).unwrap();
215 assert_eq!(digest, decoded);
216 }
217}