1#![cfg_attr(not(feature = "std"), no_std)]
22
23use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
24use scale_info::TypeInfo;
25use sha3::{Digest, Keccak256};
26use sp_core::{ecdsa, H160};
27
28pub use serde::{de::DeserializeOwned, Deserialize, Serialize};
29
30pub const SYSTEM_ACCOUNT_SIZE: u64 = 148;
37
38#[derive(
44 Eq,
45 PartialEq,
46 Copy,
47 Clone,
48 Encode,
49 Decode,
50 TypeInfo,
51 MaxEncodedLen,
52 Default,
53 PartialOrd,
54 Ord,
55 DecodeWithMemTracking,
56)]
57pub struct AccountId20(pub [u8; 20]);
58
59impl_serde::impl_fixed_hash_serde!(AccountId20, 20);
60
61#[cfg(feature = "std")]
62impl std::fmt::Display for AccountId20 {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 write!(f, "{:?}", self.0)
68 }
69}
70
71impl core::fmt::Debug for AccountId20 {
72 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
73 write!(f, "{:?}", H160(self.0))
74 }
75}
76
77impl From<[u8; 20]> for AccountId20 {
78 fn from(bytes: [u8; 20]) -> Self {
79 Self(bytes)
80 }
81}
82
83impl From<AccountId20> for [u8; 20] {
84 fn from(value: AccountId20) -> Self {
85 value.0
86 }
87}
88
89impl From<[u8; 32]> for AccountId20 {
94 fn from(bytes: [u8; 32]) -> Self {
95 let mut buffer = [0u8; 20];
96 buffer.copy_from_slice(&bytes[..20]);
97 Self(buffer)
98 }
99}
100impl From<sp_runtime::AccountId32> for AccountId20 {
101 fn from(account: sp_runtime::AccountId32) -> Self {
102 let bytes: &[u8; 32] = account.as_ref();
103 Self::from(*bytes)
104 }
105}
106
107impl From<H160> for AccountId20 {
108 fn from(h160: H160) -> Self {
109 Self(h160.0)
110 }
111}
112
113impl From<AccountId20> for H160 {
114 fn from(value: AccountId20) -> Self {
115 H160(value.0)
116 }
117}
118
119#[cfg(feature = "std")]
120impl std::str::FromStr for AccountId20 {
121 type Err = &'static str;
122 fn from_str(input: &str) -> Result<Self, Self::Err> {
123 H160::from_str(input)
124 .map(Into::into)
125 .map_err(|_| "invalid hex address.")
126 }
127}
128
129#[derive(
130 Eq,
131 PartialEq,
132 Clone,
133 Encode,
134 Decode,
135 sp_core::RuntimeDebug,
136 TypeInfo,
137 Serialize,
138 Deserialize,
139 DecodeWithMemTracking,
140)]
141pub struct EthereumSignature(ecdsa::Signature);
142
143impl From<ecdsa::Signature> for EthereumSignature {
144 fn from(x: ecdsa::Signature) -> Self {
145 EthereumSignature(x)
146 }
147}
148
149impl From<sp_runtime::MultiSignature> for EthereumSignature {
150 fn from(signature: sp_runtime::MultiSignature) -> Self {
151 match signature {
152 sp_runtime::MultiSignature::Ed25519(_) => {
153 panic!("Ed25519 not supported for EthereumSignature")
154 }
155 sp_runtime::MultiSignature::Sr25519(_) => {
156 panic!("Sr25519 not supported for EthereumSignature")
157 }
158 sp_runtime::MultiSignature::Ecdsa(sig) => Self(sig),
159 }
160 }
161}
162
163impl sp_runtime::traits::Verify for EthereumSignature {
164 type Signer = EthereumSigner;
165 fn verify<L: sp_runtime::traits::Lazy<[u8]>>(&self, mut msg: L, signer: &AccountId20) -> bool {
166 let mut m = [0u8; 32];
167 m.copy_from_slice(Keccak256::digest(msg.get()).as_slice());
168 match sp_io::crypto::secp256k1_ecdsa_recover(self.0.as_ref(), &m) {
169 Ok(pubkey) => {
170 AccountId20(H160::from_slice(&Keccak256::digest(pubkey).as_slice()[12..32]).0)
171 == *signer
172 }
173 Err(sp_io::EcdsaVerifyError::BadRS) => {
174 log::error!(target: "evm", "Error recovering: Incorrect value of R or S");
175 false
176 }
177 Err(sp_io::EcdsaVerifyError::BadV) => {
178 log::error!(target: "evm", "Error recovering: Incorrect value of V");
179 false
180 }
181 Err(sp_io::EcdsaVerifyError::BadSignature) => {
182 log::error!(target: "evm", "Error recovering: Invalid signature");
183 false
184 }
185 }
186 }
187}
188
189#[derive(
191 Eq,
192 PartialEq,
193 Ord,
194 PartialOrd,
195 Clone,
196 Encode,
197 Decode,
198 sp_core::RuntimeDebug,
199 TypeInfo,
200 DecodeWithMemTracking,
201)]
202#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
203pub struct EthereumSigner([u8; 20]);
204
205impl sp_runtime::traits::IdentifyAccount for EthereumSigner {
206 type AccountId = AccountId20;
207 fn into_account(self) -> AccountId20 {
208 AccountId20(self.0)
209 }
210}
211
212impl From<[u8; 20]> for EthereumSigner {
213 fn from(x: [u8; 20]) -> Self {
214 EthereumSigner(x)
215 }
216}
217
218impl From<ecdsa::Public> for EthereumSigner {
219 fn from(x: ecdsa::Public) -> Self {
220 let decompressed = libsecp256k1::PublicKey::parse_slice(
221 &x.0,
222 Some(libsecp256k1::PublicKeyFormat::Compressed),
223 )
224 .expect("Wrong compressed public key provided")
225 .serialize();
226 let mut m = [0u8; 64];
227 m.copy_from_slice(&decompressed[1..65]);
228 let account = H160::from_slice(&Keccak256::digest(m).as_slice()[12..32]);
229 EthereumSigner(account.into())
230 }
231}
232
233impl From<libsecp256k1::PublicKey> for EthereumSigner {
234 fn from(x: libsecp256k1::PublicKey) -> Self {
235 let mut m = [0u8; 64];
236 m.copy_from_slice(&x.serialize()[1..65]);
237 let account = H160::from_slice(&Keccak256::digest(m).as_slice()[12..32]);
238 EthereumSigner(account.into())
239 }
240}
241
242#[cfg(feature = "std")]
243impl std::fmt::Display for EthereumSigner {
244 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
245 write!(fmt, "ethereum signature: {:?}", H160::from_slice(&self.0))
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252 use sp_core::{ecdsa, Pair, H256};
253 use sp_runtime::traits::IdentifyAccount;
254
255 #[test]
256 fn test_account_derivation_1() {
257 let secret_key =
259 hex::decode("502f97299c472b88754accd412b7c9a6062ef3186fba0c0388365e1edec24875")
260 .unwrap();
261 let mut expected_hex_account = [0u8; 20];
262 hex::decode_to_slice(
263 "976f8456e4e2034179b284a23c0e0c8f6d3da50c",
264 &mut expected_hex_account,
265 )
266 .expect("example data is 20 bytes of valid hex");
267
268 let public_key = ecdsa::Pair::from_seed_slice(&secret_key).unwrap().public();
269 let account: EthereumSigner = public_key.into();
270 let expected_account = AccountId20::from(expected_hex_account);
271 assert_eq!(account.into_account(), expected_account);
272 }
273 #[test]
274 fn test_account_derivation_2() {
275 let secret_key =
277 hex::decode("0f02ba4d7f83e59eaa32eae9c3c4d99b68ce76decade21cdab7ecce8f4aef81a")
278 .unwrap();
279 let mut expected_hex_account = [0u8; 20];
280 hex::decode_to_slice(
281 "420e9f260b40af7e49440cead3069f8e82a5230f",
282 &mut expected_hex_account,
283 )
284 .expect("example data is 20 bytes of valid hex");
285
286 let public_key = ecdsa::Pair::from_seed_slice(&secret_key).unwrap().public();
287 let account: EthereumSigner = public_key.into();
288 let expected_account = AccountId20::from(expected_hex_account);
289 assert_eq!(account.into_account(), expected_account);
290 }
291 #[test]
292 fn test_account_derivation_3() {
293 let m = hex::decode("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
294 .unwrap();
295 let old = AccountId20(H160::from(H256::from_slice(Keccak256::digest(&m).as_slice())).0);
296 let new = AccountId20(H160::from_slice(&Keccak256::digest(&m).as_slice()[12..32]).0);
297 assert_eq!(new, old);
298 }
299}