diff --git a/token-core/tcx-eos/src/address.rs b/token-core/tcx-eos/src/address.rs index 22dee907..19c1065d 100644 --- a/token-core/tcx-eos/src/address.rs +++ b/token-core/tcx-eos/src/address.rs @@ -2,25 +2,30 @@ use bitcoin::util::base58; use std::str::FromStr; use tcx_common::{ripemd160, CommonError}; use tcx_constants::CoinInfo; -use tcx_keystore::{Address, Result}; +use tcx_keystore::{keystore::PublicKeyEncoder, Address, Result}; use tcx_primitive::TypedPublicKey; #[derive(PartialEq, Eq, Clone)] -pub struct EosAddress { - pubkey_bytes: Vec, - checksum: Vec, -} +pub struct EosAddress {} -impl Address for EosAddress { - fn from_public_key(public_key: &TypedPublicKey, _coin: &CoinInfo) -> Result { +#[derive(PartialEq, Eq, Clone)] +pub struct EosPublicKeyEncoder {} + +impl PublicKeyEncoder for EosPublicKeyEncoder { + fn encode(public_key: &TypedPublicKey, _coin_info: &CoinInfo) -> Result { let pubkey_bytes = public_key.to_bytes(); let hashed_bytes = ripemd160(&pubkey_bytes); let checksum = hashed_bytes[..4].to_vec(); + let mut bytes = vec![]; + bytes.extend_from_slice(&pubkey_bytes); + bytes.extend_from_slice(&checksum); + Ok(format!("EOS{}", base58::encode_slice(&bytes))) + } +} - Ok(EosAddress { - pubkey_bytes, - checksum, - }) +impl Address for EosAddress { + fn from_public_key(_public_key: &TypedPublicKey, _coin: &CoinInfo) -> Result { + Ok(EosAddress {}) } fn is_valid(address: &str, _coin: &CoinInfo) -> bool { @@ -32,70 +37,54 @@ impl Address for EosAddress { impl FromStr for EosAddress { type Err = failure::Error; fn from_str(s: &str) -> std::result::Result { - if let Some(s) = s.strip_prefix("EOS") { - let s = &s[3..]; - let bytes = base58::from(s).map_err(|_| CommonError::InvalidAddress)?; - let checksum = bytes[bytes.len() - 4..].to_vec(); - let pubkey_bytes = bytes[..bytes.len() - 4].to_vec(); - - let hashed_bytes = ripemd160(&pubkey_bytes); - let expected_checksum = hashed_bytes[..4].to_vec(); - if checksum != expected_checksum { - return Err(CommonError::InvalidAddressChecksum.into()); - } - - Ok(EosAddress { - pubkey_bytes, - checksum, - }) - } else { - Err(CommonError::InvalidAddress.into()) - } + Ok(EosAddress {}) } } impl ToString for EosAddress { fn to_string(&self) -> String { - let mut bytes = vec![]; - bytes.extend_from_slice(&self.pubkey_bytes); - bytes.extend_from_slice(&self.checksum); - format!("EOS{}", base58::encode_slice(&bytes)) + "".to_string() } } #[cfg(test)] mod tests { - use std::str::FromStr; - use crate::address::EosAddress; + use crate::address::EosPublicKeyEncoder; + use tcx_common::FromHex; use tcx_constants::CoinInfo; - use tcx_keystore::Address; + use tcx_keystore::{Address, PublicKeyEncoder}; + use tcx_primitive::{PublicKey, Secp256k1PublicKey, TypedPublicKey}; #[test] - fn test_is_valid() { + fn test_encode_public_key() { let tests = [ - "EOS88XhiiP7Cu5TmAUJqHbyuhyYgd6sei68AU266PyetDDAtjmYWF", - "EOS5varo7aGmCFQw77DNiiWUj3YQA7ZmWUMC4NDDXeeaeEAXk436S", - "EOS6w47YkvVGLzvKeozV5ZK34QApCmALrwoH2Dwhnirs5TZ9mg5io", - "EOS5varo7aGmCFQw77DNiiWUj3YQA7ZmWUMC4NDDXeeaeEAXk436S", + ( + "0x037b5253c24ce2a293566f9e066051366cda5073e4a43b25f07c990d7c9ac0aab5", + "EOS7mYcbf9BumHjUUCPoXh2nxzkipQZDQCZC7EmRq8cwB1exEYHfy", + ), + ( + "0x03f6a261f3b4d7c24014f2026b09ad409076c566b39b99b8e0a7196f391caec508", + "EOS8hrUMSKjQZK4QsXLfAVTwmmD4nTfF9Lb11ZQN3zVYrdxhApgFr", + ), + ( + "0x03844a01522a26156df32b587d80df60d76072480e299c6d3241c7b2b929c07625", + "EOS7qVgE5PF58jAV7HmFPNEAEdyZmE4UBasTRa7AZ1AhJGxYovBwc", + ), + ( + "0x035cda3171ba9107ec3f398c8e33b17803fd9d6a815ee5d544a71759455396319c", + "EOS7Y8KPZQDMhDWjHaM3nWRWwYSoP75KpSatFbanKRPRaUKDWi2UA", + ), ]; for i in tests { - assert!(EosAddress::is_valid(i, &CoinInfo::default())); + let bytes = Vec::from_0x_hex(i.0).unwrap(); + let k1_pub_key = Secp256k1PublicKey::from_slice(&bytes).unwrap(); + let typed_pub_key = TypedPublicKey::Secp256k1(k1_pub_key); + assert_eq!( + EosPublicKeyEncoder::encode(&typed_pub_key, &CoinInfo::default()).unwrap(), + i.1 + ); } } - - #[test] - fn test_invalid_address_checksum() { - let address = "EOS5varo7aGmCFQw77DNiiWUj3YQA7ZmWUMC4NDDXeeaeEAXk436R"; - let addr = EosAddress::from_str(address); - assert_eq!(addr.err().unwrap().to_string(), "invalid_address_checksum"); - } - - #[test] - fn test_invalid_address() { - let address = "TEST5varo7aGmCFQw77DNiiWUj3YQA7ZmWUMC4NDDXeeaeEAXk436S"; - let addr = EosAddress::from_str(address); - assert_eq!(addr.err().unwrap().to_string(), "invalid_address"); - } } diff --git a/token-core/tcx-eos/src/lib.rs b/token-core/tcx-eos/src/lib.rs index 1aafc87c..95f3a681 100644 --- a/token-core/tcx-eos/src/lib.rs +++ b/token-core/tcx-eos/src/lib.rs @@ -16,6 +16,7 @@ pub mod eos { pub type MessageInput = crate::transaction::EosMessageInput; pub type MessageOutput = crate::transaction::EosMessageOutput; + pub type PubKeyEncoder = crate::address::EosPublicKeyEncoder; } pub fn encode_eos_wif(private_key_bytes: &[u8]) -> Result { diff --git a/token-core/tcx-keystore/src/keystore/hd.rs b/token-core/tcx-keystore/src/keystore/hd.rs index 053a86fd..6783f461 100644 --- a/token-core/tcx-keystore/src/keystore/hd.rs +++ b/token-core/tcx-keystore/src/keystore/hd.rs @@ -206,7 +206,7 @@ impl HdKeystore { network: coin_info.network.to_string(), ext_pub_key, seg_wit: coin_info.seg_wit.to_string(), - public_key: public_key.to_bytes().to_hex(), + public_key: public_key, }; Ok(account) @@ -230,7 +230,9 @@ mod tests { use crate::Source; use bitcoin_hashes::hex::ToHex; use std::string::ToString; + use tcx_common::FromHex; use tcx_constants::{CurveType, TEST_MNEMONIC, TEST_PASSWORD}; + use tcx_primitive::{PublicKey, Secp256k1PublicKey, TypedPublicKey}; // A mnemonic word separated by a full-width or half-width space static MNEMONIC_WITH_WHITESPACE: &'static str = @@ -358,6 +360,15 @@ mod tests { let acc = keystore.derive_coin::(&coin_info).unwrap(); + let k1_pub_key = Secp256k1PublicKey::from_slice( + &Vec::from_hex_auto( + "026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868", + ) + .unwrap(), + ) + .unwrap(); + let public_key = TypedPublicKey::Secp256k1(k1_pub_key); + let expected = Account { address: "026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868".to_string(), derivation_path: "m/44'/0'/0'/0/0".to_string(), @@ -366,7 +377,7 @@ mod tests { seg_wit: "NONE".to_string(), curve: CurveType::SECP256k1, coin: "BITCOIN".to_string(), - public_key: "026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868".to_string() + public_key }; assert_eq!(acc, expected); @@ -457,6 +468,16 @@ mod tests { let acc = keystore.derive_coin::(&coin_info).unwrap(); + let k1_pub_key = Secp256k1PublicKey::from_slice( + &Vec::from_hex_auto( + "026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868", + ) + .unwrap(), + ) + .unwrap(); + let public_key = TypedPublicKey::Secp256k1(k1_pub_key); + + //TODO: why btc address is publickey let expected = Account { address: "026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868".to_string(), derivation_path: "m/44'/0'/0'/0/0".to_string(), @@ -465,7 +486,7 @@ mod tests { seg_wit: "NONE".to_string(), curve: CurveType::SECP256k1, coin: "BITCOIN".to_string(), - public_key: "026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868".to_string() + public_key }; assert_eq!(acc, expected); @@ -514,6 +535,14 @@ mod tests { let acc = keystore.derive_coin::(&coin_info).unwrap(); + let k1_pub_key = Secp256k1PublicKey::from_slice( + &Vec::from_hex_auto( + "026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868", + ) + .unwrap(), + ) + .unwrap(); + let public_key = TypedPublicKey::Secp256k1(k1_pub_key); let expected = Account { address: "026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868".to_string(), derivation_path: "m/44'/0'/0'/0/0".to_string(), @@ -522,7 +551,7 @@ mod tests { seg_wit: "NONE".to_string(), curve: CurveType::SECP256k1, coin: "BITCOIN".to_string(), - public_key: "026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868".to_string() + public_key }; assert_eq!(acc, expected); diff --git a/token-core/tcx-keystore/src/keystore/mod.rs b/token-core/tcx-keystore/src/keystore/mod.rs index f6190fdb..4a670b7c 100644 --- a/token-core/tcx-keystore/src/keystore/mod.rs +++ b/token-core/tcx-keystore/src/keystore/mod.rs @@ -72,8 +72,7 @@ fn transform_mnemonic_error(err: failure::Error) -> Error { } /// Account that presents one blockchain wallet on a fixtures -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Clone, PartialEq)] pub struct Account { pub address: String, pub derivation_path: String, @@ -82,7 +81,11 @@ pub struct Account { pub network: String, pub seg_wit: String, pub ext_pub_key: String, - pub public_key: String, + pub public_key: TypedPublicKey, +} + +pub trait PublicKeyEncoder: Sized + Clone + PartialEq + Eq { + fn encode(public_key: &TypedPublicKey, coin_info: &CoinInfo) -> Result; } /// Chain address interface, for encapsulate derivation @@ -340,7 +343,7 @@ impl Keystore { network: coin_info.network.to_string(), seg_wit: coin_info.seg_wit.to_string(), ext_pub_key: xpub.to_string(), - public_key: typed_pk.to_bytes().to_0x_hex(), + public_key: typed_pk, }; Ok(account) } @@ -512,7 +515,9 @@ pub(crate) mod tests { coin_info_from_param, CoinInfo, CurveType, TEST_MNEMONIC, TEST_PASSWORD, TEST_PRIVATE_KEY, }; use tcx_crypto::Key; - use tcx_primitive::{Ss58Codec, TypedDeterministicPublicKey, TypedPublicKey}; + use tcx_primitive::{ + PublicKey, Secp256k1PublicKey, Ss58Codec, TypedDeterministicPublicKey, TypedPublicKey, + }; #[derive(Clone, PartialEq, Eq)] pub(crate) struct MockAddress(Vec); @@ -866,19 +871,22 @@ pub(crate) mod tests { seg_wit: "NONE".to_string(), }; + let k1_pub_key = Secp256k1PublicKey::from_slice( + &Vec::from_hex_auto( + "026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868", + ) + .unwrap(), + ) + .unwrap(); + let public_key = TypedPublicKey::Secp256k1(k1_pub_key); + let account = keystore.derive_coin::(&coin_info).unwrap(); - assert_eq!( - "026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868", - account.public_key - ); + assert_eq!(public_key, account.public_key); assert_eq!(account.curve, CurveType::SECP256k1); let accounts = keystore.derive_coins::(&[coin_info]).unwrap(); assert_eq!(accounts.len(), 1); - assert_eq!( - "026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868", - accounts[0].public_key - ); + assert_eq!(public_key, accounts[0].public_key); assert_eq!(accounts[0].curve, CurveType::SECP256k1); let public_key = keystore @@ -928,19 +936,22 @@ pub(crate) mod tests { seg_wit: "NONE".to_string(), }; + let k1_pub_key = Secp256k1PublicKey::from_slice( + &Vec::from_hex_auto( + "0280c98b8ea7cab630defb0c09a4295c2193cdee016c1d5b9b0cb18572b9c370fe", + ) + .unwrap(), + ) + .unwrap(); + let public_key = TypedPublicKey::Secp256k1(k1_pub_key); + let account = keystore.derive_coin::(&coin_info).unwrap(); - assert_eq!( - "0280c98b8ea7cab630defb0c09a4295c2193cdee016c1d5b9b0cb18572b9c370fe", - account.public_key - ); + assert_eq!(public_key, account.public_key); assert_eq!(account.curve, CurveType::SECP256k1); let accounts = keystore.derive_coins::(&[coin_info]).unwrap(); assert_eq!(accounts.len(), 1); - assert_eq!( - "0280c98b8ea7cab630defb0c09a4295c2193cdee016c1d5b9b0cb18572b9c370fe", - accounts[0].public_key - ); + assert_eq!(public_key, accounts[0].public_key); assert_eq!(accounts[0].curve, CurveType::SECP256k1); let public_key = keystore diff --git a/token-core/tcx-keystore/src/keystore/private.rs b/token-core/tcx-keystore/src/keystore/private.rs index fd64abba..f6bd4b02 100644 --- a/token-core/tcx-keystore/src/keystore/private.rs +++ b/token-core/tcx-keystore/src/keystore/private.rs @@ -128,7 +128,7 @@ impl PrivateKeystore { network: coin.network.to_string(), seg_wit: coin.seg_wit.to_string(), ext_pub_key: "".to_string(), - public_key: pub_key.to_bytes().to_hex(), + public_key: pub_key, }; Ok(acc) @@ -153,6 +153,7 @@ mod tests { use tcx_common::FromHex; use tcx_constants::{CoinInfo, CurveType, TEST_MNEMONIC, TEST_PASSWORD, TEST_PRIVATE_KEY}; use tcx_crypto::Key; + use tcx_primitive::{PublicKey, Secp256k1PublicKey, TypedPublicKey}; #[test] fn test_from_private_key() { @@ -247,7 +248,11 @@ mod tests { for (i, coin_info) in coin_infos.iter().enumerate() { let acc = keystore.derive_coin::(&coin_info).unwrap(); - assert_eq!(acc.public_key, excepts[i]); + + let k1_pub_key = + Secp256k1PublicKey::from_slice(&Vec::from_hex_auto(excepts[i]).unwrap()).unwrap(); + let public_key = TypedPublicKey::Secp256k1(k1_pub_key); + assert_eq!(acc.public_key, public_key); } } } diff --git a/token-core/tcx-keystore/src/lib.rs b/token-core/tcx-keystore/src/lib.rs index 0d3e0e58..aeb04442 100644 --- a/token-core/tcx-keystore/src/lib.rs +++ b/token-core/tcx-keystore/src/lib.rs @@ -26,7 +26,7 @@ mod signer; pub use keystore::{ fingerprint_from_mnemonic, fingerprint_from_private_key, fingerprint_from_seed, mnemonic_to_seed, Account, Address, HdKeystore, Keystore, KeystoreGuard, Metadata, - PrivateKeystore, Source, + PrivateKeystore, PublicKeyEncoder, Source, }; pub use signer::{HashSigner, MessageSigner, SignatureParameters, Signer, TransactionSigner}; diff --git a/token-core/tcx-primitive/src/bls.rs b/token-core/tcx-primitive/src/bls.rs index 4933a605..060069a1 100644 --- a/token-core/tcx-primitive/src/bls.rs +++ b/token-core/tcx-primitive/src/bls.rs @@ -2,7 +2,7 @@ use crate::ecc::{KeyError, PrivateKey as TraitPrivateKey, PublicKey as TraitPubl use crate::Result; use blst::min_pk::{PublicKey, SecretKey}; -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub struct BLSPublicKey(PublicKey); #[derive(Clone)] diff --git a/token-core/tcx-primitive/src/ecc.rs b/token-core/tcx-primitive/src/ecc.rs index 0d76eda1..2743dc4b 100644 --- a/token-core/tcx-primitive/src/ecc.rs +++ b/token-core/tcx-primitive/src/ecc.rs @@ -1,3 +1,4 @@ +use serde::Serialize; use tcx_common::{FromHex, ToHex}; use super::Result; @@ -199,6 +200,7 @@ impl TypedPrivateKey { } } +#[derive(Debug, Clone, PartialEq)] pub enum TypedPublicKey { Secp256k1(Secp256k1PublicKey), SR25519(Sr25519PublicKey), diff --git a/token-core/tcx-primitive/src/ed25519.rs b/token-core/tcx-primitive/src/ed25519.rs index cd548d1c..0534188c 100644 --- a/token-core/tcx-primitive/src/ed25519.rs +++ b/token-core/tcx-primitive/src/ed25519.rs @@ -6,7 +6,7 @@ use sp_core::ed25519::{Pair, Public}; use sp_core::Pair as TraitPair; use std::convert::TryFrom; -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub struct Ed25519PublicKey(pub Public); #[derive(Clone)] diff --git a/token-core/tcx-primitive/src/secp256k1.rs b/token-core/tcx-primitive/src/secp256k1.rs index b9116dc0..dff2db36 100644 --- a/token-core/tcx-primitive/src/secp256k1.rs +++ b/token-core/tcx-primitive/src/secp256k1.rs @@ -26,7 +26,7 @@ fn transform_secp256k1_error(err: secp256k1::Error) -> KeyError { } } -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub struct Secp256k1PublicKey(pub PublicKey); #[derive(Clone)] diff --git a/token-core/tcx-primitive/src/sr25519.rs b/token-core/tcx-primitive/src/sr25519.rs index 9a3ec62c..270d7dfe 100644 --- a/token-core/tcx-primitive/src/sr25519.rs +++ b/token-core/tcx-primitive/src/sr25519.rs @@ -9,7 +9,7 @@ use sp_core::Pair as TraitPair; //use sp_core::crypto::Ss58Codec; -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub struct Sr25519PublicKey(pub Public); #[derive(Clone)] diff --git a/token-core/tcx-tezos/src/address.rs b/token-core/tcx-tezos/src/address.rs index db18093a..73a7fa2f 100644 --- a/token-core/tcx-tezos/src/address.rs +++ b/token-core/tcx-tezos/src/address.rs @@ -1,13 +1,29 @@ use bitcoin::util::base58; use blake2b_simd::Params; use std::str::FromStr; +use tcx_common::sha256d; use tcx_constants::CoinInfo; use tcx_keystore::Address; +use tcx_keystore::PublicKeyEncoder; use tcx_keystore::Result; use tcx_primitive::TypedPublicKey; use tcx_common::FromHex; +#[derive(PartialEq, Eq, Clone)] +pub struct TezosPublicKeyEncoder {} + +impl PublicKeyEncoder for TezosPublicKeyEncoder { + fn encode(public_key: &TypedPublicKey, coin_info: &CoinInfo) -> Result { + let edpk_prefix: Vec = vec![0x0D, 0x0F, 0x25, 0xD9]; + let to_hash = [edpk_prefix, public_key.to_bytes()].concat(); + let hashed = sha256d(&to_hash); + let hash_with_checksum = [to_hash, hashed[0..4].to_vec()].concat(); + let edpk = base58::encode_slice(&hash_with_checksum); + Ok(edpk) + } +} + #[derive(PartialEq, Eq, Clone)] pub struct TezosAddress(String); diff --git a/token-core/tcx-tezos/src/lib.rs b/token-core/tcx-tezos/src/lib.rs index c7d8d27f..e7a09bab 100644 --- a/token-core/tcx-tezos/src/lib.rs +++ b/token-core/tcx-tezos/src/lib.rs @@ -34,6 +34,7 @@ pub mod tezos { pub type Address = crate::address::TezosAddress; pub type TransactionInput = crate::transaction::TezosRawTxIn; pub type TransactionOutput = crate::transaction::TezosTxOut; + pub type PubKeyEncoder = crate::address::TezosPublicKeyEncoder; } #[cfg(test)] diff --git a/token-core/tcx/src/handler.rs b/token-core/tcx/src/handler.rs index 4f4b1549..c3520c7b 100644 --- a/token-core/tcx/src/handler.rs +++ b/token-core/tcx/src/handler.rs @@ -1,4 +1,3 @@ -use base58::ToBase58; use bytes::BytesMut; use prost::Message; use serde_json::Value; @@ -6,7 +5,7 @@ use std::fs; use std::io::Read; use std::path::Path; use std::str::FromStr; -use tcx_eos::address::EosAddress; +use tcx_eos::address::{EosAddress, EosPublicKeyEncoder}; use tcx_eos::encode_eos_wif; use tcx_eth2::transaction::{SignBlsToExecutionChangeParam, SignBlsToExecutionChangeResult}; use tcx_keystore::keystore::IdentityNetwork; @@ -499,6 +498,16 @@ pub(crate) fn derive_accounts(data: &[u8]) -> Result> { for derivation in param.derivations { let account = derive_account(guard.keystore_mut(), &derivation)?; + let mut coin_info = coin_info_from_param( + &derivation.chain_type, + &derivation.network, + &derivation.seg_wit, + &derivation.curve, + )?; + if !derivation.path.is_empty() { + coin_info.derivation_path = derivation.path; + } + let enc_xpub = if account.ext_pub_key.is_empty() { Ok("".to_string()) } else { @@ -509,7 +518,7 @@ pub(crate) fn derive_accounts(data: &[u8]) -> Result> { address: account.address.to_owned(), path: account.derivation_path.to_owned(), curve: account.curve.as_str().to_string(), - public_key: account.public_key, + public_key: encode_public_key_internal(&account.public_key, &coin_info)?, extended_public_key: account.ext_pub_key.to_string(), encrypted_extended_public_key: enc_xpub, }; @@ -717,45 +726,30 @@ pub(crate) fn get_public_keys(data: &[u8]) -> Result> { }?; let mut guard = KeystoreGuard::unlock_by_password(keystore, ¶m.password)?; - let public_keys: Vec> = param + let public_keys: Vec = param .derivations .iter() .map(|derivation| { - let public_key = guard + guard .keystore_mut() .get_public_key(CurveType::from_str(&derivation.curve), &derivation.path) - .expect("PublicKeyProcessed"); - public_key.to_bytes() + .expect("PublicKeyProcessed") }) .collect(); let mut public_key_strs: Vec = vec![]; - for (idx, _) in public_keys.iter().enumerate().take(param.derivations.len()) { - let pub_key = public_keys[idx].to_vec(); - let public_key_str_ret: Result = match param.derivations[idx].chain_type.as_str() { - "TEZOS" => { - let edpk_prefix: Vec = vec![0x0D, 0x0F, 0x25, 0xD9]; - let to_hash = [edpk_prefix, pub_key].concat(); - let hashed = sha256d(&to_hash); - let hash_with_checksum = [to_hash, hashed[0..4].to_vec()].concat(); - let edpk = hash_with_checksum.to_base58(); - Ok(edpk) - } - "EOS" => { - let secp256k1_pub_key = Secp256k1PublicKey::from_slice(&pub_key)?; - let typed_pub_key = TypedPublicKey::Secp256k1(secp256k1_pub_key); - let eos_addr = EosAddress::from_public_key( - &typed_pub_key, - &CoinInfo { - coin: "EOS".to_string(), - curve: CurveType::SECP256k1, - ..Default::default() - }, - )?; - Ok(eos_addr.to_string()) - } - _ => Ok(pub_key.to_0x_hex()), + for idx in 0..param.derivations.len() { + let pub_key = &public_keys[idx]; + let derivation = ¶m.derivations[idx]; + let coin_info = CoinInfo { + coin: derivation.chain_type.to_string(), + derivation_path: derivation.path.to_string(), + curve: CurveType::from_str(&derivation.curve), + ..Default::default() }; + + let public_key_str_ret = encode_public_key_internal(&pub_key, &coin_info); + let pub_key_str = public_key_str_ret?; public_key_strs.push(pub_key_str); } @@ -1058,13 +1052,13 @@ pub(crate) fn derive_sub_accounts(data: &[u8]) -> Result> { .relative_paths .iter() .map(|relative_path| { - let coin_info = CoinInfo { - coin: param.chain_type.to_string(), - derivation_path: relative_path.to_string(), - curve, - network: param.network.to_string(), - seg_wit: param.seg_wit.to_string(), - }; + let mut coin_info = coin_info_from_param( + ¶m.chain_type, + ¶m.network, + ¶m.seg_wit, + ¶m.curve, + )?; + coin_info.derivation_path = relative_path.to_string(); let acc: Account = derive_sub_account(&xpub, &coin_info)?; let enc_xpub = encrypt_xpub(¶m.extended_public_key.to_string(), &acc.network)?; @@ -1075,7 +1069,7 @@ pub(crate) fn derive_sub_accounts(data: &[u8]) -> Result> { path: relative_path.to_string(), extended_public_key: param.extended_public_key.to_string(), encrypted_extended_public_key: enc_xpub, - public_key: acc.public_key, + public_key: encode_public_key_internal(&acc.public_key, &coin_info)?, curve: param.curve.to_string(), }; Ok(acc_rsp) @@ -1146,10 +1140,13 @@ pub(crate) fn migrate_keystore(data: &[u8]) -> Result> { pub(crate) fn mnemonic_to_public(data: &[u8]) -> Result> { let param = MnemonicToPublicKeyParam::decode(data)?; let public_key = tcx_primitive::mnemonic_to_public(¶m.mnemonic, ¶m.path, ¶m.curve)?; - let public_key_str = match param.encoding.to_uppercase().as_str() { - "EOS" => EosAddress::from_public_key(&public_key, &CoinInfo::default())?.to_string(), - _ => public_key.to_bytes().to_0x_hex(), + let coin_info = CoinInfo { + derivation_path: param.path, + curve: CurveType::from_str(¶m.curve), + coin: param.encoding, + ..Default::default() }; + let public_key_str = encode_public_key_internal(&public_key, &coin_info)?; encode_message(MnemonicToPublicKeyResult { public_key: public_key_str, }) diff --git a/token-core/tcx/src/lib.rs b/token-core/tcx/src/lib.rs index 9f1629cd..6eb51565 100644 --- a/token-core/tcx/src/lib.rs +++ b/token-core/tcx/src/lib.rs @@ -569,7 +569,7 @@ mod tests { network: "MAINNET".to_string(), seg_wit: "NONE".to_string(), chain_id: "".to_string(), - curve: "".to_string(), + curve: "secp256k1".to_string(), bech32_prefix: "".to_string(), }, Derivation { @@ -578,7 +578,7 @@ mod tests { network: "MAINNET".to_string(), seg_wit: "P2WPKH".to_string(), chain_id: "".to_string(), - curve: "".to_string(), + curve: "secp256k1".to_string(), bech32_prefix: "".to_string(), }, Derivation { @@ -587,7 +587,7 @@ mod tests { network: "TESTNET".to_string(), seg_wit: "NONE".to_string(), chain_id: "".to_string(), - curve: "".to_string(), + curve: "secp256k1".to_string(), bech32_prefix: "".to_string(), }, Derivation { @@ -596,7 +596,7 @@ mod tests { network: "".to_string(), seg_wit: "".to_string(), chain_id: "".to_string(), - curve: "".to_string(), + curve: "secp256k1".to_string(), bech32_prefix: "".to_string(), }, Derivation { @@ -605,7 +605,7 @@ mod tests { network: "TESTNET".to_string(), seg_wit: "".to_string(), chain_id: "".to_string(), - curve: "".to_string(), + curve: "secp256k1".to_string(), bech32_prefix: "".to_string(), }, Derivation { @@ -614,7 +614,7 @@ mod tests { network: "".to_string(), seg_wit: "".to_string(), chain_id: "".to_string(), - curve: "".to_string(), + curve: "sr25519".to_string(), bech32_prefix: "".to_string(), }, Derivation { @@ -623,7 +623,7 @@ mod tests { network: "".to_string(), seg_wit: "".to_string(), chain_id: "".to_string(), - curve: "".to_string(), + curve: "sr25519".to_string(), bech32_prefix: "".to_string(), }, Derivation { @@ -770,10 +770,7 @@ mod tests { derived_accounts.accounts[9].address ); - assert_eq!( - "EOS7Nf9TU1vZaQQgZA3cELTHJf1nnDJ6xVvqHvVzbHehsgcjrzNkq", - derived_accounts.accounts[10].address - ); + assert_eq!("", derived_accounts.accounts[10].address); assert_eq!( "0x37c6713aa848bCdeE372A620eEbCdcCBA55c695F", derived_accounts.accounts[11].address @@ -1033,7 +1030,7 @@ mod tests { assert_eq!( "EOS5Vubes67f2xXCRDJXx5WJRsMBuf4gTfzukbqLnyjZQCyoPjPZu", - derived_accounts.accounts[7].address + derived_accounts.accounts[7].public_key ); assert_eq!( diff --git a/token-core/tcx/src/macros.rs b/token-core/tcx/src/macros.rs index b99566aa..07bc603b 100644 --- a/token-core/tcx/src/macros.rs +++ b/token-core/tcx/src/macros.rs @@ -1,6 +1,8 @@ use std::str::FromStr; use tcx_constants::CoinInfo; -use tcx_keystore::{Address, Keystore, MessageSigner, SignatureParameters, TransactionSigner}; +use tcx_keystore::{ + Address, Keystore, MessageSigner, PublicKeyEncoder, SignatureParameters, TransactionSigner, +}; use tcx_primitive::TypedPublicKey; @@ -70,9 +72,19 @@ impl ToString for MockAddress { } } +#[derive(Clone, PartialEq, Eq)] +pub struct MockPublicKeyEncoder(); + +impl PublicKeyEncoder for MockPublicKeyEncoder { + fn encode(_public_key: &TypedPublicKey, _coin_info: &CoinInfo) -> tcx_keystore::Result { + Err(format_err!("unsupported_chain")) + } +} + macro_rules! use_chains { ($($chain:path),+ $(,)?) => { - use crate::macros::{MockTransactionInput, MockTransactionOutput, MockAddress, MockMessageInput, MockMessageOutput}; + use tcx_keystore::PublicKeyEncoder; + use crate::macros::{MockTransactionInput, MockTransactionOutput, MockAddress, MockPublicKeyEncoder, MockMessageInput, MockMessageOutput}; #[allow(dead_code)] fn sign_transaction_internal(params: &SignParam, keystore: &mut Keystore) -> std::result::Result, failure::Error> { @@ -177,6 +189,19 @@ macro_rules! use_chains { Err(format_err!("unsupported_chain")) } + + fn encode_public_key_internal(public_key: &TypedPublicKey, coin_info:&CoinInfo,) -> Result { + type PubKeyEncoder = MockPublicKeyEncoder; + let faker_encoder = std::any::TypeId::of::(); + $({ + use $chain::*; + if CHAINS.contains(&coin_info.coin.as_str()) && std::any::TypeId::of::() != faker_encoder { + return PubKeyEncoder::encode(&public_key, coin_info) + } + })* + + return Ok(public_key.to_bytes().to_0x_hex()) + } }; }