ab_core_primitives/
hashes.rs

1//! Hashes-related data structures and functions.
2
3use ab_io_type::trivial_type::TrivialType;
4use blake3::OUT_LEN;
5use core::array::TryFromSliceError;
6use core::fmt;
7use derive_more::{AsMut, AsRef, Deref, DerefMut, From, Into};
8#[cfg(feature = "scale-codec")]
9use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
10#[cfg(feature = "scale-codec")]
11use scale_info::TypeInfo;
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14#[cfg(feature = "serde")]
15use serde::{Deserializer, Serializer};
16
17/// BLAKE3 hash output transparent wrapper
18#[derive(
19    Default,
20    Copy,
21    Clone,
22    Eq,
23    PartialEq,
24    Ord,
25    PartialOrd,
26    Hash,
27    From,
28    Into,
29    AsRef,
30    AsMut,
31    Deref,
32    DerefMut,
33    TrivialType,
34)]
35#[cfg_attr(
36    feature = "scale-codec",
37    derive(Encode, Decode, TypeInfo, MaxEncodedLen)
38)]
39#[repr(C)]
40pub struct Blake3Hash([u8; Blake3Hash::SIZE]);
41
42impl fmt::Display for Blake3Hash {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        for byte in self.0 {
45            write!(f, "{byte:02x}")?;
46        }
47        Ok(())
48    }
49}
50
51#[cfg(feature = "serde")]
52#[derive(Serialize, Deserialize)]
53#[serde(transparent)]
54struct Blake3HashBinary([u8; Blake3Hash::SIZE]);
55
56#[cfg(feature = "serde")]
57#[derive(Serialize, Deserialize)]
58#[serde(transparent)]
59struct Blake3HashHex(#[serde(with = "hex")] [u8; Blake3Hash::SIZE]);
60
61#[cfg(feature = "serde")]
62impl Serialize for Blake3Hash {
63    #[inline]
64    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
65    where
66        S: Serializer,
67    {
68        if serializer.is_human_readable() {
69            Blake3HashHex(self.0).serialize(serializer)
70        } else {
71            Blake3HashBinary(self.0).serialize(serializer)
72        }
73    }
74}
75
76#[cfg(feature = "serde")]
77impl<'de> Deserialize<'de> for Blake3Hash {
78    #[inline]
79    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
80    where
81        D: Deserializer<'de>,
82    {
83        Ok(Self(if deserializer.is_human_readable() {
84            Blake3HashHex::deserialize(deserializer)?.0
85        } else {
86            Blake3HashBinary::deserialize(deserializer)?.0
87        }))
88    }
89}
90
91impl fmt::Debug for Blake3Hash {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        for byte in self.0 {
94            write!(f, "{byte:02x}")?;
95        }
96        Ok(())
97    }
98}
99
100impl AsRef<[u8]> for Blake3Hash {
101    #[inline]
102    fn as_ref(&self) -> &[u8] {
103        &self.0
104    }
105}
106
107impl AsMut<[u8]> for Blake3Hash {
108    #[inline]
109    fn as_mut(&mut self) -> &mut [u8] {
110        &mut self.0
111    }
112}
113
114impl From<&[u8; Self::SIZE]> for Blake3Hash {
115    #[inline]
116    fn from(value: &[u8; Self::SIZE]) -> Self {
117        Self(*value)
118    }
119}
120
121impl TryFrom<&[u8]> for Blake3Hash {
122    type Error = TryFromSliceError;
123
124    #[inline]
125    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
126        Ok(Self(value.try_into()?))
127    }
128}
129
130impl Blake3Hash {
131    /// Size in bytes
132    pub const SIZE: usize = OUT_LEN;
133
134    /// Create new instance
135    pub const fn new(hash: [u8; OUT_LEN]) -> Self {
136        Self(hash)
137    }
138
139    /// Get internal representation
140    pub const fn as_bytes(&self) -> &[u8; Self::SIZE] {
141        &self.0
142    }
143}
144
145/// BLAKE3 hashing of a single value.
146#[inline(always)]
147pub fn blake3_hash(data: &[u8]) -> Blake3Hash {
148    Blake3Hash(*blake3::hash(data).as_bytes())
149}
150
151/// BLAKE3 hashing of a single value in parallel (only useful for large values well above 128kiB).
152#[cfg(feature = "parallel")]
153#[inline(always)]
154pub fn blake3_hash_parallel(data: &[u8]) -> Blake3Hash {
155    let mut state = blake3::Hasher::new();
156    state.update_rayon(data);
157    state.finalize().as_bytes().into()
158}
159
160/// BLAKE3 keyed hashing of a single value.
161#[inline(always)]
162pub fn blake3_hash_with_key(key: &[u8; 32], data: &[u8]) -> Blake3Hash {
163    blake3::keyed_hash(key, data).as_bytes().into()
164}
165
166/// BLAKE3 keyed hashing of a list of values.
167#[inline(always)]
168pub fn blake3_hash_list_with_key(key: &[u8; 32], data: &[&[u8]]) -> Blake3Hash {
169    let mut state = blake3::Hasher::new_keyed(key);
170    for d in data {
171        state.update(d);
172    }
173    state.finalize().as_bytes().into()
174}
175
176/// BLAKE3 hashing of a list of values.
177#[inline(always)]
178pub fn blake3_hash_list(data: &[&[u8]]) -> Blake3Hash {
179    let mut state = blake3::Hasher::new();
180    for d in data {
181        state.update(d);
182    }
183    state.finalize().as_bytes().into()
184}