commonware_cryptography/sha256/
mod.rs1use crate::{Array, Error, Hasher};
24use commonware_utils::{hex, SizedSerialize};
25use rand::{CryptoRng, Rng};
26use sha2::{Digest as _, Sha256 as ISha256};
27use std::{
28 fmt::{Debug, Display},
29 ops::Deref,
30};
31
32const DIGEST_LENGTH: usize = 32;
33
34pub fn hash(message: &[u8]) -> Digest {
36 let array: [u8; DIGEST_LENGTH] = ISha256::digest(message).into();
37 Digest::from(array)
38}
39
40#[derive(Debug)]
42pub struct Sha256 {
43 hasher: ISha256,
44}
45
46impl Default for Sha256 {
47 fn default() -> Self {
48 Self::new()
49 }
50}
51
52impl Clone for Sha256 {
53 fn clone(&self) -> Self {
54 Self::default()
56 }
57}
58
59impl Hasher for Sha256 {
60 type Digest = Digest;
61
62 fn new() -> Self {
63 Self {
64 hasher: ISha256::new(),
65 }
66 }
67
68 fn update(&mut self, message: &[u8]) {
69 self.hasher.update(message);
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) {
79 self.hasher = ISha256::new();
80 }
81
82 fn random<R: Rng + CryptoRng>(rng: &mut R) -> Self::Digest {
83 let mut digest = [0u8; DIGEST_LENGTH];
84 rng.fill_bytes(&mut digest);
85 Self::Digest::from(digest)
86 }
87}
88
89#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
91#[repr(transparent)]
92pub struct Digest([u8; DIGEST_LENGTH]);
93
94impl Array for Digest {}
95
96impl SizedSerialize for Digest {
97 const SERIALIZED_LEN: usize = DIGEST_LENGTH;
98}
99
100impl From<[u8; DIGEST_LENGTH]> for Digest {
101 fn from(value: [u8; DIGEST_LENGTH]) -> Self {
102 Self(value)
103 }
104}
105
106impl TryFrom<&[u8]> for Digest {
107 type Error = Error;
108 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
109 if value.len() != DIGEST_LENGTH {
110 return Err(Error::InvalidDigestLength);
111 }
112 let array: [u8; DIGEST_LENGTH] =
113 value.try_into().map_err(|_| Error::InvalidDigestLength)?;
114 Ok(Self(array))
115 }
116}
117
118impl TryFrom<&Vec<u8>> for Digest {
119 type Error = Error;
120 fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
121 Self::try_from(value.as_slice())
122 }
123}
124
125impl TryFrom<Vec<u8>> for Digest {
126 type Error = Error;
127 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
128 if value.len() != DIGEST_LENGTH {
129 return Err(Error::InvalidDigestLength);
130 }
131
132 let boxed_slice = value.into_boxed_slice();
135 let boxed_array: Box<[u8; DIGEST_LENGTH]> = boxed_slice
136 .try_into()
137 .map_err(|_| Error::InvalidDigestLength)?;
138 Ok(Self(*boxed_array))
139 }
140}
141
142impl AsRef<[u8]> for Digest {
143 fn as_ref(&self) -> &[u8] {
144 &self.0
145 }
146}
147
148impl Deref for Digest {
149 type Target = [u8];
150 fn deref(&self) -> &[u8] {
151 &self.0
152 }
153}
154
155impl Debug for Digest {
156 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157 write!(f, "{}", hex(&self.0))
158 }
159}
160
161impl Display for Digest {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 write!(f, "{}", hex(&self.0))
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170 use commonware_utils::hex;
171
172 const HELLO_DIGEST: &str = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
173
174 #[test]
175 fn test_sha256() {
176 let msg = b"hello world";
177
178 let mut hasher = Sha256::new();
180 hasher.update(msg);
181 let digest = hasher.finalize();
182 assert!(Digest::try_from(digest.as_ref()).is_ok());
183 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
184
185 hasher.update(msg);
187 let digest = hasher.finalize();
188 assert!(Digest::try_from(digest.as_ref()).is_ok());
189 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
190
191 let hash = hash(msg);
193 assert_eq!(hex(hash.as_ref()), HELLO_DIGEST);
194 }
195
196 #[test]
197 fn test_sha256_len() {
198 assert_eq!(Digest::SERIALIZED_LEN, DIGEST_LENGTH);
199 }
200}