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};
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 Sha256 {
62 pub fn fill(b: u8) -> <Self as Hasher>::Digest {
65 <Self as Hasher>::Digest::decode(vec![b; DIGEST_LENGTH].as_ref()).unwrap()
66 }
67}
68
69impl Hasher for Sha256 {
70 type Digest = Digest;
71
72 fn new() -> Self {
73 Self {
74 hasher: ISha256::new(),
75 }
76 }
77
78 fn update(&mut self, message: &[u8]) {
79 self.hasher.update(message);
80 }
81
82 fn finalize(&mut self) -> Self::Digest {
83 let finalized = self.hasher.finalize_reset();
84 let array: [u8; DIGEST_LENGTH] = finalized.into();
85 Self::Digest::from(array)
86 }
87
88 fn reset(&mut self) {
89 self.hasher = ISha256::new();
90 }
91}
92
93#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
95#[repr(transparent)]
96pub struct Digest([u8; DIGEST_LENGTH]);
97
98impl Write for Digest {
99 fn write(&self, buf: &mut impl BufMut) {
100 self.0.write(buf);
101 }
102}
103
104impl Read for Digest {
105 type Cfg = ();
106
107 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
108 let array = <[u8; DIGEST_LENGTH]>::read(buf)?;
109 Ok(Self(array))
110 }
111}
112
113impl FixedSize for Digest {
114 const SIZE: usize = DIGEST_LENGTH;
115}
116
117impl Array for Digest {}
118
119impl From<[u8; DIGEST_LENGTH]> for Digest {
120 fn from(value: [u8; DIGEST_LENGTH]) -> Self {
121 Self(value)
122 }
123}
124
125impl AsRef<[u8]> for Digest {
126 fn as_ref(&self) -> &[u8] {
127 &self.0
128 }
129}
130
131impl Deref for Digest {
132 type Target = [u8];
133 fn deref(&self) -> &[u8] {
134 &self.0
135 }
136}
137
138impl Debug for Digest {
139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140 write!(f, "{}", hex(&self.0))
141 }
142}
143
144impl Display for Digest {
145 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146 write!(f, "{}", hex(&self.0))
147 }
148}
149
150impl crate::Digest for Digest {
151 fn random<R: Rng + CryptoRng>(rng: &mut R) -> Self {
152 let mut array = [0u8; DIGEST_LENGTH];
153 rng.fill_bytes(&mut array);
154 Self(array)
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161 use commonware_codec::{DecodeExt, Encode};
162 use commonware_utils::hex;
163
164 const HELLO_DIGEST: &str = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
165
166 #[test]
167 fn test_sha256() {
168 let msg = b"hello world";
169
170 let mut hasher = Sha256::new();
172 hasher.update(msg);
173 let digest = hasher.finalize();
174 assert!(Digest::decode(digest.as_ref()).is_ok());
175 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
176
177 hasher.update(msg);
179 let digest = hasher.finalize();
180 assert!(Digest::decode(digest.as_ref()).is_ok());
181 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
182
183 let hash = hash(msg);
185 assert_eq!(hex(hash.as_ref()), HELLO_DIGEST);
186 }
187
188 #[test]
189 fn test_sha256_len() {
190 assert_eq!(Digest::SIZE, DIGEST_LENGTH);
191 }
192
193 #[test]
194 fn test_codec() {
195 let msg = b"hello world";
196 let mut hasher = Sha256::new();
197 hasher.update(msg);
198 let digest = hasher.finalize();
199
200 let encoded = digest.encode();
201 assert_eq!(encoded.len(), DIGEST_LENGTH);
202 assert_eq!(encoded, digest.as_ref());
203
204 let decoded = Digest::decode(encoded).unwrap();
205 assert_eq!(digest, decoded);
206 }
207}