ethrex_levm/opcode_handlers/
keccak.rs1use crate::{
7 errors::{OpcodeResult, VMError},
8 gas_cost,
9 memory::calculate_memory_size,
10 opcode_handlers::OpcodeHandler,
11 utils::size_offset_to_usize,
12 vm::VM,
13};
14use ethrex_common::{U256, utils::u256_from_big_endian};
15
16const EMPTY_KECCAK_U256: U256 = U256([
20 0x7bfad8045d85a470,
21 0xe500b653ca82273b,
22 0x927e7db2dcc703c0,
23 0xc5d2460186f7233c,
24]);
25
26pub struct OpKeccak256Handler;
27impl OpcodeHandler for OpKeccak256Handler {
28 #[inline(always)]
29 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
30 let [offset, len] = *vm.current_call_frame.stack.pop()?;
31 let (len, offset) = size_offset_to_usize(len, offset)?;
32
33 vm.current_call_frame
34 .increase_consumed_gas(gas_cost::keccak256(
35 calculate_memory_size(offset, len)?,
36 vm.current_call_frame.memory.len(),
37 len,
38 )?)?;
39
40 let hash = if len == 0 {
45 EMPTY_KECCAK_U256
46 } else {
47 let crypto = vm.crypto;
48 u256_from_big_endian(&vm.current_call_frame.memory.with_range(
49 offset,
50 len,
51 |bytes| crypto.keccak256(bytes),
52 )?)
53 };
54 vm.current_call_frame.stack.push(hash)?;
55
56 Ok(OpcodeResult::Continue)
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use ethrex_common::constants::EMPTY_KECCAK_HASH;
64 use ethrex_crypto::{Crypto, NativeCrypto};
65
66 #[test]
67 fn empty_keccak_const_matches_hash() {
68 let expected = u256_from_big_endian(&NativeCrypto.keccak256(&[]));
69 assert_eq!(EMPTY_KECCAK_U256, expected);
70 }
71
72 #[test]
73 fn empty_keccak_const_matches_common_constant() {
74 assert_eq!(
77 EMPTY_KECCAK_U256,
78 u256_from_big_endian(EMPTY_KECCAK_HASH.as_bytes())
79 );
80 }
81}