diff --git a/Cargo.toml b/Cargo.toml index fae49aaeac..aeb9ba97bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Alloy Contributors"] license = "MIT OR Apache-2.0" homepage = "https://github.com/alloy-rs/core" repository = "https://github.com/alloy-rs/core" -exclude = ["benches/", "tests/"] +exclude = ["tests"] [workspace.metadata.docs.rs] all-features = true @@ -46,6 +46,9 @@ strum = { version = "0.25", features = ["derive"] } num_enum = "0.7" thiserror = "1.0" +keccak-asm = { version = "0.1.0", default-features = false } +tiny-keccak = "2.0" + # misc alloy-rlp = { version = "0.3", default-features = false } alloy-rlp-derive = { version = "0.3", default-features = false } @@ -65,6 +68,5 @@ proptest-derive = "0.4" rand = { version = "0.8", default-features = false } ruint = { version = "1.11.1", default-features = false, features = ["alloc"] } ruint-macro = { version = "1", default-features = false } -tiny-keccak = "2.0" winnow = { version = "0.5.19", default-features = false, features = ["alloc"] } postgres-types = "0.2.6" diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 56d60af5d6..b7682f72d5 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -24,6 +24,7 @@ hex.workspace = true itoa.workspace = true ruint.workspace = true tiny-keccak = { workspace = true, features = ["keccak"] } +keccak-asm = { workspace = true, optional = true } # macros derive_more.workspace = true @@ -65,6 +66,7 @@ std = [ "hex/std", "ruint/std", "alloy-rlp?/std", + "keccak-asm?/std", "proptest?/std", "rand?/std", "serde?/std", @@ -72,6 +74,7 @@ std = [ postgres = ["dep:postgres-types", "std", "ruint/postgres"] tiny-keccak = [] native-keccak = [] +asm-keccak = ["dep:keccak-asm"] getrandom = ["dep:getrandom"] rand = ["dep:rand", "getrandom", "ruint/rand"] rlp = ["dep:alloy-rlp", "ruint/alloy-rlp"] @@ -93,7 +96,7 @@ arbitrary = [ hex-compat = ["hex/hex"] [[bench]] -name = "address" -path = "benches/address.rs" +name = "primitives" +path = "benches/primitives.rs" harness = false required-features = ["rand"] diff --git a/crates/primitives/benches/address.rs b/crates/primitives/benches/address.rs deleted file mode 100644 index f46d4922ce..0000000000 --- a/crates/primitives/benches/address.rs +++ /dev/null @@ -1,18 +0,0 @@ -use alloy_primitives::Address; -use criterion::{criterion_group, criterion_main, Criterion}; -use std::hint::black_box; - -fn address(c: &mut Criterion) { - let mut g = c.benchmark_group("address"); - g.bench_function("checksum", |b| { - let address = Address::random(); - let out = &mut [0u8; 42]; - b.iter(|| { - let x = address.to_checksum_raw(black_box(out), None); - black_box(x); - }) - }); -} - -criterion_group!(benches, address); -criterion_main!(benches); diff --git a/crates/primitives/benches/primitives.rs b/crates/primitives/benches/primitives.rs new file mode 100644 index 0000000000..f45c2418a3 --- /dev/null +++ b/crates/primitives/benches/primitives.rs @@ -0,0 +1,28 @@ +use alloy_primitives::{keccak256, Address, B256}; +use criterion::{criterion_group, criterion_main, Criterion}; +use std::hint::black_box; + +fn primitives(c: &mut Criterion) { + let mut g = c.benchmark_group("primitives"); + g.bench_function("address/checksum", |b| { + let address = Address::random(); + let out = &mut [0u8; 42]; + b.iter(|| { + let x = address.to_checksum_raw(black_box(out), None); + black_box(x); + }) + }); + g.bench_function("keccak256/32", |b| { + let mut out = B256::random(); + b.iter(|| { + for _ in 0..10 { + out = keccak256(out); + } + black_box(&out); + }); + }); + g.finish(); +} + +criterion_group!(benches, primitives); +criterion_main!(benches); diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 4dd4b4f70d..72014b4a27 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -62,6 +62,10 @@ pub use { tiny_keccak::{self, Hasher, Keccak}, }; +#[cfg(feature = "asm-keccak")] +#[doc(no_inline)] +pub use keccak_asm::{self, digest, Keccak256}; + /// Re-export of [`ruint::uint!`] for convenience. Note that users of this macro /// must also add [`ruint`] to their `Cargo.toml` as a dependency. #[doc(inline)] diff --git a/crates/primitives/src/utils/mod.rs b/crates/primitives/src/utils/mod.rs index 74fd0d3bd7..0075d3958a 100644 --- a/crates/primitives/src/utils/mod.rs +++ b/crates/primitives/src/utils/mod.rs @@ -62,7 +62,7 @@ pub fn keccak256>(bytes: T) -> B256 { let mut output = MaybeUninit::::uninit(); cfg_if::cfg_if! { - if #[cfg(all(feature = "native-keccak", not(feature = "tiny-keccak")))] { + if #[cfg(all(feature = "native-keccak", not(feature = "tiny-keccak"), not(miri)))] { #[link(wasm_import_module = "vm_hooks")] extern "C" { /// When targeting VMs with native keccak hooks, the `native-keccak` feature @@ -83,14 +83,21 @@ pub fn keccak256>(bytes: T) -> B256 { } // SAFETY: The output is 32-bytes, and the input comes from a slice. - unsafe { native_keccak256(bytes.as_ptr(), bytes.len(), output.as_mut_ptr().cast()) }; + unsafe { native_keccak256(bytes.as_ptr(), bytes.len(), output.as_mut_ptr().cast::()) }; + } else if #[cfg(all(feature = "asm-keccak", not(miri)))] { + use keccak_asm::{digest::Digest, Keccak256}; + + let mut hasher = Keccak256::new(); + hasher.update(bytes); + // SAFETY: Never reads from `output`. + hasher.finalize_into(unsafe { (&mut (*output.as_mut_ptr()).0).into() }); } else { use tiny_keccak::{Hasher, Keccak}; let mut hasher = Keccak::v256(); hasher.update(bytes); // SAFETY: Never reads from `output`. - hasher.finalize(unsafe { (*output.as_mut_ptr()).as_mut_slice() }); + hasher.finalize(unsafe { &mut (*output.as_mut_ptr()).0 }); } }