celestia_tendermint/
hash.rs

1//! Hash functions and their outputs
2
3use core::{
4    convert::TryFrom,
5    fmt::{self, Debug, Display},
6    str::FromStr,
7};
8
9use bytes::Bytes;
10use celestia_tendermint_proto::Protobuf;
11use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
12use subtle_encoding::{Encoding, Hex};
13
14use crate::serializers::cow_str::CowStr;
15use crate::{error::Error, prelude::*};
16
17/// Output size for the SHA-256 hash function
18pub const SHA256_HASH_SIZE: usize = 32;
19
20/// Hash algorithms
21#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
22pub enum Algorithm {
23    /// SHA-256
24    Sha256,
25}
26
27/// Hash digests
28#[derive(Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Default)]
29pub enum Hash {
30    /// SHA-256 hashes
31    Sha256([u8; SHA256_HASH_SIZE]),
32    /// Empty hash
33    #[default]
34    None,
35}
36
37impl Protobuf<Vec<u8>> for Hash {}
38
39/// Default conversion from `Vec<u8>` is SHA256 Hash or `None`
40impl TryFrom<Vec<u8>> for Hash {
41    type Error = Error;
42
43    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
44        if value.is_empty() {
45            return Ok(Hash::None);
46        }
47        Hash::from_bytes(Algorithm::Sha256, &value)
48    }
49}
50
51impl From<Hash> for Vec<u8> {
52    fn from(value: Hash) -> Self {
53        match value {
54            Hash::Sha256(s) => s.to_vec(),
55            Hash::None => vec![],
56        }
57    }
58}
59
60impl AsRef<[u8]> for Hash {
61    fn as_ref(&self) -> &[u8] {
62        match self {
63            Hash::Sha256(ref h) => h.as_ref(),
64            Hash::None => &[],
65        }
66    }
67}
68
69impl From<Hash> for Bytes {
70    fn from(h: Hash) -> Self {
71        Self::copy_from_slice(h.as_ref())
72    }
73}
74
75impl TryFrom<Bytes> for Hash {
76    type Error = Error;
77
78    fn try_from(value: Bytes) -> Result<Self, Self::Error> {
79        Self::from_bytes(Algorithm::Sha256, value.as_ref())
80    }
81}
82
83impl Hash {
84    /// Create a new `Hash` with the given algorithm type
85    pub fn from_bytes(alg: Algorithm, bytes: &[u8]) -> Result<Hash, Error> {
86        if bytes.is_empty() {
87            return Ok(Hash::None);
88        }
89        match alg {
90            Algorithm::Sha256 => {
91                if bytes.len() == SHA256_HASH_SIZE {
92                    let mut h = [0u8; SHA256_HASH_SIZE];
93                    h.copy_from_slice(bytes);
94                    Ok(Hash::Sha256(h))
95                } else {
96                    Err(Error::invalid_hash_size())
97                }
98            },
99        }
100    }
101
102    /// Decode a `Hash` from upper-case hexadecimal
103    pub fn from_hex_upper(alg: Algorithm, s: &str) -> Result<Hash, Error> {
104        if s.is_empty() {
105            return Ok(Hash::None);
106        }
107        match alg {
108            Algorithm::Sha256 => {
109                let mut h = [0u8; SHA256_HASH_SIZE];
110                Hex::upper_case()
111                    .decode_to_slice(s.as_bytes(), &mut h)
112                    .map_err(Error::subtle_encoding)?;
113                Ok(Hash::Sha256(h))
114            },
115        }
116    }
117
118    /// Return the digest algorithm used to produce this hash
119    pub fn algorithm(self) -> Algorithm {
120        match self {
121            Hash::Sha256(_) => Algorithm::Sha256,
122            Hash::None => Algorithm::Sha256,
123        }
124    }
125
126    /// Borrow the `Hash` as a byte slice
127    pub fn as_bytes(&self) -> &[u8] {
128        match self {
129            Hash::Sha256(ref h) => h.as_ref(),
130            Hash::None => &[],
131        }
132    }
133
134    /// Convenience function to check for Hash::None
135    pub fn is_empty(&self) -> bool {
136        self == &Hash::None
137    }
138}
139
140impl Debug for Hash {
141    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142        match self {
143            Hash::Sha256(_) => write!(f, "Hash::Sha256({self})"),
144            Hash::None => write!(f, "Hash::None"),
145        }
146    }
147}
148
149impl Display for Hash {
150    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151        let hex = match self {
152            Hash::Sha256(ref h) => Hex::upper_case().encode_to_string(h).unwrap(),
153            Hash::None => String::new(),
154        };
155
156        write!(f, "{hex}")
157    }
158}
159
160impl FromStr for Hash {
161    type Err = Error;
162
163    fn from_str(s: &str) -> Result<Self, Error> {
164        Self::from_hex_upper(Algorithm::Sha256, s)
165    }
166}
167
168impl<'de> Deserialize<'de> for Hash {
169    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
170        let hex = CowStr::deserialize(deserializer)?;
171
172        if hex.is_empty() {
173            Ok(Hash::None)
174        } else {
175            Ok(Self::from_str(&hex).map_err(|e| D::Error::custom(format!("{e}")))?)
176        }
177    }
178}
179
180impl Serialize for Hash {
181    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
182        self.to_string().serialize(serializer)
183    }
184}
185
186/// Serialization/deserialization for `Hash` that allows for empty hashes.
187pub mod allow_empty {
188    use super::*;
189
190    /// Serialize [`Hash`](enum@crate::hash::Hash) into a string.
191    pub fn serialize<S>(value: &Hash, serializer: S) -> Result<S::Ok, S::Error>
192    where
193        S: Serializer,
194    {
195        value.to_string().serialize(serializer)
196    }
197
198    /// Deserialize [`Hash`](enum@crate::hash::Hash) from a string, allowing for
199    /// empty hashes.
200    pub fn deserialize<'de, D>(deserializer: D) -> Result<Hash, D::Error>
201    where
202        D: Deserializer<'de>,
203    {
204        let hex = <&str>::deserialize(deserializer)?;
205        Hash::from_str(hex).map_err(serde::de::Error::custom)
206    }
207}
208
209/// AppHash is usually a SHA256 hash, but in reality it can be any kind of data
210#[derive(Clone, PartialEq, Eq, Default)]
211pub struct AppHash(Vec<u8>);
212
213impl Protobuf<Vec<u8>> for AppHash {}
214
215impl TryFrom<Vec<u8>> for AppHash {
216    type Error = Error;
217
218    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
219        Ok(AppHash(value))
220    }
221}
222impl From<AppHash> for Vec<u8> {
223    fn from(value: AppHash) -> Self {
224        value.0
225    }
226}
227
228impl TryFrom<Bytes> for AppHash {
229    type Error = Error;
230
231    fn try_from(value: Bytes) -> Result<Self, Self::Error> {
232        Ok(AppHash(value.to_vec()))
233    }
234}
235impl From<AppHash> for Bytes {
236    fn from(value: AppHash) -> Self {
237        value.0.into()
238    }
239}
240
241impl AppHash {
242    /// Return the hash bytes as a byte slice.
243    pub fn as_bytes(&self) -> &[u8] {
244        &self.0
245    }
246
247    /// Decode a `Hash` from upper-case hexadecimal
248    pub fn from_hex_upper(s: &str) -> Result<Self, Error> {
249        if s.len() % 2 != 0 {
250            return Err(Error::invalid_app_hash_length());
251        }
252        let mut h = vec![0; s.len() / 2];
253        Hex::upper_case()
254            .decode_to_slice(s.as_bytes(), &mut h)
255            .map_err(Error::subtle_encoding)?;
256        Ok(AppHash(h))
257    }
258}
259
260impl AsRef<[u8]> for AppHash {
261    fn as_ref(&self) -> &[u8] {
262        self.0.as_ref()
263    }
264}
265
266impl Debug for AppHash {
267    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
268        write!(
269            f,
270            "AppHash({})",
271            Hex::upper_case().encode_to_string(&self.0).unwrap()
272        )
273    }
274}
275
276impl Display for AppHash {
277    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278        write!(
279            f,
280            "{}",
281            Hex::upper_case().encode_to_string(&self.0).unwrap()
282        )
283    }
284}
285
286impl FromStr for AppHash {
287    type Err = Error;
288
289    fn from_str(s: &str) -> Result<Self, Error> {
290        Self::from_hex_upper(s)
291    }
292}