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}