aurora_engine_precompiles/
hash.rs1use aurora_evm::{Context, ExitError};
2
3use crate::prelude::sdk;
4use crate::prelude::types::{Address, EthGas, make_address};
5use crate::prelude::vec;
6use crate::{EvmPrecompileResult, Precompile, PrecompileOutput, utils};
7
8mod costs {
9 use crate::prelude::types::EthGas;
10
11 pub(super) const SHA256_BASE: EthGas = EthGas::new(60);
12
13 pub(super) const SHA256_PER_WORD: EthGas = EthGas::new(12);
14
15 pub(super) const RIPEMD160_BASE: EthGas = EthGas::new(600);
16
17 pub(super) const RIPEMD160_PER_WORD: EthGas = EthGas::new(120);
18}
19
20mod consts {
21 pub(super) const SHA256_WORD_LEN: u64 = 32;
22
23 pub(super) const RIPEMD_WORD_LEN: u64 = 32;
24}
25
26pub struct SHA256;
28
29impl SHA256 {
30 pub const ADDRESS: Address = make_address(0, 2);
31}
32
33impl Precompile for SHA256 {
34 fn required_gas(input: &[u8]) -> Result<EthGas, ExitError> {
35 let input_len = u64::try_from(input.len()).map_err(utils::err_usize_conv)?;
36 Ok(
37 input_len.div_ceil(consts::SHA256_WORD_LEN) * costs::SHA256_PER_WORD
38 + costs::SHA256_BASE,
39 )
40 }
41
42 fn run(
46 &self,
47 input: &[u8],
48 target_gas: Option<EthGas>,
49 _context: &Context,
50 _is_static: bool,
51 ) -> EvmPrecompileResult {
52 let cost = Self::required_gas(input)?;
53 if let Some(target_gas) = target_gas {
54 if cost > target_gas {
55 return Err(ExitError::OutOfGas);
56 }
57 }
58
59 let output = sdk::sha256(input).as_bytes().to_vec();
60 Ok(PrecompileOutput::without_logs(cost, output))
61 }
62}
63
64pub struct RIPEMD160;
66
67impl RIPEMD160 {
68 pub const ADDRESS: Address = make_address(0, 3);
69}
70
71impl Precompile for RIPEMD160 {
72 fn required_gas(input: &[u8]) -> Result<EthGas, ExitError> {
73 let input_len = u64::try_from(input.len()).map_err(utils::err_usize_conv)?;
74 Ok(
75 input_len.div_ceil(consts::RIPEMD_WORD_LEN) * costs::RIPEMD160_PER_WORD
76 + costs::RIPEMD160_BASE,
77 )
78 }
79
80 fn run(
84 &self,
85 input: &[u8],
86 target_gas: Option<EthGas>,
87 _context: &Context,
88 _is_static: bool,
89 ) -> EvmPrecompileResult {
90 let cost = Self::required_gas(input)?;
91 if let Some(target_gas) = target_gas {
92 if cost > target_gas {
93 return Err(ExitError::OutOfGas);
94 }
95 }
96
97 let hash = sdk::ripemd160(input);
98 let mut output = vec![0u8; 32];
101 output[12..].copy_from_slice(&hash);
102 Ok(PrecompileOutput::without_logs(cost, output))
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use crate::utils::new_context;
109
110 use super::*;
111
112 #[test]
113 fn test_sha256() {
114 let input = b"";
115 let expected =
116 hex::decode("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
117 .unwrap();
118
119 let res = SHA256
120 .run(input, Some(EthGas::new(60)), &new_context(), false)
121 .unwrap()
122 .output;
123 assert_eq!(res, expected);
124 }
125
126 #[test]
127 fn test_ripemd160() {
128 let input = b"";
129 let expected =
130 hex::decode("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31")
131 .unwrap();
132
133 let res = RIPEMD160
134 .run(input, Some(EthGas::new(600)), &new_context(), false)
135 .unwrap()
136 .output;
137 assert_eq!(res, expected);
138 }
139}