1use core::{
4 fmt::{self, Debug, Display},
5 str::FromStr,
6};
7
8use bytes::Bytes;
9use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
10use subtle_encoding::{base64, Encoding, Hex};
11use tendermint_proto::serializers::cow_str::CowStr;
12use tendermint_proto::Protobuf;
13
14use crate::{error::Error, prelude::*};
15
16pub const SHA256_HASH_SIZE: usize = 32;
18
19#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
21pub enum Algorithm {
22 Sha256,
24}
25
26#[derive(Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Default)]
28pub enum Hash {
29 Sha256([u8; SHA256_HASH_SIZE]),
31 #[default]
33 None,
34}
35
36impl Protobuf<Vec<u8>> for Hash {}
37
38impl TryFrom<Vec<u8>> for Hash {
40 type Error = Error;
41
42 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
43 if value.is_empty() {
44 return Ok(Hash::None);
45 }
46 Hash::from_bytes(Algorithm::Sha256, &value)
47 }
48}
49
50impl From<Hash> for Vec<u8> {
51 fn from(value: Hash) -> Self {
52 match value {
53 Hash::Sha256(s) => s.to_vec(),
54 Hash::None => vec![],
55 }
56 }
57}
58
59impl AsRef<[u8]> for Hash {
60 fn as_ref(&self) -> &[u8] {
61 match self {
62 Hash::Sha256(ref h) => h.as_ref(),
63 Hash::None => &[],
64 }
65 }
66}
67
68impl From<Hash> for Bytes {
69 fn from(h: Hash) -> Self {
70 Self::copy_from_slice(h.as_ref())
71 }
72}
73
74impl TryFrom<Bytes> for Hash {
75 type Error = Error;
76
77 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
78 Self::from_bytes(Algorithm::Sha256, value.as_ref())
79 }
80}
81
82impl Hash {
83 pub fn from_bytes(alg: Algorithm, bytes: &[u8]) -> Result<Hash, Error> {
85 if bytes.is_empty() {
86 return Ok(Hash::None);
87 }
88 match alg {
89 Algorithm::Sha256 => {
90 if bytes.len() == SHA256_HASH_SIZE {
91 let mut h = [0u8; SHA256_HASH_SIZE];
92 h.copy_from_slice(bytes);
93 Ok(Hash::Sha256(h))
94 } else {
95 Err(Error::invalid_hash_size())
96 }
97 },
98 }
99 }
100
101 pub fn from_hex_upper(alg: Algorithm, s: &str) -> Result<Hash, Error> {
103 if s.is_empty() {
104 return Ok(Hash::None);
105 }
106 match alg {
107 Algorithm::Sha256 => {
108 let mut h = [0u8; SHA256_HASH_SIZE];
109 Hex::upper_case()
110 .decode_to_slice(s.as_bytes(), &mut h)
111 .map_err(Error::subtle_encoding)?;
112 Ok(Hash::Sha256(h))
113 },
114 }
115 }
116
117 pub fn algorithm(self) -> Algorithm {
119 match self {
120 Hash::Sha256(_) => Algorithm::Sha256,
121 Hash::None => Algorithm::Sha256,
122 }
123 }
124
125 pub fn as_bytes(&self) -> &[u8] {
127 match self {
128 Hash::Sha256(ref h) => h.as_ref(),
129 Hash::None => &[],
130 }
131 }
132
133 pub fn is_empty(&self) -> bool {
135 self == &Hash::None
136 }
137}
138
139impl Debug for Hash {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 match self {
142 Hash::Sha256(_) => write!(f, "Hash::Sha256({self})"),
143 Hash::None => write!(f, "Hash::None"),
144 }
145 }
146}
147
148impl Display for Hash {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 let hex = match self {
151 Hash::Sha256(ref h) => Hex::upper_case().encode_to_string(h).unwrap(),
152 Hash::None => String::new(),
153 };
154
155 write!(f, "{hex}")
156 }
157}
158
159impl FromStr for Hash {
160 type Err = Error;
161
162 fn from_str(s: &str) -> Result<Self, Error> {
163 Self::from_hex_upper(Algorithm::Sha256, s)
164 }
165}
166
167impl<'de> Deserialize<'de> for Hash {
168 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
169 let hex = CowStr::deserialize(deserializer)?;
170
171 if hex.is_empty() {
172 Err(D::Error::custom("empty hash"))
173 } else {
174 Ok(Self::from_str(&hex).map_err(|e| D::Error::custom(format!("{e}")))?)
175 }
176 }
177}
178
179impl Serialize for Hash {
180 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
181 self.to_string().serialize(serializer)
182 }
183}
184
185pub mod allow_empty {
187 use super::*;
188
189 pub fn serialize<S>(value: &Hash, serializer: S) -> Result<S::Ok, S::Error>
191 where
192 S: Serializer,
193 {
194 value.to_string().serialize(serializer)
195 }
196
197 pub fn deserialize<'de, D>(deserializer: D) -> Result<Hash, D::Error>
200 where
201 D: Deserializer<'de>,
202 {
203 let hex = CowStr::deserialize(deserializer)?;
204 Hash::from_str(&hex).map_err(serde::de::Error::custom)
205 }
206}
207
208#[derive(Clone, PartialEq, Eq, Default)]
210pub struct AppHash(Vec<u8>);
211
212impl Protobuf<Vec<u8>> for AppHash {}
213
214impl TryFrom<Vec<u8>> for AppHash {
215 type Error = Error;
216
217 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
218 Ok(AppHash(value))
219 }
220}
221impl From<AppHash> for Vec<u8> {
222 fn from(value: AppHash) -> Self {
223 value.0
224 }
225}
226
227impl TryFrom<Bytes> for AppHash {
228 type Error = Error;
229
230 fn try_from(value: Bytes) -> Result<Self, Self::Error> {
231 Ok(AppHash(value.to_vec()))
232 }
233}
234impl From<AppHash> for Bytes {
235 fn from(value: AppHash) -> Self {
236 value.0.into()
237 }
238}
239
240impl AppHash {
241 pub fn as_bytes(&self) -> &[u8] {
243 &self.0
244 }
245
246 pub fn from_hex_upper(s: &str) -> Result<Self, Error> {
248 if s.len() % 2 != 0 {
249 return Err(Error::invalid_app_hash_length());
250 }
251 let mut h = vec![0; s.len() / 2];
252 Hex::upper_case()
253 .decode_to_slice(s.as_bytes(), &mut h)
254 .map_err(Error::subtle_encoding)?;
255 Ok(AppHash(h))
256 }
257
258 pub fn from_base64(s: &str) -> Result<Self, Error> {
260 let h = base64::decode(s).map_err(Error::subtle_encoding)?;
261 Ok(AppHash(h))
262 }
263}
264
265impl AsRef<[u8]> for AppHash {
266 fn as_ref(&self) -> &[u8] {
267 self.0.as_ref()
268 }
269}
270
271impl Debug for AppHash {
272 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273 write!(
274 f,
275 "AppHash({})",
276 Hex::upper_case().encode_to_string(&self.0).unwrap()
277 )
278 }
279}
280
281impl Display for AppHash {
282 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283 write!(
284 f,
285 "{}",
286 Hex::upper_case().encode_to_string(&self.0).unwrap()
287 )
288 }
289}
290
291impl FromStr for AppHash {
292 type Err = Error;
293
294 fn from_str(s: &str) -> Result<Self, Error> {
295 Self::from_hex_upper(s).or_else(|_| Self::from_base64(s))
296 }
297}
298
299#[cfg(test)]
300mod tests {
301 use super::*;
302
303 #[derive(Debug, serde::Deserialize)]
304 struct AppHashTest {
305 #[serde(default)]
306 #[serde(with = "crate::serializers::apphash")]
307 pub app_hash: AppHash,
308 }
309
310 #[derive(Debug, serde::Deserialize)]
311 struct HashTest {
312 hash: Hash,
313 #[serde(with = "super::allow_empty")]
314 empty_hash: Hash,
315 }
316
317 #[test]
318 fn apphash_decode_base64() {
319 let test = serde_json::from_str::<AppHashTest>(
320 r#"{"app_hash":"MfX9f+bYoI8IioRb4YT/8/VhPvtNjgWFgTi4mmMSkBc="}"#,
321 )
322 .unwrap();
323
324 assert_eq!(
325 test.app_hash.as_ref(),
326 &[
327 0x31, 0xF5, 0xFD, 0x7F, 0xE6, 0xD8, 0xA0, 0x8F, 0x08, 0x8A, 0x84, 0x5B, 0xE1, 0x84,
328 0xFF, 0xF3, 0xF5, 0x61, 0x3E, 0xFB, 0x4D, 0x8E, 0x05, 0x85, 0x81, 0x38, 0xB8, 0x9A,
329 0x63, 0x12, 0x90, 0x17
330 ]
331 );
332 }
333
334 #[test]
335 fn apphash_decode_hex() {
336 let test = serde_json::from_str::<AppHashTest>(
337 r#"{"app_hash":"31F5FD7FE6D8A08F088A845BE184FFF3F5613EFB4D8E05858138B89A63129017"}"#,
338 )
339 .unwrap();
340
341 assert_eq!(
342 test.app_hash.as_ref(),
343 &[
344 0x31, 0xF5, 0xFD, 0x7F, 0xE6, 0xD8, 0xA0, 0x8F, 0x08, 0x8A, 0x84, 0x5B, 0xE1, 0x84,
345 0xFF, 0xF3, 0xF5, 0x61, 0x3E, 0xFB, 0x4D, 0x8E, 0x05, 0x85, 0x81, 0x38, 0xB8, 0x9A,
346 0x63, 0x12, 0x90, 0x17
347 ]
348 );
349 }
350
351 #[test]
352 fn hash_decode_hex() {
353 let s = r#"{
354 "hash": "9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08",
355 "empty_hash": ""
356 }"#;
357
358 let expected_hash = &[
359 0x9F, 0x86, 0xD0, 0x81, 0x88, 0x4C, 0x7D, 0x65, 0x9A, 0x2F, 0xEA, 0xA0, 0xC5, 0x5A,
360 0xD0, 0x15, 0xA3, 0xBF, 0x4F, 0x1B, 0x2B, 0x0B, 0x82, 0x2C, 0xD1, 0x5D, 0x6C, 0x15,
361 0xB0, 0xF0, 0x0A, 0x08,
362 ];
363
364 let test = serde_json::from_str::<HashTest>(s).unwrap();
365 assert_eq!(test.hash.as_ref(), expected_hash);
366 assert_eq!(test.empty_hash, Hash::None);
367
368 let json_value = serde_json::from_str::<serde_json::Value>(s).unwrap();
370 let test = serde_json::from_value::<HashTest>(json_value).unwrap();
371 assert_eq!(test.hash.as_ref(), expected_hash);
372 assert_eq!(test.empty_hash, Hash::None);
373 }
374}