1use std::ops::{BitXor, BitXorAssign};
2
3use massa_serialization::{Deserializer, SerializeError, Serializer};
4use nom::{
5 error::{context, ContextError, ParseError},
6 IResult,
7};
8
9use crate::Hash;
10
11#[derive(Clone, Copy, PartialEq, Eq)]
13pub struct HashXof<const SIZE: usize>(pub [u8; SIZE]);
14
15impl<const SIZE: usize> HashXof<SIZE> {
16 pub fn from_bytes(bytes: &[u8; SIZE]) -> Self {
18 HashXof(*bytes)
19 }
20
21 pub fn to_bytes(&self) -> &[u8; SIZE] {
23 &self.0
24 }
25
26 pub fn compute_from(data: &[u8]) -> HashXof<SIZE> {
28 let mut hasher = blake3::Hasher::new();
29 hasher.update(data);
30 let mut hash = [0u8; SIZE];
31 let mut output_reader = hasher.finalize_xof();
32 output_reader.fill(&mut hash);
33 HashXof(hash)
34 }
35
36 pub fn compute_from_tuple(data: &[&[u8]]) -> Self {
38 let mut hasher = blake3::Hasher::new();
39 for d in data {
40 hasher.update(&(d.len() as u64).to_be_bytes());
41 hasher.update(d);
42 }
43 let mut hash = [0u8; SIZE];
44 let mut output_reader = hasher.finalize_xof();
45 output_reader.fill(&mut hash);
46 HashXof(hash)
47 }
48
49 pub fn to_bs58_check(&self) -> String {
59 bs58::encode(self.0).with_check().into_string()
60 }
61}
62
63impl<const SIZE: usize> BitXorAssign for HashXof<SIZE> {
66 fn bitxor_assign(&mut self, rhs: Self) {
67 *self = *self ^ rhs;
68 }
69}
70
71impl<const SIZE: usize> BitXor for HashXof<SIZE> {
74 type Output = Self;
75
76 fn bitxor(self, other: Self) -> Self {
77 let xored = self
78 .0
79 .iter()
80 .zip(other.0.iter())
81 .map(|(a, b)| a ^ b)
82 .collect::<Vec<u8>>()
83 .try_into()
84 .unwrap();
85 HashXof(xored)
86 }
87}
88
89impl<const SIZE: usize> std::fmt::Display for HashXof<SIZE> {
90 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
91 write!(f, "{}", Hash::compute_from(self.to_bytes()).to_bs58_check())
92 }
93}
94
95impl<const SIZE: usize> std::fmt::Debug for HashXof<SIZE> {
96 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
97 write!(f, "{}", self.to_bs58_check())
98 }
99}
100
101#[derive(Default, Clone)]
103pub struct HashXofSerializer;
104
105impl HashXofSerializer {
106 pub const fn new() -> Self {
108 Self
109 }
110}
111
112impl<const SIZE: usize> Serializer<HashXof<SIZE>> for HashXofSerializer {
113 fn serialize(&self, value: &HashXof<SIZE>, buffer: &mut Vec<u8>) -> Result<(), SerializeError> {
114 buffer.extend(value.to_bytes());
115 Ok(())
116 }
117}
118
119#[derive(Default, Clone)]
121pub struct HashXofDeserializer;
122
123impl HashXofDeserializer {
124 pub const fn new() -> Self {
126 Self
127 }
128}
129
130impl<const SIZE: usize> Deserializer<HashXof<SIZE>> for HashXofDeserializer {
131 fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>(
143 &self,
144 buffer: &'a [u8],
145 ) -> IResult<&'a [u8], HashXof<SIZE>, E> {
146 context("Failed hashxof deserialization", |input: &'a [u8]| {
147 if buffer.len() < SIZE {
148 return Err(nom::Err::Error(ParseError::from_error_kind(
149 input,
150 nom::error::ErrorKind::LengthValue,
151 )));
152 }
153 Ok((
154 &buffer[SIZE..],
155 HashXof::from_bytes(&buffer[..SIZE].try_into().map_err(|_| {
156 nom::Err::Error(ParseError::from_error_kind(
157 input,
158 nom::error::ErrorKind::Fail,
159 ))
160 })?),
161 ))
162 })(buffer)
163 }
164}