Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ categories = ["cryptography::cryptocurrencies"]
rust-version = "1.83.0"

[dependencies]
spin = { version = "0.9", default-features = false, features = ["lazy", "once"], optional = true }
ring = { version = "0.17", optional = true }
sha2 = { version = "0.10", optional = true }
sha2 = { version = "0.10", default-features = false, optional = true }

[target.'cfg(target_arch = "x86_64")'.dependencies]
cpufeatures = "0.2"
sha2 = "0.10"
sha2 = { version = "0.10", default-features = false }

[dev-dependencies]
rustc-hex = "2"
Expand All @@ -26,8 +27,10 @@ rustc-hex = "2"
wasm-bindgen-test = "0.3.33"

[features]
default = ["zero_hash_cache", "ring"]
zero_hash_cache = []
default = ["std", "zero_hash_cache", "ring"]
std = ["sha2?/std", "ring?/std"]
# spin backs the zero hash cache only under no_std; std builds use std::sync::LazyLock.
zero_hash_cache = ["dep:spin"]
ring = ["dep:ring"]
sha2 = ["dep:sha2"]
# Enable ring's WASM support (wasm32-unknown-unknown target).
Expand Down
40 changes: 25 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@
//! Now this crate serves primarily as a wrapper over two SHA256 crates: `sha2` and `ring` – which
//! it switches between at runtime based on the availability of SHA intrinsics.

#![cfg_attr(not(feature = "std"), no_std)]

// Selecting a backend is the consumer's choice, so say so once and clearly rather than letting
// the failure surface as cascading type errors from an empty `DynamicImpl`.
#[cfg(all(
not(feature = "ring"),
not(feature = "sha2"),
not(target_arch = "x86_64")
))]
compile_error!(
"ethereum_hashing needs a sha256 backend: enable the `sha2` feature (portable, required for \
wasm) or the `ring` feature. With --no-default-features neither is on by default."
);

extern crate alloc;

use alloc::{vec, vec::Vec};

#[cfg(test)]
mod tests;

Expand All @@ -17,8 +35,12 @@ pub use self::DynamicContext as Context;
#[cfg(any(target_arch = "x86_64", feature = "sha2"))]
use sha2_impl::Sha2CrateImpl;

#[cfg(feature = "zero_hash_cache")]
use std::sync::LazyLock;
#[cfg(all(feature = "zero_hash_cache", feature = "std"))]
use std::sync::LazyLock as Lazy;
// `spin` only where there is no `std::sync`: a spin lock is strictly worse under contention, so
// std builds keep the futex backed one.
#[cfg(all(feature = "zero_hash_cache", not(feature = "std")))]
use spin::Lazy;

/// Length of a SHA256 hash in bytes.
pub const HASH_LEN: usize = 32;
Expand Down Expand Up @@ -151,18 +173,6 @@ impl DynamicImpl {
{
Self::Ring
}

// Compile error if no implementation available
#[cfg(all(
not(feature = "ring"),
not(target_arch = "x86_64"),
not(feature = "sha2")
))]
{
compile_error!(
"Either 'ring' or 'sha2' feature must be enabled on non-x86_64 architectures"
);
}
}
}

Expand Down Expand Up @@ -235,7 +245,7 @@ pub const ZERO_HASHES_MAX_INDEX: usize = 48;

#[cfg(feature = "zero_hash_cache")]
/// Cached zero hashes where `ZERO_HASHES[i]` is the hash of a Merkle tree with 2^i zero leaves.
pub static ZERO_HASHES: LazyLock<Vec<[u8; HASH_LEN]>> = LazyLock::new(|| {
pub static ZERO_HASHES: Lazy<Vec<[u8; HASH_LEN]>> = Lazy::new(|| {
let mut hashes = vec![[0; HASH_LEN]; ZERO_HASHES_MAX_INDEX + 1];

for i in 0..ZERO_HASHES_MAX_INDEX {
Expand Down
1 change: 1 addition & 0 deletions src/sha2_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#![cfg(any(target_arch = "x86_64", feature = "sha2"))]

use crate::{Sha256, Sha256Context, HASH_LEN};
use alloc::vec::Vec;
use sha2::Digest;

/// Implementation of SHA256 using the `sha2` crate (fastest on x86_64 CPUs with SHA extensions).
Expand Down