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