1#[macro_export]
4macro_rules! hex_fmt_impl(
6 ($reverse:expr, $ty:ident) => (
7 $crate::hex_fmt_impl!($reverse, $ty, );
8 );
9 ($reverse:expr, $ty:ident, $($gen:ident: $gent:ident),*) => (
10 impl<$($gen: $gent),*> $crate::_export::_core::fmt::LowerHex for $ty<$($gen),*> {
11 #[inline]
12 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
13 if $reverse {
14 $crate::_export::_core::fmt::LowerHex::fmt(&self.0.backward_hex(), f)
15 } else {
16 $crate::_export::_core::fmt::LowerHex::fmt(&self.0.forward_hex(), f)
17 }
18 }
19 }
20
21 impl<$($gen: $gent),*> $crate::_export::_core::fmt::UpperHex for $ty<$($gen),*> {
22 #[inline]
23 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
24 if $reverse {
25 $crate::_export::_core::fmt::UpperHex::fmt(&self.0.backward_hex(), f)
26 } else {
27 $crate::_export::_core::fmt::UpperHex::fmt(&self.0.forward_hex(), f)
28 }
29 }
30 }
31
32 impl<$($gen: $gent),*> $crate::_export::_core::fmt::Display for $ty<$($gen),*> {
33 #[inline]
34 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
35 $crate::_export::_core::fmt::LowerHex::fmt(&self, f)
36 }
37 }
38
39 impl<$($gen: $gent),*> $crate::_export::_core::fmt::Debug for $ty<$($gen),*> {
40 #[inline]
41 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
42 write!(f, "{:#}", self)
43 }
44 }
45 );
46);
47
48#[macro_export]
50macro_rules! borrow_slice_impl(
51 ($ty:ident) => (
52 $crate::borrow_slice_impl!($ty, );
53 );
54 ($ty:ident, $($gen:ident: $gent:ident),*) => (
55 impl<$($gen: $gent),*> $crate::_export::_core::borrow::Borrow<[u8]> for $ty<$($gen),*> {
56 fn borrow(&self) -> &[u8] {
57 &self[..]
58 }
59 }
60
61 impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8]> for $ty<$($gen),*> {
62 fn as_ref(&self) -> &[u8] {
63 &self[..]
64 }
65 }
66 )
67);
68
69macro_rules! engine_input_impl(
70 () => (
71 #[cfg(not(hashes_fuzz))]
72 fn input(&mut self, mut inp: &[u8]) {
73 while !inp.is_empty() {
74 let buf_idx = self.length % <Self as crate::HashEngine>::BLOCK_SIZE;
75 let rem_len = <Self as crate::HashEngine>::BLOCK_SIZE - buf_idx;
76 let write_len = cmp::min(rem_len, inp.len());
77
78 self.buffer[buf_idx..buf_idx + write_len]
79 .copy_from_slice(&inp[..write_len]);
80 self.length += write_len;
81 if self.length % <Self as crate::HashEngine>::BLOCK_SIZE == 0 {
82 self.process_block();
83 }
84 inp = &inp[write_len..];
85 }
86 }
87
88 #[cfg(hashes_fuzz)]
89 fn input(&mut self, inp: &[u8]) {
90 for c in inp {
91 self.buffer[0] ^= *c;
92 }
93 self.length += inp.len();
94 }
95 )
96);
97
98#[macro_export]
180macro_rules! hash_newtype {
181 ($($(#[$($type_attrs:tt)*])* $type_vis:vis struct $newtype:ident($(#[$field_attrs:tt])* $field_vis:vis $hash:path);)+) => {
182 $(
183 $($crate::hash_newtype_known_attrs!(#[ $($type_attrs)* ]);)*
184
185 $crate::hash_newtype_struct! {
186 $type_vis struct $newtype($(#[$field_attrs])* $field_vis $hash);
187
188 $({ $($type_attrs)* })*
189 }
190
191 $crate::hex_fmt_impl!(<$newtype as $crate::Hash>::DISPLAY_BACKWARD, $newtype);
192 $crate::serde_impl!($newtype, <$newtype as $crate::Hash>::LEN);
193 $crate::borrow_slice_impl!($newtype);
194
195 impl $newtype {
196 #[allow(unused)] pub fn from_raw_hash(inner: $hash) -> $newtype {
199 $newtype(inner)
200 }
201
202 #[allow(unused)] pub fn to_raw_hash(self) -> $hash {
205 self.0
206 }
207
208 #[allow(unused)] pub fn as_raw_hash(&self) -> &$hash {
211 &self.0
212 }
213 }
214
215 impl $crate::_export::_core::convert::From<$hash> for $newtype {
216 fn from(inner: $hash) -> $newtype {
217 Self { 0: inner }
219 }
220 }
221
222 impl $crate::_export::_core::convert::From<$newtype> for $hash {
223 fn from(hashtype: $newtype) -> $hash {
224 hashtype.0
225 }
226 }
227
228 impl $crate::Hash for $newtype {
229 type Engine = <$hash as $crate::Hash>::Engine;
230 type Bytes = <$hash as $crate::Hash>::Bytes;
231
232 const LEN: usize = <$hash as $crate::Hash>::LEN;
233 const DISPLAY_BACKWARD: bool = $crate::hash_newtype_get_direction!($hash, $(#[$($type_attrs)*])*);
234
235 fn engine() -> Self::Engine {
236 <$hash as $crate::Hash>::engine()
237 }
238
239 fn from_engine(e: Self::Engine) -> Self {
240 Self::from(<$hash as $crate::Hash>::from_engine(e))
241 }
242
243 #[inline]
244 fn from_slice(sl: &[u8]) -> Result<$newtype, $crate::FromSliceError> {
245 Ok($newtype(<$hash as $crate::Hash>::from_slice(sl)?))
246 }
247
248 #[inline]
249 fn from_byte_array(bytes: Self::Bytes) -> Self {
250 $newtype(<$hash as $crate::Hash>::from_byte_array(bytes))
251 }
252
253 #[inline]
254 fn to_byte_array(self) -> Self::Bytes {
255 self.0.to_byte_array()
256 }
257
258 #[inline]
259 fn as_byte_array(&self) -> &Self::Bytes {
260 self.0.as_byte_array()
261 }
262
263 #[inline]
264 fn all_zeros() -> Self {
265 let zeros = <$hash>::all_zeros();
266 $newtype(zeros)
267 }
268 }
269
270 impl $crate::_export::_core::str::FromStr for $newtype {
271 type Err = $crate::hex::HexToArrayError;
272 fn from_str(s: &str) -> $crate::_export::_core::result::Result<$newtype, Self::Err> {
273 use $crate::hex::{FromHex, HexToBytesIter};
274 use $crate::Hash;
275
276 let inner: <$hash as Hash>::Bytes = if <Self as $crate::Hash>::DISPLAY_BACKWARD {
277 FromHex::from_byte_iter(HexToBytesIter::new(s)?.rev())?
278 } else {
279 FromHex::from_byte_iter(HexToBytesIter::new(s)?)?
280 };
281 Ok($newtype(<$hash>::from_byte_array(inner)))
282 }
283 }
284
285 impl $crate::_export::_core::convert::AsRef<[u8; <$hash as $crate::Hash>::LEN]> for $newtype {
286 fn as_ref(&self) -> &[u8; <$hash as $crate::Hash>::LEN] {
287 AsRef::<[u8; <$hash as $crate::Hash>::LEN]>::as_ref(&self.0)
288 }
289 }
290
291 impl<I: $crate::_export::_core::slice::SliceIndex<[u8]>> $crate::_export::_core::ops::Index<I> for $newtype {
292 type Output = I::Output;
293
294 #[inline]
295 fn index(&self, index: I) -> &Self::Output {
296 &self.0[index]
297 }
298 }
299 )+
300 };
301}
302
303#[doc(hidden)]
314#[macro_export]
315macro_rules! hash_newtype_struct {
316 ($(#[$other_attrs:meta])* $type_vis:vis struct $newtype:ident($(#[$field_attrs:meta])* $field_vis:vis $hash:path);) => {
317 $(#[$other_attrs])*
318 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
319 $type_vis struct $newtype($(#[$field_attrs])* $field_vis $hash);
320 };
321 ($(#[$other_attrs:meta])* $type_vis:vis struct $newtype:ident($(#[$field_attrs:meta])* $field_vis:vis $hash:path); { hash_newtype($($ignore:tt)*) } $($type_attrs:tt)*) => {
322 $crate::hash_newtype_struct! {
323 $(#[$other_attrs])*
324 $type_vis struct $newtype($(#[$field_attrs])* $field_vis $hash);
325
326 $($type_attrs)*
327 }
328 };
329 ($(#[$other_attrs:meta])* $type_vis:vis struct $newtype:ident($(#[$field_attrs:meta])* $field_vis:vis $hash:path); { $other_attr:meta } $($type_attrs:tt)*) => {
330 $crate::hash_newtype_struct! {
331 $(#[$other_attrs])*
332 #[$other_attr]
333 $type_vis struct $newtype($(#[$field_attrs])* $field_vis $hash);
334
335 $($type_attrs)*
336 }
337 };
338}
339
340#[doc(hidden)]
349#[macro_export]
350macro_rules! hash_newtype_get_direction {
351 ($hash:ty, ) => { <$hash as $crate::Hash>::DISPLAY_BACKWARD };
352 ($hash:ty, #[hash_newtype(forward)] $($others:tt)*) => { { $crate::hash_newtype_forbid_direction!(forward, $($others)*); false } };
353 ($hash:ty, #[hash_newtype(backward)] $($others:tt)*) => { { $crate::hash_newtype_forbid_direction!(backward, $($others)*); true } };
354 ($hash:ty, #[$($ignore:tt)*] $($others:tt)*) => { $crate::hash_newtype_get_direction!($hash, $($others)*) };
355}
356
357#[doc(hidden)]
361#[macro_export]
362macro_rules! hash_newtype_forbid_direction {
363 ($direction:ident, ) => {};
364 ($direction:ident, #[hash_newtype(forward)] $(others:tt)*) => {
365 compile_error!(concat!("Cannot set display direction to forward: ", stringify!($direction), " was already specified"));
366 };
367 ($direction:ident, #[hash_newtype(backward)] $(others:tt)*) => {
368 compile_error!(concat!("Cannot set display direction to backward: ", stringify!($direction), " was already specified"));
369 };
370 ($direction:ident, #[$($ignore:tt)*] $(#[$others:tt])*) => {
371 $crate::hash_newtype_forbid_direction!($direction, $(#[$others])*)
372 };
373}
374
375#[doc(hidden)]
381#[macro_export]
382macro_rules! hash_newtype_known_attrs {
383 (#[hash_newtype(forward)]) => {};
384 (#[hash_newtype(backward)]) => {};
385 (#[hash_newtype($($unknown:tt)*)]) => { compile_error!(concat!("Unrecognized attribute ", stringify!($($unknown)*))); };
386 ($($ignore:tt)*) => {};
387}
388
389#[cfg(feature = "schemars")]
390pub mod json_hex_string {
391 use schemars::gen::SchemaGenerator;
392 use schemars::schema::{Schema, SchemaObject};
393 use schemars::JsonSchema;
394 macro_rules! define_custom_hex {
395 ($name:ident, $len:expr) => {
396 pub fn $name(gen: &mut SchemaGenerator) -> Schema {
397 let mut schema: SchemaObject = <String>::json_schema(gen).into();
398 schema.string = Some(Box::new(schemars::schema::StringValidation {
399 max_length: Some($len * 2),
400 min_length: Some($len * 2),
401 pattern: Some("[0-9a-fA-F]+".to_owned()),
402 }));
403 schema.into()
404 }
405 };
406 }
407 define_custom_hex!(len_8, 8);
408 define_custom_hex!(len_20, 20);
409 define_custom_hex!(len_32, 32);
410 define_custom_hex!(len_64, 64);
411}
412
413#[cfg(test)]
414mod test {
415 use crate::{sha256, Hash};
416
417 #[test]
418 fn hash_as_ref_array() {
419 let hash = sha256::Hash::hash(&[3, 50]);
420 let r = AsRef::<[u8; 32]>::as_ref(&hash);
421 assert_eq!(r, hash.as_byte_array());
422 }
423
424 #[test]
425 fn hash_as_ref_slice() {
426 let hash = sha256::Hash::hash(&[3, 50]);
427 let r = AsRef::<[u8]>::as_ref(&hash);
428 assert_eq!(r, hash.as_byte_array());
429 }
430
431 #[test]
432 fn hash_borrow() {
433 use core::borrow::Borrow;
434
435 let hash = sha256::Hash::hash(&[3, 50]);
436 let borrowed: &[u8] = hash.borrow();
437 assert_eq!(borrowed, hash.as_byte_array());
438 }
439
440 hash_newtype! {
441 struct TestHash(crate::sha256d::Hash);
443 }
444
445 #[test]
446 fn display() {
447 let want = "0000000000000000000000000000000000000000000000000000000000000000";
448 let got = format!("{}", TestHash::all_zeros());
449 assert_eq!(got, want)
450 }
451
452 #[test]
453 fn display_alternate() {
454 let want = "0x0000000000000000000000000000000000000000000000000000000000000000";
455 let got = format!("{:#}", TestHash::all_zeros());
456 assert_eq!(got, want)
457 }
458
459 #[test]
460 fn lower_hex() {
461 let want = "0000000000000000000000000000000000000000000000000000000000000000";
462 let got = format!("{:x}", TestHash::all_zeros());
463 assert_eq!(got, want)
464 }
465
466 #[test]
467 fn lower_hex_alternate() {
468 let want = "0x0000000000000000000000000000000000000000000000000000000000000000";
469 let got = format!("{:#x}", TestHash::all_zeros());
470 assert_eq!(got, want)
471 }
472
473 #[test]
474 fn inner_hash_as_ref_array() {
475 let hash = TestHash::all_zeros();
476 let r = AsRef::<[u8; 32]>::as_ref(&hash);
477 assert_eq!(r, hash.as_byte_array());
478 }
479
480 #[test]
481 fn inner_hash_as_ref_slice() {
482 let hash = TestHash::all_zeros();
483 let r = AsRef::<[u8]>::as_ref(&hash);
484 assert_eq!(r, hash.as_byte_array());
485 }
486}