aurora_engine_precompiles/
secp256k1.rs1use aurora_evm::{Context, ExitError};
2
3use crate::prelude::types::{Address, EthGas, make_address};
4use crate::prelude::{Borrowed, H256, sdk, vec::Vec};
5use crate::{EvmPrecompileResult, Precompile, PrecompileOutput};
6
7mod costs {
8 use crate::prelude::types::EthGas;
9
10 pub(super) const ECRECOVER_BASE: EthGas = EthGas::new(3_000);
11}
12
13mod consts {
14 pub(super) const INPUT_LEN: usize = 128;
15 pub(super) const SIGNATURE_LENGTH: usize = 65;
16}
17
18pub fn ecrecover(
24 hash: H256,
25 signature: &[u8; consts::SIGNATURE_LENGTH],
26) -> Result<Address, ExitError> {
27 sdk::ecrecover(hash, signature).map_err(|e| ExitError::Other(Borrowed(e.as_str())))
28}
29
30pub struct ECRecover;
31
32impl ECRecover {
33 pub const ADDRESS: Address = make_address(0, 1);
34}
35
36impl Precompile for ECRecover {
37 fn required_gas(_input: &[u8]) -> Result<EthGas, ExitError> {
38 Ok(costs::ECRECOVER_BASE)
39 }
40
41 fn run(
42 &self,
43 input: &[u8],
44 target_gas: Option<EthGas>,
45 _context: &Context,
46 _is_static: bool,
47 ) -> EvmPrecompileResult {
48 let cost = Self::required_gas(input)?;
49 if let Some(target_gas) = target_gas {
50 if cost > target_gas {
51 return Err(ExitError::OutOfGas);
52 }
53 }
54
55 let mut input = input.to_vec();
56 input.resize(consts::INPUT_LEN, 0);
57
58 let mut hash = [0; 32];
59 hash.copy_from_slice(&input[0..32]);
60
61 let mut v = [0; 32];
62 v.copy_from_slice(&input[32..64]);
63
64 let mut signature = [0; consts::SIGNATURE_LENGTH]; signature[0..32].copy_from_slice(&input[64..96]); signature[32..64].copy_from_slice(&input[96..128]); let v_bit = match v[31] {
69 27 | 28 if v[..31] == [0; 31] => v[31] - 27,
70 _ => {
71 return Ok(PrecompileOutput::without_logs(cost, Vec::new()));
72 }
73 };
74 signature[64] = v_bit; let address_res = ecrecover(H256::from_slice(&hash), &signature);
77 let output = address_res
78 .map(|a| {
79 let mut output = [0u8; 32];
80 output[12..32].copy_from_slice(a.as_bytes());
81 output.to_vec()
82 })
83 .unwrap_or_default();
84
85 Ok(PrecompileOutput::without_logs(cost, output))
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92 use crate::utils::new_context;
93
94 #[test]
95 fn test_ecrecover() {
96 let input = hex::decode("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
97 let expected =
98 hex::decode("000000000000000000000000c08b5542d177ac6686946920409741463a15dddb")
99 .unwrap();
100
101 let res = ECRecover
102 .run(&input, Some(EthGas::new(3_000)), &new_context(), false)
103 .unwrap()
104 .output;
105 assert_eq!(res, expected);
106
107 let input = hex::decode("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
109
110 let res = ECRecover.run(&input, Some(EthGas::new(2_999)), &new_context(), false);
111 assert!(matches!(res, Err(ExitError::OutOfGas)));
112
113 let input = hex::decode("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001a650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
115 let expected: Vec<u8> = Vec::new();
116
117 let res = ECRecover
118 .run(&input, Some(EthGas::new(3_000)), &new_context(), false)
119 .unwrap()
120 .output;
121 assert_eq!(res, expected);
122
123 let input = hex::decode("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000").unwrap();
124 let expected: Vec<u8> = Vec::new();
125
126 let res = ECRecover
127 .run(&input, Some(EthGas::new(3_000)), &new_context(), false)
128 .unwrap()
129 .output;
130 assert_eq!(res, expected);
131
132 let input = hex::decode("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b").unwrap();
133 let expected: Vec<u8> = Vec::new();
134
135 let res = ECRecover
136 .run(&input, Some(EthGas::new(3_000)), &new_context(), false)
137 .unwrap()
138 .output;
139 assert_eq!(res, expected);
140
141 let input = hex::decode("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000001b").unwrap();
142 let expected: Vec<u8> = Vec::new();
143
144 let res = ECRecover
145 .run(&input, Some(EthGas::new(3_000)), &new_context(), false)
146 .unwrap()
147 .output;
148 assert_eq!(res, expected);
149
150 let input = hex::decode("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap();
151 let expected: Vec<u8> = Vec::new();
152
153 let res = ECRecover
154 .run(&input, Some(EthGas::new(3_000)), &new_context(), false)
155 .unwrap()
156 .output;
157 assert_eq!(res, expected);
158 }
159
160 #[test]
161 fn test_ecrecover_geth_tests() {
162 let input = hex::decode("a8b53bdf3306a35a7103ab5504a0c9b492295564b6202b1942a84ef300107281000000000000000000000000000000000000000000000000000000000000001b307835653165303366353363653138623737326363623030393366663731663366353366356337356237346463623331613835616138623838393262346538621122334455667788991011121314151617181920212223242526272829303132").unwrap();
163 let expected: Vec<u8> = Vec::new();
164 let res = ECRecover
165 .run(&input, Some(EthGas::new(3_000)), &new_context(), false)
166 .unwrap()
167 .output;
168 assert_eq!(res, expected);
169
170 let input = hex::decode("18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549").unwrap();
171 let expected =
172 hex::decode("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b")
173 .unwrap();
174 let res = ECRecover
175 .run(&input, Some(EthGas::new(3_000)), &new_context(), false)
176 .unwrap()
177 .output;
178 assert_eq!(res, expected);
179
180 let input = hex::decode("18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c100000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549").unwrap();
181 let expected: Vec<u8> = Vec::new();
182 let res = ECRecover
183 .run(&input, Some(EthGas::new(3_000)), &new_context(), false)
184 .unwrap()
185 .output;
186 assert_eq!(res, expected);
187
188 let input = hex::decode("18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000001000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549").unwrap();
189 let expected: Vec<u8> = Vec::new();
190 let res = ECRecover
191 .run(&input, Some(EthGas::new(3_000)), &new_context(), false)
192 .unwrap()
193 .output;
194 assert_eq!(res, expected);
195
196 let input = hex::decode("18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000001000000000000000000000011c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549").unwrap();
197 let expected: Vec<u8> = Vec::new();
198 let res = ECRecover
199 .run(&input, Some(EthGas::new(3_000)), &new_context(), false)
200 .unwrap()
201 .output;
202 assert_eq!(res, expected);
203 }
204
205 #[test]
206 fn test_extra_input_length() {
207 let input = hex::decode("18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549aabbccddeeff").unwrap();
208 let expected =
209 hex::decode("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b")
210 .unwrap();
211 let res = ECRecover
212 .run(&input, Some(EthGas::new(3_000)), &new_context(), false)
213 .unwrap()
214 .output;
215 assert_eq!(res, expected);
216 }
217}