tendermint/
hash.rs

1//! Hash functions and their outputs
2
3use 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
15/// Output size for the SHA-256 hash function
16pub const SHA256_HASH_SIZE: usize = 32;
17
18/// Hash algorithms
19#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
20pub enum Algorithm {
21    /// SHA-256
22    Sha256,
23}
24
25/// Hash digests
26#[derive(Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Default)]
27pub enum Hash {
28    /// SHA-256 hashes
29    Sha256([u8; SHA256_HASH_SIZE]),
30    /// Empty hash
31    #[default]
32    None,
33}
34
35impl Protobuf<Vec<u8>> for Hash {}
36
37/// Default conversion from `Vec<u8>` is SHA256 Hash or `None`
38impl 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    /// Create a new `Hash` with the given algorithm type
83    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    /// Decode a `Hash` from upper-case hexadecimal
101    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    /// Return the digest algorithm used to produce this hash
117    pub fn algorithm(self) -> Algorithm {
118        match self {
119            Hash::Sha256(_) => Algorithm::Sha256,
120            Hash::None => Algorithm::Sha256,
121        }
122    }
123
124    /// Borrow the `Hash` as a byte slice
125    pub fn as_bytes(&self) -> &[u8] {
126        match self {
127            Hash::Sha256(ref h) => h.as_ref(),
128            Hash::None => &[],
129        }
130    }
131
132    /// Convenience function to check for Hash::None
133    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
184/// Serialization/deserialization for `Hash` that allows for empty hashes.
185pub mod allow_empty {
186    use super::*;
187
188    /// Serialize [`Hash`](enum@crate::hash::Hash) into a string.
189    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    /// Deserialize [`Hash`](enum@crate::hash::Hash) from a string, allowing for
197    /// empty hashes.
198    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/// AppHash is usually a SHA256 hash, but in reality it can be any kind of data
208#[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    /// Return the hash bytes as a byte slice.
241    pub fn as_bytes(&self) -> &[u8] {
242        &self.0
243    }
244
245    /// Decode a `Hash` from upper-case hexadecimal
246    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    /// Decode a `Hash` from base64-encoded string
258    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}