1use std::fmt;
10use std::fs;
11use std::io;
12use std::ops;
13use std::path::Path;
14use std::str::FromStr;
15
16use hex::FromHex;
17use hex::FromHexError;
18use serde::de;
19use serde::de::Deserialize;
20use serde::de::Deserializer;
21use serde::de::Visitor;
22use serde::ser::Serialize;
23use serde::ser::Serializer;
24use sha2::Digest as _;
25use sha2::Sha256;
26
27const DIGEST_LENGTH: usize = 32;
28
29#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Default)]
31pub struct Digest([u8; DIGEST_LENGTH]);
32
33impl Digest {
34 pub fn new(data: &[u8]) -> Self {
36 Digest(Sha256::digest(data).into())
37 }
38
39 pub fn digest_reader<R: io::Read>(mut reader: R) -> io::Result<Self> {
41 let mut hasher = Sha256::default();
42 let mut buf = [0u8; 16384];
43
44 loop {
45 let n = reader.read(&mut buf)?;
46 if n == 0 {
47 break;
48 }
49 hasher.update(&buf[..n]);
50 }
51
52 Ok(Digest(hasher.finalize().into()))
53 }
54
55 pub fn digest_path<P: AsRef<Path>>(path: P) -> io::Result<Self> {
57 Self::digest_reader(fs::File::open(path)?)
58 }
59}
60
61#[derive(Default)]
64pub struct DigestBuilder(Sha256);
65
66impl DigestBuilder {
67 pub fn update(&mut self, data: &[u8]) {
69 self.0.update(data);
70 }
71
72 pub fn finish(self) -> Digest {
74 Digest(self.0.finalize().into())
75 }
76}
77
78impl fmt::LowerHex for Digest {
79 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80 for byte in &self.0 {
81 write!(f, "{byte:02x}")?;
82 }
83 Ok(())
84 }
85}
86
87impl fmt::UpperHex for Digest {
88 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89 for byte in &self.0 {
90 write!(f, "{byte:02X}")?;
91 }
92 Ok(())
93 }
94}
95
96impl fmt::Display for Digest {
97 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98 <Self as fmt::LowerHex>::fmt(self, f)
99 }
100}
101
102impl fmt::Debug for Digest {
103 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104 <Self as fmt::Display>::fmt(self, f)
105 }
106}
107
108impl ops::Deref for Digest {
109 type Target = [u8; DIGEST_LENGTH];
110
111 fn deref(&self) -> &Self::Target {
112 &self.0
113 }
114}
115
116impl Serialize for Digest {
117 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
118 where
119 S: Serializer,
120 {
121 if serializer.is_human_readable() {
122 serializer.serialize_str(&self.to_string())
123 } else {
124 serializer.serialize_bytes(self.0.as_ref())
125 }
126 }
127}
128
129impl<'de> Deserialize<'de> for Digest {
130 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
131 where
132 D: Deserializer<'de>,
133 {
134 struct DigestVisitor;
135
136 impl<'de> Visitor<'de> for DigestVisitor {
137 type Value = Digest;
138
139 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
140 write!(f, "hex string or 32 bytes")
141 }
142
143 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
144 where
145 E: de::Error,
146 {
147 let v = <[u8; DIGEST_LENGTH]>::from_hex(v).map_err(|e| match e {
148 FromHexError::InvalidHexCharacter { c, .. } => E::invalid_value(
149 de::Unexpected::Char(c),
150 &"string with only hexadecimal characters",
151 ),
152 FromHexError::InvalidStringLength => {
153 E::invalid_length(v.len(), &"hex string with a valid length")
154 }
155 FromHexError::OddLength => {
156 E::invalid_length(v.len(), &"hex string with an even length")
157 }
158 })?;
159 Ok(Digest(v))
160 }
161
162 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
163 where
164 E: de::Error,
165 {
166 if v.len() != DIGEST_LENGTH {
167 return Err(E::invalid_length(v.len(), &"32 bytes"));
168 }
169 let mut inner = [0; DIGEST_LENGTH];
170 inner.copy_from_slice(v);
171 Ok(Digest(inner))
172 }
173 }
174
175 if deserializer.is_human_readable() {
176 deserializer.deserialize_str(DigestVisitor)
177 } else {
178 deserializer.deserialize_bytes(DigestVisitor)
179 }
180 }
181}
182
183impl FromHex for Digest {
184 type Error = FromHexError;
185
186 fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
187 <[u8; DIGEST_LENGTH]>::from_hex(hex).map(Digest)
188 }
189}
190
191impl AsRef<[u8]> for Digest {
192 fn as_ref(&self) -> &[u8] {
193 &self.0
194 }
195}
196
197impl FromStr for Digest {
198 type Err = FromHexError;
199
200 fn from_str(s: &str) -> Result<Self, Self::Err> {
201 Digest::from_hex(s)
202 }
203}
204
205#[cfg(test)]
206mod test {
207 use super::*;
208
209 #[test]
210 fn test_from_hex() {
211 let s = "b1fbeefc23e6a149a6f7d0c2fb635bfc78f7ddc2da963ea9c6a63eb324260e6d";
212 assert_eq!(Digest::from_str(s).unwrap().to_string(), s);
213 }
214
215 #[test]
228 fn digest_is_independent_of_optimisation_level() {
229 assert_eq!(
230 Digest::new(b"").to_string(),
231 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
232 );
233 assert_eq!(
234 Digest::new(b"abc").to_string(),
235 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
236 );
237 let long = vec![0x61u8; 1_000_000];
241 assert_eq!(
242 Digest::new(&long).to_string(),
243 "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"
244 );
245 }
246}