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, parse_ether, parse_units, ParseUnits, Unit, UnitsError,
14};
15
16#[doc(hidden)]
17#[deprecated(since = "0.5.0", note = "use `Unit::ETHER.wei()` instead")]
18pub const WEI_IN_ETHER: crate::U256 = Unit::ETHER.wei_const();
19
20#[doc(hidden)]
21#[deprecated(since = "0.5.0", note = "use `Unit` instead")]
22pub type Units = Unit;
23
24pub const EIP191_PREFIX: &str = "\x19Ethereum Signed Message:\n";
26
27#[macro_export]
29macro_rules! try_vec {
30 () => {
31 $crate::private::Vec::new()
32 };
33 ($elem:expr; $n:expr) => {
34 $crate::utils::vec_try_from_elem($elem, $n)
35 };
36 ($($x:expr),+ $(,)?) => {
37 match $crate::utils::box_try_new([$($x),+]) {
38 ::core::result::Result::Ok(x) => ::core::result::Result::Ok(<[_]>::into_vec(x)),
39 ::core::result::Result::Err(e) => ::core::result::Result::Err(e),
40 }
41 };
42}
43
44#[inline]
49pub fn box_try_new<T>(value: T) -> Result<Box<T>, TryReserveError> {
50 let mut boxed = box_try_new_uninit::<T>()?;
51 unsafe {
52 boxed.as_mut_ptr().write(value);
53 let ptr = Box::into_raw(boxed);
54 Ok(Box::from_raw(ptr.cast()))
55 }
56}
57
58#[inline]
63pub fn box_try_new_uninit<T>() -> Result<Box<MaybeUninit<T>>, TryReserveError> {
64 let mut vec = Vec::<MaybeUninit<T>>::new();
65
66 vec.try_reserve_exact(1)?;
68
69 vec.shrink_to(1);
72
73 let mut vec = ManuallyDrop::new(vec);
74
75 Ok(unsafe { Box::from_raw(vec.as_mut_ptr()) })
77}
78
79pub fn try_collect_vec<I: Iterator<Item = T>, T>(iter: I) -> Result<Vec<T>, TryReserveError> {
81 let mut vec = Vec::new();
82 if let Some(size_hint) = iter.size_hint().1 {
83 vec.try_reserve(size_hint.max(4))?;
84 }
85 vec.extend(iter);
86 Ok(vec)
87}
88
89#[inline]
91pub fn vec_try_with_capacity<T>(capacity: usize) -> Result<Vec<T>, TryReserveError> {
92 let mut vec = Vec::new();
93 vec.try_reserve(capacity).map(|()| vec)
94}
95
96#[doc(hidden)]
99pub fn vec_try_from_elem<T: Clone>(elem: T, n: usize) -> Result<Vec<T>, TryReserveError> {
100 let mut vec = Vec::new();
101 vec.try_reserve(n)?;
102 vec.resize(n, elem);
103 Ok(vec)
104}
105
106pub fn eip191_hash_message<T: AsRef<[u8]>>(message: T) -> B256 {
115 keccak256(eip191_message(message))
116}
117
118pub fn eip191_message<T: AsRef<[u8]>>(message: T) -> Vec<u8> {
125 fn eip191_message(message: &[u8]) -> Vec<u8> {
126 let len = message.len();
127 let mut len_string_buffer = itoa::Buffer::new();
128 let len_string = len_string_buffer.format(len);
129
130 let mut eth_message = Vec::with_capacity(EIP191_PREFIX.len() + len_string.len() + len);
131 eth_message.extend_from_slice(EIP191_PREFIX.as_bytes());
132 eth_message.extend_from_slice(len_string.as_bytes());
133 eth_message.extend_from_slice(message);
134 eth_message
135 }
136
137 eip191_message(message.as_ref())
138}
139
140pub fn keccak256<T: AsRef<[u8]>>(bytes: T) -> B256 {
144 fn keccak256(bytes: &[u8]) -> B256 {
145 let mut output = MaybeUninit::<B256>::uninit();
146
147 cfg_if! {
148 if #[cfg(all(feature = "native-keccak", not(any(feature = "sha3-keccak", feature = "tiny-keccak", miri))))] {
149 #[link(wasm_import_module = "vm_hooks")]
150 extern "C" {
151 fn native_keccak256(bytes: *const u8, len: usize, output: *mut u8);
167 }
168
169 unsafe { native_keccak256(bytes.as_ptr(), bytes.len(), output.as_mut_ptr().cast::<u8>()) };
171 } else {
172 let mut hasher = Keccak256::new();
173 hasher.update(bytes);
174 unsafe { hasher.finalize_into_raw(output.as_mut_ptr().cast()) };
176 }
177 }
178
179 unsafe { output.assume_init() }
181 }
182
183 keccak256(bytes.as_ref())
184}
185
186mod keccak256_state {
187 cfg_if::cfg_if! {
188 if #[cfg(all(feature = "asm-keccak", not(miri)))] {
189 pub(super) use keccak_asm::Digest;
190
191 pub(super) type State = keccak_asm::Keccak256;
192 } else if #[cfg(feature = "sha3-keccak")] {
193 pub(super) use sha3::Digest;
194
195 pub(super) type State = sha3::Keccak256;
196 } else {
197 pub(super) use tiny_keccak::Hasher as Digest;
198
199 #[derive(Clone)]
201 pub(super) struct State(tiny_keccak::Keccak);
202
203 impl State {
204 #[inline]
205 pub(super) fn new() -> Self {
206 Self(tiny_keccak::Keccak::v256())
207 }
208
209 #[inline]
210 pub(super) fn finalize_into(self, output: &mut [u8; 32]) {
211 self.0.finalize(output);
212 }
213
214 #[inline]
215 pub(super) fn update(&mut self, bytes: &[u8]) {
216 self.0.update(bytes);
217 }
218 }
219 }
220 }
221}
222#[allow(unused_imports)]
223use keccak256_state::Digest;
224
225#[derive(Clone)]
232pub struct Keccak256 {
233 state: keccak256_state::State,
234}
235
236impl Default for Keccak256 {
237 #[inline]
238 fn default() -> Self {
239 Self::new()
240 }
241}
242
243impl fmt::Debug for Keccak256 {
244 #[inline]
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 f.debug_struct("Keccak256").finish_non_exhaustive()
247 }
248}
249
250impl Keccak256 {
251 #[inline]
253 pub fn new() -> Self {
254 Self { state: keccak256_state::State::new() }
255 }
256
257 #[inline]
259 pub fn update(&mut self, bytes: impl AsRef<[u8]>) {
260 self.state.update(bytes.as_ref());
261 }
262
263 #[inline]
265 pub fn finalize(self) -> B256 {
266 let mut output = MaybeUninit::<B256>::uninit();
267 unsafe { self.finalize_into_raw(output.as_mut_ptr().cast()) };
269 unsafe { output.assume_init() }
271 }
272
273 #[inline]
279 #[track_caller]
280 pub fn finalize_into(self, output: &mut [u8]) {
281 self.finalize_into_array(output.try_into().unwrap())
282 }
283
284 #[inline]
286 #[allow(clippy::useless_conversion)]
287 pub fn finalize_into_array(self, output: &mut [u8; 32]) {
288 self.state.finalize_into(output.into());
289 }
290
291 #[inline]
297 pub unsafe fn finalize_into_raw(self, output: *mut u8) {
298 self.finalize_into_array(&mut *output.cast::<[u8; 32]>())
299 }
300}
301
302#[cfg(test)]
303mod tests {
304 use super::*;
305 use alloc::string::ToString;
306
307 #[test]
310 fn test_hash_message() {
311 let msg = "Hello World";
312 let eip191_msg = eip191_message(msg);
313 let hash = keccak256(&eip191_msg);
314 assert_eq!(
315 eip191_msg,
316 [EIP191_PREFIX.as_bytes(), msg.len().to_string().as_bytes(), msg.as_bytes()].concat()
317 );
318 assert_eq!(
319 hash,
320 b256!("0xa1de988600a42c4b4ab089b619297c17d53cffae5d5120d82d8a92d0bb3b78f2")
321 );
322 assert_eq!(eip191_hash_message(msg), hash);
323 }
324
325 #[test]
326 fn keccak256_hasher() {
327 let expected = b256!("0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad");
328 assert_eq!(keccak256("hello world"), expected);
329
330 let mut hasher = Keccak256::new();
331 hasher.update(b"hello");
332 hasher.update(b" world");
333
334 assert_eq!(hasher.clone().finalize(), expected);
335
336 let mut hash = [0u8; 32];
337 hasher.clone().finalize_into(&mut hash);
338 assert_eq!(hash, expected);
339
340 let mut hash = [0u8; 32];
341 hasher.clone().finalize_into_array(&mut hash);
342 assert_eq!(hash, expected);
343
344 let mut hash = [0u8; 32];
345 unsafe { hasher.finalize_into_raw(hash.as_mut_ptr()) };
346 assert_eq!(hash, expected);
347 }
348
349 #[test]
350 fn test_try_boxing() {
351 let x = Box::new(42);
352 let y = box_try_new(42).unwrap();
353 assert_eq!(x, y);
354
355 let x = vec![1; 3];
356 let y = try_vec![1; 3].unwrap();
357 assert_eq!(x, y);
358
359 let x = vec![1, 2, 3];
360 let y = try_vec![1, 2, 3].unwrap();
361 assert_eq!(x, y);
362 }
363}