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, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
91#[repr(transparent)]
92pub struct Digest([u8; DIGEST_LENGTH]);
93
94impl Array for Digest {
95 type Error = Error;
96}
97
98impl SizedSerialize for Digest {
99 const SERIALIZED_LEN: usize = DIGEST_LENGTH;
100}
101
102impl From<[u8; DIGEST_LENGTH]> for Digest {
103 fn from(value: [u8; DIGEST_LENGTH]) -> Self {
104 Self(value)
105 }
106}
107
108impl TryFrom<&[u8]> for Digest {
109 type Error = Error;
110 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
111 if value.len() != DIGEST_LENGTH {
112 return Err(Error::InvalidDigestLength);
113 }
114 let array: [u8; DIGEST_LENGTH] =
115 value.try_into().map_err(|_| Error::InvalidDigestLength)?;
116 Ok(Self(array))
117 }
118}
119
120impl TryFrom<&Vec<u8>> for Digest {
121 type Error = Error;
122 fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
123 Self::try_from(value.as_slice())
124 }
125}
126
127impl TryFrom<Vec<u8>> for Digest {
128 type Error = Error;
129 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
130 if value.len() != DIGEST_LENGTH {
131 return Err(Error::InvalidDigestLength);
132 }
133
134 let boxed_slice = value.into_boxed_slice();
137 let boxed_array: Box<[u8; DIGEST_LENGTH]> = boxed_slice
138 .try_into()
139 .map_err(|_| Error::InvalidDigestLength)?;
140 Ok(Self(*boxed_array))
141 }
142}
143
144impl AsRef<[u8]> for Digest {
145 fn as_ref(&self) -> &[u8] {
146 &self.0
147 }
148}
149
150impl Deref for Digest {
151 type Target = [u8];
152 fn deref(&self) -> &[u8] {
153 &self.0
154 }
155}
156
157impl Debug for Digest {
158 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159 write!(f, "{}", hex(&self.0))
160 }
161}
162
163impl Display for Digest {
164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165 write!(f, "{}", hex(&self.0))
166 }
167}
168
169impl crate::Digest for Digest {}
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174 use commonware_utils::hex;
175
176 const HELLO_DIGEST: &str = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
177
178 #[test]
179 fn test_sha256() {
180 let msg = b"hello world";
181
182 let mut hasher = Sha256::new();
184 hasher.update(msg);
185 let digest = hasher.finalize();
186 assert!(Digest::try_from(digest.as_ref()).is_ok());
187 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
188
189 hasher.update(msg);
191 let digest = hasher.finalize();
192 assert!(Digest::try_from(digest.as_ref()).is_ok());
193 assert_eq!(hex(digest.as_ref()), HELLO_DIGEST);
194
195 let hash = hash(msg);
197 assert_eq!(hex(hash.as_ref()), HELLO_DIGEST);
198 }
199
200 #[test]
201 fn test_sha256_len() {
202 assert_eq!(Digest::SERIALIZED_LEN, DIGEST_LENGTH);
203 }
204}