diff --git a/ethbloom/Cargo.toml b/ethbloom/Cargo.toml index 038378a64..1f2de0a62 100644 --- a/ethbloom/Cargo.toml +++ b/ethbloom/Cargo.toml @@ -26,6 +26,7 @@ default = ["std", "serialize", "rustc-hex"] std = ["fixed-hash/std", "crunchy/std"] serialize = ["std", "impl-serde"] rustc-hex = ["fixed-hash/rustc-hex"] +arbitrary = ["fixed-hash/arbitrary"] [[bench]] name = "bloom" diff --git a/ethereum-types/Cargo.toml b/ethereum-types/Cargo.toml index b04c87bbd..8d9dc0739 100644 --- a/ethereum-types/Cargo.toml +++ b/ethereum-types/Cargo.toml @@ -22,3 +22,4 @@ serde_json = "1.0.41" default = ["std", "serialize"] std = ["uint-crate/std", "fixed-hash/std", "ethbloom/std", "primitive-types/std"] serialize = ["std", "impl-serde", "primitive-types/serde", "ethbloom/serialize"] +arbitrary = ["ethbloom/arbitrary", "fixed-hash/arbitrary", "uint-crate/arbitrary"] diff --git a/fixed-hash/Cargo.toml b/fixed-hash/Cargo.toml index 93903ef7d..33fd076a0 100644 --- a/fixed-hash/Cargo.toml +++ b/fixed-hash/Cargo.toml @@ -19,6 +19,7 @@ quickcheck = { version = "0.9.0", optional = true } rand = { version = "0.7.2", optional = true, default-features = false } rustc-hex = { version = "2.0.1", optional = true, default-features = false } static_assertions = "1.0.0" +arbitrary = { version = "0.4", optional = true } [dev-dependencies] rand_xorshift = "0.2.0" diff --git a/fixed-hash/README.md b/fixed-hash/README.md index c07db2f23..1974bea8f 100644 --- a/fixed-hash/README.md +++ b/fixed-hash/README.md @@ -64,3 +64,5 @@ fixed-hash = { version = "0.3", default-features = false } - 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. diff --git a/fixed-hash/src/hash.rs b/fixed-hash/src/hash.rs index e7fdf0e4c..972b750b4 100644 --- a/fixed-hash/src/hash.rs +++ b/fixed-hash/src/hash.rs @@ -316,6 +316,7 @@ macro_rules! construct_fixed_hash { 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); } } @@ -636,6 +637,42 @@ macro_rules! impl_quickcheck_for_fixed_hash { }; } +// 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 { diff --git a/fixed-hash/src/lib.rs b/fixed-hash/src/lib.rs index 748101c9f..228f551e0 100644 --- a/fixed-hash/src/lib.rs +++ b/fixed-hash/src/lib.rs @@ -46,6 +46,10 @@ pub use rand; #[doc(hidden)] pub use quickcheck; +#[cfg(feature = "arbitrary")] +#[doc(hidden)] +pub use arbitrary; + #[macro_use] mod hash; diff --git a/primitive-types/Cargo.toml b/primitive-types/Cargo.toml index 06e6e154d..fcbdc4e63 100644 --- a/primitive-types/Cargo.toml +++ b/primitive-types/Cargo.toml @@ -22,3 +22,4 @@ rustc-hex = ["fixed-hash/rustc-hex"] serde = ["std", "impl-serde"] codec = ["impl-codec"] rlp = ["impl-rlp"] +arbitrary = ["fixed-hash/arbitrary", "uint/arbitrary"] diff --git a/uint/Cargo.toml b/uint/Cargo.toml index 257b3fa7f..97d489884 100644 --- a/uint/Cargo.toml +++ b/uint/Cargo.toml @@ -16,6 +16,7 @@ qc = { package = "quickcheck", version = "0.9.0", optional = true } rand = { version = "0.7.2", default-features = false, optional = true } rustc-hex = { version = "2.0.1", default-features = false } static_assertions = "1.0.0" +arbitrary = { version = "0.4", optional = true } [features] default = ["std"] diff --git a/uint/README.md b/uint/README.md index 557d63991..34006f83d 100644 --- a/uint/README.md +++ b/uint/README.md @@ -69,3 +69,5 @@ see fuzz [README.md](fuzz/README.md) - Enabled by default. - `quickcheck`: Enable quickcheck-style property testing - Use with `cargo test --release --features=quickcheck`. +- `arbitrary`: Allow for creation of an `uint` object from random unstructured input for use with fuzzers that use the `arbitrary` crate. + - Disabled by default. diff --git a/uint/src/lib.rs b/uint/src/lib.rs index 144c53e32..7da1f24a5 100644 --- a/uint/src/lib.rs +++ b/uint/src/lib.rs @@ -29,6 +29,10 @@ pub use qc; #[doc(hidden)] pub use rand; +#[cfg(feature = "arbitrary")] +#[doc(hidden)] +pub use arbitrary; + #[doc(hidden)] pub use static_assertions; diff --git a/uint/src/uint.rs b/uint/src/uint.rs index 493e2e21e..26b633416 100644 --- a/uint/src/uint.rs +++ b/uint/src/uint.rs @@ -1554,6 +1554,7 @@ macro_rules! construct_uint { // `$n_words * 8` because macro expects bytes and // uints use 64 bit (8 byte) words $crate::impl_quickcheck_arbitrary_for_uint!($name, ($n_words * 8)); + $crate::impl_arbitrary_for_uint!($name, ($n_words * 8)); } } @@ -1632,3 +1633,26 @@ macro_rules! impl_quickcheck_arbitrary_for_uint { macro_rules! impl_quickcheck_arbitrary_for_uint { ($uint: ty, $n_bytes: tt) => {}; } + + +#[cfg(feature = "arbitrary")] +#[macro_export] +#[doc(hidden)] +macro_rules! impl_arbitrary_for_uint { + ($uint: ty, $n_bytes: tt) => { + impl $crate::arbitrary::Arbitrary for $uint { + fn arbitrary(u: &mut $crate::arbitrary::Unstructured<'_>) -> $crate::arbitrary::Result { + let mut res = [0u8; $n_bytes]; + u.fill_buffer(&mut res)?; + Ok(Self::from(res)) + } + } + }; +} + +#[cfg(not(feature = "arbitrary"))] +#[macro_export] +#[doc(hidden)] +macro_rules! impl_arbitrary_for_uint { + ($uint: ty, $n_bytes: tt) => {}; +}