From 6b874e993c5b17e1b78d0c974fe871bc6e11ace9 Mon Sep 17 00:00:00 2001 From: pgherveou Date: Wed, 11 Sep 2024 13:37:19 +0200 Subject: [PATCH] Add eth_address --- signer/src/ecdsa.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/signer/src/ecdsa.rs b/signer/src/ecdsa.rs index 52de73aee6..ae96ed72ea 100644 --- a/signer/src/ecdsa.rs +++ b/signer/src/ecdsa.rs @@ -3,13 +3,14 @@ // see LICENSE for license details. //! An ecdsa keypair implementation. -use codec::Encode; - use crate::crypto::{seed_from_entropy, DeriveJunction, SecretUri}; +use codec::Encode; use core::{fmt::Display, str::FromStr}; use hex::FromHex; use secp256k1::{ecdsa::RecoverableSignature, Message, Secp256k1, SecretKey}; use secrecy::ExposeSecret; +use sp_crypto_hashing::keccak_256; +use subxt_core::utils::H160; const SECRET_KEY_LENGTH: usize = 32; @@ -150,6 +151,13 @@ impl Keypair { Self::from_secret_key(acc) } + /// Get the Ethereum address for this key pair. + /// See https://ethereum.org/en/developers/docs/accounts/#account-creation + pub fn eth_address(&self) -> H160 { + let pk = self.0.public_key().serialize_uncompressed(); + H160::from_slice(&keccak_256(&pk[1..])[12..]) + } + /// Obtain the [`PublicKey`] part of this key pair, which can be used in calls to [`verify()`]. /// or otherwise converted into an address. In case of ECDSA, the public key bytes are not /// equivalent to a Substrate `AccountId32`. They have to be hashed to obtain `AccountId32`. @@ -453,4 +461,17 @@ mod test { assert_eq!(pair.public_key().0, sp_pair.public().0); } + + #[test] + fn check_eth_address() { + // See https://goethereumbook.org/wallet-generate + let private_key = + hex_literal::hex!("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19"); + let pair = Keypair::from_secret_key(private_key).unwrap(); + + assert_eq!( + pair.eth_address(), + H160::from_str("0x96216849c49358B10257cb55b28eA603c874b05E").unwrap() + ); + } }