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