cml_crypto/chain_crypto/
hash.rs

1//! module to provide some handy interfaces atop the hashes so we have
2//! the common interfaces for the project to work with.
3
4use std::hash::{Hash, Hasher};
5use std::io::{BufRead, Write};
6use std::str::FromStr;
7use std::{error, fmt, result};
8
9use cbor_event::{self, de::Deserializer, se::Serializer};
10use cryptoxide::blake2b::Blake2b;
11use cryptoxide::digest::Digest as _;
12use cryptoxide::sha3;
13use hex::FromHexError;
14
15use crate::chain_crypto::bech32::{self, Bech32};
16
17#[derive(Debug, PartialEq, Clone)]
18pub enum Error {
19    InvalidHashSize(usize, usize),
20    InvalidHexEncoding(FromHexError),
21}
22impl fmt::Display for Error {
23    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24        match self {
25            Error::InvalidHashSize(sz, expected) => write!(
26                f,
27                "invalid hash size, expected {expected} but received {sz} bytes."
28            ),
29            Error::InvalidHexEncoding(_) => write!(f, "invalid hex encoding for hash value"),
30        }
31    }
32}
33impl error::Error for Error {
34    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
35        match self {
36            Error::InvalidHashSize(..) => None,
37            Error::InvalidHexEncoding(err) => Some(err),
38        }
39    }
40}
41
42impl From<FromHexError> for Error {
43    fn from(err: FromHexError) -> Self {
44        Error::InvalidHexEncoding(err)
45    }
46}
47
48pub type Result<T> = result::Result<T, Error>;
49
50/// defines a blake2b object
51macro_rules! define_blake2b_new {
52    ($hash_ty:ty) => {
53        impl $hash_ty {
54            pub fn new(buf: &[u8]) -> Self {
55                let mut b2b = Blake2b::new(Self::HASH_SIZE);
56                let mut out = [0; Self::HASH_SIZE];
57                b2b.input(buf);
58                b2b.result(&mut out);
59                Self::from(out)
60            }
61        }
62    };
63}
64macro_rules! define_hash_object {
65    ($hash_ty:ty, $constructor:expr, $hash_size:ident, $bech32_hrp:expr) => {
66        impl $hash_ty {
67            pub const HASH_SIZE: usize = $hash_size;
68
69            pub fn as_hash_bytes(&self) -> &[u8; Self::HASH_SIZE] {
70                &self.0
71            }
72
73            pub fn try_from_slice(slice: &[u8]) -> Result<Self> {
74                if slice.len() != Self::HASH_SIZE {
75                    return Err(Error::InvalidHashSize(slice.len(), Self::HASH_SIZE));
76                }
77                let mut buf = [0; Self::HASH_SIZE];
78
79                buf[0..Self::HASH_SIZE].clone_from_slice(slice);
80                Ok(Self::from(buf))
81            }
82        }
83        impl AsRef<[u8]> for $hash_ty {
84            fn as_ref(&self) -> &[u8] {
85                self.0.as_ref()
86            }
87        }
88        impl From<$hash_ty> for [u8; $hash_size] {
89            fn from(bytes: $hash_ty) -> Self {
90                bytes.0
91            }
92        }
93        impl<'a> From<&'a $hash_ty> for &'a [u8; $hash_size] {
94            fn from(bytes: &'a $hash_ty) -> Self {
95                &bytes.0
96            }
97        }
98        impl From<[u8; Self::HASH_SIZE]> for $hash_ty {
99            fn from(bytes: [u8; Self::HASH_SIZE]) -> Self {
100                $constructor(bytes)
101            }
102        }
103        // allow since both act on the raw bytes
104        #[allow(clippy::derived_hash_with_manual_eq)]
105        impl Hash for $hash_ty {
106            fn hash<H: Hasher>(&self, state: &mut H) {
107                self.0.hash(state)
108            }
109        }
110        impl FromStr for $hash_ty {
111            type Err = Error;
112            fn from_str(s: &str) -> result::Result<Self, Self::Err> {
113                let bytes = hex::decode(s)?;
114                Self::try_from_slice(&bytes)
115            }
116        }
117        impl fmt::Display for $hash_ty {
118            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119                write!(f, "{}", hex::encode(self.as_ref()))
120            }
121        }
122        impl fmt::Debug for $hash_ty {
123            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124                f.write_str(concat!(stringify!($hash_ty), "(0x"))?;
125                write!(f, "{}", hex::encode(self.as_ref()))?;
126                f.write_str(")")
127            }
128        }
129        impl Bech32 for $hash_ty {
130            const BECH32_HRP: &'static str = $bech32_hrp;
131
132            fn try_from_bech32_str(bech32_str: &str) -> bech32::Result<Self> {
133                let bytes = bech32::try_from_bech32_to_bytes::<Self>(bech32_str)?;
134                Self::try_from_slice(&bytes).map_err(bech32::Error::data_invalid)
135            }
136
137            fn to_bech32_str(&self) -> String {
138                bech32::to_bech32_from_bytes::<Self>(self.as_ref())
139            }
140        }
141        impl cbor_event::de::Deserialize for $hash_ty {
142            fn deserialize<R: BufRead>(reader: &mut Deserializer<R>) -> cbor_event::Result<Self> {
143                let bytes = reader.bytes()?;
144                match Self::try_from_slice(&bytes) {
145                    Ok(digest) => Ok(digest),
146                    Err(Error::InvalidHashSize(sz, expected)) => {
147                        Err(cbor_event::Error::NotEnough(sz, expected))
148                    }
149                    Err(err) => Err(cbor_event::Error::CustomError(format!(
150                        "unexpected error: {:?}",
151                        err
152                    ))),
153                }
154            }
155        }
156        impl cbor_event::se::Serialize for $hash_ty {
157            fn serialize<'se, W: Write>(
158                &self,
159                serializer: &'se mut Serializer<W>,
160            ) -> cbor_event::Result<&'se mut Serializer<W>> {
161                serializer.write_bytes(self.as_ref())
162            }
163        }
164
165        #[cfg(feature = "generic-serialization")]
166        impl serde::Serialize for $hash_ty {
167            #[inline]
168            fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
169            where
170                S: serde::Serializer,
171            {
172                if serializer.is_human_readable() {
173                    serializer.serialize_str(&hex::encode(self.as_ref()))
174                } else {
175                    serializer.serialize_bytes(&self.as_ref())
176                }
177            }
178        }
179        #[cfg(feature = "generic-serialization")]
180        impl<'de> serde::Deserialize<'de> for $hash_ty {
181            fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
182            where
183                D: serde::Deserializer<'de>,
184            {
185                struct HashVisitor;
186                impl<'de> serde::de::Visitor<'de> for HashVisitor {
187                    type Value = $hash_ty;
188
189                    fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
190                        write!(fmt, "Expecting a Blake2b_256 hash (`Hash`)")
191                    }
192
193                    fn visit_str<'a, E>(self, v: &'a str) -> result::Result<Self::Value, E>
194                    where
195                        E: serde::de::Error,
196                    {
197                        match Self::Value::from_str(&v) {
198                            Err(Error::HexadecimalError(err)) => Err(E::custom(format!("{}", err))),
199                            Err(Error::InvalidHashSize(sz, _)) => {
200                                Err(E::invalid_length(sz, &"32 bytes"))
201                            }
202                            Ok(h) => Ok(h),
203                        }
204                    }
205
206                    fn visit_bytes<'a, E>(self, v: &'a [u8]) -> result::Result<Self::Value, E>
207                    where
208                        E: serde::de::Error,
209                    {
210                        match Self::Value::try_from_slice(v) {
211                            Err(Error::InvalidHashSize(sz, _)) => {
212                                Err(E::invalid_length(sz, &"32 bytes"))
213                            }
214                            Err(err) => panic!("unexpected error: {}", err),
215                            Ok(h) => Ok(h),
216                        }
217                    }
218                }
219
220                if deserializer.is_human_readable() {
221                    deserializer.deserialize_str(HashVisitor)
222                } else {
223                    deserializer.deserialize_bytes(HashVisitor)
224                }
225            }
226        }
227    };
228}
229
230pub const HASH_SIZE_224: usize = 28;
231pub const HASH_SIZE_256: usize = 32;
232
233/// Blake2b 256 bits
234#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
235pub struct Blake2b256([u8; HASH_SIZE_256]);
236define_hash_object!(Blake2b256, Blake2b256, HASH_SIZE_256, "blake2b256");
237define_blake2b_new!(Blake2b256);
238
239/// Blake2b 224 bits
240#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
241pub struct Blake2b224([u8; HASH_SIZE_224]);
242define_hash_object!(Blake2b224, Blake2b224, HASH_SIZE_224, "blake2b224");
243define_blake2b_new!(Blake2b224);
244
245#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
246pub struct Sha3_256([u8; HASH_SIZE_256]);
247define_hash_object!(Sha3_256, Sha3_256, HASH_SIZE_256, "sha3256");
248impl Sha3_256 {
249    pub fn new(buf: &[u8]) -> Self {
250        let mut sh3 = sha3::Sha3_256::new();
251        let mut out = [0; Self::HASH_SIZE];
252        sh3.input(buf.as_ref());
253        sh3.result(&mut out);
254        Self::from(out)
255    }
256}