diff --git a/token-core/tcx-keystore/src/keystore/mod.rs b/token-core/tcx-keystore/src/keystore/mod.rs index 5eb5d2ec..900cd1d2 100644 --- a/token-core/tcx-keystore/src/keystore/mod.rs +++ b/token-core/tcx-keystore/src/keystore/mod.rs @@ -359,13 +359,7 @@ impl Keystore { xpub: &TypedDeterministicPublicKey, coin_info: &CoinInfo, ) -> Result { - // let acc_path = get_account_path(path)?; - // let change_path = format!("{}/{}", acc_path, relative_path); - // TODO: test derive from relative path? - let typed_pk = xpub.derive(&coin_info.derivation_path)?.public_key(); - // let typed_pk = TypedPublicKey::Secp256k1(public_key); - let address = A::from_public_key(&typed_pk, &coin_info)?.to_string(); let account = Account { address, diff --git a/token-core/tcx-primitive/src/lib.rs b/token-core/tcx-primitive/src/lib.rs index 34bd97d5..dee66299 100644 --- a/token-core/tcx-primitive/src/lib.rs +++ b/token-core/tcx-primitive/src/lib.rs @@ -13,11 +13,13 @@ mod rand; mod secp256k1; mod sr25519; mod subkey; - use core::result; +use tcx_common::ToHex; pub type Result = result::Result; +use tcx_constants::CurveType; + pub use crate::bip32::{Bip32DeterministicPrivateKey, Bip32DeterministicPublicKey}; pub use crate::derive::{get_account_path, Derive, DeriveJunction, DerivePath}; pub use crate::ecc::{ @@ -45,3 +47,11 @@ pub trait Ss58Codec: Sized { /// Return the ss58-check string for this key. fn to_ss58check_with_version(&self, version: &[u8]) -> String; } + +pub fn mnemonic_to_public(mnemonic: &str, path: &str, curve: &str) -> Result { + let curve_type = CurveType::from_str(curve); + let root = TypedDeterministicPrivateKey::from_mnemonic(curve_type, mnemonic)?; + + let private_key = root.derive(&path)?.private_key(); + Ok(private_key.public_key()) +} diff --git a/token-core/tcx-proto/src/params.proto b/token-core/tcx-proto/src/params.proto index 2cd78b18..e875888e 100644 --- a/token-core/tcx-proto/src/params.proto +++ b/token-core/tcx-proto/src/params.proto @@ -182,44 +182,6 @@ message DeriveSubAccountsResult { repeated AccountResponse accounts = 1; } -// btc-fork -// message ExternalAddressParam { -// string id = 1; -// string chainType = 2; -// uint32 externalIdx = 3; -// } - -// message ExternalAddressResult { -// string address = 1; -// string derivedPath = 2; -// string type = 3; -// } - -// message ExternalAddressExtra { -// string encXpub = 1; -// message ExternalAddress { -// string address = 1; -// string derivedPath = 2; -// string type = 3; -// } -// ExternalAddress externalAddress = 2; -// } - -// message BtcForkDeriveExtraParam { -// string network = 1; -// string segWit = 2; -// } - -// message HdStoreExtendedPublicKeyParam { -// string id = 1; -// string password = 2; -// string chainType = 3; -// string address = 4; -// } - -// message HdStoreExtendedPublicKeyResponse { -// string extendedPublicKey = 1; -// } message PublicKeyParam { string id = 1; @@ -234,42 +196,32 @@ message PublicKeyResult { string publicKey = 4; } - -// message KeystoreUpdateAccount { -// string id = 1; -// string password = 2; -// string accountName = 3; -// } - - - - -message StoreDeleteParam { +message RemoveWalletParam { string id = 1; string password = 2; } -message StoreDeleteResult { +message RemoveWalletResult { bool isSuccess = 1; } -message V3KeystoreImportInput { - string keystore = 1; - string password = 2; - bool overwrite = 3; - string name = 4; - string chainType = 5; - string source = 6; -} +// message V3KeystoreImportInput { +// string keystore = 1; +// string password = 2; +// bool overwrite = 3; +// string name = 4; +// string chainType = 5; +// string source = 6; +// } -message V3KeystoreExportInput { - string id = 1; - string password = 2; -} +// message V3KeystoreExportInput { +// string id = 1; +// string password = 2; +// } -message V3KeystoreExportOutput { - string json = 1; -} +// message V3KeystoreExportOutput { +// string json = 1; +// } message EncryptDataToIpfsParam { string identifier = 1; @@ -305,4 +257,15 @@ message SignAuthenticationMessageResult { message GenerateMnemonicResult { string mnemonic = 1; +} + +message MnemonicToPublicKeyParam { + string mnemonic = 1; + string path = 2; + string curve = 3; + string encoding = 4; +} + +message MnemonicToPublicKeyResult { + string publicKey = 1; } \ No newline at end of file diff --git a/token-core/tcx/src/api.rs b/token-core/tcx/src/api.rs index c7958ea4..ef41f74e 100644 --- a/token-core/tcx/src/api.rs +++ b/token-core/tcx/src/api.rs @@ -482,7 +482,7 @@ pub struct PublicKeyResult { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct StoreDeleteParam { +pub struct RemoveWalletParam { #[prost(string, tag = "1")] pub id: ::prost::alloc::string::String, #[prost(string, tag = "2")] @@ -490,42 +490,12 @@ pub struct StoreDeleteParam { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct StoreDeleteResult { +pub struct RemoveWalletResult { #[prost(bool, tag = "1")] pub is_success: bool, } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct V3KeystoreImportInput { - #[prost(string, tag = "1")] - pub keystore: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub password: ::prost::alloc::string::String, - #[prost(bool, tag = "3")] - pub overwrite: bool, - #[prost(string, tag = "4")] - pub name: ::prost::alloc::string::String, - #[prost(string, tag = "5")] - pub chain_type: ::prost::alloc::string::String, - #[prost(string, tag = "6")] - pub source: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct V3KeystoreExportInput { - #[prost(string, tag = "1")] - pub id: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub password: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct V3KeystoreExportOutput { - #[prost(string, tag = "1")] - pub json: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] pub struct EncryptDataToIpfsParam { #[prost(string, tag = "1")] pub identifier: ::prost::alloc::string::String, @@ -582,6 +552,24 @@ pub struct GenerateMnemonicResult { #[prost(string, tag = "1")] pub mnemonic: ::prost::alloc::string::String, } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MnemonicToPublicKeyParam { + #[prost(string, tag = "1")] + pub mnemonic: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub path: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub curve: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub encoding: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct MnemonicToPublicKeyResult { + #[prost(string, tag = "1")] + pub public_key: ::prost::alloc::string::String, +} /// only support two types #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] diff --git a/token-core/tcx/src/handler.rs b/token-core/tcx/src/handler.rs index 337b2aef..529b4882 100644 --- a/token-core/tcx/src/handler.rs +++ b/token-core/tcx/src/handler.rs @@ -5,6 +5,7 @@ use std::fs; use std::io::Read; use std::path::Path; use std::str::FromStr; +use tcx_eos::address::EosAddress; use tcx_keystore::keystore::IdentityNetwork; use tcx_common::{FromHex, ToHex}; @@ -12,7 +13,7 @@ use tcx_primitive::{private_key_without_version, TypedPrivateKey}; use tcx_btc_kin::WIFDisplay; use tcx_keystore::{ - key_hash_from_mnemonic, key_hash_from_private_key, Keystore, KeystoreGuard, + key_hash_from_mnemonic, key_hash_from_private_key, Address, Keystore, KeystoreGuard, SignatureParameters, Signer, }; use tcx_keystore::{Account, HdKeystore, Metadata, PrivateKeystore, Source}; @@ -29,12 +30,12 @@ use crate::api::{ ExistsMnemonicParam, ExistsPrivateKeyParam, ExportPrivateKeyParam, ExportResult, GeneralResult, GenerateMnemonicResult, GetExtendedPublicKeysParam, GetExtendedPublicKeysResult, GetPublicKeysParam, GetPublicKeysResult, ImportMnemonicParam, ImportPrivateKeyParam, KeyType, - KeystoreCommonExistsParam, KeystoreMigrationParam, KeystoreResult, + KeystoreCommonExistsParam, KeystoreMigrationParam, KeystoreResult, MnemonicToPublicKeyParam, + MnemonicToPublicKeyResult, RemoveWalletParam, RemoveWalletResult, SignAuthenticationMessageParam, SignAuthenticationMessageResult, SignHashesParam, - SignHashesResult, StoreDeleteParam, StoreDeleteResult, WalletKeyParam, - ZksyncPrivateKeyFromSeedParam, ZksyncPrivateKeyFromSeedResult, - ZksyncPrivateKeyToPubkeyHashParam, ZksyncPrivateKeyToPubkeyHashResult, ZksyncSignMusigParam, - ZksyncSignMusigResult, + SignHashesResult, WalletKeyParam, ZksyncPrivateKeyFromSeedParam, + ZksyncPrivateKeyFromSeedResult, ZksyncPrivateKeyToPubkeyHashParam, + ZksyncPrivateKeyToPubkeyHashResult, ZksyncSignMusigParam, ZksyncSignMusigResult, }; use crate::api::{InitTokenCoreXParam, SignParam}; use crate::error_handling::Result; @@ -269,6 +270,7 @@ fn encrypt_xpub(xpub: &str, network: &str) -> Result { Ok(base64::encode(&encrypted)) } +#[allow(dead_code)] fn decrypt_xpub(enc_xpub: &str) -> Result { let encrypted = base64::decode(enc_xpub)?; let key = tcx_crypto::XPUB_COMMON_KEY_128.read(); @@ -897,7 +899,7 @@ pub(crate) fn generate_mnemonic() -> Result> { } pub(crate) fn remove_wallet(data: &[u8]) -> Result> { - let param: StoreDeleteParam = StoreDeleteParam::decode(data)?; + let param: RemoveWalletParam = RemoveWalletParam::decode(data)?; let map = KEYSTORE_MAP.read(); let keystore: &Keystore = match map.get(¶m.id) { Some(keystore) => Ok(keystore), @@ -909,7 +911,7 @@ pub(crate) fn remove_wallet(data: &[u8]) -> Result> { } filemanager::delete_keystore_file(¶m.id)?; - let result = StoreDeleteResult { is_success: true }; + let result = RemoveWalletResult { is_success: true }; encode_message(result) } @@ -1076,3 +1078,15 @@ pub(crate) fn migrate_keystore(data: &[u8]) -> Result> { Err(format_err!("invalid version in keystore")) } } + +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(), + }; + 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 1f3236dd..ddb4477a 100644 --- a/token-core/tcx/src/lib.rs +++ b/token-core/tcx/src/lib.rs @@ -2,11 +2,6 @@ use std::ffi::{CStr, CString}; use std::os::raw::c_char; -use handler::{ - decrypt_data_from_ipfs, derive_sub_accounts, encrypt_data_to_ipfs, exists_mnemonic, - exists_private_key, migrate_keystore, remove_wallet, sign_authentication_message, sign_message, -}; -// use handler::{eth_v3keystore_export, eth_v3keystore_import}; use prost::Message; pub mod api; @@ -20,11 +15,14 @@ use std::result; use crate::error_handling::{landingpad, LAST_BACKTRACE, LAST_ERROR}; use crate::handler::{ - create_keystore, delete_keystore, derive_accounts, encode_message, eth_recover_address, - exists_json, export_json, export_mnemonic, export_private_key, generate_mnemonic, + create_keystore, decrypt_data_from_ipfs, delete_keystore, derive_accounts, derive_sub_accounts, + encode_message, encrypt_data_to_ipfs, eth_recover_address, exists_json, exists_mnemonic, + exists_private_key, export_json, export_mnemonic, export_private_key, generate_mnemonic, get_derived_key, get_extended_public_keys, get_public_keys, import_json, import_mnemonic, - import_private_key, sign_hashes, sign_tx, unlock_then_crash, verify_password, - zksync_private_key_from_seed, zksync_private_key_to_pubkey_hash, zksync_sign_musig, + import_private_key, migrate_keystore, mnemonic_to_public, remove_wallet, + sign_authentication_message, sign_hashes, sign_message, sign_tx, unlock_then_crash, + verify_password, zksync_private_key_from_seed, zksync_private_key_to_pubkey_hash, + zksync_sign_musig, }; mod filemanager; @@ -119,7 +117,7 @@ pub unsafe extern "C" fn call_tcx_api(hex_str: *const c_char) -> *const c_char { } "get_public_keys" => landingpad(|| get_public_keys(&action.param.unwrap().value)), "sign_hashes" => landingpad(|| sign_hashes(&action.param.unwrap().value)), - + "mnemonic_to_public" => landingpad(|| mnemonic_to_public(&action.param.unwrap().value)), _ => landingpad(|| Err(format_err!("unsupported_method"))), }; match reply { @@ -180,8 +178,9 @@ mod tests { ExportPrivateKeyParam, ExportResult, GeneralResult, GenerateMnemonicResult, GetPublicKeysParam, GetPublicKeysResult, ImportMnemonicParam, ImportPrivateKeyParam, InitTokenCoreXParam, KeyType, KeystoreCommonAccountsParam, KeystoreCommonExistsParam, - KeystoreResult, PrivateKeyStoreExportParam, PublicKeyDerivation, PublicKeyParam, - PublicKeyResult, SignHashesParam, SignHashesResult, SignParam, WalletKeyParam, + KeystoreResult, MnemonicToPublicKeyParam, MnemonicToPublicKeyResult, + PrivateKeyStoreExportParam, PublicKeyDerivation, PublicKeyParam, PublicKeyResult, + SignHashesParam, SignHashesResult, SignParam, WalletKeyParam, ZksyncPrivateKeyFromSeedParam, ZksyncPrivateKeyFromSeedResult, ZksyncPrivateKeyToPubkeyHashParam, ZksyncPrivateKeyToPubkeyHashResult, ZksyncSignMusigParam, ZksyncSignMusigResult, @@ -3595,6 +3594,39 @@ mod tests { }) } + #[test] + pub fn test_mnemonic_to_public() { + run_test(|| { + let params = MnemonicToPublicKeyParam { + mnemonic: TEST_MNEMONIC.to_string(), + path: "m/44'/194'/0'/0/0".to_string(), + curve: "SECP256k1".to_string(), + encoding: "EOS".to_string(), + }; + + let result_bytes = mnemonic_to_public(&encode_message(params).unwrap()).unwrap(); + let result = MnemonicToPublicKeyResult::decode(result_bytes.as_slice()).unwrap(); + assert_eq!( + "EOS88XhiiP7Cu5TmAUJqHbyuhyYgd6sei68AU266PyetDDAtjmYWF", + result.public_key + ); + + let params = MnemonicToPublicKeyParam { + mnemonic: TEST_MNEMONIC.to_string(), + path: "m/44'/60'/0'/0/0".to_string(), + curve: "SECP256k1".to_string(), + encoding: "HEX".to_string(), + }; + + let result_bytes = mnemonic_to_public(&encode_message(params).unwrap()).unwrap(); + let result = MnemonicToPublicKeyResult::decode(result_bytes.as_slice()).unwrap(); + assert_eq!( + "0x0280c98b8ea7cab630defb0c09a4295c2193cdee016c1d5b9b0cb18572b9c370fe", + result.public_key + ); + }) + } + // #[test] // pub fn test_eth_ec_sign() { // run_test(|| {