ab_core_primitives/
hashes.rs

1//! Hashes-related data structures and functions.
2
3use ab_io_type::trivial_type::TrivialType;
4use blake3::{Hash, OUT_LEN};
5use core::array::TryFromSliceError;
6use core::{fmt, mem};
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, Deserializer, Serialize, Serializer};
14
15/// BLAKE3 hash output transparent wrapper
16#[derive(
17    Default,
18    Copy,
19    Clone,
20    Eq,
21    PartialEq,
22    Ord,
23    PartialOrd,
24    Hash,
25    From,
26    Into,
27    AsRef,
28    AsMut,
29    Deref,
30    DerefMut,
31    TrivialType,
32)]
33#[cfg_attr(
34    feature = "scale-codec",
35    derive(Encode, Decode, TypeInfo, MaxEncodedLen)
36)]
37#[repr(C)]
38pub struct Blake3Hash([u8; Blake3Hash::SIZE]);
39
40impl fmt::Display for Blake3Hash {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        for byte in self.0 {
43            write!(f, "{byte:02x}")?;
44        }
45        Ok(())
46    }
47}
48
49#[cfg(feature = "serde")]
50#[derive(Serialize, Deserialize)]
51#[serde(transparent)]
52struct Blake3HashBinary([u8; Blake3Hash::SIZE]);
53
54#[cfg(feature = "serde")]
55#[derive(Serialize, Deserialize)]
56#[serde(transparent)]
57struct Blake3HashHex(#[serde(with = "hex")] [u8; Blake3Hash::SIZE]);
58
59#[cfg(feature = "serde")]
60impl Serialize for Blake3Hash {
61    #[inline]
62    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
63    where
64        S: Serializer,
65    {
66        if serializer.is_human_readable() {
67            Blake3HashHex(self.0).serialize(serializer)
68        } else {
69            Blake3HashBinary(self.0).serialize(serializer)
70        }
71    }
72}
73
74#[cfg(feature = "serde")]
75impl<'de> Deserialize<'de> for Blake3Hash {
76    #[inline]
77    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
78    where
79        D: Deserializer<'de>,
80    {
81        Ok(Self(if deserializer.is_human_readable() {
82            Blake3HashHex::deserialize(deserializer)?.0
83        } else {
84            Blake3HashBinary::deserialize(deserializer)?.0
85        }))
86    }
87}
88
89impl fmt::Debug for Blake3Hash {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        for byte in self.0 {
92            write!(f, "{byte:02x}")?;
93        }
94        Ok(())
95    }
96}
97
98impl AsRef<[u8]> for Blake3Hash {
99    #[inline(always)]
100    fn as_ref(&self) -> &[u8] {
101        &self.0
102    }
103}
104
105impl AsMut<[u8]> for Blake3Hash {
106    #[inline(always)]
107    fn as_mut(&mut self) -> &mut [u8] {
108        &mut self.0
109    }
110}
111
112impl From<&[u8; Self::SIZE]> for Blake3Hash {
113    #[inline(always)]
114    fn from(value: &[u8; Self::SIZE]) -> Self {
115        Self(*value)
116    }
117}
118
119impl TryFrom<&[u8]> for Blake3Hash {
120    type Error = TryFromSliceError;
121
122    #[inline(always)]
123    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
124        Ok(Self(value.try_into()?))
125    }
126}
127
128impl From<Hash> for Blake3Hash {
129    #[inline(always)]
130    fn from(value: Hash) -> Self {
131        Self(value.into())
132    }
133}
134
135impl Blake3Hash {
136    /// Size in bytes
137    pub const SIZE: usize = OUT_LEN;
138
139    /// Create new instance
140    #[inline(always)]
141    pub const fn new(hash: [u8; OUT_LEN]) -> Self {
142        Self(hash)
143    }
144
145    /// Get internal representation
146    #[inline(always)]
147    pub const fn as_bytes(&self) -> &[u8; Self::SIZE] {
148        &self.0
149    }
150
151    /// Convenient conversion from slice of underlying representation for efficiency purposes
152    #[inline(always)]
153    pub const fn slice_from_repr(value: &[[u8; Self::SIZE]]) -> &[Self] {
154        // SAFETY: `Blake3Hash` is `#[repr(C)]` and guaranteed to have the same memory layout
155        unsafe { mem::transmute(value) }
156    }
157
158    /// Convenient conversion to slice of underlying representation for efficiency purposes
159    #[inline(always)]
160    pub const fn repr_from_slice(value: &[Self]) -> &[[u8; Self::SIZE]] {
161        // SAFETY: `Blake3Hash` is `#[repr(C)]` and guaranteed to have the same memory layout
162        unsafe { mem::transmute(value) }
163    }
164}