aurora_engine_precompiles/
hash.rs1#[cfg(feature = "contract")]
2use crate::prelude::sdk;
3use crate::prelude::types::{make_address, Address, EthGas};
4use crate::prelude::vec;
5use crate::{utils, EvmPrecompileResult, Precompile, PrecompileOutput};
6use aurora_evm::{Context, ExitError};
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> {
37 let input_len = u64::try_from(input.len()).map_err(utils::err_usize_conv)?;
38 Ok(
39 (input_len + consts::SHA256_WORD_LEN - 1) / consts::SHA256_WORD_LEN
40 * costs::SHA256_PER_WORD
41 + costs::SHA256_BASE,
42 )
43 }
44
45 #[cfg(not(feature = "contract"))]
49 fn run(
50 &self,
51 input: &[u8],
52 target_gas: Option<EthGas>,
53 _context: &Context,
54 _is_static: bool,
55 ) -> EvmPrecompileResult {
56 use sha2::Digest;
57
58 let cost = Self::required_gas(input)?;
59 if let Some(target_gas) = target_gas {
60 if cost > target_gas {
61 return Err(ExitError::OutOfGas);
62 }
63 }
64
65 let output = sha2::Sha256::digest(input).to_vec();
66 Ok(PrecompileOutput::without_logs(cost, output))
67 }
68
69 #[cfg(feature = "contract")]
73 fn run(
74 &self,
75 input: &[u8],
76 target_gas: Option<EthGas>,
77 _context: &Context,
78 _is_static: bool,
79 ) -> EvmPrecompileResult {
80 let cost = Self::required_gas(input)?;
81 if let Some(target_gas) = target_gas {
82 if cost > target_gas {
83 return Err(ExitError::OutOfGas);
84 }
85 }
86
87 let output = sdk::sha256(input).as_bytes().to_vec();
88 Ok(PrecompileOutput::without_logs(cost, output))
89 }
90}
91
92pub struct RIPEMD160;
94
95impl RIPEMD160 {
96 pub const ADDRESS: Address = make_address(0, 3);
97
98 #[cfg(not(feature = "contract"))]
99 fn internal_impl(input: &[u8]) -> [u8; 20] {
100 use ripemd::{Digest, Ripemd160};
101
102 let hash = Ripemd160::digest(input);
103 let mut output = [0u8; 20];
104 output.copy_from_slice(&hash);
105 output
106 }
107}
108
109impl Precompile for RIPEMD160 {
110 fn required_gas(input: &[u8]) -> Result<EthGas, ExitError> {
113 let input_len = u64::try_from(input.len()).map_err(utils::err_usize_conv)?;
114 Ok(
115 (input_len + consts::RIPEMD_WORD_LEN - 1) / consts::RIPEMD_WORD_LEN
116 * costs::RIPEMD160_PER_WORD
117 + costs::RIPEMD160_BASE,
118 )
119 }
120
121 fn run(
125 &self,
126 input: &[u8],
127 target_gas: Option<EthGas>,
128 _context: &Context,
129 _is_static: bool,
130 ) -> EvmPrecompileResult {
131 let cost = Self::required_gas(input)?;
132 if let Some(target_gas) = target_gas {
133 if cost > target_gas {
134 return Err(ExitError::OutOfGas);
135 }
136 }
137
138 #[cfg(not(feature = "contract"))]
139 let hash = Self::internal_impl(input);
140 #[cfg(feature = "contract")]
141 let hash = sdk::ripemd160(input);
142 let mut output = vec![0u8; 32];
145 output[12..].copy_from_slice(&hash);
146 Ok(PrecompileOutput::without_logs(cost, output))
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use crate::utils::new_context;
153
154 use super::*;
155
156 #[test]
157 fn test_sha256() {
158 let input = b"";
159 let expected =
160 hex::decode("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
161 .unwrap();
162
163 let res = SHA256
164 .run(input, Some(EthGas::new(60)), &new_context(), false)
165 .unwrap()
166 .output;
167 assert_eq!(res, expected);
168 }
169
170 #[test]
171 fn test_ripemd160() {
172 let input = b"";
173 let expected =
174 hex::decode("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31")
175 .unwrap();
176
177 let res = RIPEMD160
178 .run(input, Some(EthGas::new(600)), &new_context(), false)
179 .unwrap()
180 .output;
181 assert_eq!(res, expected);
182 }
183}