1#![allow(missing_docs)]
46
47use sha2::Digest as Sha2Digest;
48use sha3::Digest as Sha3Digest;
49use uor_foundation::enforcement::{Hasher, ShapeViolation};
50use uor_foundation_sdk::axis;
51
52axis! {
53 pub trait HashAxis: AxisExtension {
64 const AXIS_ADDRESS: &'static str = "https://uor.foundation/axis/HashAxis";
65 const MAX_OUTPUT_BYTES: usize = 64;
66 fn hash(input: &[u8], out: &mut [u8]) -> Result<usize, ShapeViolation>;
72 }
73}
74
75fn out_too_small_violation() -> ShapeViolation {
76 ShapeViolation {
77 shape_iri: "https://uor.foundation/axis/HashAxis",
78 constraint_iri: "https://uor.foundation/axis/HashAxis/outputBuffer",
79 property_iri: "https://uor.foundation/axis/outputBufferBytes",
80 expected_range: "https://uor.foundation/axis/DigestBytesFit",
81 min_count: 0,
82 max_count: 0,
83 kind: uor_foundation::ViolationKind::ValueCheck,
84 }
85}
86
87const SHA256_BYTES: usize = 32;
91
92#[derive(Debug, Clone)]
94pub struct Sha256Hasher {
95 inner: sha2::Sha256,
96}
97
98impl Default for Sha256Hasher {
99 fn default() -> Self {
100 Self::initial()
101 }
102}
103
104impl HashAxis for Sha256Hasher {
105 const AXIS_ADDRESS: &'static str = "https://uor.foundation/axis/HashAxis/Sha256";
106 const MAX_OUTPUT_BYTES: usize = SHA256_BYTES;
107
108 fn hash(input: &[u8], out: &mut [u8]) -> Result<usize, ShapeViolation> {
109 if out.len() < SHA256_BYTES {
110 return Err(out_too_small_violation());
111 }
112 let digest = sha2::Sha256::digest(input);
113 out[..SHA256_BYTES].copy_from_slice(&digest);
114 Ok(SHA256_BYTES)
115 }
116}
117
118axis_extension_impl_for_hash_axis!(Sha256Hasher);
119
120impl Hasher for Sha256Hasher {
121 const OUTPUT_BYTES: usize = SHA256_BYTES;
122
123 fn initial() -> Self {
124 Self {
125 inner: sha2::Sha256::new(),
126 }
127 }
128
129 fn fold_byte(mut self, b: u8) -> Self {
130 Sha2Digest::update(&mut self.inner, [b]);
131 self
132 }
133
134 fn fold_bytes(mut self, bytes: &[u8]) -> Self {
135 Sha2Digest::update(&mut self.inner, bytes);
136 self
137 }
138
139 fn finalize(self) -> [u8; 32] {
140 let result = Sha2Digest::finalize(self.inner);
141 let mut out = [0u8; 32];
142 out.copy_from_slice(&result);
143 out
144 }
145}
146
147const SHA512_BYTES: usize = 64;
151
152#[derive(Debug, Clone)]
154pub struct Sha512Hasher {
155 inner: sha2::Sha512,
156}
157
158impl Default for Sha512Hasher {
159 fn default() -> Self {
160 <Self as Hasher<64>>::initial()
161 }
162}
163
164impl HashAxis for Sha512Hasher {
165 const AXIS_ADDRESS: &'static str = "https://uor.foundation/axis/HashAxis/Sha512";
166 const MAX_OUTPUT_BYTES: usize = SHA512_BYTES;
167
168 fn hash(input: &[u8], out: &mut [u8]) -> Result<usize, ShapeViolation> {
169 if out.len() < SHA512_BYTES {
170 return Err(out_too_small_violation());
171 }
172 let digest = sha2::Sha512::digest(input);
173 out[..SHA512_BYTES].copy_from_slice(&digest);
174 Ok(SHA512_BYTES)
175 }
176}
177
178axis_extension_impl_for_hash_axis!(Sha512Hasher);
179
180impl Hasher<64> for Sha512Hasher {
181 const OUTPUT_BYTES: usize = SHA512_BYTES;
182
183 fn initial() -> Self {
184 Self {
185 inner: sha2::Sha512::new(),
186 }
187 }
188
189 fn fold_byte(mut self, b: u8) -> Self {
190 Sha2Digest::update(&mut self.inner, [b]);
191 self
192 }
193
194 fn fold_bytes(mut self, bytes: &[u8]) -> Self {
195 Sha2Digest::update(&mut self.inner, bytes);
196 self
197 }
198
199 fn finalize(self) -> [u8; 64] {
200 let result = Sha2Digest::finalize(self.inner);
201 let mut out = [0u8; 64];
202 out.copy_from_slice(&result);
203 out
204 }
205}
206
207const SHA3_256_BYTES: usize = 32;
211
212#[derive(Debug, Clone)]
214pub struct Sha3_256Hasher {
215 inner: sha3::Sha3_256,
216}
217
218impl Default for Sha3_256Hasher {
219 fn default() -> Self {
220 Self::initial()
221 }
222}
223
224impl HashAxis for Sha3_256Hasher {
225 const AXIS_ADDRESS: &'static str = "https://uor.foundation/axis/HashAxis/Sha3_256";
226 const MAX_OUTPUT_BYTES: usize = SHA3_256_BYTES;
227
228 fn hash(input: &[u8], out: &mut [u8]) -> Result<usize, ShapeViolation> {
229 if out.len() < SHA3_256_BYTES {
230 return Err(out_too_small_violation());
231 }
232 let digest = sha3::Sha3_256::digest(input);
233 out[..SHA3_256_BYTES].copy_from_slice(&digest);
234 Ok(SHA3_256_BYTES)
235 }
236}
237
238axis_extension_impl_for_hash_axis!(Sha3_256Hasher);
239
240impl Hasher for Sha3_256Hasher {
241 const OUTPUT_BYTES: usize = SHA3_256_BYTES;
242
243 fn initial() -> Self {
244 Self {
245 inner: sha3::Sha3_256::new(),
246 }
247 }
248
249 fn fold_byte(mut self, b: u8) -> Self {
250 Sha3Digest::update(&mut self.inner, [b]);
251 self
252 }
253
254 fn fold_bytes(mut self, bytes: &[u8]) -> Self {
255 Sha3Digest::update(&mut self.inner, bytes);
256 self
257 }
258
259 fn finalize(self) -> [u8; 32] {
260 let result = Sha3Digest::finalize(self.inner);
261 let mut out = [0u8; 32];
262 out.copy_from_slice(&result);
263 out
264 }
265}
266
267const KECCAK256_BYTES: usize = 32;
271
272#[derive(Debug, Clone)]
276pub struct Keccak256Hasher {
277 inner: sha3::Keccak256,
278}
279
280impl Default for Keccak256Hasher {
281 fn default() -> Self {
282 Self::initial()
283 }
284}
285
286impl HashAxis for Keccak256Hasher {
287 const AXIS_ADDRESS: &'static str = "https://uor.foundation/axis/HashAxis/Keccak256";
288 const MAX_OUTPUT_BYTES: usize = KECCAK256_BYTES;
289
290 fn hash(input: &[u8], out: &mut [u8]) -> Result<usize, ShapeViolation> {
291 if out.len() < KECCAK256_BYTES {
292 return Err(out_too_small_violation());
293 }
294 let digest = sha3::Keccak256::digest(input);
295 out[..KECCAK256_BYTES].copy_from_slice(&digest);
296 Ok(KECCAK256_BYTES)
297 }
298}
299
300axis_extension_impl_for_hash_axis!(Keccak256Hasher);
301
302impl Hasher for Keccak256Hasher {
303 const OUTPUT_BYTES: usize = KECCAK256_BYTES;
304
305 fn initial() -> Self {
306 Self {
307 inner: sha3::Keccak256::new(),
308 }
309 }
310
311 fn fold_byte(mut self, b: u8) -> Self {
312 Sha3Digest::update(&mut self.inner, [b]);
313 self
314 }
315
316 fn fold_bytes(mut self, bytes: &[u8]) -> Self {
317 Sha3Digest::update(&mut self.inner, bytes);
318 self
319 }
320
321 fn finalize(self) -> [u8; 32] {
322 let result = Sha3Digest::finalize(self.inner);
323 let mut out = [0u8; 32];
324 out.copy_from_slice(&result);
325 out
326 }
327}
328
329const BLAKE3_BYTES: usize = 32;
333
334#[derive(Debug, Clone, Default)]
337pub struct Blake3Hasher {
338 inner: blake3::Hasher,
339}
340
341impl HashAxis for Blake3Hasher {
342 const AXIS_ADDRESS: &'static str = "https://uor.foundation/axis/HashAxis/Blake3";
343 const MAX_OUTPUT_BYTES: usize = BLAKE3_BYTES;
344
345 fn hash(input: &[u8], out: &mut [u8]) -> Result<usize, ShapeViolation> {
346 if out.len() < BLAKE3_BYTES {
347 return Err(out_too_small_violation());
348 }
349 let digest = blake3::hash(input);
350 out[..BLAKE3_BYTES].copy_from_slice(digest.as_bytes());
351 Ok(BLAKE3_BYTES)
352 }
353}
354
355axis_extension_impl_for_hash_axis!(Blake3Hasher);
356
357impl Hasher for Blake3Hasher {
358 const OUTPUT_BYTES: usize = BLAKE3_BYTES;
359
360 fn initial() -> Self {
361 Self::default()
362 }
363
364 fn fold_byte(mut self, b: u8) -> Self {
365 self.inner.update(&[b]);
366 self
367 }
368
369 fn fold_bytes(mut self, bytes: &[u8]) -> Self {
370 self.inner.update(bytes);
371 self
372 }
373
374 fn finalize(self) -> [u8; 32] {
375 *self.inner.finalize().as_bytes()
376 }
377}