cardano_serialization_lib/chain_crypto/
hash.rs1use 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
49macro_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#[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}