commonware_cryptography/sha256/
mod.rs1use crate::Hasher;
24use bytes::{Buf, BufMut};
25use commonware_codec::{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 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 Write for Digest {
97 fn write(&self, buf: &mut impl BufMut) {
98 self.0.write(buf);
99 }
100}
101
102impl Read for Digest {
103 type Cfg = ();
104
105 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
106 let array = <[u8; DIGEST_LENGTH]>::read(buf)?;
107 Ok(Self(array))
108 }
109}
110
111impl FixedSize for Digest {
112 const SIZE: usize = DIGEST_LENGTH;
113}
114
115impl Array for Digest {}
116
117impl From<[u8; DIGEST_LENGTH]> for Digest {
118 fn from(value: [u8; DIGEST_LENGTH]) -> Self {
119 Self(value)
120 }
121}
122
123impl AsRef<[u8]> for Digest {
124 fn as_ref(&self) -> &[u8] {
125 &self.0
126 }
127}
128
129impl Deref for Digest {
130 type Target = [u8];
131 fn deref(&self) -> &[u8] {
132 &self.0
133 }
134}
135
136impl Debug for Digest {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 write!(f, "{}", hex(&self.0))
139 }
140}
141
142impl Display for Digest {
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 write!(f, "{}", hex(&self.0))
145 }
146}
147
148impl crate::Digest for Digest {}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153 use commonware_codec::{DecodeExt, Encode};
154 use commonware_utils::hex;
155
156 const HELLO_DIGEST: &str = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
157
158 #[test]
159 fn test_sha256() {
160 let msg = b"hello world";
161
162 let mut hasher = Sha256::new();
164 hasher.update(msg);
165 let digest = hasher.finalize();
166 assert!(Digest::decode(digest.as_ref()).is_ok());
167 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
168
169 hasher.update(msg);
171 let digest = hasher.finalize();
172 assert!(Digest::decode(digest.as_ref()).is_ok());
173 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
174
175 let hash = hash(msg);
177 assert_eq!(hex(hash.as_ref()), HELLO_DIGEST);
178 }
179
180 #[test]
181 fn test_sha256_len() {
182 assert_eq!(Digest::SIZE, DIGEST_LENGTH);
183 }
184
185 #[test]
186 fn test_codec() {
187 let msg = b"hello world";
188 let mut hasher = Sha256::new();
189 hasher.update(msg);
190 let digest = hasher.finalize();
191
192 let encoded = digest.encode();
193 assert_eq!(encoded.len(), DIGEST_LENGTH);
194 assert_eq!(encoded, digest.as_ref());
195
196 let decoded = Digest::decode(encoded).unwrap();
197 assert_eq!(digest, decoded);
198 }
199}