fixed-hash-0.8.0/.cargo_vcs_info.json0000644000000001500000000000100130550ustar { "git": { "sha1": "6aa58bfeaa870b4f7387e50319004151443f7297" }, "path_in_vcs": "fixed-hash" }fixed-hash-0.8.0/CHANGELOG.md000064400000000000000000000022771046102023000134720ustar 00000000000000# Changelog The format is based on [Keep a Changelog]. [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ ## [Unreleased] ## [0.8.0] - 2022-09-20 ### Breaking - Migrated to 2021 edition, enforcing MSRV of `1.56.1`. [#601](https://github.com/paritytech/parity-common/pull/601) - Updated `arbitrary` to 1.0. [#530](https://github.com/paritytech/parity-common/pull/530) - Updated `quickcheck` to 1.0. [#674](https://github.com/paritytech/parity-common/pull/674) ## [0.7.0] - 2021-01-05 ### Breaking - Updated `rand` to 0.8. [#488](https://github.com/paritytech/parity-common/pull/488) ## [0.6.1] - 2020-04-27 - Added `arbitrary` feature. [#378](https://github.com/paritytech/parity-common/pull/378) ## [0.6.0] - 2020-03-16 - Removed `libc` feature. [#317](https://github.com/paritytech/parity-common/pull/317) - License changed from MIT to dual MIT/Apache2. [#342](https://github.com/paritytech/parity-common/pull/342) ## [0.5.2] - 2019-12-19 ### Fixed - Re-export `alloc` for both std and no-std to fix compilation. [#268](https://github.com/paritytech/parity-common/pull/268) ## [0.5.1] - 2019-10-24 ### Dependencies - Updated dependencies. [#239](https://github.com/paritytech/parity-common/pull/239) fixed-hash-0.8.0/Cargo.toml0000644000000033570000000000100110670ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.56.1" name = "fixed-hash" version = "0.8.0" authors = ["Parity Technologies "] description = "Macros to define custom fixed-size hash types" homepage = "https://github.com/paritytech/parity-common" documentation = "https://docs.rs/fixed-hash/" readme = "README.md" license = "MIT OR Apache-2.0" repository = "https://github.com/paritytech/parity-common" [package.metadata.docs.rs] features = [ "quickcheck", "api-dummy", ] [[bench]] name = "cmp" harness = false [dependencies.arbitrary] version = "1.0" optional = true [dependencies.byteorder] version = "1.4.2" optional = true default-features = false [dependencies.quickcheck] version = "1" optional = true [dependencies.rand] version = "0.8.0" optional = true default-features = false [dependencies.rustc-hex] version = "2.0.1" optional = true default-features = false [dependencies.static_assertions] version = "1.0.0" [dev-dependencies.criterion] version = "0.4.0" [dev-dependencies.rand] version = "0.8.0" features = ["std_rng"] default-features = false [dev-dependencies.rand_xorshift] version = "0.3.0" [features] api-dummy = [] default = [ "std", "rand", "rustc-hex", "byteorder", ] std = [ "rustc-hex/std", "rand/std", "byteorder/std", ] fixed-hash-0.8.0/Cargo.toml.orig000064400000000000000000000023171046102023000145430ustar 00000000000000[package] name = "fixed-hash" version = "0.8.0" authors = ["Parity Technologies "] license = "MIT OR Apache-2.0" homepage = "https://github.com/paritytech/parity-common" repository = "https://github.com/paritytech/parity-common" description = "Macros to define custom fixed-size hash types" documentation = "https://docs.rs/fixed-hash/" readme = "README.md" edition = "2021" rust-version = "1.56.1" [package.metadata.docs.rs] features = ["quickcheck", "api-dummy"] [dependencies] byteorder = { version = "1.4.2", optional = true, default-features = false } quickcheck = { version = "1", optional = true } rand = { version = "0.8.0", optional = true, default-features = false } rustc-hex = { version = "2.0.1", optional = true, default-features = false } static_assertions = "1.0.0" arbitrary = { version = "1.0", optional = true } [dev-dependencies] rand_xorshift = "0.3.0" criterion = "0.4.0" rand = { version = "0.8.0", default-features = false, features = ["std_rng"] } [features] default = ["std", "rand", "rustc-hex", "byteorder"] std = ["rustc-hex/std", "rand/std", "byteorder/std"] api-dummy = [] # Feature used by docs.rs to display documentation of hash types [[bench]] name = "cmp" harness = false fixed-hash-0.8.0/README.md000064400000000000000000000035141046102023000131330ustar 00000000000000# Fixed Hash Provides macros to construct custom fixed-size hash types. ## Examples Simple 256 bit (32 bytes) hash type. ```rust use fixed_hash::construct_fixed_hash; construct_fixed_hash! { /// My 256 bit hash type. pub struct H256(32); } ``` Opt-in to add conversions between differently sized hashes. ```rust construct_fixed_hash!{ struct H256(32); } construct_fixed_hash!{ struct H160(20); } // auto-implement conversions between H256 and H160 impl_fixed_hash_conversions!(H256, H160); // now use the generated conversions assert_eq!(H256::from(H160::zero()), H256::zero()); assert_eq!(H160::from(H256::zero()), H160::zero()); ``` It is possible to add attributes to your types, for example to make them serializable. ```rust construct_fixed_hash!{ /// My serializable hash type. #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] struct H160(20); } ``` ## Features By default this is an standard library depending crate. For a `#[no_std]` environment use it as follows: ``` fixed-hash = { version = "0.3", default-features = false } ``` ### Available Features - `std`: Use the standard library instead of the core library. - Using this feature enables the following features - `rustc-hex/std` - `rand/std` - `byteorder/std` - Enabled by default. - `libc`: Use `libc` for implementations of `PartialEq` and `Ord`. - Enabled by default. - `rand`: Provide API based on the `rand` crate. - Enabled by default. - `byteorder`: Provide API based on the `byteorder` crate. - Enabled by default. - `quickcheck`: Provide `quickcheck` implementation for hash types. - Disabled by default. - `api-dummy`: Generate a dummy hash type for API documentation. - Enabled by default at `docs.rs` - `arbitrary`: Allow for creation of a hash from random unstructured input. - Disabled by default. fixed-hash-0.8.0/benches/cmp.rs000064400000000000000000000060541046102023000144120ustar 00000000000000// Copyright 2020 Parity Technologies // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Benchmarks for fixed-hash cmp implementation. use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; use fixed_hash::construct_fixed_hash; construct_fixed_hash! { pub struct H256(32); } criterion_group!(cmp, eq_equal, eq_nonequal, compare,); criterion_main!(cmp); fn eq_equal(c: &mut Criterion) { let mut group = c.benchmark_group("eq_self"); for input in [ H256::zero(), H256::repeat_byte(0xAA), H256::from([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x2D, 0x6D, 0x19, 0x40, 0x84, 0xC2, 0xDE, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, ]), H256([u8::max_value(); 32]), ] { group.bench_with_input(BenchmarkId::from_parameter(input), &input, |b, x| { b.iter(|| black_box(x.eq(black_box(x)))) }); } group.finish(); } fn eq_nonequal(c: &mut Criterion) { let mut group = c.benchmark_group("eq_nonequal"); for input in [ ( H256::zero(), H256::from([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ]), ), (H256::repeat_byte(0xAA), H256::repeat_byte(0xA1)), ( H256::from([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x2D, 0x6D, 0x19, 0x40, 0x84, 0xC2, 0xDE, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, ]), H256::from([ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x2D, 0x6D, 0x19, 0x40, 0x84, 0xC2, 0xDE, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, ]), ), ] { group.bench_with_input(BenchmarkId::from_parameter(input.0), &input, |b, (x, y)| { b.iter(|| black_box(x.eq(black_box(y)))) }); } group.finish(); } fn compare(c: &mut Criterion) { let mut group = c.benchmark_group("compare"); for input in [ ( H256::zero(), H256::from([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ]), ), (H256::zero(), H256::zero()), (H256::repeat_byte(0xAA), H256::repeat_byte(0xAA)), (H256::repeat_byte(0xAA), H256::repeat_byte(0xA1)), ( H256::from([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x2D, 0x6D, 0x19, 0x40, 0x84, 0xC2, 0xDF, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, ]), H256::from([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x2D, 0x6D, 0x19, 0x40, 0x84, 0xC2, 0xDE, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, ]), ), ] { group.bench_with_input(BenchmarkId::from_parameter(input.1), &input, |b, (x, y)| { b.iter(|| black_box(x.cmp(black_box(y)))) }); } group.finish(); } fixed-hash-0.8.0/src/hash.rs000064400000000000000000000516241046102023000137410ustar 00000000000000// Copyright 2020 Parity Technologies // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. /// Construct a fixed-size hash type. /// /// # Examples /// /// Create a public unformatted hash type with 32 bytes size. /// /// ``` /// use fixed_hash::construct_fixed_hash; /// /// construct_fixed_hash!{ pub struct H256(32); } /// assert_eq!(std::mem::size_of::(), 32); /// ``` /// /// With additional attributes and doc comments. /// /// ``` /// use fixed_hash::construct_fixed_hash; /// construct_fixed_hash!{ /// /// My unformatted 160 bytes sized hash type. /// #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] /// pub struct H160(20); /// } /// assert_eq!(std::mem::size_of::(), 20); /// ``` /// /// The visibility modifier is optional and you can create a private hash type. /// /// ``` /// use fixed_hash::construct_fixed_hash; /// construct_fixed_hash!{ struct H512(64); } /// assert_eq!(std::mem::size_of::(), 64); /// ``` #[macro_export(local_inner_macros)] macro_rules! construct_fixed_hash { ( $(#[$attr:meta])* $visibility:vis struct $name:ident ( $n_bytes:expr ); ) => { #[repr(C)] $(#[$attr])* $visibility struct $name (pub [u8; $n_bytes]); impl From<[u8; $n_bytes]> for $name { /// Constructs a hash type from the given bytes array of fixed length. /// /// # Note /// /// The given bytes are interpreted in big endian order. #[inline] fn from(bytes: [u8; $n_bytes]) -> Self { $name(bytes) } } impl<'a> From<&'a [u8; $n_bytes]> for $name { /// Constructs a hash type from the given reference /// to the bytes array of fixed length. /// /// # Note /// /// The given bytes are interpreted in big endian order. #[inline] fn from(bytes: &'a [u8; $n_bytes]) -> Self { $name(*bytes) } } impl<'a> From<&'a mut [u8; $n_bytes]> for $name { /// Constructs a hash type from the given reference /// to the mutable bytes array of fixed length. /// /// # Note /// /// The given bytes are interpreted in big endian order. #[inline] fn from(bytes: &'a mut [u8; $n_bytes]) -> Self { $name(*bytes) } } impl From<$name> for [u8; $n_bytes] { #[inline] fn from(s: $name) -> Self { s.0 } } impl AsRef<[u8]> for $name { #[inline] fn as_ref(&self) -> &[u8] { self.as_bytes() } } impl AsMut<[u8]> for $name { #[inline] fn as_mut(&mut self) -> &mut [u8] { self.as_bytes_mut() } } impl $name { /// Returns a new fixed hash where all bits are set to the given byte. #[inline] pub const fn repeat_byte(byte: u8) -> $name { $name([byte; $n_bytes]) } /// Returns a new zero-initialized fixed hash. #[inline] pub const fn zero() -> $name { $name::repeat_byte(0u8) } /// Returns the size of this hash in bytes. #[inline] pub const fn len_bytes() -> usize { $n_bytes } /// Extracts a byte slice containing the entire fixed hash. #[inline] pub fn as_bytes(&self) -> &[u8] { &self.0 } /// Extracts a mutable byte slice containing the entire fixed hash. #[inline] pub fn as_bytes_mut(&mut self) -> &mut [u8] { &mut self.0 } /// Extracts a reference to the byte array containing the entire fixed hash. #[inline] pub const fn as_fixed_bytes(&self) -> &[u8; $n_bytes] { &self.0 } /// Extracts a reference to the byte array containing the entire fixed hash. #[inline] pub fn as_fixed_bytes_mut(&mut self) -> &mut [u8; $n_bytes] { &mut self.0 } /// Returns the inner bytes array. #[inline] pub const fn to_fixed_bytes(self) -> [u8; $n_bytes] { self.0 } /// Returns a constant raw pointer to the value. #[inline] pub fn as_ptr(&self) -> *const u8 { self.as_bytes().as_ptr() } /// Returns a mutable raw pointer to the value. #[inline] pub fn as_mut_ptr(&mut self) -> *mut u8 { self.as_bytes_mut().as_mut_ptr() } /// Assign the bytes from the byte slice `src` to `self`. /// /// # Note /// /// The given bytes are interpreted in big endian order. /// /// # Panics /// /// If the length of `src` and the number of bytes in `self` do not match. pub fn assign_from_slice(&mut self, src: &[u8]) { $crate::core_::assert_eq!(src.len(), $n_bytes); self.as_bytes_mut().copy_from_slice(src); } /// Create a new fixed-hash from the given slice `src`. /// /// # Note /// /// The given bytes are interpreted in big endian order. /// /// # Panics /// /// If the length of `src` and the number of bytes in `Self` do not match. pub fn from_slice(src: &[u8]) -> Self { $crate::core_::assert_eq!(src.len(), $n_bytes); let mut ret = Self::zero(); ret.assign_from_slice(src); ret } /// Returns `true` if all bits set in `b` are also set in `self`. #[inline] pub fn covers(&self, b: &Self) -> bool { &(b & self) == b } /// Returns `true` if no bits are set. #[inline] pub fn is_zero(&self) -> bool { self.as_bytes().iter().all(|&byte| byte == 0u8) } } impl $crate::core_::fmt::Debug for $name { fn fmt(&self, f: &mut $crate::core_::fmt::Formatter) -> $crate::core_::fmt::Result { $crate::core_::write!(f, "{:#x}", self) } } impl $crate::core_::fmt::Display for $name { fn fmt(&self, f: &mut $crate::core_::fmt::Formatter) -> $crate::core_::fmt::Result { $crate::core_::write!(f, "0x")?; for i in &self.0[0..2] { $crate::core_::write!(f, "{:02x}", i)?; } $crate::core_::write!(f, "…")?; for i in &self.0[$n_bytes - 2..$n_bytes] { $crate::core_::write!(f, "{:02x}", i)?; } Ok(()) } } impl $crate::core_::fmt::LowerHex for $name { fn fmt(&self, f: &mut $crate::core_::fmt::Formatter) -> $crate::core_::fmt::Result { if f.alternate() { $crate::core_::write!(f, "0x")?; } for i in &self.0[..] { $crate::core_::write!(f, "{:02x}", i)?; } Ok(()) } } impl $crate::core_::fmt::UpperHex for $name { fn fmt(&self, f: &mut $crate::core_::fmt::Formatter) -> $crate::core_::fmt::Result { if f.alternate() { $crate::core_::write!(f, "0X")?; } for i in &self.0[..] { $crate::core_::write!(f, "{:02X}", i)?; } Ok(()) } } impl $crate::core_::marker::Copy for $name {} #[cfg_attr(feature = "dev", allow(expl_impl_clone_on_copy))] impl $crate::core_::clone::Clone for $name { fn clone(&self) -> $name { let mut ret = $name::zero(); ret.0.copy_from_slice(&self.0); ret } } impl $crate::core_::cmp::Eq for $name {} impl $crate::core_::cmp::PartialOrd for $name { fn partial_cmp(&self, other: &Self) -> Option<$crate::core_::cmp::Ordering> { Some(self.cmp(other)) } } impl $crate::core_::hash::Hash for $name { fn hash(&self, state: &mut H) where H: $crate::core_::hash::Hasher { state.write(&self.0); } } impl $crate::core_::ops::Index for $name where I: $crate::core_::slice::SliceIndex<[u8]> { type Output = I::Output; #[inline] fn index(&self, index: I) -> &I::Output { &self.as_bytes()[index] } } impl $crate::core_::ops::IndexMut for $name where I: $crate::core_::slice::SliceIndex<[u8], Output = [u8]> { #[inline] fn index_mut(&mut self, index: I) -> &mut I::Output { &mut self.as_bytes_mut()[index] } } impl $crate::core_::default::Default for $name { #[inline] fn default() -> Self { Self::zero() } } impl_ops_for_hash!($name, BitOr, bitor, BitOrAssign, bitor_assign, |, |=); impl_ops_for_hash!($name, BitAnd, bitand, BitAndAssign, bitand_assign, &, &=); impl_ops_for_hash!($name, BitXor, bitxor, BitXorAssign, bitxor_assign, ^, ^=); impl_byteorder_for_fixed_hash!($name); impl_rand_for_fixed_hash!($name); impl_cmp_for_fixed_hash!($name); impl_rustc_hex_for_fixed_hash!($name); impl_quickcheck_for_fixed_hash!($name); impl_arbitrary_for_fixed_hash!($name); } } // Implementation for disabled byteorder crate support. // // # Note // // Feature guarded macro definitions instead of feature guarded impl blocks // to work around the problems of introducing `byteorder` crate feature in // a user crate. #[cfg(not(feature = "byteorder"))] #[macro_export] #[doc(hidden)] macro_rules! impl_byteorder_for_fixed_hash { ( $name:ident ) => {}; } // Implementation for enabled byteorder crate support. // // # Note // // Feature guarded macro definitions instead of feature guarded impl blocks // to work around the problems of introducing `byteorder` crate feature in // a user crate. #[cfg(feature = "byteorder")] #[macro_export] #[doc(hidden)] macro_rules! impl_byteorder_for_fixed_hash { ( $name:ident ) => { /// Utilities using the `byteorder` crate. impl $name { /// Returns the least significant `n` bytes as slice. /// /// # Panics /// /// If `n` is greater than the number of bytes in `self`. #[inline] fn least_significant_bytes(&self, n: usize) -> &[u8] { $crate::core_::assert_eq!(true, n <= Self::len_bytes()); &self[(Self::len_bytes() - n)..] } fn to_low_u64_with_byteorder(&self) -> u64 where B: $crate::byteorder::ByteOrder, { let mut buf = [0x0; 8]; let capped = $crate::core_::cmp::min(Self::len_bytes(), 8); buf[(8 - capped)..].copy_from_slice(self.least_significant_bytes(capped)); B::read_u64(&buf) } /// Returns the lowest 8 bytes interpreted as big-endian. /// /// # Note /// /// For hash type with less than 8 bytes the missing bytes /// are interpreted as being zero. #[inline] pub fn to_low_u64_be(&self) -> u64 { self.to_low_u64_with_byteorder::<$crate::byteorder::BigEndian>() } /// Returns the lowest 8 bytes interpreted as little-endian. /// /// # Note /// /// For hash type with less than 8 bytes the missing bytes /// are interpreted as being zero. #[inline] pub fn to_low_u64_le(&self) -> u64 { self.to_low_u64_with_byteorder::<$crate::byteorder::LittleEndian>() } /// Returns the lowest 8 bytes interpreted as native-endian. /// /// # Note /// /// For hash type with less than 8 bytes the missing bytes /// are interpreted as being zero. #[inline] pub fn to_low_u64_ne(&self) -> u64 { self.to_low_u64_with_byteorder::<$crate::byteorder::NativeEndian>() } fn from_low_u64_with_byteorder(val: u64) -> Self where B: $crate::byteorder::ByteOrder, { let mut buf = [0x0; 8]; B::write_u64(&mut buf, val); let capped = $crate::core_::cmp::min(Self::len_bytes(), 8); let mut bytes = [0x0; $crate::core_::mem::size_of::()]; bytes[(Self::len_bytes() - capped)..].copy_from_slice(&buf[..capped]); Self::from_slice(&bytes) } /// Creates a new hash type from the given `u64` value. /// /// # Note /// /// - The given `u64` value is interpreted as big endian. /// - Ignores the most significant bits of the given value /// if the hash type has less than 8 bytes. #[inline] pub fn from_low_u64_be(val: u64) -> Self { Self::from_low_u64_with_byteorder::<$crate::byteorder::BigEndian>(val) } /// Creates a new hash type from the given `u64` value. /// /// # Note /// /// - The given `u64` value is interpreted as little endian. /// - Ignores the most significant bits of the given value /// if the hash type has less than 8 bytes. #[inline] pub fn from_low_u64_le(val: u64) -> Self { Self::from_low_u64_with_byteorder::<$crate::byteorder::LittleEndian>(val) } /// Creates a new hash type from the given `u64` value. /// /// # Note /// /// - The given `u64` value is interpreted as native endian. /// - Ignores the most significant bits of the given value /// if the hash type has less than 8 bytes. #[inline] pub fn from_low_u64_ne(val: u64) -> Self { Self::from_low_u64_with_byteorder::<$crate::byteorder::NativeEndian>(val) } } }; } // Implementation for disabled rand crate support. // // # Note // // Feature guarded macro definitions instead of feature guarded impl blocks // to work around the problems of introducing `rand` crate feature in // a user crate. #[cfg(not(feature = "rand"))] #[macro_export] #[doc(hidden)] macro_rules! impl_rand_for_fixed_hash { ( $name:ident ) => {}; } // Implementation for enabled rand crate support. // // # Note // // Feature guarded macro definitions instead of feature guarded impl blocks // to work around the problems of introducing `rand` crate feature in // a user crate. #[cfg(feature = "rand")] #[macro_export] #[doc(hidden)] macro_rules! impl_rand_for_fixed_hash { ( $name:ident ) => { impl $crate::rand::distributions::Distribution<$name> for $crate::rand::distributions::Standard { fn sample(&self, rng: &mut R) -> $name { let mut ret = $name::zero(); for byte in ret.as_bytes_mut().iter_mut() { *byte = rng.gen(); } ret } } /// Utilities using the `rand` crate. impl $name { /// Assign `self` to a cryptographically random value using the /// given random number generator. pub fn randomize_using(&mut self, rng: &mut R) where R: $crate::rand::Rng + ?Sized, { use $crate::rand::distributions::Distribution; *self = $crate::rand::distributions::Standard.sample(rng); } /// Assign `self` to a cryptographically random value. pub fn randomize(&mut self) { let mut rng = $crate::rand::rngs::OsRng; self.randomize_using(&mut rng); } /// Create a new hash with cryptographically random content using the /// given random number generator. pub fn random_using(rng: &mut R) -> Self where R: $crate::rand::Rng + ?Sized, { let mut ret = Self::zero(); ret.randomize_using(rng); ret } /// Create a new hash with cryptographically random content. pub fn random() -> Self { let mut hash = Self::zero(); hash.randomize(); hash } } }; } #[macro_export] #[doc(hidden)] macro_rules! impl_cmp_for_fixed_hash { ( $name:ident ) => { impl $crate::core_::cmp::PartialEq for $name { #[inline] fn eq(&self, other: &Self) -> bool { self.as_bytes() == other.as_bytes() } } impl $crate::core_::cmp::Ord for $name { #[inline] fn cmp(&self, other: &Self) -> $crate::core_::cmp::Ordering { self.as_bytes().cmp(other.as_bytes()) } } }; } // Implementation for disabled rustc-hex crate support. // // # Note // // Feature guarded macro definitions instead of feature guarded impl blocks // to work around the problems of introducing `rustc-hex` crate feature in // a user crate. #[cfg(not(feature = "rustc-hex"))] #[macro_export] #[doc(hidden)] macro_rules! impl_rustc_hex_for_fixed_hash { ( $name:ident ) => {}; } // Implementation for enabled rustc-hex crate support. // // # Note // // Feature guarded macro definitions instead of feature guarded impl blocks // to work around the problems of introducing `rustc-hex` crate feature in // a user crate. #[cfg(feature = "rustc-hex")] #[macro_export] #[doc(hidden)] macro_rules! impl_rustc_hex_for_fixed_hash { ( $name:ident ) => { impl $crate::core_::str::FromStr for $name { type Err = $crate::rustc_hex::FromHexError; /// Creates a hash type instance from the given string. /// /// # Note /// /// The given input string is interpreted in big endian. /// /// # Errors /// /// - When encountering invalid non hex-digits /// - Upon empty string input or invalid input length in general fn from_str(input: &str) -> $crate::core_::result::Result<$name, $crate::rustc_hex::FromHexError> { let input = input.strip_prefix("0x").unwrap_or(input); let mut iter = $crate::rustc_hex::FromHexIter::new(input); let mut result = Self::zero(); for byte in result.as_mut() { *byte = iter.next().ok_or(Self::Err::InvalidHexLength)??; } if iter.next().is_some() { return Err(Self::Err::InvalidHexLength) } Ok(result) } } }; } // Implementation for disabled quickcheck crate support. // // # Note // // Feature guarded macro definitions instead of feature guarded impl blocks // to work around the problems of introducing `quickcheck` crate feature in // a user crate. #[cfg(not(feature = "quickcheck"))] #[macro_export] #[doc(hidden)] macro_rules! impl_quickcheck_for_fixed_hash { ( $name:ident ) => {}; } // Implementation for enabled quickcheck crate support. // // # Note // // Feature guarded macro definitions instead of feature guarded impl blocks // to work around the problems of introducing `quickcheck` crate feature in // a user crate. #[cfg(feature = "quickcheck")] #[macro_export] #[doc(hidden)] macro_rules! impl_quickcheck_for_fixed_hash { ( $name:ident ) => { impl $crate::quickcheck::Arbitrary for $name { fn arbitrary(g: &mut $crate::quickcheck::Gen) -> Self { let res: [u8; Self::len_bytes()] = $crate::core_::array::from_fn(|_| u8::arbitrary(g)); Self::from(res) } } }; } // When the `arbitrary` feature is disabled. // // # Note // // Feature guarded macro definitions instead of feature guarded impl blocks // to work around the problems of introducing `arbitrary` crate feature in // a user crate. #[cfg(not(feature = "arbitrary"))] #[macro_export] #[doc(hidden)] macro_rules! impl_arbitrary_for_fixed_hash { ( $name:ident ) => {}; } // When the `arbitrary` feature is enabled. // // # Note // // Feature guarded macro definitions instead of feature guarded impl blocks // to work around the problems of introducing `arbitrary` crate feature in // a user crate. #[cfg(feature = "arbitrary")] #[macro_export] #[doc(hidden)] macro_rules! impl_arbitrary_for_fixed_hash { ( $name:ident ) => { impl $crate::arbitrary::Arbitrary<'_> for $name { fn arbitrary(u: &mut $crate::arbitrary::Unstructured<'_>) -> $crate::arbitrary::Result { let mut res = Self::zero(); u.fill_buffer(&mut res.0)?; Ok(Self::from(res)) } } }; } #[macro_export] #[doc(hidden)] macro_rules! impl_ops_for_hash { ( $impl_for:ident, $ops_trait_name:ident, $ops_fn_name:ident, $ops_assign_trait_name:ident, $ops_assign_fn_name:ident, $ops_tok:tt, $ops_assign_tok:tt ) => { impl<'r> $crate::core_::ops::$ops_assign_trait_name<&'r $impl_for> for $impl_for { fn $ops_assign_fn_name(&mut self, rhs: &'r $impl_for) { for (lhs, rhs) in self.as_bytes_mut().iter_mut().zip(rhs.as_bytes()) { *lhs $ops_assign_tok rhs; } } } impl $crate::core_::ops::$ops_assign_trait_name<$impl_for> for $impl_for { #[inline] fn $ops_assign_fn_name(&mut self, rhs: $impl_for) { *self $ops_assign_tok &rhs; } } impl<'l, 'r> $crate::core_::ops::$ops_trait_name<&'r $impl_for> for &'l $impl_for { type Output = $impl_for; fn $ops_fn_name(self, rhs: &'r $impl_for) -> Self::Output { let mut ret = self.clone(); ret $ops_assign_tok rhs; ret } } impl $crate::core_::ops::$ops_trait_name<$impl_for> for $impl_for { type Output = $impl_for; #[inline] fn $ops_fn_name(self, rhs: Self) -> Self::Output { &self $ops_tok &rhs } } }; } /// Implements lossy conversions between the given types. /// /// # Note /// /// - Both types must be of different sizes. /// - Type `large_ty` must have a larger memory footprint compared to `small_ty`. /// /// # Panics /// /// Both `From` implementations will panic if sizes of the given types /// do not meet the requirements stated above. /// /// # Example /// /// ``` /// use fixed_hash::{construct_fixed_hash, impl_fixed_hash_conversions}; /// construct_fixed_hash!{ struct H160(20); } /// construct_fixed_hash!{ struct H256(32); } /// impl_fixed_hash_conversions!(H256, H160); /// // now use it! /// assert_eq!(H256::from(H160::zero()), H256::zero()); /// assert_eq!(H160::from(H256::zero()), H160::zero()); /// ``` #[macro_export(local_inner_macros)] macro_rules! impl_fixed_hash_conversions { ($large_ty:ident, $small_ty:ident) => { $crate::static_assertions::const_assert!( $crate::core_::mem::size_of::<$small_ty>() < $crate::core_::mem::size_of::<$large_ty>() ); impl From<$small_ty> for $large_ty { fn from(value: $small_ty) -> $large_ty { let large_ty_size = $large_ty::len_bytes(); let small_ty_size = $small_ty::len_bytes(); $crate::core_::debug_assert!( large_ty_size > small_ty_size && large_ty_size % 2 == 0 && small_ty_size % 2 == 0 ); let mut ret = $large_ty::zero(); ret.as_bytes_mut()[(large_ty_size - small_ty_size)..large_ty_size].copy_from_slice(value.as_bytes()); ret } } impl From<$large_ty> for $small_ty { fn from(value: $large_ty) -> $small_ty { let large_ty_size = $large_ty::len_bytes(); let small_ty_size = $small_ty::len_bytes(); $crate::core_::debug_assert!( large_ty_size > small_ty_size && large_ty_size % 2 == 0 && small_ty_size % 2 == 0 ); let mut ret = $small_ty::zero(); ret.as_bytes_mut() .copy_from_slice(&value[(large_ty_size - small_ty_size)..large_ty_size]); ret } } }; } fixed-hash-0.8.0/src/lib.rs000064400000000000000000000031001046102023000135460ustar 00000000000000// Copyright 2020 Parity Technologies // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![cfg_attr(not(feature = "std"), no_std)] // Re-export liballoc using an alias so that the macros can work without // requiring `extern crate alloc` downstream. #[doc(hidden)] pub extern crate alloc as alloc_; // Re-export libcore using an alias so that the macros can work without // requiring `use core` downstream. #[doc(hidden)] pub use core as core_; // This disables a warning for unused #[macro_use(..)] // which is incorrect since the compiler does not check // for all available configurations. #[allow(unused_imports)] #[doc(hidden)] pub use static_assertions; // Export `const_assert` macro so that users of this crate do not // have to import the `static_assertions` crate themselves. #[doc(hidden)] pub use static_assertions::const_assert; #[cfg(feature = "byteorder")] #[doc(hidden)] pub use byteorder; #[cfg(feature = "rustc-hex")] #[doc(hidden)] pub use rustc_hex; #[cfg(feature = "rand")] #[doc(hidden)] pub use rand; #[cfg(feature = "quickcheck")] #[doc(hidden)] pub use quickcheck; #[cfg(feature = "arbitrary")] #[doc(hidden)] pub use arbitrary; #[macro_use] mod hash; #[cfg(test)] mod tests; #[cfg(feature = "api-dummy")] construct_fixed_hash! { /// Go here for an overview of the hash type API. pub struct ApiDummy(32); } fixed-hash-0.8.0/src/tests.rs000064400000000000000000000221001046102023000141430ustar 00000000000000// Copyright 2020 Parity Technologies // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. construct_fixed_hash! { pub struct H32(4); } construct_fixed_hash! { pub struct H64(8); } construct_fixed_hash! { pub struct H128(16); } construct_fixed_hash! { pub struct H160(20); } construct_fixed_hash! { pub struct H256(32); } impl_fixed_hash_conversions!(H256, H160); mod repeat_byte { use super::*; #[test] fn patterns() { assert_eq!(H32::repeat_byte(0xFF), H32::from([0xFF; 4])); assert_eq!(H32::repeat_byte(0xAA), H32::from([0xAA; 4])); } #[test] fn zero() { assert_eq!(H32::repeat_byte(0x0), H32::zero()); assert_eq!(H32::repeat_byte(0x0), H32::from([0x0; 4])); } } #[test] fn len_bytes() { assert_eq!(H32::len_bytes(), 4); assert_eq!(H64::len_bytes(), 8); assert_eq!(H128::len_bytes(), 16); assert_eq!(H160::len_bytes(), 20); assert_eq!(H256::len_bytes(), 32); } #[test] fn as_bytes() { assert_eq!(H32::from([0x55; 4]).as_bytes(), &[0x55; 4]); assert_eq!(H32::from([0x42; 4]).as_bytes_mut(), &mut [0x42; 4]); } mod assign_from_slice { use super::*; #[test] fn zeros_to_ones() { assert_eq!(H32::from([0xFF; 4]), { let mut cmp = H32::zero(); cmp.assign_from_slice(&[0xFF; 4]); cmp }); } #[test] #[should_panic] fn fail_too_few_elems() { let mut dummy = H32::zero(); dummy.assign_from_slice(&[0x42; 3]); } #[test] #[should_panic] fn fail_too_many_elems() { let mut dummy = H32::zero(); dummy.assign_from_slice(&[0x42; 5]); } } mod from_slice { use super::*; #[test] fn simple() { assert_eq!(H32::from([0x10; 4]), H32::from_slice(&[0x10; 4])); } #[test] #[should_panic] fn fail_too_few_elems() { H32::from_slice(&[0x10; 3]); } #[test] #[should_panic] fn fail_too_many_elems() { H32::from_slice(&[0x10; 5]); } } mod covers { use super::*; #[test] fn simple() { assert!(H32::from([0xFF; 4]).covers(&H32::zero())); assert!(!(H32::zero().covers(&H32::from([0xFF; 4])))); } #[test] fn zero_covers_zero() { assert!(H32::zero().covers(&H32::zero())); } #[test] fn ones_covers_ones() { assert!(H32::from([0xFF; 4]).covers(&H32::from([0xFF; 4]))); } #[test] fn complex_covers() { #[rustfmt::skip] assert!( H32::from([0b0110_0101, 0b1000_0001, 0b1010_1010, 0b0110_0011]).covers(& H32::from([0b0010_0100, 0b1000_0001, 0b0010_1010, 0b0110_0010])) ); } #[test] fn complex_uncovers() { #[rustfmt::skip] assert!( !( H32::from([0b0010_0100, 0b1000_0001, 0b0010_1010, 0b0110_0010]).covers(& H32::from([0b0110_0101, 0b1000_0001, 0b1010_1010, 0b0110_0011])) ) ); } } mod is_zero { use super::*; #[test] fn all_true() { assert!(H32::zero().is_zero()); assert!(H64::zero().is_zero()); assert!(H128::zero().is_zero()); assert!(H160::zero().is_zero()); assert!(H256::zero().is_zero()); } #[test] fn all_false() { assert!(!H32::repeat_byte(42).is_zero()); assert!(!H64::repeat_byte(42).is_zero()); assert!(!H128::repeat_byte(42).is_zero()); assert!(!H160::repeat_byte(42).is_zero()); assert!(!H256::repeat_byte(42).is_zero()); } } #[cfg(feature = "byteorder")] mod to_low_u64 { use super::*; #[test] fn smaller_size() { assert_eq!(H32::from([0x01, 0x23, 0x45, 0x67]).to_low_u64_be(), 0x0123_4567); assert_eq!(H32::from([0x01, 0x23, 0x45, 0x67]).to_low_u64_le(), 0x6745_2301_0000_0000); } #[test] fn equal_size() { assert_eq!(H64::from([0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]).to_low_u64_le(), 0xEFCD_AB89_6745_2301); assert_eq!(H64::from([0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]).to_low_u64_be(), 0x0123_4567_89AB_CDEF) } #[test] #[rustfmt::skip] fn larger_size() { assert_eq!( H128::from([ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02 ]).to_low_u64_be(), 0x0908070605040302 ); assert_eq!( H128::from([ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02 ]).to_low_u64_le(), 0x0203040506070809 ) } } #[cfg(feature = "byteorder")] mod from_low_u64 { use super::*; #[test] fn smaller_size() { assert_eq!(H32::from_low_u64_be(0x0123_4567_89AB_CDEF), H32::from([0x01, 0x23, 0x45, 0x67])); assert_eq!(H32::from_low_u64_le(0x0123_4567_89AB_CDEF), H32::from([0xEF, 0xCD, 0xAB, 0x89])); } #[test] fn equal_size() { assert_eq!( H64::from_low_u64_be(0x0123_4567_89AB_CDEF), H64::from([0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]) ); assert_eq!( H64::from_low_u64_le(0x0123_4567_89AB_CDEF), H64::from([0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01]) ) } #[test] #[rustfmt::skip] fn larger_size() { assert_eq!( H128::from_low_u64_be(0x0123_4567_89AB_CDEF), H128::from([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF ]) ); assert_eq!( H128::from_low_u64_le(0x0123_4567_89AB_CDEF), H128::from([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01 ]) ) } } #[cfg(feature = "rand")] mod rand { use super::*; use ::rand::{rngs::StdRng, SeedableRng}; #[test] fn random() { let mut rng = StdRng::seed_from_u64(123); assert_eq!(H32::random_using(&mut rng), H32::from([0xeb, 0x96, 0xaf, 0x1c])); } } #[cfg(feature = "rustc-hex")] mod from_str { use super::*; #[test] fn valid() { use crate::core_::str::FromStr; assert_eq!( H64::from_str("0123456789ABCDEF").unwrap(), H64::from([0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]) ) } #[test] fn empty_str() { use crate::core_::str::FromStr; assert!(H64::from_str("").is_err()) } #[test] fn invalid_digits() { use crate::core_::str::FromStr; assert!(H64::from_str("Hello, World!").is_err()) } #[test] fn too_many_digits() { use crate::core_::str::FromStr; assert!(H64::from_str("0123456789ABCDEF0").is_err()) } } #[test] fn from_h160_to_h256() { let h160 = H160::from([ 0xEF, 0x2D, 0x6D, 0x19, 0x40, 0x84, 0xC2, 0xDE, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, ]); let h256 = H256::from(h160); let expected = H256::from([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x2D, 0x6D, 0x19, 0x40, 0x84, 0xC2, 0xDE, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, ]); assert_eq!(h256, expected); } #[test] #[rustfmt::skip] fn from_h256_to_h160_lossless() { let h256 = H256::from([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x2D, 0x6D, 0x19, 0x40, 0x84, 0xC2, 0xDE, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, ]); let h160 = H160::from(h256); let expected = H160::from([ 0xEF, 0x2D, 0x6D, 0x19, 0x40, 0x84, 0xC2, 0xDE, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, ]); assert_eq!(h160, expected); } #[test] #[rustfmt::skip] fn from_h256_to_h160_lossy() { let h256 = H256::from([ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x2D, 0x6D, 0x19, 0x40, 0x84, 0xC2, 0xDE, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, ]); let h160 = H160::from(h256); let expected = H160::from([ 0xEF, 0x2D, 0x6D, 0x19, 0x40, 0x84, 0xC2, 0xDE, 0x36, 0xE0, 0xDA, 0xBF, 0xCE, 0x45, 0xD0, 0x46, 0xB3, 0x7D, 0x11, 0x06, ]); assert_eq!(h160, expected); } #[cfg(all(feature = "std", feature = "byteorder"))] #[test] fn display_and_debug() { fn test_for(x: u64, hex: &'static str, display: &'static str) { let hash = H64::from_low_u64_be(x); assert_eq!(format!("{}", hash), format!("0x{}", display)); assert_eq!(format!("{:?}", hash), format!("0x{}", hex)); assert_eq!(format!("{:x}", hash), hex); assert_eq!(format!("{:#x}", hash), format!("0x{}", hex)); } test_for(0x0001, "0000000000000001", "0000…0001"); test_for(0x000f, "000000000000000f", "0000…000f"); test_for(0x0010, "0000000000000010", "0000…0010"); test_for(0x00ff, "00000000000000ff", "0000…00ff"); test_for(0x0100, "0000000000000100", "0000…0100"); test_for(0x0fff, "0000000000000fff", "0000…0fff"); test_for(0x1000, "0000000000001000", "0000…1000"); } mod ops { use super::*; fn lhs() -> H32 { H32::from([0b0011_0110, 0b0001_0011, 0b1010_1010, 0b0001_0010]) } fn rhs() -> H32 { H32::from([0b0101_0101, 0b1111_1111, 0b1100_1100, 0b0000_1111]) } #[test] fn bitand() { assert_eq!( lhs() & rhs(), H32::from([ 0b0011_0110 & 0b0101_0101, 0b0001_0011 & 0b1111_1111, 0b1010_1010 & 0b1100_1100, 0b0001_0010 & 0b0000_1111 ]) ) } #[test] fn bitor() { assert_eq!( lhs() | rhs(), H32::from([ 0b0011_0110 | 0b0101_0101, 0b0001_0011 | 0b1111_1111, 0b1010_1010 | 0b1100_1100, 0b0001_0010 | 0b0000_1111 ]) ) } #[test] fn bitxor() { assert_eq!( lhs() ^ rhs(), H32::from([ 0b0011_0110 ^ 0b0101_0101, 0b0001_0011 ^ 0b1111_1111, 0b1010_1010 ^ 0b1100_1100, 0b0001_0010 ^ 0b0000_1111 ]) ) } }