cardano_serialization_lib/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::str::FromStr;
6use std::{error, fmt, result};
7
8use cryptoxide::blake2b::Blake2b;
9use cryptoxide::digest::Digest as _;
10use cryptoxide::sha3;
11use hex::FromHexError;
12
13use crate::chain_crypto::bech32::{self, Bech32};
14
15#[derive(Debug, PartialEq, Clone)]
16pub enum Error {
17    InvalidHashSize(usize, usize),
18    InvalidHexEncoding(FromHexError),
19}
20impl fmt::Display for Error {
21    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22        match self {
23            Error::InvalidHashSize(sz, expected) => write!(
24                f,
25                "invalid hash size, expected {} but received {} bytes.",
26                expected, sz
27            ),
28            Error::InvalidHexEncoding(_) => write!(f, "invalid hex encoding for hash value"),
29        }
30    }
31}
32impl error::Error for Error {
33    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
34        match self {
35            Error::InvalidHashSize(..) => None,
36            Error::InvalidHexEncoding(err) => Some(err),
37        }
38    }
39}
40
41impl From<FromHexError> for Error {
42    fn from(err: FromHexError) -> Self {
43        Error::InvalidHexEncoding(err)
44    }
45}
46
47pub type Result<T> = result::Result<T, Error>;
48
49/// defines a blake2b object
50macro_rules! define_blake2b_new {
51    ($hash_ty:ty) => {
52        impl $hash_ty {
53            pub fn new(buf: &[u8]) -> Self {
54                let mut b2b = Blake2b::new(Self::HASH_SIZE);
55                let mut out = [0; Self::HASH_SIZE];
56                b2b.input(buf);
57                b2b.result(&mut out);
58                Self::from(out)
59            }
60        }
61    };
62}
63macro_rules! define_hash_object {
64    ($hash_ty:ty, $constructor:expr, $hash_size:ident, $bech32_hrp:expr) => {
65        impl $hash_ty {
66            pub const HASH_SIZE: usize = $hash_size;
67
68            pub fn as_hash_bytes(&self) -> &[u8; Self::HASH_SIZE] {
69                &self.0
70            }
71
72            pub fn try_from_slice(slice: &[u8]) -> Result<Self> {
73                if slice.len() != Self::HASH_SIZE {
74                    return Err(Error::InvalidHashSize(slice.len(), Self::HASH_SIZE));
75                }
76                let mut buf = [0; Self::HASH_SIZE];
77
78                buf[0..Self::HASH_SIZE].clone_from_slice(slice);
79                Ok(Self::from(buf))
80            }
81        }
82        impl AsRef<[u8]> for $hash_ty {
83            fn as_ref(&self) -> &[u8] {
84                self.0.as_ref()
85            }
86        }
87        impl From<$hash_ty> for [u8; $hash_size] {
88            fn from(bytes: $hash_ty) -> Self {
89                bytes.0
90            }
91        }
92        impl<'a> From<&'a $hash_ty> for &'a [u8; $hash_size] {
93            fn from(bytes: &'a $hash_ty) -> Self {
94                &bytes.0
95            }
96        }
97        impl From<[u8; Self::HASH_SIZE]> for $hash_ty {
98            fn from(bytes: [u8; Self::HASH_SIZE]) -> Self {
99                $constructor(bytes)
100            }
101        }
102        impl Hash for $hash_ty {
103            fn hash<H: Hasher>(&self, state: &mut H) {
104                self.0.hash(state)
105            }
106        }
107        impl FromStr for $hash_ty {
108            type Err = Error;
109            fn from_str(s: &str) -> result::Result<Self, Self::Err> {
110                let bytes = hex::decode(s)?;
111                Self::try_from_slice(&bytes)
112            }
113        }
114        impl fmt::Display for $hash_ty {
115            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116                write!(f, "{}", hex::encode(self.as_ref()))
117            }
118        }
119        impl fmt::Debug for $hash_ty {
120            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121                f.write_str(concat!(stringify!($hash_ty), "(0x"))?;
122                write!(f, "{}", hex::encode(self.as_ref()))?;
123                f.write_str(")")
124            }
125        }
126        impl Bech32 for $hash_ty {
127            const BECH32_HRP: &'static str = $bech32_hrp;
128
129            fn try_from_bech32_str(bech32_str: &str) -> bech32::Result<Self> {
130                let bytes = bech32::try_from_bech32_to_bytes::<Self>(bech32_str)?;
131                Self::try_from_slice(&bytes).map_err(bech32::Error::data_invalid)
132            }
133
134            fn to_bech32_str(&self) -> String {
135                bech32::to_bech32_from_bytes::<Self>(self.as_ref())
136            }
137        }
138    };
139}
140
141pub const HASH_SIZE_256: usize = 32;
142
143/// Blake2b 256 bits
144#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
145pub struct Blake2b256([u8; HASH_SIZE_256]);
146define_hash_object!(Blake2b256, Blake2b256, HASH_SIZE_256, "blake2b256");
147define_blake2b_new!(Blake2b256);
148
149#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
150pub struct Sha3_256([u8; HASH_SIZE_256]);
151define_hash_object!(Sha3_256, Sha3_256, HASH_SIZE_256, "sha3256");
152impl Sha3_256 {
153    pub fn new(buf: &[u8]) -> Self {
154        let mut sh3 = sha3::Sha3_256::new();
155        let mut out = [0; Self::HASH_SIZE];
156        sh3.input(buf.as_ref());
157        sh3.result(&mut out);
158        Self::from(out)
159    }
160}