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