Ethereum hashing

This commit is contained in:
Michael Sproul
2023-01-16 17:27:10 +11:00
parent 69bdd1d61f
commit 1ee4514b7d
31 changed files with 27 additions and 305 deletions

View File

@@ -57,7 +57,6 @@ members = [
"consensus/swap_or_not_shuffle",
"crypto/bls",
"crypto/eth2_hashing",
"crypto/eth2_key_derivation",
"crypto/eth2_keystore",
"crypto/eth2_wallet",

View File

@@ -30,7 +30,7 @@ serde_derive = "1.0.116"
slog = { version = "2.5.2", features = ["max_level_trace"] }
sloggers = { version = "2.1.1", features = ["json"] }
slot_clock = { path = "../../common/slot_clock" }
eth2_hashing = "0.3.0"
ethereum_hashing = "1.0.0-beta.2"
ethereum_ssz = "1.0.0-beta.2"
ssz_types = "1.0.0-beta.0"
ethereum_ssz_derive = "1.0.0-beta.2"

View File

@@ -992,7 +992,7 @@ fn descriptive_db_error(item: &str, error: &StoreError) -> String {
mod test {
use super::*;
use crate::validator_monitor::DEFAULT_INDIVIDUAL_TRACKING_THRESHOLD;
use eth2_hashing::hash;
use ethereum_hashing::hash;
use genesis::{
generate_deterministic_keypairs, interop_genesis_state, DEFAULT_ETH1_BLOCK_HASH,
};

View File

@@ -1,7 +1,7 @@
use crate::metrics;
use eth1::{Config as Eth1Config, Eth1Block, Service as HttpService};
use eth2::lighthouse::Eth1SyncStatusData;
use eth2_hashing::hash;
use ethereum_hashing::hash;
use int_to_bytes::int_to_bytes32;
use slog::{debug, error, trace, Logger};
use ssz::{Decode, Encode};

View File

@@ -17,7 +17,7 @@ rayon = "1.4.1"
state_processing = { path = "../../consensus/state_processing" }
merkle_proof = { path = "../../consensus/merkle_proof" }
ethereum_ssz = "1.0.0-beta.2"
eth2_hashing = "0.3.0"
ethereum_hashing = "1.0.0-beta.2"
tree_hash = "1.0.0-beta.0"
tokio = { version = "1.14.0", features = ["full"] }
slog = "2.5.2"

View File

@@ -1,5 +1,5 @@
use crate::common::genesis_deposits;
use eth2_hashing::hash;
use ethereum_hashing::hash;
use rayon::prelude::*;
use ssz::Encode;
use state_processing::initialize_beacon_state_from_eth1;

View File

@@ -9,7 +9,7 @@ edition = "2021"
[dependencies]
lazy_static = "1.4.0"
num-bigint = "0.4.2"
eth2_hashing = "0.3.0"
ethereum_hashing = "1.0.0-beta.2"
hex = "0.4.2"
serde_yaml = "0.8.13"
serde = "1.0.116"

View File

@@ -20,7 +20,7 @@
extern crate lazy_static;
use bls::{Keypair, PublicKey, SecretKey};
use eth2_hashing::hash;
use ethereum_hashing::hash;
use num_bigint::BigUint;
use serde_derive::{Deserialize, Serialize};
use std::convert::TryInto;

View File

@@ -7,7 +7,7 @@ edition = "2021"
[dependencies]
ethereum-types = "0.14.1"
ssz_types = "1.0.0-beta.0"
eth2_hashing = "0.3.0"
ethereum_hashing = "1.0.0-beta.2"
ethereum_ssz_derive = "1.0.0-beta.2"
ethereum_ssz = "1.0.0-beta.2"
tree_hash = "1.0.0-beta.0"

View File

@@ -1,7 +1,7 @@
use crate::cache_arena;
use crate::SmallVec8;
use crate::{Error, Hash256};
use eth2_hashing::{hash32_concat, ZERO_HASHES};
use ethereum_hashing::{hash32_concat, ZERO_HASHES};
use smallvec::smallvec;
use ssz_derive::{Decode, Encode};
use tree_hash::BYTES_PER_CHUNK;

View File

@@ -1,6 +1,6 @@
use crate::impls::hash256_iter;
use crate::{CacheArena, CachedTreeHash, Error, Hash256, TreeHashCache};
use eth2_hashing::ZERO_HASHES;
use ethereum_hashing::ZERO_HASHES;
use quickcheck_macros::quickcheck;
use ssz_types::{
typenum::{Unsigned, U16, U255, U256, U257},

View File

@@ -6,7 +6,7 @@ edition = "2021"
[dependencies]
ethereum-types = "0.14.1"
eth2_hashing = "0.3.0"
ethereum_hashing = "1.0.0-beta.2"
lazy_static = "1.4.0"
safe_arith = { path = "../safe_arith" }

View File

@@ -1,4 +1,4 @@
use eth2_hashing::{hash, hash32_concat, ZERO_HASHES};
use ethereum_hashing::{hash, hash32_concat, ZERO_HASHES};
use ethereum_types::H256;
use lazy_static::lazy_static;
use safe_arith::ArithError;

View File

@@ -21,7 +21,7 @@ safe_arith = { path = "../safe_arith" }
tree_hash = "1.0.0-beta.0"
types = { path = "../types", default-features = false }
rayon = "1.4.1"
eth2_hashing = "0.3.0"
ethereum_hashing = "1.0.0-beta.2"
int_to_bytes = { path = "../int_to_bytes" }
smallvec = "1.6.1"
arbitrary = { version = "1.0", features = ["derive"], optional = true }

View File

@@ -1,4 +1,4 @@
use eth2_hashing::hash;
use ethereum_hashing::hash;
use int_to_bytes::int_to_bytes32;
use merkle_proof::{MerkleTree, MerkleTreeError};
use safe_arith::SafeArith;

View File

@@ -12,7 +12,7 @@ harness = false
criterion = "0.3.3"
[dependencies]
eth2_hashing = "0.3.0"
ethereum_hashing = "1.0.0-beta.2"
ethereum-types = "0.14.1"
[features]

View File

@@ -1,5 +1,5 @@
use crate::Hash256;
use eth2_hashing::{Context, Sha256Context};
use ethereum_hashing::{Context, Sha256Context};
use std::cmp::max;
/// Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy.

View File

@@ -1,5 +1,5 @@
use crate::Hash256;
use eth2_hashing::hash_fixed;
use ethereum_hashing::hash_fixed;
use std::mem;
const SEED_SIZE: usize = 32;

View File

@@ -15,7 +15,7 @@ compare_fields = { path = "../../common/compare_fields" }
compare_fields_derive = { path = "../../common/compare_fields_derive" }
eth2_interop_keypairs = { path = "../../common/eth2_interop_keypairs" }
ethereum-types = "0.14.1"
eth2_hashing = "0.3.0"
ethereum_hashing = "1.0.0-beta.2"
hex = "0.4.2"
int_to_bytes = { path = "../int_to_bytes" }
log = "0.4.11"

View File

@@ -5,7 +5,7 @@ use crate::*;
use compare_fields::CompareFields;
use compare_fields_derive::CompareFields;
use derivative::Derivative;
use eth2_hashing::hash;
use ethereum_hashing::hash;
use int_to_bytes::{int_to_bytes4, int_to_bytes8};
use pubkey_cache::PubkeyCache;
use safe_arith::{ArithError, SafeArith};

View File

@@ -1,5 +1,5 @@
use crate::*;
use eth2_hashing::{hash32_concat, ZERO_HASHES};
use ethereum_hashing::{hash32_concat, ZERO_HASHES};
use int_to_bytes::int_to_bytes32;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};

View File

@@ -1,7 +1,7 @@
use crate::{
ChainSpec, Domain, EthSpec, Fork, Hash256, PublicKey, SecretKey, Signature, SignedRoot, Slot,
};
use eth2_hashing::hash;
use ethereum_hashing::hash;
use safe_arith::{ArithError, SafeArith};
use ssz::Encode;
use std::cmp;

View File

@@ -86,7 +86,7 @@ impl SubnetId {
let subscription_event_idx = epoch.as_u64() / spec.epochs_per_subnet_subscription;
let permutation_seed =
eth2_hashing::hash(&int_to_bytes::int_to_bytes8(subscription_event_idx));
ethereum_hashing::hash(&int_to_bytes::int_to_bytes8(subscription_event_idx));
let num_subnets = 1 << spec.attestation_subnet_prefix_bits();

View File

@@ -5,7 +5,7 @@ use crate::{
ChainSpec, Domain, EthSpec, Fork, Hash256, PublicKey, SecretKey, Signature, SignedRoot, Slot,
SyncAggregatorSelectionData,
};
use eth2_hashing::hash;
use ethereum_hashing::hash;
use safe_arith::{ArithError, SafeArith};
use ssz::Encode;
use ssz_types::typenum::Unsigned;

View File

@@ -13,7 +13,7 @@ serde = "1.0.116"
serde_derive = "1.0.116"
ethereum_serde_utils = "1.0.0-beta.0"
hex = "0.4.2"
eth2_hashing = "0.3.0"
ethereum_hashing = "1.0.0-beta.2"
ethereum-types = "0.14.1"
arbitrary = { version = "1.0", features = ["derive"], optional = true }
zeroize = { version = "1.4.2", features = ["zeroize_derive"] }

View File

@@ -1,5 +1,5 @@
use crate::PublicKey;
use eth2_hashing::hash;
use ethereum_hashing::hash;
use ssz::Encode;
/// Returns the withdrawal credentials for a given public key.

View File

@@ -1,2 +0,0 @@
[target.wasm32-unknown-unknown]
runner = 'wasm-bindgen-test-runner'

View File

@@ -1,24 +0,0 @@
[package]
name = "eth2_hashing"
version = "0.3.0"
authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2021"
license = "Apache-2.0"
description = "Hashing primitives used in Ethereum 2.0"
[dependencies]
lazy_static = { version = "1.4.0", optional = true }
cpufeatures = { version = "0.2.5", optional = true }
ring = "0.16.19"
sha2 = "0.10"
[dev-dependencies]
rustc-hex = "2.1.0"
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "0.3.18"
[features]
default = ["zero_hash_cache", "detect-cpufeatures"]
zero_hash_cache = ["lazy_static"]
detect-cpufeatures = ["cpufeatures"]

View File

@@ -1,251 +0,0 @@
//! Optimized SHA256 for use in Ethereum 2.0.
//!
//! The initial purpose of this crate was to provide an abstraction over the hash function used in
//! Ethereum 2.0. The hash function changed during the specification process, so defining it once in
//! this crate made it easy to replace.
//!
//! 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.
pub use self::DynamicContext as Context;
use sha2::Digest;
#[cfg(feature = "zero_hash_cache")]
use lazy_static::lazy_static;
/// Length of a SHA256 hash in bytes.
pub const HASH_LEN: usize = 32;
/// Returns the digest of `input` using the best available implementation.
pub fn hash(input: &[u8]) -> Vec<u8> {
DynamicImpl::best().hash(input)
}
/// Hash function returning a fixed-size array (to save on allocations).
///
/// Uses the best available implementation based on CPU features.
pub fn hash_fixed(input: &[u8]) -> [u8; HASH_LEN] {
DynamicImpl::best().hash_fixed(input)
}
/// Compute the hash of two slices concatenated.
pub fn hash32_concat(h1: &[u8], h2: &[u8]) -> [u8; 32] {
let mut ctxt = DynamicContext::new();
ctxt.update(h1);
ctxt.update(h2);
ctxt.finalize()
}
/// Context trait for abstracting over implementation contexts.
pub trait Sha256Context {
fn new() -> Self;
fn update(&mut self, bytes: &[u8]);
fn finalize(self) -> [u8; HASH_LEN];
}
/// Top-level trait implemented by both `sha2` and `ring` implementations.
pub trait Sha256 {
type Context: Sha256Context;
fn hash(&self, input: &[u8]) -> Vec<u8>;
fn hash_fixed(&self, input: &[u8]) -> [u8; HASH_LEN];
}
/// Implementation of SHA256 using the `sha2` crate (fastest on CPUs with SHA extensions).
struct Sha2CrateImpl;
impl Sha256Context for sha2::Sha256 {
fn new() -> Self {
sha2::Digest::new()
}
fn update(&mut self, bytes: &[u8]) {
sha2::Digest::update(self, bytes)
}
fn finalize(self) -> [u8; HASH_LEN] {
sha2::Digest::finalize(self).into()
}
}
impl Sha256 for Sha2CrateImpl {
type Context = sha2::Sha256;
fn hash(&self, input: &[u8]) -> Vec<u8> {
Self::Context::digest(input).into_iter().collect()
}
fn hash_fixed(&self, input: &[u8]) -> [u8; HASH_LEN] {
Self::Context::digest(input).into()
}
}
/// Implementation of SHA256 using the `ring` crate (fastest on CPUs without SHA extensions).
pub struct RingImpl;
impl Sha256Context for ring::digest::Context {
fn new() -> Self {
Self::new(&ring::digest::SHA256)
}
fn update(&mut self, bytes: &[u8]) {
self.update(bytes)
}
fn finalize(self) -> [u8; HASH_LEN] {
let mut output = [0; HASH_LEN];
output.copy_from_slice(self.finish().as_ref());
output
}
}
impl Sha256 for RingImpl {
type Context = ring::digest::Context;
fn hash(&self, input: &[u8]) -> Vec<u8> {
ring::digest::digest(&ring::digest::SHA256, input)
.as_ref()
.into()
}
fn hash_fixed(&self, input: &[u8]) -> [u8; HASH_LEN] {
let mut ctxt = Self::Context::new(&ring::digest::SHA256);
ctxt.update(input);
ctxt.finalize()
}
}
/// Default dynamic implementation that switches between available implementations.
pub enum DynamicImpl {
Sha2,
Ring,
}
// Runtime latch for detecting the availability of SHA extensions on x86_64.
//
// Inspired by the runtime switch within the `sha2` crate itself.
#[cfg(all(feature = "detect-cpufeatures", target_arch = "x86_64"))]
cpufeatures::new!(x86_sha_extensions, "sha", "sse2", "ssse3", "sse4.1");
#[inline(always)]
pub fn have_sha_extensions() -> bool {
#[cfg(all(feature = "detect-cpufeatures", target_arch = "x86_64"))]
return x86_sha_extensions::get();
#[cfg(not(all(feature = "detect-cpufeatures", target_arch = "x86_64")))]
return false;
}
impl DynamicImpl {
/// Choose the best available implementation based on the currently executing CPU.
#[inline(always)]
pub fn best() -> Self {
if have_sha_extensions() {
Self::Sha2
} else {
Self::Ring
}
}
}
impl Sha256 for DynamicImpl {
type Context = DynamicContext;
#[inline(always)]
fn hash(&self, input: &[u8]) -> Vec<u8> {
match self {
Self::Sha2 => Sha2CrateImpl.hash(input),
Self::Ring => RingImpl.hash(input),
}
}
#[inline(always)]
fn hash_fixed(&self, input: &[u8]) -> [u8; HASH_LEN] {
match self {
Self::Sha2 => Sha2CrateImpl.hash_fixed(input),
Self::Ring => RingImpl.hash_fixed(input),
}
}
}
/// Context encapsulating all implemenation contexts.
///
/// This enum ends up being 8 bytes larger than the largest inner context.
pub enum DynamicContext {
Sha2(sha2::Sha256),
Ring(ring::digest::Context),
}
impl Sha256Context for DynamicContext {
fn new() -> Self {
match DynamicImpl::best() {
DynamicImpl::Sha2 => Self::Sha2(Sha256Context::new()),
DynamicImpl::Ring => Self::Ring(Sha256Context::new()),
}
}
fn update(&mut self, bytes: &[u8]) {
match self {
Self::Sha2(ctxt) => Sha256Context::update(ctxt, bytes),
Self::Ring(ctxt) => Sha256Context::update(ctxt, bytes),
}
}
fn finalize(self) -> [u8; HASH_LEN] {
match self {
Self::Sha2(ctxt) => Sha256Context::finalize(ctxt),
Self::Ring(ctxt) => Sha256Context::finalize(ctxt),
}
}
}
/// The max index that can be used with `ZERO_HASHES`.
#[cfg(feature = "zero_hash_cache")]
pub const ZERO_HASHES_MAX_INDEX: usize = 48;
#[cfg(feature = "zero_hash_cache")]
lazy_static! {
/// Cached zero hashes where `ZERO_HASHES[i]` is the hash of a Merkle tree with 2^i zero leaves.
pub static ref ZERO_HASHES: Vec<Vec<u8>> = {
let mut hashes = vec![vec![0; 32]; ZERO_HASHES_MAX_INDEX + 1];
for i in 0..ZERO_HASHES_MAX_INDEX {
hashes[i + 1] = hash32_concat(&hashes[i], &hashes[i])[..].to_vec();
}
hashes
};
}
#[cfg(test)]
mod tests {
use super::*;
use rustc_hex::FromHex;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_test::*;
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn test_hashing() {
let input: Vec<u8> = b"hello world".as_ref().into();
let output = hash(input.as_ref());
let expected_hex = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
let expected: Vec<u8> = expected_hex.from_hex().unwrap();
assert_eq!(expected, output);
}
#[cfg(feature = "zero_hash_cache")]
mod zero_hash {
use super::*;
#[test]
fn zero_hash_zero() {
assert_eq!(ZERO_HASHES[0], vec![0; 32]);
}
}
}

View File

@@ -31,7 +31,7 @@ slog = { version = "2.5.2", features = ["max_level_trace"] }
sloggers = { version = "2.1.1", features = ["json"] }
types = { "path" = "../consensus/types" }
bls = { path = "../crypto/bls" }
eth2_hashing = "0.3.0"
ethereum_hashing = "1.0.0-beta.2"
clap = "2.33.3"
env_logger = "0.9.0"
environment = { path = "./environment" }

View File

@@ -8,7 +8,7 @@ use clap_utils::{flags::DISABLE_MALLOC_TUNING_FLAG, get_eth2_network_config};
use directory::{parse_path_or_default, DEFAULT_BEACON_NODE_DIR, DEFAULT_VALIDATOR_DIR};
use env_logger::{Builder, Env};
use environment::{EnvironmentBuilder, LoggerConfig};
use eth2_hashing::have_sha_extensions;
use ethereum_hashing::have_sha_extensions;
use eth2_network_config::{Eth2NetworkConfig, DEFAULT_HARDCODED_NETWORK, HARDCODED_NET_NAMES};
use lighthouse_version::VERSION;
use malloc_utils::configure_memory_allocator;