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