alloy_primitives/utils/
mod.rs1use crate::B256;
4use alloc::{boxed::Box, collections::TryReserveError, vec::Vec};
5use cfg_if::cfg_if;
6use core::{
7 fmt,
8 mem::{ManuallyDrop, MaybeUninit},
9};
10
11mod units;
12pub use units::{
13 format_ether, format_units, format_units_with, parse_ether, parse_units, DecimalSeparator,
14 ParseUnits, Unit, UnitsError,
15};
16
17#[doc(hidden)]
18#[deprecated(since = "0.5.0", note = "use `Unit::ETHER.wei()` instead")]
19pub const WEI_IN_ETHER: crate::U256 = Unit::ETHER.wei_const();
20
21#[doc(hidden)]
22#[deprecated(since = "0.5.0", note = "use `Unit` instead")]
23pub type Units = Unit;
24
25pub const EIP191_PREFIX: &str = "\x19Ethereum Signed Message:\n";
27
28pub const KECCAK256_EMPTY: B256 =
30 b256!("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
31
32#[macro_export]
34macro_rules! try_vec {
35 () => {
36 $crate::private::Vec::new()
37 };
38 ($elem:expr; $n:expr) => {
39 $crate::utils::vec_try_from_elem($elem, $n)
40 };
41 ($($x:expr),+ $(,)?) => {
42 match $crate::utils::box_try_new([$($x),+]) {
43 ::core::result::Result::Ok(x) => ::core::result::Result::Ok(<[_]>::into_vec(x)),
44 ::core::result::Result::Err(e) => ::core::result::Result::Err(e),
45 }
46 };
47}
48
49#[inline]
54pub fn box_try_new<T>(value: T) -> Result<Box<T>, TryReserveError> {
55 let mut boxed = box_try_new_uninit::<T>()?;
56 unsafe {
57 boxed.as_mut_ptr().write(value);
58 let ptr = Box::into_raw(boxed);
59 Ok(Box::from_raw(ptr.cast()))
60 }
61}
62
63#[inline]
68pub fn box_try_new_uninit<T>() -> Result<Box<MaybeUninit<T>>, TryReserveError> {
69 let mut vec = Vec::<MaybeUninit<T>>::new();
70
71 vec.try_reserve_exact(1)?;
73
74 vec.shrink_to(1);
77
78 let mut vec = ManuallyDrop::new(vec);
79
80 Ok(unsafe { Box::from_raw(vec.as_mut_ptr()) })
82}
83
84pub fn try_collect_vec<I: Iterator<Item = T>, T>(iter: I) -> Result<Vec<T>, TryReserveError> {
86 let mut vec = Vec::new();
87 if let Some(size_hint) = iter.size_hint().1 {
88 vec.try_reserve(size_hint.max(4))?;
89 }
90 vec.extend(iter);
91 Ok(vec)
92}
93
94#[inline]
96pub fn vec_try_with_capacity<T>(capacity: usize) -> Result<Vec<T>, TryReserveError> {
97 let mut vec = Vec::new();
98 vec.try_reserve(capacity).map(|()| vec)
99}
100
101#[doc(hidden)]
104pub fn vec_try_from_elem<T: Clone>(elem: T, n: usize) -> Result<Vec<T>, TryReserveError> {
105 let mut vec = Vec::new();
106 vec.try_reserve(n)?;
107 vec.resize(n, elem);
108 Ok(vec)
109}
110
111pub fn eip191_hash_message<T: AsRef<[u8]>>(message: T) -> B256 {
120 keccak256(eip191_message(message))
121}
122
123pub fn eip191_message<T: AsRef<[u8]>>(message: T) -> Vec<u8> {
130 fn eip191_message(message: &[u8]) -> Vec<u8> {
131 let len = message.len();
132 let mut len_string_buffer = itoa::Buffer::new();
133 let len_string = len_string_buffer.format(len);
134
135 let mut eth_message = Vec::with_capacity(EIP191_PREFIX.len() + len_string.len() + len);
136 eth_message.extend_from_slice(EIP191_PREFIX.as_bytes());
137 eth_message.extend_from_slice(len_string.as_bytes());
138 eth_message.extend_from_slice(message);
139 eth_message
140 }
141
142 eip191_message(message.as_ref())
143}
144
145pub fn keccak256<T: AsRef<[u8]>>(bytes: T) -> B256 {
149 fn keccak256(bytes: &[u8]) -> B256 {
150 let mut output = MaybeUninit::<B256>::uninit();
151
152 cfg_if! {
153 if #[cfg(all(feature = "native-keccak", not(any(feature = "sha3-keccak", feature = "tiny-keccak", miri))))] {
154 #[link(wasm_import_module = "vm_hooks")]
155 extern "C" {
156 fn native_keccak256(bytes: *const u8, len: usize, output: *mut u8);
172 }
173
174 unsafe { native_keccak256(bytes.as_ptr(), bytes.len(), output.as_mut_ptr().cast::<u8>()) };
176 } else {
177 let mut hasher = Keccak256::new();
178 hasher.update(bytes);
179 unsafe { hasher.finalize_into_raw(output.as_mut_ptr().cast()) };
181 }
182 }
183
184 unsafe { output.assume_init() }
186 }
187
188 keccak256(bytes.as_ref())
189}
190
191mod keccak256_state {
192 cfg_if::cfg_if! {
193 if #[cfg(all(feature = "asm-keccak", not(miri)))] {
194 pub(super) use keccak_asm::Digest;
195
196 pub(super) type State = keccak_asm::Keccak256;
197 } else if #[cfg(feature = "sha3-keccak")] {
198 pub(super) use sha3::Digest;
199
200 pub(super) type State = sha3::Keccak256;
201 } else {
202 pub(super) use tiny_keccak::Hasher as Digest;
203
204 #[derive(Clone)]
206 pub(super) struct State(tiny_keccak::Keccak);
207
208 impl State {
209 #[inline]
210 pub(super) fn new() -> Self {
211 Self(tiny_keccak::Keccak::v256())
212 }
213
214 #[inline]
215 pub(super) fn finalize_into(self, output: &mut [u8; 32]) {
216 self.0.finalize(output);
217 }
218
219 #[inline]
220 pub(super) fn update(&mut self, bytes: &[u8]) {
221 self.0.update(bytes);
222 }
223 }
224 }
225 }
226}
227#[allow(unused_imports)]
228use keccak256_state::Digest;
229
230#[derive(Clone)]
237pub struct Keccak256 {
238 state: keccak256_state::State,
239}
240
241impl Default for Keccak256 {
242 #[inline]
243 fn default() -> Self {
244 Self::new()
245 }
246}
247
248impl fmt::Debug for Keccak256 {
249 #[inline]
250 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251 f.debug_struct("Keccak256").finish_non_exhaustive()
252 }
253}
254
255impl Keccak256 {
256 #[inline]
258 pub fn new() -> Self {
259 Self { state: keccak256_state::State::new() }
260 }
261
262 #[inline]
264 pub fn update(&mut self, bytes: impl AsRef<[u8]>) {
265 self.state.update(bytes.as_ref());
266 }
267
268 #[inline]
270 pub fn finalize(self) -> B256 {
271 let mut output = MaybeUninit::<B256>::uninit();
272 unsafe { self.finalize_into_raw(output.as_mut_ptr().cast()) };
274 unsafe { output.assume_init() }
276 }
277
278 #[inline]
284 #[track_caller]
285 pub fn finalize_into(self, output: &mut [u8]) {
286 self.finalize_into_array(output.try_into().unwrap())
287 }
288
289 #[inline]
291 #[allow(clippy::useless_conversion)]
292 pub fn finalize_into_array(self, output: &mut [u8; 32]) {
293 self.state.finalize_into(output.into());
294 }
295
296 #[inline]
302 pub unsafe fn finalize_into_raw(self, output: *mut u8) {
303 self.finalize_into_array(&mut *output.cast::<[u8; 32]>())
304 }
305}
306
307#[cfg(test)]
308mod tests {
309 use super::*;
310 use alloc::string::ToString;
311
312 #[test]
315 fn test_hash_message() {
316 let msg = "Hello World";
317 let eip191_msg = eip191_message(msg);
318 let hash = keccak256(&eip191_msg);
319 assert_eq!(
320 eip191_msg,
321 [EIP191_PREFIX.as_bytes(), msg.len().to_string().as_bytes(), msg.as_bytes()].concat()
322 );
323 assert_eq!(
324 hash,
325 b256!("0xa1de988600a42c4b4ab089b619297c17d53cffae5d5120d82d8a92d0bb3b78f2")
326 );
327 assert_eq!(eip191_hash_message(msg), hash);
328 }
329
330 #[test]
331 fn keccak256_hasher() {
332 let expected = b256!("0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad");
333 assert_eq!(keccak256("hello world"), expected);
334
335 let mut hasher = Keccak256::new();
336 hasher.update(b"hello");
337 hasher.update(b" world");
338
339 assert_eq!(hasher.clone().finalize(), expected);
340
341 let mut hash = [0u8; 32];
342 hasher.clone().finalize_into(&mut hash);
343 assert_eq!(hash, expected);
344
345 let mut hash = [0u8; 32];
346 hasher.clone().finalize_into_array(&mut hash);
347 assert_eq!(hash, expected);
348
349 let mut hash = [0u8; 32];
350 unsafe { hasher.finalize_into_raw(hash.as_mut_ptr()) };
351 assert_eq!(hash, expected);
352 }
353
354 #[test]
355 fn test_try_boxing() {
356 let x = Box::new(42);
357 let y = box_try_new(42).unwrap();
358 assert_eq!(x, y);
359
360 let x = vec![1; 3];
361 let y = try_vec![1; 3].unwrap();
362 assert_eq!(x, y);
363
364 let x = vec![1, 2, 3];
365 let y = try_vec![1, 2, 3].unwrap();
366 assert_eq!(x, y);
367 }
368}