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