zemse_ethereum_hashing/
lib.rs1#[cfg(feature = "zero_hash_cache")]
11use std::sync::LazyLock;
12
13use sha2_impl::Sha2CrateImpl;
14pub use self::DynamicContext as Context;
15
16mod sha2_impl;
17
18pub const HASH_LEN: usize = 32;
20
21
22pub fn hash(input: &[u8]) -> Vec<u8> {
24 DynamicImpl::best().hash(input)
25}
26
27pub fn hash_fixed(input: &[u8]) -> [u8; HASH_LEN] {
31 DynamicImpl::best().hash_fixed(input)
32}
33
34pub fn hash32_concat(h1: &[u8], h2: &[u8]) -> [u8; 32] {
36 let mut ctxt = DynamicContext::new();
37 ctxt.update(h1);
38 ctxt.update(h2);
39 ctxt.finalize()
40}
41
42pub trait Sha256Context {
44 fn new() -> Self;
45
46 fn update(&mut self, bytes: &[u8]);
47
48 fn finalize(self) -> [u8; HASH_LEN];
49}
50
51pub trait Sha256 {
53 type Context: Sha256Context;
54
55 fn hash(&self, input: &[u8]) -> Vec<u8>;
56
57 fn hash_fixed(&self, input: &[u8]) -> [u8; HASH_LEN];
58}
59
60pub enum DynamicImpl {
62 Sha2,
63}
64
65#[inline(always)]
66pub fn have_sha_extensions() -> bool {
67 false
68}
69
70impl DynamicImpl {
71 #[inline(always)]
73 pub fn best() -> Self {
74 Self::Sha2
75 }
76}
77
78impl Sha256 for DynamicImpl {
79 type Context = DynamicContext;
80
81 #[inline(always)]
82 fn hash(&self, input: &[u8]) -> Vec<u8> {
83 match self {
84 Self::Sha2 => Sha2CrateImpl.hash(input),
85 }
86 }
87
88 #[inline(always)]
89 fn hash_fixed(&self, input: &[u8]) -> [u8; HASH_LEN] {
90 match self {
91 Self::Sha2 => Sha2CrateImpl.hash_fixed(input),
92 }
93 }
94}
95
96pub enum DynamicContext {
100 Sha2(sha2::Sha256),
101}
102
103impl Sha256Context for DynamicContext {
104 fn new() -> Self {
105 match DynamicImpl::best() {
106 DynamicImpl::Sha2 => Self::Sha2(Sha256Context::new()),
107 }
108 }
109
110 fn update(&mut self, bytes: &[u8]) {
111 match self {
112 Self::Sha2(ctxt) => Sha256Context::update(ctxt, bytes),
113 }
114 }
115
116 fn finalize(self) -> [u8; HASH_LEN] {
117 match self {
118 Self::Sha2(ctxt) => Sha256Context::finalize(ctxt),
119 }
120 }
121}
122
123#[cfg(feature = "zero_hash_cache")]
125pub const ZERO_HASHES_MAX_INDEX: usize = 48;
126
127#[cfg(feature = "zero_hash_cache")]
128pub static ZERO_HASHES: LazyLock<Vec<[u8; HASH_LEN]>> = LazyLock::new(|| {
130 let mut hashes = vec![[0; HASH_LEN]; ZERO_HASHES_MAX_INDEX + 1];
131
132 for i in 0..ZERO_HASHES_MAX_INDEX {
133 hashes[i + 1] = hash32_concat(&hashes[i], &hashes[i]);
134 }
135
136 hashes
137});
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142 use rustc_hex::FromHex;
143
144 #[cfg(target_arch = "wasm32")]
145 use wasm_bindgen_test::*;
146
147 #[cfg_attr(not(target_arch = "wasm32"), test)]
148 #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
149 fn test_hashing() {
150 let input: Vec<u8> = b"hello world".as_ref().into();
151
152 let output = hash(input.as_ref());
153 let expected_hex = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
154 let expected: Vec<u8> = expected_hex.from_hex().unwrap();
155 assert_eq!(expected, output);
156 }
157
158 #[cfg(feature = "zero_hash_cache")]
159 mod zero_hash {
160 use super::*;
161
162 #[test]
163 fn zero_hash_zero() {
164 assert_eq!(ZERO_HASHES[0], [0; 32]);
165 }
166 }
167}