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