From f74de1b673481fa2cf2376e909eadabfbab0850d Mon Sep 17 00:00:00 2001 From: Satoshi Otomakan Date: Tue, 3 Dec 2024 19:58:33 +0100 Subject: [PATCH] Revert "[TON]: Add support for TON 24-words mnemonic (#3998)" This reverts commit 0b167710b325d299398ca82ef57ee8e630e54633. --- .../TestTheOpenNetworkWallet.kt | 17 - .../core/app/utils/TestKeyStore.kt | 48 - include/TrustWalletCore/TWStoredKey.h | 38 - include/TrustWalletCore/TWTONWallet.h | 36 +- rust/Cargo.lock | 28 - rust/Cargo.toml | 1 - rust/chains/tw_ton/Cargo.toml | 1 - .../src/test_utils/address_utils.rs | 4 +- rust/tw_hash/Cargo.toml | 1 - rust/tw_hash/src/ffi.rs | 2 - rust/tw_hash/src/hmac.rs | 15 +- rust/tw_hash/src/lib.rs | 2 - rust/tw_hash/src/pbkdf2.rs | 10 - rust/tw_hd_wallet/Cargo.toml | 14 - rust/tw_hd_wallet/src/bip39/bip39_english.rs | 2070 ----------------- rust/tw_hd_wallet/src/bip39/mod.rs | 9 - rust/tw_hd_wallet/src/lib.rs | 18 - rust/tw_hd_wallet/src/ton/mnemonic.rs | 38 - rust/tw_hd_wallet/src/ton/mod.rs | 169 -- rust/tw_hd_wallet/tests/ton_mnemonic.rs | 156 -- rust/tw_keypair/src/ed25519/keypair.rs | 9 - rust/tw_keypair/src/ed25519/private.rs | 27 +- rust/tw_keypair/src/ffi/privkey.rs | 18 +- rust/tw_keypair/src/ffi/pubkey.rs | 2 +- .../src/test_utils/tw_crypto_box_helpers.rs | 6 +- .../src/test_utils/tw_private_key_helper.rs | 17 +- rust/tw_keypair/src/tw/private.rs | 13 - rust/tw_keypair/tests/crypto_box_ffi_tests.rs | 19 +- rust/tw_memory/Cargo.toml | 1 - rust/tw_memory/src/ffi/tw_data.rs | 13 - rust/tw_memory/src/test_utils/tw_wrapper.rs | 38 +- rust/tw_tests/tests/chains/ton/ton_wallet.rs | 32 +- rust/wallet_core_rs/Cargo.toml | 3 - rust/wallet_core_rs/src/ffi/mod.rs | 2 - rust/wallet_core_rs/src/ffi/ton/mod.rs | 1 + rust/wallet_core_rs/src/ffi/ton/wallet.rs | 55 + rust/wallet_core_rs/src/ffi/wallet/mod.rs | 5 - .../src/ffi/wallet/ton_wallet.rs | 128 - src/DerivationPath.cpp | 4 - src/Keystore/StoredKey.cpp | 112 +- src/Keystore/StoredKey.h | 44 +- src/TheOpenNetwork/TONWallet.cpp | 54 - src/TheOpenNetwork/TONWallet.h | 47 - src/interface/TWStoredKey.cpp | 26 - src/interface/TWTONWallet.cpp | 35 - src/rust/Wrapper.h | 8 +- swift/Sources/KeyStore.swift | 157 +- swift/Sources/Wallet.swift | 6 +- swift/Tests/Keystore/Data/ton_wallet.json | 30 - swift/Tests/Keystore/KeyStoreTests.swift | 111 +- swift/Tests/Keystore/WalletTests.swift | 50 - .../TheOpenNetwork/TWTONWalletTests.cpp | 19 - tests/common/Keystore/Data/ton-wallet.json | 30 - tests/common/Keystore/StoredKeyConstants.h | 19 - tests/common/Keystore/StoredKeyTONTests.cpp | 172 -- tests/common/Keystore/StoredKeyTests.cpp | 22 +- tests/interface/TWStoredKeyTests.cpp | 126 +- wasm/src/keystore/default-impl.ts | 46 +- wasm/src/keystore/types.ts | 12 +- wasm/tests/KeyStore+extension.test.ts | 45 - wasm/tests/setup.test.ts | 2 - 61 files changed, 202 insertions(+), 4041 deletions(-) delete mode 100644 rust/tw_hash/src/pbkdf2.rs delete mode 100644 rust/tw_hd_wallet/Cargo.toml delete mode 100644 rust/tw_hd_wallet/src/bip39/bip39_english.rs delete mode 100644 rust/tw_hd_wallet/src/bip39/mod.rs delete mode 100644 rust/tw_hd_wallet/src/lib.rs delete mode 100644 rust/tw_hd_wallet/src/ton/mnemonic.rs delete mode 100644 rust/tw_hd_wallet/src/ton/mod.rs delete mode 100644 rust/tw_hd_wallet/tests/ton_mnemonic.rs create mode 100644 rust/wallet_core_rs/src/ffi/ton/wallet.rs delete mode 100644 rust/wallet_core_rs/src/ffi/wallet/mod.rs delete mode 100644 rust/wallet_core_rs/src/ffi/wallet/ton_wallet.rs delete mode 100644 src/TheOpenNetwork/TONWallet.cpp delete mode 100644 src/TheOpenNetwork/TONWallet.h delete mode 100644 swift/Tests/Keystore/Data/ton_wallet.json delete mode 100644 tests/common/Keystore/Data/ton-wallet.json delete mode 100644 tests/common/Keystore/StoredKeyConstants.h delete mode 100644 tests/common/Keystore/StoredKeyTONTests.cpp diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkWallet.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkWallet.kt index b8f4b7d1b56..9305072bb75 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkWallet.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/theopennetwork/TestTheOpenNetworkWallet.kt @@ -4,7 +4,6 @@ package com.trustwallet.core.app.blockchains.theopennetwork -import com.trustwallet.core.app.utils.toHex import com.trustwallet.core.app.utils.toHexByteArray import org.junit.Assert.assertEquals import org.junit.Test @@ -27,20 +26,4 @@ class TestTheOpenNetworkWallet { val expected = "te6cckECFgEAAwQAAgE0AQIBFP8A9KQT9LzyyAsDAFEAAAAAKamjF/IpqTcfp8IQiz2Q6iLJvnBf9dDP6u6cu5Nm/wFxV5NXQAIBIAQFAgFIBgcE+PKDCNcYINMf0x/THwL4I7vyZO1E0NMf0x/T//QE0VFDuvKhUVG68qIF+QFUEGT5EPKj+AAkpMjLH1JAyx9SMMv/UhD0AMntVPgPAdMHIcAAn2xRkyDXSpbTB9QC+wDoMOAhwAHjACHAAuMAAcADkTDjDQOkyMsfEssfy/8ICQoLAubQAdDTAyFxsJJfBOAi10nBIJJfBOAC0x8hghBwbHVnvSKCEGRzdHK9sJJfBeAD+kAwIPpEAcjKB8v/ydDtRNCBAUDXIfQEMFyBAQj0Cm+hMbOSXwfgBdM/yCWCEHBsdWe6kjgw4w0DghBkc3RyupJfBuMNDA0CASAODwBu0gf6ANTUIvkABcjKBxXL/8nQd3SAGMjLBcsCIs8WUAX6AhTLaxLMzMlz+wDIQBSBAQj0UfKnAgBwgQEI1xj6ANM/yFQgR4EBCPRR8qeCEG5vdGVwdIAYyMsFywJQBs8WUAT6AhTLahLLH8s/yXP7AAIAbIEBCNcY+gDTPzBSJIEBCPRZ8qeCEGRzdHJwdIAYyMsFywJQBc8WUAP6AhPLassfEss/yXP7AAAK9ADJ7VQAeAH6APQEMPgnbyIwUAqhIb7y4FCCEHBsdWeDHrFwgBhQBMsFJs8WWPoCGfQAy2kXyx9SYMs/IMmAQPsABgCKUASBAQj0WTDtRNCBAUDXIMgBzxb0AMntVAFysI4jghBkc3Rygx6xcIAYUAXLBVADzxYj+gITy2rLH8s/yYBA+wCSXwPiAgEgEBEAWb0kK29qJoQICga5D6AhhHDUCAhHpJN9KZEM5pA+n/mDeBKAG3gQFImHFZ8xhAIBWBITABG4yX7UTQ1wsfgAPbKd+1E0IEBQNch9AQwAsjKB8v/ydABgQEI9ApvoTGACASAUFQAZrc52omhAIGuQ64X/wAAZrx32omhAEGuQ64WPwEXtMkg=" assertEquals(stateInit, expected) } - - @Test - fun TheOpenNetworkWalletIsValidMnemonic() { - val validMnemonic = "sight shed side garbage illness clean health wet all win bench wide exist find galaxy drift task suggest portion fresh valve crime radar combine" - val noPassphrase = "" - val invalidPassphrase = "Expected empty passphrase" - assert(TONWallet.isValidMnemonic(validMnemonic, noPassphrase)) - assert(!TONWallet.isValidMnemonic(validMnemonic, invalidPassphrase)) - } - - @Test - fun TheOpenNetworkWalletGetKey() { - val tonMnemonic = "sight shed side garbage illness clean health wet all win bench wide exist find galaxy drift task suggest portion fresh valve crime radar combine" - val wallet = TONWallet(tonMnemonic, "") - assertEquals(wallet.key.data().toHex(), "0xb471884e691a9f5bb641b14f33bb9e555f759c24e368c4c0d997db3a60704220") - } } \ No newline at end of file diff --git a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt index 1843ea86257..599d3369216 100644 --- a/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt +++ b/android/app/src/androidTest/java/com/trustwallet/core/app/utils/TestKeyStore.kt @@ -4,7 +4,6 @@ import org.junit.Assert.* import org.junit.Test import wallet.core.jni.StoredKey import wallet.core.jni.CoinType -import wallet.core.jni.Derivation import wallet.core.jni.StoredKeyEncryption class TestKeyStore { @@ -18,12 +17,9 @@ class TestKeyStore { val keyStore = StoredKey("Test Wallet", "password".toByteArray()) val result = keyStore.decryptMnemonic("wrong".toByteArray()) val result2 = keyStore.decryptMnemonic("password".toByteArray()) - val result3 = keyStore.decryptTONMnemonic("password".toByteArray()) assertNull(result) assertNotNull(result2) - // StoredKey is an HD by default, so `decryptTONMnemonic` should return null. - assertNull(result3) } @Test @@ -95,48 +91,4 @@ class TestKeyStore { val privateKey = newKeyStore.decryptPrivateKey("".toByteArray()) assertNull(privateKey) } - - @Test - fun testImportTONWallet() { - val tonMnemonic = "laundry myself fitness beyond prize piano match acid vacuum already abandon dance occur pause grocery company inject excuse weasel carpet fog grunt trick spike" - val password = "password".toByteArray() - - val keyStore = StoredKey.importTONWallet(tonMnemonic, "Test Wallet", password, CoinType.TON) - - val decrypted1 = keyStore.decryptTONMnemonic("wrong".toByteArray()) - val decrypted2 = keyStore.decryptTONMnemonic("password".toByteArray()) - assertNull(decrypted1) - assertNotNull(decrypted2) - - assertEquals(keyStore.accountCount(), 1) - - // `StoredKey.account(index)` is only allowed. - // `StoredKey.accountForCoin(coin, wallet)` is not supported. - val tonAccount = keyStore.account(0) - assertEquals(tonAccount.address(), "UQDdB2lMwYM9Gxc-ln--Tu8cz-TYksQxYuUsMs2Pd4cHerYz") - assertEquals(tonAccount.coin(), CoinType.TON) - assertEquals(tonAccount.publicKey(), "c9af50596bd5c1c5a15fb32bef8d4f1ee5244b287aea1f49f6023a79f9b2f055") - assertEquals(tonAccount.extendedPublicKey(), "") - assertEquals(tonAccount.derivation(), Derivation.DEFAULT) - assertEquals(tonAccount.derivationPath(), "") - - val privateKey = keyStore.privateKey(CoinType.TON, password) - assertEquals(privateKey.data().toHex(), "0x859cd74ab605afb7ce9f5316a1f6d59217a130b75b494efd249913be874c9d46") - - // HD wallet is not supported for TON wallet - val hdWallet = keyStore.wallet(password) - assertNull(hdWallet) - } - - @Test - fun testExportTONWallet() { - val tonMnemonic = "laundry myself fitness beyond prize piano match acid vacuum already abandon dance occur pause grocery company inject excuse weasel carpet fog grunt trick spike" - val password = "password".toByteArray() - - val keyStore = StoredKey.importTONWallet(tonMnemonic, "Test Wallet", password, CoinType.TON) - val json = keyStore.exportJSON() - - val newKeyStore = StoredKey.importJSON(json) - assertEquals(newKeyStore.decryptTONMnemonic(password), tonMnemonic) - } } diff --git a/include/TrustWalletCore/TWStoredKey.h b/include/TrustWalletCore/TWStoredKey.h index 6df17e7a220..58a07e521c0 100644 --- a/include/TrustWalletCore/TWStoredKey.h +++ b/include/TrustWalletCore/TWStoredKey.h @@ -74,29 +74,6 @@ struct TWStoredKey* _Nullable TWStoredKeyImportHDWallet(TWString* _Nonnull mnemo TW_EXPORT_STATIC_METHOD struct TWStoredKey* _Nullable TWStoredKeyImportHDWalletWithEncryption(TWString* _Nonnull mnemonic, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin, enum TWStoredKeyEncryption encryption); -/// Imports a TON-specific wallet with a 24-words mnemonic. -/// -/// \param tonMnemonic Non-null TON mnemonic -/// \param name The name of the stored key to import as a non-null string -/// \param password Non-null block of data, password of the stored key -/// \param coin the coin type -/// \note Returned object needs to be deleted with \TWStoredKeyDelete -/// \return Nullptr if the key can't be imported, the stored key otherwise -TW_EXPORT_STATIC_METHOD -struct TWStoredKey* _Nullable TWStoredKeyImportTONWallet(TWString* _Nonnull tonMnemonic, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin); - -/// Imports a TON-specific wallet with a 24-words mnemonic. -/// -/// \param tonMnemonic Non-null TON mnemonic -/// \param name The name of the stored key to import as a non-null string -/// \param password Non-null block of data, password of the stored key -/// \param coin the coin type -/// \param encryption cipher encryption mode -/// \note Returned object needs to be deleted with \TWStoredKeyDelete -/// \return Nullptr if the key can't be imported, the stored key otherwise -TW_EXPORT_STATIC_METHOD -struct TWStoredKey* _Nullable TWStoredKeyImportTONWalletWithEncryption(TWString* _Nonnull tonMnemonic, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin, enum TWStoredKeyEncryption encryption); - /// Imports a key from JSON. /// /// \param json Json stored key import format as a non-null block of data @@ -175,13 +152,6 @@ TWString* _Nonnull TWStoredKeyName(struct TWStoredKey* _Nonnull key); TW_EXPORT_PROPERTY bool TWStoredKeyIsMnemonic(struct TWStoredKey* _Nonnull key); -/// Whether this key is a TON mnemonic phrase. -/// -/// \param key Non-null pointer to a stored key -/// \return true if the given stored key is a TON mnemonic, false otherwise -TW_EXPORT_PROPERTY -bool TWStoredKeyIsTONMnemonic(struct TWStoredKey* _Nonnull key); - /// The number of accounts. /// /// \param key Non-null pointer to a stored key @@ -291,14 +261,6 @@ TWData* _Nullable TWStoredKeyDecryptPrivateKey(struct TWStoredKey* _Nonnull key, TW_EXPORT_METHOD TWString* _Nullable TWStoredKeyDecryptMnemonic(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password); -/// Decrypts the TON mnemonic phrase. -/// -/// \param key Non-null pointer to a stored key -/// \param password Non-null block of data, password of the stored key -/// \return TON decrypted mnemonic if success, null pointer otherwise -TW_EXPORT_METHOD -TWString* _Nullable TWStoredKeyDecryptTONMnemonic(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password); - /// Returns the private key for a specific coin. Returned object needs to be deleted. /// /// \param key Non-null pointer to a stored key diff --git a/include/TrustWalletCore/TWTONWallet.h b/include/TrustWalletCore/TWTONWallet.h index 53d230482bc..098702faa6a 100644 --- a/include/TrustWalletCore/TWTONWallet.h +++ b/include/TrustWalletCore/TWTONWallet.h @@ -5,7 +5,6 @@ #pragma once #include "TWBase.h" -#include "TWPrivateKey.h" #include "TWPublicKey.h" #include "TWString.h" @@ -15,39 +14,6 @@ TW_EXTERN_C_BEGIN TW_EXPORT_CLASS struct TWTONWallet; -/// Determines whether the English mnemonic and passphrase are valid. -/// -/// \param mnemonic Non-null english mnemonic -/// \param passphrase Nullable optional passphrase -/// \note passphrase can be null or empty string if no passphrase required -/// \return whether the mnemonic and passphrase are valid (valid checksum) -TW_EXPORT_STATIC_METHOD -bool TWTONWalletIsValidMnemonic(TWString* _Nonnull mnemonic, TWString* _Nullable passphrase); - -/// Creates a \TONWallet from a valid TON mnemonic and passphrase. -/// -/// \param mnemonic Non-null english mnemonic -/// \param passphrase Nullable optional passphrase -/// \note Null is returned on invalid mnemonic and passphrase -/// \note passphrase can be null or empty string if no passphrase required -/// \return Nullable TWTONWallet -TW_EXPORT_STATIC_METHOD -struct TWTONWallet* _Nullable TWTONWalletCreateWithMnemonic(TWString* _Nonnull mnemonic, TWString* _Nullable passphrase); - -/// Delete the given \TONWallet -/// -/// \param wallet Non-null pointer to private key -TW_EXPORT_METHOD -void TWTONWalletDelete(struct TWTONWallet* _Nonnull wallet); - -/// Generates Ed25519 private key associated with the wallet. -/// -/// \param wallet non-null TWTONWallet -/// \note Returned object needs to be deleted with \TWPrivateKeyDelete -/// \return The Ed25519 private key -TW_EXPORT_METHOD -struct TWPrivateKey* _Nonnull TWTONWalletGetKey(struct TWTONWallet* _Nonnull wallet); - /// Constructs a TON Wallet V4R2 stateInit encoded as BoC (BagOfCells) for the given `public_key`. /// /// \param publicKey wallet's public key. @@ -55,6 +21,6 @@ struct TWPrivateKey* _Nonnull TWTONWalletGetKey(struct TWTONWallet* _Nonnull wal /// \param walletId wallet's ID allows to create multiple wallets for the same private key. /// \return Pointer to a base64 encoded Bag Of Cells (BoC) StateInit. Null if invalid public key provided. TW_EXPORT_STATIC_METHOD -TWString *_Nullable TWTONWalletBuildV4R2StateInit(struct TWPublicKey* _Nonnull publicKey, int32_t workchain, int32_t walletId); +TWString *_Nullable TWTONWalletBuildV4R2StateInit(struct TWPublicKey *_Nonnull publicKey, int32_t workchain, int32_t walletId); TW_EXTERN_C_END diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 55201c9282e..0c16a96d581 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1105,16 +1105,6 @@ dependencies = [ "nom", ] -[[package]] -name = "pbkdf2" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ca0b5a68607598bf3bad68f32227a8164f6254833f84eafaac409cd6746c31" -dependencies = [ - "digest 0.10.6", - "hmac", -] - [[package]] name = "pkcs8" version = "0.10.2" @@ -1981,7 +1971,6 @@ dependencies = [ "digest 0.10.6", "groestl", "hmac", - "pbkdf2", "ripemd", "serde", "serde_json", @@ -1993,18 +1982,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "tw_hd_wallet" -version = "0.1.0" -dependencies = [ - "lazy_static", - "tw_encoding", - "tw_hash", - "tw_keypair", - "tw_misc", - "zeroize", -] - [[package]] name = "tw_internet_computer" version = "0.1.0" @@ -2055,9 +2032,6 @@ dependencies = [ [[package]] name = "tw_memory" version = "0.1.0" -dependencies = [ - "zeroize", -] [[package]] name = "tw_misc" @@ -2224,7 +2198,6 @@ dependencies = [ "tw_number", "tw_proto", "tw_ton_sdk", - "zeroize", ] [[package]] @@ -2340,7 +2313,6 @@ dependencies = [ "tw_encoding", "tw_ethereum", "tw_hash", - "tw_hd_wallet", "tw_keypair", "tw_memory", "tw_misc", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 0b427b07caa..692beec2692 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -27,7 +27,6 @@ members = [ "tw_encoding", "tw_evm", "tw_hash", - "tw_hd_wallet", "tw_keypair", "tw_memory", "tw_misc", diff --git a/rust/chains/tw_ton/Cargo.toml b/rust/chains/tw_ton/Cargo.toml index 145508522a6..076a7d84f61 100644 --- a/rust/chains/tw_ton/Cargo.toml +++ b/rust/chains/tw_ton/Cargo.toml @@ -14,4 +14,3 @@ tw_number = { path = "../../tw_number" } tw_misc = { path = "../../tw_misc" } tw_proto = { path = "../../tw_proto" } tw_ton_sdk = { path = "../../frameworks/tw_ton_sdk" } -zeroize = "1.8.1" diff --git a/rust/tw_any_coin/src/test_utils/address_utils.rs b/rust/tw_any_coin/src/test_utils/address_utils.rs index a1039463f9e..b7e896d2664 100644 --- a/rust/tw_any_coin/src/test_utils/address_utils.rs +++ b/rust/tw_any_coin/src/test_utils/address_utils.rs @@ -19,9 +19,9 @@ use tw_keypair::test_utils::tw_public_key_helper::TWPublicKeyHelper; use tw_keypair::tw::PublicKeyType; use tw_memory::test_utils::tw_data_helper::TWDataHelper; use tw_memory::test_utils::tw_string_helper::TWStringHelper; -use tw_memory::test_utils::tw_wrapper::{TWAutoWrapper, WithDestructor}; +use tw_memory::test_utils::tw_wrapper::{TWWrapper, WithDestructor}; -pub type TWAnyAddressHelper = TWAutoWrapper; +pub type TWAnyAddressHelper = TWWrapper; impl WithDestructor for TWAnyAddress { fn destructor() -> unsafe extern "C" fn(*mut Self) { diff --git a/rust/tw_hash/Cargo.toml b/rust/tw_hash/Cargo.toml index 3373eda15c9..c9b8ab18c42 100644 --- a/rust/tw_hash/Cargo.toml +++ b/rust/tw_hash/Cargo.toml @@ -13,7 +13,6 @@ blake2b-ref = "0.3.1" digest = "0.10.6" groestl = "0.10.1" hmac = "0.12.1" -pbkdf2 = "0.12.1" ripemd = "0.1.3" serde = { version = "1.0", features = ["derive"], optional = true } sha1 = "0.10.5" diff --git a/rust/tw_hash/src/ffi.rs b/rust/tw_hash/src/ffi.rs index 2867ffa4a8d..08c4faf44b9 100644 --- a/rust/tw_hash/src/ffi.rs +++ b/rust/tw_hash/src/ffi.rs @@ -14,7 +14,6 @@ pub enum CHashingCode { Ok = 0, InvalidHashLength = 1, InvalidArgument = 2, - InvalidPassword = 3, } impl From for CHashingCode { @@ -22,7 +21,6 @@ impl From for CHashingCode { match e { Error::FromHexError(_) | Error::InvalidArgument => CHashingCode::InvalidArgument, Error::InvalidHashLength => CHashingCode::InvalidHashLength, - Error::InvalidPassword => CHashingCode::InvalidPassword, } } } diff --git a/rust/tw_hash/src/hmac.rs b/rust/tw_hash/src/hmac.rs index 538d0409b15..475c5bbdb7f 100644 --- a/rust/tw_hash/src/hmac.rs +++ b/rust/tw_hash/src/hmac.rs @@ -3,19 +3,14 @@ // Copyright © 2017 Trust Wallet. use hmac::{Hmac, Mac}; -use sha2::{Sha256, Sha512}; +use sha2::Sha256; type HmacSha256 = Hmac; -type HmacSha512 = Hmac; pub fn hmac_sha256(key: &[u8], input: &[u8]) -> Vec { - let mut mac = HmacSha256::new_from_slice(key).expect("Hmac constructor should never fail"); + let mut mac = HmacSha256::new_from_slice(key).unwrap(); mac.update(input); - mac.finalize().into_bytes().to_vec() -} - -pub fn hmac_sha512(key: &[u8], input: &[u8]) -> Vec { - let mut mac = HmacSha512::new_from_slice(key).expect("Hmac constructor should never fail"); - mac.update(input); - mac.finalize().into_bytes().to_vec() + let res = mac.finalize(); + let code_bytes = res.into_bytes(); + code_bytes.to_vec() } diff --git a/rust/tw_hash/src/lib.rs b/rust/tw_hash/src/lib.rs index 6d1817edea6..2371346ee7a 100644 --- a/rust/tw_hash/src/lib.rs +++ b/rust/tw_hash/src/lib.rs @@ -9,7 +9,6 @@ pub mod ffi; pub mod groestl; pub mod hasher; pub mod hmac; -pub mod pbkdf2; pub mod ripemd; pub mod sha1; pub mod sha2; @@ -29,7 +28,6 @@ pub enum Error { FromHexError(FromHexError), InvalidHashLength, InvalidArgument, - InvalidPassword, } impl From for Error { diff --git a/rust/tw_hash/src/pbkdf2.rs b/rust/tw_hash/src/pbkdf2.rs deleted file mode 100644 index 30135d2dc17..00000000000 --- a/rust/tw_hash/src/pbkdf2.rs +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// -// Copyright © 2017 Trust Wallet. - -use crate::H512; -use sha2::Sha512; - -pub fn pbkdf2_hmac_sha512(password: &[u8], salt: &[u8], rounds: u32) -> H512 { - pbkdf2::pbkdf2_hmac_array::(password, salt, rounds).into() -} diff --git a/rust/tw_hd_wallet/Cargo.toml b/rust/tw_hd_wallet/Cargo.toml deleted file mode 100644 index 72acc5d0022..00000000000 --- a/rust/tw_hd_wallet/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "tw_hd_wallet" -version = "0.1.0" -edition = "2021" - -[dependencies] -lazy_static = "1.4.0" -tw_hash = { path = "../tw_hash" } -tw_keypair = { path = "../tw_keypair" } -zeroize = "1.8.1" - -[dev-dependencies] -tw_encoding = { path = "../tw_encoding" } -tw_misc = { path = "../tw_misc" } diff --git a/rust/tw_hd_wallet/src/bip39/bip39_english.rs b/rust/tw_hd_wallet/src/bip39/bip39_english.rs deleted file mode 100644 index ae0c461da23..00000000000 --- a/rust/tw_hd_wallet/src/bip39/bip39_english.rs +++ /dev/null @@ -1,2070 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// -// Copyright © 2017 Trust Wallet. - -use lazy_static::lazy_static; -use std::collections::HashMap; - -lazy_static! { - pub static ref BIP39_WORDS_MAP: HashMap<&'static str, usize> = { - BIP39_WORDS_LIST - .iter() - .enumerate() - .map(|(idx, word)| (*word, idx)) - .collect() - }; -} - -/// https://github.com/trustwallet/wallet-core/blob/43c92837db9f5d773f2545473f29c8a597d86de5/trezor-crypto/include/TrezorCrypto/bip39_english.h#L24-L367 -/// https://github.com/dvc94ch/rust-bip39/blob/master/src/language/english.rs -#[rustfmt::skip] -pub const BIP39_WORDS_LIST: [&str; 2048] = [ - "abandon", - "ability", - "able", - "about", - "above", - "absent", - "absorb", - "abstract", - "absurd", - "abuse", - "access", - "accident", - "account", - "accuse", - "achieve", - "acid", - "acoustic", - "acquire", - "across", - "act", - "action", - "actor", - "actress", - "actual", - "adapt", - "add", - "addict", - "address", - "adjust", - "admit", - "adult", - "advance", - "advice", - "aerobic", - "affair", - "afford", - "afraid", - "again", - "age", - "agent", - "agree", - "ahead", - "aim", - "air", - "airport", - "aisle", - "alarm", - "album", - "alcohol", - "alert", - "alien", - "all", - "alley", - "allow", - "almost", - "alone", - "alpha", - "already", - "also", - "alter", - "always", - "amateur", - "amazing", - "among", - "amount", - "amused", - "analyst", - "anchor", - "ancient", - "anger", - "angle", - "angry", - "animal", - "ankle", - "announce", - "annual", - "another", - "answer", - "antenna", - "antique", - "anxiety", - "any", - "apart", - "apology", - "appear", - "apple", - "approve", - "april", - "arch", - "arctic", - "area", - "arena", - "argue", - "arm", - "armed", - "armor", - "army", - "around", - "arrange", - "arrest", - "arrive", - "arrow", - "art", - "artefact", - "artist", - "artwork", - "ask", - "aspect", - "assault", - "asset", - "assist", - "assume", - "asthma", - "athlete", - "atom", - "attack", - "attend", - "attitude", - "attract", - "auction", - "audit", - "august", - "aunt", - "author", - "auto", - "autumn", - "average", - "avocado", - "avoid", - "awake", - "aware", - "away", - "awesome", - "awful", - "awkward", - "axis", - "baby", - "bachelor", - "bacon", - "badge", - "bag", - "balance", - "balcony", - "ball", - "bamboo", - "banana", - "banner", - "bar", - "barely", - "bargain", - "barrel", - "base", - "basic", - "basket", - "battle", - "beach", - "bean", - "beauty", - "because", - "become", - "beef", - "before", - "begin", - "behave", - "behind", - "believe", - "below", - "belt", - "bench", - "benefit", - "best", - "betray", - "better", - "between", - "beyond", - "bicycle", - "bid", - "bike", - "bind", - "biology", - "bird", - "birth", - "bitter", - "black", - "blade", - "blame", - "blanket", - "blast", - "bleak", - "bless", - "blind", - "blood", - "blossom", - "blouse", - "blue", - "blur", - "blush", - "board", - "boat", - "body", - "boil", - "bomb", - "bone", - "bonus", - "book", - "boost", - "border", - "boring", - "borrow", - "boss", - "bottom", - "bounce", - "box", - "boy", - "bracket", - "brain", - "brand", - "brass", - "brave", - "bread", - "breeze", - "brick", - "bridge", - "brief", - "bright", - "bring", - "brisk", - "broccoli", - "broken", - "bronze", - "broom", - "brother", - "brown", - "brush", - "bubble", - "buddy", - "budget", - "buffalo", - "build", - "bulb", - "bulk", - "bullet", - "bundle", - "bunker", - "burden", - "burger", - "burst", - "bus", - "business", - "busy", - "butter", - "buyer", - "buzz", - "cabbage", - "cabin", - "cable", - "cactus", - "cage", - "cake", - "call", - "calm", - "camera", - "camp", - "can", - "canal", - "cancel", - "candy", - "cannon", - "canoe", - "canvas", - "canyon", - "capable", - "capital", - "captain", - "car", - "carbon", - "card", - "cargo", - "carpet", - "carry", - "cart", - "case", - "cash", - "casino", - "castle", - "casual", - "cat", - "catalog", - "catch", - "category", - "cattle", - "caught", - "cause", - "caution", - "cave", - "ceiling", - "celery", - "cement", - "census", - "century", - "cereal", - "certain", - "chair", - "chalk", - "champion", - "change", - "chaos", - "chapter", - "charge", - "chase", - "chat", - "cheap", - "check", - "cheese", - "chef", - "cherry", - "chest", - "chicken", - "chief", - "child", - "chimney", - "choice", - "choose", - "chronic", - "chuckle", - "chunk", - "churn", - "cigar", - "cinnamon", - "circle", - "citizen", - "city", - "civil", - "claim", - "clap", - "clarify", - "claw", - "clay", - "clean", - "clerk", - "clever", - "click", - "client", - "cliff", - "climb", - "clinic", - "clip", - "clock", - "clog", - "close", - "cloth", - "cloud", - "clown", - "club", - "clump", - "cluster", - "clutch", - "coach", - "coast", - "coconut", - "code", - "coffee", - "coil", - "coin", - "collect", - "color", - "column", - "combine", - "come", - "comfort", - "comic", - "common", - "company", - "concert", - "conduct", - "confirm", - "congress", - "connect", - "consider", - "control", - "convince", - "cook", - "cool", - "copper", - "copy", - "coral", - "core", - "corn", - "correct", - "cost", - "cotton", - "couch", - "country", - "couple", - "course", - "cousin", - "cover", - "coyote", - "crack", - "cradle", - "craft", - "cram", - "crane", - "crash", - "crater", - "crawl", - "crazy", - "cream", - "credit", - "creek", - "crew", - "cricket", - "crime", - "crisp", - "critic", - "crop", - "cross", - "crouch", - "crowd", - "crucial", - "cruel", - "cruise", - "crumble", - "crunch", - "crush", - "cry", - "crystal", - "cube", - "culture", - "cup", - "cupboard", - "curious", - "current", - "curtain", - "curve", - "cushion", - "custom", - "cute", - "cycle", - "dad", - "damage", - "damp", - "dance", - "danger", - "daring", - "dash", - "daughter", - "dawn", - "day", - "deal", - "debate", - "debris", - "decade", - "december", - "decide", - "decline", - "decorate", - "decrease", - "deer", - "defense", - "define", - "defy", - "degree", - "delay", - "deliver", - "demand", - "demise", - "denial", - "dentist", - "deny", - "depart", - "depend", - "deposit", - "depth", - "deputy", - "derive", - "describe", - "desert", - "design", - "desk", - "despair", - "destroy", - "detail", - "detect", - "develop", - "device", - "devote", - "diagram", - "dial", - "diamond", - "diary", - "dice", - "diesel", - "diet", - "differ", - "digital", - "dignity", - "dilemma", - "dinner", - "dinosaur", - "direct", - "dirt", - "disagree", - "discover", - "disease", - "dish", - "dismiss", - "disorder", - "display", - "distance", - "divert", - "divide", - "divorce", - "dizzy", - "doctor", - "document", - "dog", - "doll", - "dolphin", - "domain", - "donate", - "donkey", - "donor", - "door", - "dose", - "double", - "dove", - "draft", - "dragon", - "drama", - "drastic", - "draw", - "dream", - "dress", - "drift", - "drill", - "drink", - "drip", - "drive", - "drop", - "drum", - "dry", - "duck", - "dumb", - "dune", - "during", - "dust", - "dutch", - "duty", - "dwarf", - "dynamic", - "eager", - "eagle", - "early", - "earn", - "earth", - "easily", - "east", - "easy", - "echo", - "ecology", - "economy", - "edge", - "edit", - "educate", - "effort", - "egg", - "eight", - "either", - "elbow", - "elder", - "electric", - "elegant", - "element", - "elephant", - "elevator", - "elite", - "else", - "embark", - "embody", - "embrace", - "emerge", - "emotion", - "employ", - "empower", - "empty", - "enable", - "enact", - "end", - "endless", - "endorse", - "enemy", - "energy", - "enforce", - "engage", - "engine", - "enhance", - "enjoy", - "enlist", - "enough", - "enrich", - "enroll", - "ensure", - "enter", - "entire", - "entry", - "envelope", - "episode", - "equal", - "equip", - "era", - "erase", - "erode", - "erosion", - "error", - "erupt", - "escape", - "essay", - "essence", - "estate", - "eternal", - "ethics", - "evidence", - "evil", - "evoke", - "evolve", - "exact", - "example", - "excess", - "exchange", - "excite", - "exclude", - "excuse", - "execute", - "exercise", - "exhaust", - "exhibit", - "exile", - "exist", - "exit", - "exotic", - "expand", - "expect", - "expire", - "explain", - "expose", - "express", - "extend", - "extra", - "eye", - "eyebrow", - "fabric", - "face", - "faculty", - "fade", - "faint", - "faith", - "fall", - "false", - "fame", - "family", - "famous", - "fan", - "fancy", - "fantasy", - "farm", - "fashion", - "fat", - "fatal", - "father", - "fatigue", - "fault", - "favorite", - "feature", - "february", - "federal", - "fee", - "feed", - "feel", - "female", - "fence", - "festival", - "fetch", - "fever", - "few", - "fiber", - "fiction", - "field", - "figure", - "file", - "film", - "filter", - "final", - "find", - "fine", - "finger", - "finish", - "fire", - "firm", - "first", - "fiscal", - "fish", - "fit", - "fitness", - "fix", - "flag", - "flame", - "flash", - "flat", - "flavor", - "flee", - "flight", - "flip", - "float", - "flock", - "floor", - "flower", - "fluid", - "flush", - "fly", - "foam", - "focus", - "fog", - "foil", - "fold", - "follow", - "food", - "foot", - "force", - "forest", - "forget", - "fork", - "fortune", - "forum", - "forward", - "fossil", - "foster", - "found", - "fox", - "fragile", - "frame", - "frequent", - "fresh", - "friend", - "fringe", - "frog", - "front", - "frost", - "frown", - "frozen", - "fruit", - "fuel", - "fun", - "funny", - "furnace", - "fury", - "future", - "gadget", - "gain", - "galaxy", - "gallery", - "game", - "gap", - "garage", - "garbage", - "garden", - "garlic", - "garment", - "gas", - "gasp", - "gate", - "gather", - "gauge", - "gaze", - "general", - "genius", - "genre", - "gentle", - "genuine", - "gesture", - "ghost", - "giant", - "gift", - "giggle", - "ginger", - "giraffe", - "girl", - "give", - "glad", - "glance", - "glare", - "glass", - "glide", - "glimpse", - "globe", - "gloom", - "glory", - "glove", - "glow", - "glue", - "goat", - "goddess", - "gold", - "good", - "goose", - "gorilla", - "gospel", - "gossip", - "govern", - "gown", - "grab", - "grace", - "grain", - "grant", - "grape", - "grass", - "gravity", - "great", - "green", - "grid", - "grief", - "grit", - "grocery", - "group", - "grow", - "grunt", - "guard", - "guess", - "guide", - "guilt", - "guitar", - "gun", - "gym", - "habit", - "hair", - "half", - "hammer", - "hamster", - "hand", - "happy", - "harbor", - "hard", - "harsh", - "harvest", - "hat", - "have", - "hawk", - "hazard", - "head", - "health", - "heart", - "heavy", - "hedgehog", - "height", - "hello", - "helmet", - "help", - "hen", - "hero", - "hidden", - "high", - "hill", - "hint", - "hip", - "hire", - "history", - "hobby", - "hockey", - "hold", - "hole", - "holiday", - "hollow", - "home", - "honey", - "hood", - "hope", - "horn", - "horror", - "horse", - "hospital", - "host", - "hotel", - "hour", - "hover", - "hub", - "huge", - "human", - "humble", - "humor", - "hundred", - "hungry", - "hunt", - "hurdle", - "hurry", - "hurt", - "husband", - "hybrid", - "ice", - "icon", - "idea", - "identify", - "idle", - "ignore", - "ill", - "illegal", - "illness", - "image", - "imitate", - "immense", - "immune", - "impact", - "impose", - "improve", - "impulse", - "inch", - "include", - "income", - "increase", - "index", - "indicate", - "indoor", - "industry", - "infant", - "inflict", - "inform", - "inhale", - "inherit", - "initial", - "inject", - "injury", - "inmate", - "inner", - "innocent", - "input", - "inquiry", - "insane", - "insect", - "inside", - "inspire", - "install", - "intact", - "interest", - "into", - "invest", - "invite", - "involve", - "iron", - "island", - "isolate", - "issue", - "item", - "ivory", - "jacket", - "jaguar", - "jar", - "jazz", - "jealous", - "jeans", - "jelly", - "jewel", - "job", - "join", - "joke", - "journey", - "joy", - "judge", - "juice", - "jump", - "jungle", - "junior", - "junk", - "just", - "kangaroo", - "keen", - "keep", - "ketchup", - "key", - "kick", - "kid", - "kidney", - "kind", - "kingdom", - "kiss", - "kit", - "kitchen", - "kite", - "kitten", - "kiwi", - "knee", - "knife", - "knock", - "know", - "lab", - "label", - "labor", - "ladder", - "lady", - "lake", - "lamp", - "language", - "laptop", - "large", - "later", - "latin", - "laugh", - "laundry", - "lava", - "law", - "lawn", - "lawsuit", - "layer", - "lazy", - "leader", - "leaf", - "learn", - "leave", - "lecture", - "left", - "leg", - "legal", - "legend", - "leisure", - "lemon", - "lend", - "length", - "lens", - "leopard", - "lesson", - "letter", - "level", - "liar", - "liberty", - "library", - "license", - "life", - "lift", - "light", - "like", - "limb", - "limit", - "link", - "lion", - "liquid", - "list", - "little", - "live", - "lizard", - "load", - "loan", - "lobster", - "local", - "lock", - "logic", - "lonely", - "long", - "loop", - "lottery", - "loud", - "lounge", - "love", - "loyal", - "lucky", - "luggage", - "lumber", - "lunar", - "lunch", - "luxury", - "lyrics", - "machine", - "mad", - "magic", - "magnet", - "maid", - "mail", - "main", - "major", - "make", - "mammal", - "man", - "manage", - "mandate", - "mango", - "mansion", - "manual", - "maple", - "marble", - "march", - "margin", - "marine", - "market", - "marriage", - "mask", - "mass", - "master", - "match", - "material", - "math", - "matrix", - "matter", - "maximum", - "maze", - "meadow", - "mean", - "measure", - "meat", - "mechanic", - "medal", - "media", - "melody", - "melt", - "member", - "memory", - "mention", - "menu", - "mercy", - "merge", - "merit", - "merry", - "mesh", - "message", - "metal", - "method", - "middle", - "midnight", - "milk", - "million", - "mimic", - "mind", - "minimum", - "minor", - "minute", - "miracle", - "mirror", - "misery", - "miss", - "mistake", - "mix", - "mixed", - "mixture", - "mobile", - "model", - "modify", - "mom", - "moment", - "monitor", - "monkey", - "monster", - "month", - "moon", - "moral", - "more", - "morning", - "mosquito", - "mother", - "motion", - "motor", - "mountain", - "mouse", - "move", - "movie", - "much", - "muffin", - "mule", - "multiply", - "muscle", - "museum", - "mushroom", - "music", - "must", - "mutual", - "myself", - "mystery", - "myth", - "naive", - "name", - "napkin", - "narrow", - "nasty", - "nation", - "nature", - "near", - "neck", - "need", - "negative", - "neglect", - "neither", - "nephew", - "nerve", - "nest", - "net", - "network", - "neutral", - "never", - "news", - "next", - "nice", - "night", - "noble", - "noise", - "nominee", - "noodle", - "normal", - "north", - "nose", - "notable", - "note", - "nothing", - "notice", - "novel", - "now", - "nuclear", - "number", - "nurse", - "nut", - "oak", - "obey", - "object", - "oblige", - "obscure", - "observe", - "obtain", - "obvious", - "occur", - "ocean", - "october", - "odor", - "off", - "offer", - "office", - "often", - "oil", - "okay", - "old", - "olive", - "olympic", - "omit", - "once", - "one", - "onion", - "online", - "only", - "open", - "opera", - "opinion", - "oppose", - "option", - "orange", - "orbit", - "orchard", - "order", - "ordinary", - "organ", - "orient", - "original", - "orphan", - "ostrich", - "other", - "outdoor", - "outer", - "output", - "outside", - "oval", - "oven", - "over", - "own", - "owner", - "oxygen", - "oyster", - "ozone", - "pact", - "paddle", - "page", - "pair", - "palace", - "palm", - "panda", - "panel", - "panic", - "panther", - "paper", - "parade", - "parent", - "park", - "parrot", - "party", - "pass", - "patch", - "path", - "patient", - "patrol", - "pattern", - "pause", - "pave", - "payment", - "peace", - "peanut", - "pear", - "peasant", - "pelican", - "pen", - "penalty", - "pencil", - "people", - "pepper", - "perfect", - "permit", - "person", - "pet", - "phone", - "photo", - "phrase", - "physical", - "piano", - "picnic", - "picture", - "piece", - "pig", - "pigeon", - "pill", - "pilot", - "pink", - "pioneer", - "pipe", - "pistol", - "pitch", - "pizza", - "place", - "planet", - "plastic", - "plate", - "play", - "please", - "pledge", - "pluck", - "plug", - "plunge", - "poem", - "poet", - "point", - "polar", - "pole", - "police", - "pond", - "pony", - "pool", - "popular", - "portion", - "position", - "possible", - "post", - "potato", - "pottery", - "poverty", - "powder", - "power", - "practice", - "praise", - "predict", - "prefer", - "prepare", - "present", - "pretty", - "prevent", - "price", - "pride", - "primary", - "print", - "priority", - "prison", - "private", - "prize", - "problem", - "process", - "produce", - "profit", - "program", - "project", - "promote", - "proof", - "property", - "prosper", - "protect", - "proud", - "provide", - "public", - "pudding", - "pull", - "pulp", - "pulse", - "pumpkin", - "punch", - "pupil", - "puppy", - "purchase", - "purity", - "purpose", - "purse", - "push", - "put", - "puzzle", - "pyramid", - "quality", - "quantum", - "quarter", - "question", - "quick", - "quit", - "quiz", - "quote", - "rabbit", - "raccoon", - "race", - "rack", - "radar", - "radio", - "rail", - "rain", - "raise", - "rally", - "ramp", - "ranch", - "random", - "range", - "rapid", - "rare", - "rate", - "rather", - "raven", - "raw", - "razor", - "ready", - "real", - "reason", - "rebel", - "rebuild", - "recall", - "receive", - "recipe", - "record", - "recycle", - "reduce", - "reflect", - "reform", - "refuse", - "region", - "regret", - "regular", - "reject", - "relax", - "release", - "relief", - "rely", - "remain", - "remember", - "remind", - "remove", - "render", - "renew", - "rent", - "reopen", - "repair", - "repeat", - "replace", - "report", - "require", - "rescue", - "resemble", - "resist", - "resource", - "response", - "result", - "retire", - "retreat", - "return", - "reunion", - "reveal", - "review", - "reward", - "rhythm", - "rib", - "ribbon", - "rice", - "rich", - "ride", - "ridge", - "rifle", - "right", - "rigid", - "ring", - "riot", - "ripple", - "risk", - "ritual", - "rival", - "river", - "road", - "roast", - "robot", - "robust", - "rocket", - "romance", - "roof", - "rookie", - "room", - "rose", - "rotate", - "rough", - "round", - "route", - "royal", - "rubber", - "rude", - "rug", - "rule", - "run", - "runway", - "rural", - "sad", - "saddle", - "sadness", - "safe", - "sail", - "salad", - "salmon", - "salon", - "salt", - "salute", - "same", - "sample", - "sand", - "satisfy", - "satoshi", - "sauce", - "sausage", - "save", - "say", - "scale", - "scan", - "scare", - "scatter", - "scene", - "scheme", - "school", - "science", - "scissors", - "scorpion", - "scout", - "scrap", - "screen", - "script", - "scrub", - "sea", - "search", - "season", - "seat", - "second", - "secret", - "section", - "security", - "seed", - "seek", - "segment", - "select", - "sell", - "seminar", - "senior", - "sense", - "sentence", - "series", - "service", - "session", - "settle", - "setup", - "seven", - "shadow", - "shaft", - "shallow", - "share", - "shed", - "shell", - "sheriff", - "shield", - "shift", - "shine", - "ship", - "shiver", - "shock", - "shoe", - "shoot", - "shop", - "short", - "shoulder", - "shove", - "shrimp", - "shrug", - "shuffle", - "shy", - "sibling", - "sick", - "side", - "siege", - "sight", - "sign", - "silent", - "silk", - "silly", - "silver", - "similar", - "simple", - "since", - "sing", - "siren", - "sister", - "situate", - "six", - "size", - "skate", - "sketch", - "ski", - "skill", - "skin", - "skirt", - "skull", - "slab", - "slam", - "sleep", - "slender", - "slice", - "slide", - "slight", - "slim", - "slogan", - "slot", - "slow", - "slush", - "small", - "smart", - "smile", - "smoke", - "smooth", - "snack", - "snake", - "snap", - "sniff", - "snow", - "soap", - "soccer", - "social", - "sock", - "soda", - "soft", - "solar", - "soldier", - "solid", - "solution", - "solve", - "someone", - "song", - "soon", - "sorry", - "sort", - "soul", - "sound", - "soup", - "source", - "south", - "space", - "spare", - "spatial", - "spawn", - "speak", - "special", - "speed", - "spell", - "spend", - "sphere", - "spice", - "spider", - "spike", - "spin", - "spirit", - "split", - "spoil", - "sponsor", - "spoon", - "sport", - "spot", - "spray", - "spread", - "spring", - "spy", - "square", - "squeeze", - "squirrel", - "stable", - "stadium", - "staff", - "stage", - "stairs", - "stamp", - "stand", - "start", - "state", - "stay", - "steak", - "steel", - "stem", - "step", - "stereo", - "stick", - "still", - "sting", - "stock", - "stomach", - "stone", - "stool", - "story", - "stove", - "strategy", - "street", - "strike", - "strong", - "struggle", - "student", - "stuff", - "stumble", - "style", - "subject", - "submit", - "subway", - "success", - "such", - "sudden", - "suffer", - "sugar", - "suggest", - "suit", - "summer", - "sun", - "sunny", - "sunset", - "super", - "supply", - "supreme", - "sure", - "surface", - "surge", - "surprise", - "surround", - "survey", - "suspect", - "sustain", - "swallow", - "swamp", - "swap", - "swarm", - "swear", - "sweet", - "swift", - "swim", - "swing", - "switch", - "sword", - "symbol", - "symptom", - "syrup", - "system", - "table", - "tackle", - "tag", - "tail", - "talent", - "talk", - "tank", - "tape", - "target", - "task", - "taste", - "tattoo", - "taxi", - "teach", - "team", - "tell", - "ten", - "tenant", - "tennis", - "tent", - "term", - "test", - "text", - "thank", - "that", - "theme", - "then", - "theory", - "there", - "they", - "thing", - "this", - "thought", - "three", - "thrive", - "throw", - "thumb", - "thunder", - "ticket", - "tide", - "tiger", - "tilt", - "timber", - "time", - "tiny", - "tip", - "tired", - "tissue", - "title", - "toast", - "tobacco", - "today", - "toddler", - "toe", - "together", - "toilet", - "token", - "tomato", - "tomorrow", - "tone", - "tongue", - "tonight", - "tool", - "tooth", - "top", - "topic", - "topple", - "torch", - "tornado", - "tortoise", - "toss", - "total", - "tourist", - "toward", - "tower", - "town", - "toy", - "track", - "trade", - "traffic", - "tragic", - "train", - "transfer", - "trap", - "trash", - "travel", - "tray", - "treat", - "tree", - "trend", - "trial", - "tribe", - "trick", - "trigger", - "trim", - "trip", - "trophy", - "trouble", - "truck", - "true", - "truly", - "trumpet", - "trust", - "truth", - "try", - "tube", - "tuition", - "tumble", - "tuna", - "tunnel", - "turkey", - "turn", - "turtle", - "twelve", - "twenty", - "twice", - "twin", - "twist", - "two", - "type", - "typical", - "ugly", - "umbrella", - "unable", - "unaware", - "uncle", - "uncover", - "under", - "undo", - "unfair", - "unfold", - "unhappy", - "uniform", - "unique", - "unit", - "universe", - "unknown", - "unlock", - "until", - "unusual", - "unveil", - "update", - "upgrade", - "uphold", - "upon", - "upper", - "upset", - "urban", - "urge", - "usage", - "use", - "used", - "useful", - "useless", - "usual", - "utility", - "vacant", - "vacuum", - "vague", - "valid", - "valley", - "valve", - "van", - "vanish", - "vapor", - "various", - "vast", - "vault", - "vehicle", - "velvet", - "vendor", - "venture", - "venue", - "verb", - "verify", - "version", - "very", - "vessel", - "veteran", - "viable", - "vibrant", - "vicious", - "victory", - "video", - "view", - "village", - "vintage", - "violin", - "virtual", - "virus", - "visa", - "visit", - "visual", - "vital", - "vivid", - "vocal", - "voice", - "void", - "volcano", - "volume", - "vote", - "voyage", - "wage", - "wagon", - "wait", - "walk", - "wall", - "walnut", - "want", - "warfare", - "warm", - "warrior", - "wash", - "wasp", - "waste", - "water", - "wave", - "way", - "wealth", - "weapon", - "wear", - "weasel", - "weather", - "web", - "wedding", - "weekend", - "weird", - "welcome", - "west", - "wet", - "whale", - "what", - "wheat", - "wheel", - "when", - "where", - "whip", - "whisper", - "wide", - "width", - "wife", - "wild", - "will", - "win", - "window", - "wine", - "wing", - "wink", - "winner", - "winter", - "wire", - "wisdom", - "wise", - "wish", - "witness", - "wolf", - "woman", - "wonder", - "wood", - "wool", - "word", - "work", - "world", - "worry", - "worth", - "wrap", - "wreck", - "wrestle", - "wrist", - "write", - "wrong", - "yard", - "year", - "yellow", - "you", - "young", - "youth", - "zebra", - "zero", - "zone", - "zoo", -]; diff --git a/rust/tw_hd_wallet/src/bip39/mod.rs b/rust/tw_hd_wallet/src/bip39/mod.rs deleted file mode 100644 index d0e1db66b2e..00000000000 --- a/rust/tw_hd_wallet/src/bip39/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// -// Copyright © 2017 Trust Wallet. - -pub mod bip39_english; - -pub fn normalize_mnemonic(mnemonic: &str) -> String { - mnemonic.trim().to_string() -} diff --git a/rust/tw_hd_wallet/src/lib.rs b/rust/tw_hd_wallet/src/lib.rs deleted file mode 100644 index cfa3a09fa16..00000000000 --- a/rust/tw_hd_wallet/src/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// -// Copyright © 2017 Trust Wallet. - -extern crate core; - -pub mod bip39; -pub mod ton; - -pub type WalletResult = Result; - -#[derive(Debug, Eq, PartialEq)] -pub enum WalletError { - InvalidMnemonicWordCount, - InvalidMnemonicUnknownWord, - InvalidMnemonicEntropy, - InvalidChecksum, -} diff --git a/rust/tw_hd_wallet/src/ton/mnemonic.rs b/rust/tw_hd_wallet/src/ton/mnemonic.rs deleted file mode 100644 index 27013cdc283..00000000000 --- a/rust/tw_hd_wallet/src/ton/mnemonic.rs +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// -// Copyright © 2017 Trust Wallet. - -use crate::bip39::bip39_english::BIP39_WORDS_MAP; -use crate::{WalletError, WalletResult}; - -pub const WORDS_LEN: usize = 24; - -/// Validates the given `mnemonic` string if it consists of 24 known words (see BIP39 words list). -/// -/// Please note there this function doesn't validate the mnemonic but it words only. -/// See [`TonWallet::new`]. -pub fn validate_mnemonic_words(mnemonic: &str) -> WalletResult<()> { - let mut invalid = false; - let mut words_count = 0; - for word in mnemonic.split(" ") { - words_count += 1; - - // Although this operation is not security-critical, we aim for constant-time operation here as well - // (i.e., no early exit on match) - // - // We expect words in lowercase only. - // It's a responsibility of the WalletCore user to transform the mnemonic if needed. - if !BIP39_WORDS_MAP.contains_key(word) { - invalid = true; - } - } - - if invalid { - return Err(WalletError::InvalidMnemonicUnknownWord); - } - if words_count != WORDS_LEN { - return Err(WalletError::InvalidMnemonicWordCount); - } - - Ok(()) -} diff --git a/rust/tw_hd_wallet/src/ton/mod.rs b/rust/tw_hd_wallet/src/ton/mod.rs deleted file mode 100644 index 2971881654a..00000000000 --- a/rust/tw_hd_wallet/src/ton/mod.rs +++ /dev/null @@ -1,169 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// -// Copyright © 2017 Trust Wallet. - -use crate::bip39::normalize_mnemonic; -use crate::ton::mnemonic::validate_mnemonic_words; -use crate::{WalletError, WalletResult}; -use tw_hash::hmac::hmac_sha512; -use tw_hash::pbkdf2::pbkdf2_hmac_sha512; -use tw_hash::{H256, H512}; -use tw_keypair::ed25519::sha512::KeyPair; -use zeroize::ZeroizeOnDrop; - -pub const TON_WALLET_SALT: &[u8] = b"TON default seed"; -pub const TON_WALLET_PBKDF_ITERATIONS: u32 = 100_000; - -/// Used to verify a pair of mnemonic and passphrase only. -const TON_BASIC_SEED_SALT: &[u8] = b"TON seed version"; -/// Equals to `(TON_WALLET_PBKDF_ITERATIONS as f64 / 256.0).floor() as u32`. -const TON_BASIC_SEED_ROUNDS: u32 = 390; - -/// Used to verify a pair of mnemonic and passphrase only. -const TON_PASSPHRASE_SEED_SALT: &[u8] = b"TON fast seed version"; -const TON_PASSPHRASE_SEED_ROUNDS: u32 = 1; - -mod mnemonic; - -#[derive(Debug, ZeroizeOnDrop)] -pub struct TonWallet { - mnemonic: String, - passphrase: Option, - entropy: H512, - seed: H512, -} - -impl TonWallet { - pub const MNEMONIC_WORDS: usize = 24; - - /// Creates `TonWallet` while validating if there should or shouldn't be a passphrase. - /// https://github.com/toncenter/tonweb-mnemonic/blob/a338a00d4ca0ed833431e0e49e4cfad766ac713c/src/functions/validate-mnemonic.ts#L20-L28 - pub fn new(mnemonic: &str, passphrase: Option) -> WalletResult { - let mnemonic = normalize_mnemonic(mnemonic); - validate_mnemonic_words(&mnemonic)?; - - match passphrase { - Some(ref passphrase) if !passphrase.is_empty() => { - // Check whether the passphrase is really needed. - if !Self::is_password_needed(&mnemonic) { - return Err(WalletError::InvalidMnemonicEntropy); - } - }, - _ => (), - }; - - let entropy = Self::ton_mnemonic_to_entropy(&mnemonic, passphrase.as_deref()); - - // The pair of `[mnemonic, Option]` should give a `basic` seed. - // Otherwise, `passphrase` is either not set or invalid. - if !is_basic_seed(&entropy) { - return Err(WalletError::InvalidMnemonicEntropy); - } - - let seed = ton_seed(&entropy); - Ok(TonWallet { - mnemonic, - passphrase, - entropy, - seed, - }) - } - - pub fn to_key_pair(&self) -> KeyPair { - let (secret, _): (H256, H256) = self.seed.split(); - KeyPair::from(secret) - } - - /// Whether the mnemonic can be used with a passphrase only. - /// https://github.com/toncenter/tonweb-mnemonic/blob/a338a00d4ca0ed833431e0e49e4cfad766ac713c/src/functions/is-password-needed.ts#L5-L11 - fn is_password_needed(mnemonic: &str) -> bool { - // Password mnemonic (without password) should be password seed, but not basic seed. - let entropy = Self::ton_mnemonic_to_entropy(mnemonic, None); - is_password_seed(&entropy) && !is_basic_seed(&entropy) - } - - /// https://github.com/toncenter/tonweb-mnemonic/blob/a338a00d4ca0ed833431e0e49e4cfad766ac713c/src/functions/common.ts#L20-L23 - fn ton_mnemonic_to_entropy(mnemonic: &str, passphrase: Option<&str>) -> H512 { - let passphrase_bytes = passphrase.map(str::as_bytes).unwrap_or(&[]); - let entropy = hmac_sha512(mnemonic.as_bytes(), passphrase_bytes); - H512::try_from(entropy.as_slice()).expect("hmac_sha512 must return 64 bytes") - } -} - -/// https://github.com/toncenter/tonweb-mnemonic/blob/a338a00d4ca0ed833431e0e49e4cfad766ac713c/src/functions/common.ts#L8-L11 -fn is_basic_seed(entropy: &H512) -> bool { - basic_seed(entropy)[0] == 0 -} - -/// https://github.com/toncenter/tonweb-mnemonic/blob/a338a00d4ca0ed833431e0e49e4cfad766ac713c/src/functions/mnemonic-to-seed.ts#L5-L17 -fn ton_seed(entropy: &H512) -> H512 { - pbkdf2_hmac_sha512( - entropy.as_slice(), - TON_WALLET_SALT, - TON_WALLET_PBKDF_ITERATIONS, - ) -} - -/// https://github.com/toncenter/tonweb-mnemonic/blob/a338a00d4ca0ed833431e0e49e4cfad766ac713c/src/functions/common.ts#L9 -fn basic_seed(entropy: &H512) -> H512 { - pbkdf2_hmac_sha512( - entropy.as_slice(), - TON_BASIC_SEED_SALT, - TON_BASIC_SEED_ROUNDS, - ) -} - -/// https://github.com/toncenter/tonweb-mnemonic/blob/a338a00d4ca0ed833431e0e49e4cfad766ac713c/src/functions/common.ts#L15 -fn password_seed(entropy: &H512) -> H512 { - pbkdf2_hmac_sha512( - entropy.as_slice(), - TON_PASSPHRASE_SEED_SALT, - TON_PASSPHRASE_SEED_ROUNDS, - ) -} - -/// https://github.com/toncenter/tonweb-mnemonic/blob/a338a00d4ca0ed833431e0e49e4cfad766ac713c/src/functions/common.ts#L14-L17 -fn is_password_seed(entropy: &H512) -> bool { - password_seed(entropy)[0] == 1 -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_is_basic_seed() { - let entropy = H512::from("db315e4b9a05d29d4921f3f99c754b52c1035bd20a6c38ae4c39068a844d2d4dccd1b16ab639494155bd635737c9120eab0b0382c6f27d941993ad2a98ee037b"); - let actual = basic_seed(&entropy); - let expected = H512::from("008303d550147ad20420875810a81496510e32e2ec7b1c4129c8fe55c0886ad2b6c8b6ad88427d3614a27997ec3760e4a6aaae45c8a1c70684aad5206e8559ce"); - assert_eq!(actual, expected); - assert!(is_basic_seed(&entropy)); - } - - #[test] - fn test_is_not_basic_seed() { - let entropy = H512::from("5ad5da67282f932eb9e0b66246af357e1e99f73b066ba1095fedf324629f67048c82e7c6d4cf09f204e2b2fcd002ab9bae25da67f99ecb918861d11ec6553a78"); - let actual = basic_seed(&entropy); - let expected = H512::from("fd1ab5001f7fec237ad7b90dbd3a8a6d716409688d23517cc80314b79f36f93a21aac798c39778684688b4763bf0294874c067ef3d28d854101c4e5616839dfd"); - assert_eq!(actual, expected); - assert!(!is_basic_seed(&entropy)); - } - - #[test] - fn test_is_password_seed() { - let entropy = H512::from("f0fc0e9610e3a215db47df1fc8dc2142ec4e8559ee1ec384fc3e51234d63c34087f4a6bdb2ad2c5a46a4504e30c9ab4ef7d92dc1836c2854ecef1f7988e60100"); - let actual = password_seed(&entropy); - let expected = H512::from("014944aac60ad889acab074b850df15b745b2c6ca5367c3ba02f4ae22e5a8953ac33413c0cd7fdb9108935bd6ed82acc73d4ac94202d83933a5480642c371eed"); - assert_eq!(actual, expected); - assert!(is_password_seed(&entropy)); - } - - #[test] - fn test_is_not_password_seed() { - let entropy = H512::from("85092586b7d675688d52b5870966546c7fb0144a2d94badd7c3960d6e9de3094016cea3aa155f5a9b3ce61d5b4ad8393984ed153dc0866304c911ba2edd2ea9e"); - let actual = password_seed(&entropy); - let expected = H512::from("31f4dd02b333be5635dc46245d67792b85e9b74d788a749caf3d45bfb1cd094a039626ba1a8bff77fa2436a6a228568d29884c2b274e09c0fe722f07980aab8e"); - assert_eq!(actual, expected); - assert!(!is_password_seed(&entropy)); - } -} diff --git a/rust/tw_hd_wallet/tests/ton_mnemonic.rs b/rust/tw_hd_wallet/tests/ton_mnemonic.rs deleted file mode 100644 index 3125140ad90..00000000000 --- a/rust/tw_hd_wallet/tests/ton_mnemonic.rs +++ /dev/null @@ -1,156 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// -// Copyright © 2017 Trust Wallet. - -use tw_encoding::hex::ToHex; -use tw_hd_wallet::ton::TonWallet; -use tw_hd_wallet::WalletError; -use tw_keypair::traits::KeyPairTrait; -use tw_misc::traits::ToBytesZeroizing; - -struct MnemonicTest { - mnemonic: &'static str, - passphrase: &'static str, - expected_private: &'static str, - expected_public: &'static str, -} - -fn mnemonic_to_keypair_impl(input: MnemonicTest) { - let passphrase = if input.passphrase.is_empty() { - None - } else { - Some(input.passphrase.to_string()) - }; - - let wallet = TonWallet::new(input.mnemonic, passphrase).unwrap(); - let key_pair = wallet.to_key_pair(); - - assert_eq!( - key_pair.private().to_zeroizing_vec().to_hex(), - input.expected_private, - "Invalid private key" - ); - assert_eq!( - key_pair.public().to_bytes().to_hex(), - input.expected_public, - "Invalid public key" - ); -} - -struct MnemonicErrorTest { - mnemonic: &'static str, - passphrase: &'static str, -} - -fn mnemonic_to_keypair_error(input: MnemonicErrorTest) { - let passphrase = if input.passphrase.is_empty() { - None - } else { - Some(input.passphrase.to_string()) - }; - - assert!( - TonWallet::new(input.mnemonic, passphrase).is_err(), - "Expected an error" - ); -} - -/// All tests generated by using `https://github.com/toncenter/tonweb-mnemonic/`. -#[test] -fn test_mnemonic_to_keypair_no_passphrase() { - mnemonic_to_keypair_impl(MnemonicTest { - mnemonic: "document shield addict crime broom point story depend suit satisfy test chicken valid tail speak fortune sound drill seek cube cheap body music recipe", - passphrase: "", - expected_private: "112d4e2e700a468f1eae699329202f1ee671d6b665caa2d92dea038cf3868c18", - expected_public: "4d656c35c830bf78d239d3225727dd1da051be0ec521c98e3012beafbb06f306", - }); - mnemonic_to_keypair_impl(MnemonicTest { - mnemonic: "slogan train glide measure mercy dizzy when satoshi vote change length pluck token walnut actress hollow guard soup solve rival summer vicious anxiety device", - passphrase: "", - expected_private: "ee11da8e64d17a8416c88a6a24a1e16569cc85a077b7b209528975c32a44a0c8", - expected_public: "3bab20a5f77e277e39443fc16c64e0479b4a9db542bf9e11c638598384c853f1", - }); - mnemonic_to_keypair_impl(MnemonicTest { - mnemonic: "laundry myself fitness beyond prize piano match acid vacuum already abandon dance occur pause grocery company inject excuse weasel carpet fog grunt trick spike", - passphrase: "", - expected_private: "859cd74ab605afb7ce9f5316a1f6d59217a130b75b494efd249913be874c9d46", - expected_public: "c9af50596bd5c1c5a15fb32bef8d4f1ee5244b287aea1f49f6023a79f9b2f055", - }); - mnemonic_to_keypair_impl(MnemonicTest { - mnemonic: "slim holiday tiny pizza donor egg round three verify post chat social offer mix rack soft loud code option learn this pipe mouse mango", - passphrase: "", - expected_private: "cdfd1e2a1f947701bddba2636c26a6d6d13efacba5e6fdc624254be9bf8cbc3b", - expected_public: "c1266dc4e8040e462af34fa7da9130950caf8c8a1bab78c9b938d2eb6e3d9a69", - }); -} - -/// All tests generated by using `https://github.com/toncenter/tonweb-mnemonic/`. -#[test] -fn test_mnemonic_to_keypair_with_passphrase() { - mnemonic_to_keypair_impl(MnemonicTest { - mnemonic: "afford skate husband stamp style affair jeans episode afraid mom pupil canal borrow artwork fetch excite shiver conduct acoustic rail crisp consider pave people", - passphrase: ".", - expected_private: "ddaed03c283c9e60883b6c7cda86af40a1a820a8181276900094db0d23b55144", - expected_public: "46aacb0e9e1faba24e0e87d4bf7ee5e54beaa4142fa1bd608324d7c67d78070e", - }); - mnemonic_to_keypair_impl(MnemonicTest { - mnemonic: "mimic close sibling chair shuffle goat fashion chunk increase tennis scene ceiling divert cross treat happy soccer sample umbrella oyster advance quality perfect call", - passphrase: "My passphrase", - expected_private: "78a6d95981847d6b7fb6b85be43071fbd83f4b0cebc1fd0c75147fde3c88d9e2", - expected_public: "452a6031290df95e972a269f3c042f5b18497ab27b8fe9915e5b5c94037382a6", - }); - mnemonic_to_keypair_impl(MnemonicTest { - mnemonic: "kind loan rifle gadget forward tortoise switch tuition orchard ball monkey glow gallery diary nature dynamic survey flush correct employ autumn wife disease coin", - passphrase: "189r012 9jr90fj--901hr8921'0r912j90", - expected_private: "ced0feac4f8cc46909a5a172d390f126afe46540c07c5163c194429269e6eb08", - expected_public: "482c9619307639a4b1699e83d771d656e5cf7be3ef877d849940cfebd718783e", - }); - mnemonic_to_keypair_impl(MnemonicTest { - mnemonic: " predict pelican worry swallow brother real truck fiber trophy melody joy kitten luggage lake woman clutch frost crop about stumble frozen kitchen mutual food ", - passphrase: "Foo Bar Zar", - expected_private: "f93ed43c379cb8210754016ffa669880b259854160446c1a12c5858258c32601", - expected_public: "f44d7f29bc8801f882097611544fcafe84cca05408006fa5b76b63f55464e4d0", - }); -} - -#[test] -fn test_mnemonic_to_keypair_error_expected_passphrase() { - // This mnemonic can only be used along with the "My passphrase" passphrase. - let mnemonic = "mimic close sibling chair shuffle goat fashion chunk increase tennis scene ceiling divert cross treat happy soccer sample umbrella oyster advance quality perfect call"; - mnemonic_to_keypair_error(MnemonicErrorTest { - mnemonic, - passphrase: "", - }); - mnemonic_to_keypair_error(MnemonicErrorTest { - mnemonic, - passphrase: "Unexpected passphrase", - }); -} - -#[test] -fn test_mnemonic_to_keypair_error_expected_no_passphrase() { - // This mnemonic can only be used without passphrase. - let mnemonic = "slogan train glide measure mercy dizzy when satoshi vote change length pluck token walnut actress hollow guard soup solve rival summer vicious anxiety device"; - mnemonic_to_keypair_error(MnemonicErrorTest { - mnemonic, - passphrase: "Hello world", - }); - mnemonic_to_keypair_error(MnemonicErrorTest { - mnemonic, - passphrase: "...", - }); -} - -#[test] -fn test_invalid_mnemonic() { - // 24 words mnemonic is supported only. - let error = TonWallet::new("cost dash dress stove morning robust group affair stomach vacant route volume yellow salute laugh", None).unwrap_err(); - assert_eq!(error, WalletError::InvalidMnemonicWordCount); - - let error = TonWallet::new("foo bar oooo edit wash faint patient cancel roof edit silly battle half engine reunion hotel joy fan unhappy oil alone sense empty mesh", None).unwrap_err(); - assert_eq!(error, WalletError::InvalidMnemonicUnknownWord); - - // Upper-case mnemonic is not allowed. - let error = TonWallet::new("TAIL SWING SUGGEST EDIT WASH FAINT PATIENT CANCEL ROOF EDIT SILLY BATTLE HALF ENGINE REUNION HOTEL JOY FAN UNHAPPY OIL ALONE SENSE EMPTY MESH", None).unwrap_err(); - assert_eq!(error, WalletError::InvalidMnemonicUnknownWord); -} diff --git a/rust/tw_keypair/src/ed25519/keypair.rs b/rust/tw_keypair/src/ed25519/keypair.rs index eed4a8ca6d0..3ac2ac1e1fa 100644 --- a/rust/tw_keypair/src/ed25519/keypair.rs +++ b/rust/tw_keypair/src/ed25519/keypair.rs @@ -6,7 +6,6 @@ use crate::ed25519::{private::PrivateKey, public::PublicKey, signature::Signatur use crate::traits::{KeyPairTrait, SigningKeyTrait, VerifyingKeyTrait}; use crate::{KeyPairError, KeyPairResult}; use tw_encoding::hex; -use tw_hash::H256; use zeroize::Zeroizing; /// Represents a pair of `ed25519` private and public keys. @@ -47,14 +46,6 @@ impl VerifyingKeyTrait for KeyPair { } } -impl From for KeyPair { - fn from(secret: H256) -> Self { - let private = PrivateKey::from(secret); - let public = private.public(); - KeyPair { private, public } - } -} - impl<'a, H: Hasher512> TryFrom<&'a [u8]> for KeyPair { type Error = KeyPairError; diff --git a/rust/tw_keypair/src/ed25519/private.rs b/rust/tw_keypair/src/ed25519/private.rs index dc5ab54a68e..984392393a6 100644 --- a/rust/tw_keypair/src/ed25519/private.rs +++ b/rust/tw_keypair/src/ed25519/private.rs @@ -11,7 +11,6 @@ use crate::{KeyPairError, KeyPairResult}; use std::fmt; use tw_encoding::hex; use tw_hash::H256; -use tw_memory::Data; use tw_misc::traits::ToBytesZeroizing; use zeroize::{ZeroizeOnDrop, Zeroizing}; @@ -38,12 +37,6 @@ impl PrivateKey { PublicKey::with_expanded_secret(&self.expanded_key) } - /// Returns a reference to the private key bytes. - /// Please note if clone bytes, it must be zeroized with [`zeroize::Zeroize::zeroize`]. - pub fn bytes(&self) -> &H256 { - &self.secret - } - /// `ed25519` signing uses a public key associated with the private key. pub(crate) fn sign_with_public_key( &self, @@ -56,7 +49,7 @@ impl PrivateKey { } impl SigningKeyTrait for PrivateKey { - type SigningMessage = Data; + type SigningMessage = Vec; type Signature = Signature; fn sign(&self, message: Self::SigningMessage) -> KeyPairResult { @@ -64,22 +57,16 @@ impl SigningKeyTrait for PrivateKey { } } -impl From for PrivateKey { - fn from(secret: H256) -> Self { - let expanded_key = ExpandedSecretKey::::with_secret(secret); - PrivateKey { - secret, - expanded_key, - } - } -} - impl TryFrom<&[u8]> for PrivateKey { type Error = KeyPairError; fn try_from(data: &[u8]) -> Result { let secret = H256::try_from(data).map_err(|_| KeyPairError::InvalidSecretKey)?; - Ok(PrivateKey::from(secret)) + let expanded_key = ExpandedSecretKey::::with_secret(secret); + Ok(PrivateKey { + secret, + expanded_key, + }) } } @@ -93,7 +80,7 @@ impl<'a, H: Hasher512> TryFrom<&'a str> for PrivateKey { } impl ToBytesZeroizing for PrivateKey { - fn to_zeroizing_vec(&self) -> Zeroizing { + fn to_zeroizing_vec(&self) -> Zeroizing> { Zeroizing::new(self.secret.to_vec()) } } diff --git a/rust/tw_keypair/src/ffi/privkey.rs b/rust/tw_keypair/src/ffi/privkey.rs index c1a1b978569..9d4efa7f8f4 100644 --- a/rust/tw_keypair/src/ffi/privkey.rs +++ b/rust/tw_keypair/src/ffi/privkey.rs @@ -8,11 +8,10 @@ use crate::ffi::pubkey::TWPublicKey; use crate::tw::{Curve, PrivateKey, PublicKeyType}; use tw_memory::ffi::c_byte_array::CByteArray; use tw_memory::ffi::c_byte_array_ref::CByteArrayRef; -use tw_memory::ffi::tw_data::TWData; use tw_memory::ffi::RawPtrTrait; use tw_misc::{try_or_else, try_or_false}; -pub struct TWPrivateKey(pub PrivateKey); +pub struct TWPrivateKey(pub(crate) PrivateKey); impl RawPtrTrait for TWPrivateKey {} @@ -68,17 +67,6 @@ pub unsafe extern "C" fn tw_private_key_is_valid( PrivateKey::is_valid(priv_key_slice, curve) } -/// Convert the given private key to raw-bytes block of data. -/// -/// \param key Non-null pointer to the private key -/// \note The returned block should be deleted with \tw_data_delete_zeroizing -/// \return Non-null block of data (raw bytes) of the given private key -#[no_mangle] -pub unsafe extern "C" fn tw_private_key_data(key: *const TWPrivateKey) -> *mut TWData { - let key = try_or_else!(TWPrivateKey::from_ptr_as_ref(key), std::ptr::null_mut); - TWData::from(key.0.bytes().to_vec()).into_ptr() -} - /// Signs a digest using ECDSA and given curve. /// /// \param key *non-null* pointer to a Private key @@ -88,7 +76,7 @@ pub unsafe extern "C" fn tw_private_key_data(key: *const TWPrivateKey) -> *mut T /// \return Signature as a C-compatible result with a C-compatible byte array. #[no_mangle] pub unsafe extern "C" fn tw_private_key_sign( - key: *const TWPrivateKey, + key: *mut TWPrivateKey, message: *const u8, message_len: usize, curve: u32, @@ -112,7 +100,7 @@ pub unsafe extern "C" fn tw_private_key_sign( /// \return *non-null* pointer to the corresponding public key. #[no_mangle] pub unsafe extern "C" fn tw_private_key_get_public_key_by_type( - key: *const TWPrivateKey, + key: *mut TWPrivateKey, pubkey_type: u32, ) -> *mut TWPublicKey { let ty = try_or_else!(PublicKeyType::from_raw(pubkey_type), std::ptr::null_mut); diff --git a/rust/tw_keypair/src/ffi/pubkey.rs b/rust/tw_keypair/src/ffi/pubkey.rs index 690f1c3e645..7f05f5f0fe9 100644 --- a/rust/tw_keypair/src/ffi/pubkey.rs +++ b/rust/tw_keypair/src/ffi/pubkey.rs @@ -10,7 +10,7 @@ use tw_memory::ffi::c_byte_array_ref::CByteArrayRef; use tw_memory::ffi::RawPtrTrait; use tw_misc::{try_or_else, try_or_false}; -pub struct TWPublicKey(pub PublicKey); +pub struct TWPublicKey(pub(crate) PublicKey); impl AsRef for TWPublicKey { fn as_ref(&self) -> &PublicKey { diff --git a/rust/tw_keypair/src/test_utils/tw_crypto_box_helpers.rs b/rust/tw_keypair/src/test_utils/tw_crypto_box_helpers.rs index 34c2a0f965a..88b4a146003 100644 --- a/rust/tw_keypair/src/test_utils/tw_crypto_box_helpers.rs +++ b/rust/tw_keypair/src/test_utils/tw_crypto_box_helpers.rs @@ -4,10 +4,10 @@ use crate::ffi::crypto_box::public_key::{tw_crypto_box_public_key_delete, TWCryptoBoxPublicKey}; use crate::ffi::crypto_box::secret_key::{tw_crypto_box_secret_key_delete, TWCryptoBoxSecretKey}; -use tw_memory::test_utils::tw_wrapper::{TWAutoWrapper, WithDestructor}; +use tw_memory::test_utils::tw_wrapper::{TWWrapper, WithDestructor}; -pub type TWCryptoBoxSecretKeyHelper = TWAutoWrapper; -pub type TWCryptoBoxPublicKeyHelper = TWAutoWrapper; +pub type TWCryptoBoxSecretKeyHelper = TWWrapper; +pub type TWCryptoBoxPublicKeyHelper = TWWrapper; impl WithDestructor for TWCryptoBoxSecretKey { fn destructor() -> unsafe extern "C" fn(*mut Self) { diff --git a/rust/tw_keypair/src/test_utils/tw_private_key_helper.rs b/rust/tw_keypair/src/test_utils/tw_private_key_helper.rs index d745fb2a1e3..6c3c3bfc629 100644 --- a/rust/tw_keypair/src/test_utils/tw_private_key_helper.rs +++ b/rust/tw_keypair/src/test_utils/tw_private_key_helper.rs @@ -2,12 +2,9 @@ // // Copyright © 2017 Trust Wallet. -use crate::ffi::privkey::{ - tw_private_key_create_with_data, tw_private_key_data, tw_private_key_delete, TWPrivateKey, -}; +use crate::ffi::privkey::{tw_private_key_create_with_data, tw_private_key_delete, TWPrivateKey}; use tw_encoding::hex; use tw_memory::ffi::c_byte_array::CByteArray; -use tw_memory::test_utils::tw_data_helper::TWDataHelper; use tw_memory::Data; pub struct TWPrivateKeyHelper { @@ -15,18 +12,6 @@ pub struct TWPrivateKeyHelper { } impl TWPrivateKeyHelper { - pub fn wrap(ptr: *mut TWPrivateKey) -> TWPrivateKeyHelper { - TWPrivateKeyHelper { ptr } - } - - pub fn bytes(&self) -> Option { - if self.ptr.is_null() { - return None; - } - let data = TWDataHelper::wrap(unsafe { tw_private_key_data(self.ptr) }); - data.to_vec() - } - pub fn with_bytes>(bytes: T) -> TWPrivateKeyHelper { let priv_key_raw = CByteArray::from(bytes.into()); let ptr = diff --git a/rust/tw_keypair/src/tw/private.rs b/rust/tw_keypair/src/tw/private.rs index b325b3ca834..0516f451798 100644 --- a/rust/tw_keypair/src/tw/private.rs +++ b/rust/tw_keypair/src/tw/private.rs @@ -55,11 +55,6 @@ impl PrivateKey { Ok(&self.bytes[Self::EXTENDED_CARDANO_RANGE]) } - /// Returns bytes (32 or 192 bytes). - pub fn bytes(&self) -> &[u8] { - &self.bytes - } - /// Checks if the given `bytes` secret is valid in general (without a concrete curve). pub fn is_valid_general(bytes: &[u8]) -> bool { if bytes.len() != Self::SIZE && bytes.len() != Self::CARDANO_SIZE { @@ -208,11 +203,3 @@ impl PrivateKey { schnorr::PrivateKey::try_from(self.key().as_slice()) } } - -impl From for PrivateKey { - fn from(key: ed25519::sha512::PrivateKey) -> Self { - PrivateKey { - bytes: key.bytes().to_vec(), - } - } -} diff --git a/rust/tw_keypair/tests/crypto_box_ffi_tests.rs b/rust/tw_keypair/tests/crypto_box_ffi_tests.rs index 4dbe6bb67e5..bf98b67b07e 100644 --- a/rust/tw_keypair/tests/crypto_box_ffi_tests.rs +++ b/rust/tw_keypair/tests/crypto_box_ffi_tests.rs @@ -17,12 +17,11 @@ use tw_keypair::test_utils::tw_crypto_box_helpers::{ TWCryptoBoxPublicKeyHelper, TWCryptoBoxSecretKeyHelper, }; use tw_memory::test_utils::tw_data_helper::TWDataHelper; -use tw_memory::test_utils::tw_wrapper::TWAutoWrapper; +use tw_memory::test_utils::tw_wrapper::TWWrapper; fn random_key_pair() -> (TWCryptoBoxSecretKeyHelper, TWCryptoBoxPublicKeyHelper) { - let secret = TWAutoWrapper::wrap(unsafe { tw_crypto_box_secret_key_create() }); - let pubkey = - TWAutoWrapper::wrap(unsafe { tw_crypto_box_secret_key_get_public_key(secret.ptr()) }); + let secret = TWWrapper::wrap(unsafe { tw_crypto_box_secret_key_create() }); + let pubkey = TWWrapper::wrap(unsafe { tw_crypto_box_secret_key_get_public_key(secret.ptr()) }); (secret, pubkey) } @@ -56,7 +55,7 @@ fn test_encrypt_decrypt_easy_error() { .decode_hex() .unwrap(), ); - let other_pubkey = TWAutoWrapper::wrap(unsafe { + let other_pubkey = TWWrapper::wrap(unsafe { tw_crypto_box_public_key_create_with_data(other_pubkey_data.ptr()) }); @@ -84,9 +83,8 @@ fn test_public_key() { let pubkey_data = TWDataHelper::create(pubkey_bytes.clone()); assert!(unsafe { tw_crypto_box_public_key_is_valid(pubkey_data.ptr()) }); - let pubkey = TWAutoWrapper::wrap(unsafe { - tw_crypto_box_public_key_create_with_data(pubkey_data.ptr()) - }); + let pubkey = + TWWrapper::wrap(unsafe { tw_crypto_box_public_key_create_with_data(pubkey_data.ptr()) }); let actual_data = TWDataHelper::wrap(unsafe { tw_crypto_box_public_key_data(pubkey.ptr()) }); assert_eq!(actual_data.to_vec().unwrap(), pubkey_bytes); } @@ -100,9 +98,8 @@ fn test_secret_key() { let secret_data = TWDataHelper::create(secret_bytes.clone()); assert!(unsafe { tw_crypto_box_secret_key_is_valid(secret_data.ptr()) }); - let pubkey = TWAutoWrapper::wrap(unsafe { - tw_crypto_box_secret_key_create_with_data(secret_data.ptr()) - }); + let pubkey = + TWWrapper::wrap(unsafe { tw_crypto_box_secret_key_create_with_data(secret_data.ptr()) }); let actual_data = TWDataHelper::wrap(unsafe { tw_crypto_box_secret_key_data(pubkey.ptr()) }); assert_eq!(actual_data.to_vec().unwrap(), secret_bytes); } diff --git a/rust/tw_memory/Cargo.toml b/rust/tw_memory/Cargo.toml index 642b3494812..2c7b443f83f 100644 --- a/rust/tw_memory/Cargo.toml +++ b/rust/tw_memory/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] -zeroize = "1.8.1" [features] test-utils = [] diff --git a/rust/tw_memory/src/ffi/tw_data.rs b/rust/tw_memory/src/ffi/tw_data.rs index 675d0d11e08..7a573d8fe4b 100644 --- a/rust/tw_memory/src/ffi/tw_data.rs +++ b/rust/tw_memory/src/ffi/tw_data.rs @@ -5,7 +5,6 @@ use crate::ffi::c_byte_array_ref::CByteArrayRef; use crate::ffi::RawPtrTrait; use crate::Data; -use zeroize::Zeroize; /// Defines a resizable block of data. /// @@ -80,18 +79,6 @@ pub unsafe extern "C" fn tw_data_delete(data: *mut TWData) { let _ = TWData::from_ptr(data); } -/// Deletes a block of data zeroizing the memory. -/// -/// \param data A non-null valid block of data -#[no_mangle] -pub unsafe extern "C" fn tw_data_delete_zeroizing(data: *mut TWData) { - // Take the ownership back to rust and drop the owner. - let Some(mut data) = TWData::from_ptr(data) else { - return; - }; - data.0.zeroize(); -} - /// Returns the raw pointer to the contents of data. /// /// \param data A non-null valid block of data diff --git a/rust/tw_memory/src/test_utils/tw_wrapper.rs b/rust/tw_memory/src/test_utils/tw_wrapper.rs index 397ee144d6c..448b16097e9 100644 --- a/rust/tw_memory/src/test_utils/tw_wrapper.rs +++ b/rust/tw_memory/src/test_utils/tw_wrapper.rs @@ -2,22 +2,17 @@ // // Copyright © 2017 Trust Wallet. -pub type Destructor = unsafe extern "C" fn(*mut T); - pub trait WithDestructor: Sized { fn destructor() -> unsafe extern "C" fn(*mut Self); } -/// Structure pointer wrapper. -/// Use this wrapper when `T` can implement the `WithDestructor` trait. -/// Otherwise, consider using `TWWrapper`. -pub struct TWAutoWrapper { +pub struct TWWrapper { ptr: *mut T, } -impl TWAutoWrapper { +impl TWWrapper { pub fn wrap(ptr: *mut T) -> Self { - TWAutoWrapper { ptr } + TWWrapper { ptr } } pub fn ptr(&self) -> *mut T { @@ -25,7 +20,7 @@ impl TWAutoWrapper { } } -impl Drop for TWAutoWrapper { +impl Drop for TWWrapper { fn drop(&mut self) { if self.ptr.is_null() { return; @@ -33,28 +28,3 @@ impl Drop for TWAutoWrapper { unsafe { (T::destructor())(self.ptr) } } } - -/// Structure pointer wrapper with a manual destructor. -pub struct TWWrapper { - ptr: *mut T, - destructor: Destructor, -} - -impl TWWrapper { - pub fn wrap(ptr: *mut T, destructor: Destructor) -> Self { - TWWrapper { ptr, destructor } - } - - pub fn ptr(&self) -> *mut T { - self.ptr - } -} - -impl Drop for TWWrapper { - fn drop(&mut self) { - if self.ptr.is_null() { - return; - } - unsafe { (self.destructor)(self.ptr) } - } -} diff --git a/rust/tw_tests/tests/chains/ton/ton_wallet.rs b/rust/tw_tests/tests/chains/ton/ton_wallet.rs index a2187e038ed..e7cdf8f35f9 100644 --- a/rust/tw_tests/tests/chains/ton/ton_wallet.rs +++ b/rust/tw_tests/tests/chains/ton/ton_wallet.rs @@ -2,44 +2,14 @@ // // Copyright © 2017 Trust Wallet. -use tw_encoding::hex::ToHex; -use tw_keypair::test_utils::tw_private_key_helper::TWPrivateKeyHelper; use tw_keypair::test_utils::tw_public_key_helper::TWPublicKeyHelper; use tw_keypair::tw::PublicKeyType; use tw_memory::test_utils::tw_string_helper::TWStringHelper; -use tw_memory::test_utils::tw_wrapper::TWWrapper; use tw_ton::resources::WALLET_ID_V5R1_TON_MAINNET; -use wallet_core_rs::ffi::wallet::ton_wallet::{ +use wallet_core_rs::ffi::ton::wallet::{ tw_ton_wallet_build_v4_r2_state_init, tw_ton_wallet_build_v5_r1_state_init, - tw_ton_wallet_create_with_mnemonic, tw_ton_wallet_delete, tw_ton_wallet_get_key, - tw_ton_wallet_is_valid_mnemonic, }; -#[test] -fn test_ton_wallet_is_valid_mnemonic() { - let mnemonic = TWStringHelper::create("protect drill sugar gallery note admit input wrist chicken swarm scheme hedgehog orbit ritual glove ski buddy slogan fragile sun delay toy lucky require"); - let passphrase = TWStringHelper::create(""); - let invalid_passphrase = TWStringHelper::create("Expected empty passphrase"); - assert!(unsafe { tw_ton_wallet_is_valid_mnemonic(mnemonic.ptr(), passphrase.ptr()) }); - assert!(!unsafe { tw_ton_wallet_is_valid_mnemonic(mnemonic.ptr(), invalid_passphrase.ptr()) }); -} - -#[test] -fn test_ton_wallet_get_key() { - let mnemonic = TWStringHelper::create("protect drill sugar gallery note admit input wrist chicken swarm scheme hedgehog orbit ritual glove ski buddy slogan fragile sun delay toy lucky require"); - let passphrase = std::ptr::null(); - let wallet = TWWrapper::wrap( - unsafe { tw_ton_wallet_create_with_mnemonic(mnemonic.ptr(), passphrase) }, - tw_ton_wallet_delete, - ); - let key = TWPrivateKeyHelper::wrap(unsafe { tw_ton_wallet_get_key(wallet.ptr()) }); - let key_data = key.bytes().unwrap(); - assert_eq!( - key_data.to_hex(), - "cdcea50b87d3f1ca859e7b2bdf9a5339b7b6804b5c70ac85198829f9607dc43b" - ); -} - #[test] fn test_ton_wallet_v4_r2_create_state_init() { let public_key = TWPublicKeyHelper::with_hex( diff --git a/rust/wallet_core_rs/Cargo.toml b/rust/wallet_core_rs/Cargo.toml index 3ce587ab341..1b8f34f853a 100644 --- a/rust/wallet_core_rs/Cargo.toml +++ b/rust/wallet_core_rs/Cargo.toml @@ -12,7 +12,6 @@ default = [ "any-coin", "bitcoin", "ethereum", - "hd_wallet", "keypair", "solana", "ton", @@ -21,7 +20,6 @@ default = [ any-coin = ["tw_any_coin"] bitcoin = ["tw_bitcoin", "tw_coin_registry"] ethereum = ["tw_ethereum", "tw_coin_registry"] -hd_wallet = ["tw_hd_wallet"] keypair = ["tw_keypair"] solana = ["tw_solana"] ton = ["tw_ton"] @@ -49,5 +47,4 @@ tw_misc = { path = "../tw_misc" } tw_proto = { path = "../tw_proto", optional = true } tw_solana = { path = "../chains/tw_solana", optional = true } tw_ton = { path = "../chains/tw_ton", optional = true } -tw_hd_wallet = { path = "../tw_hd_wallet", optional = true } uuid = { version = "1.7", features = ["v4"], optional = true } diff --git a/rust/wallet_core_rs/src/ffi/mod.rs b/rust/wallet_core_rs/src/ffi/mod.rs index 513396b4a06..7b77f1ed28a 100644 --- a/rust/wallet_core_rs/src/ffi/mod.rs +++ b/rust/wallet_core_rs/src/ffi/mod.rs @@ -12,5 +12,3 @@ pub mod solana; pub mod ton; #[cfg(feature = "utils")] pub mod utils; -#[cfg(feature = "hd_wallet")] -pub mod wallet; diff --git a/rust/wallet_core_rs/src/ffi/ton/mod.rs b/rust/wallet_core_rs/src/ffi/ton/mod.rs index fe4f7cf25f6..02721354dfc 100644 --- a/rust/wallet_core_rs/src/ffi/ton/mod.rs +++ b/rust/wallet_core_rs/src/ffi/ton/mod.rs @@ -4,3 +4,4 @@ pub mod address_converter; pub mod message_signer; +pub mod wallet; diff --git a/rust/wallet_core_rs/src/ffi/ton/wallet.rs b/rust/wallet_core_rs/src/ffi/ton/wallet.rs new file mode 100644 index 00000000000..0e3c81a1971 --- /dev/null +++ b/rust/wallet_core_rs/src/ffi/ton/wallet.rs @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Copyright © 2017 Trust Wallet. + +#![allow(clippy::missing_safety_doc)] + +use tw_keypair::ffi::pubkey::TWPublicKey; +use tw_memory::ffi::tw_string::TWString; +use tw_memory::ffi::RawPtrTrait; +use tw_misc::try_or_else; +use tw_ton::modules::wallet_provider::WalletProvider; + +/// Constructs a TON Wallet V4R2 stateInit encoded as BoC (BagOfCells) for the given `public_key`. +/// +/// \param public_key wallet's public key. +/// \param workchain TON workchain to which the wallet belongs. Usually, base chain is used (0). +/// \param wallet_id wallet's ID allows to create multiple wallets for the same private key. +/// \return Pointer to a base64 encoded Bag Of Cells (BoC) StateInit. Null if invalid public key provided. +#[no_mangle] +pub unsafe extern "C" fn tw_ton_wallet_build_v4_r2_state_init( + public_key: *const TWPublicKey, + workchain: i32, + wallet_id: i32, +) -> *mut TWString { + let public_key = try_or_else!(TWPublicKey::from_ptr_as_ref(public_key), std::ptr::null_mut); + let ed_pubkey = try_or_else!(public_key.as_ref().to_ed25519(), std::ptr::null_mut).clone(); + + let state_init = try_or_else!( + WalletProvider::v4r2_state_init(ed_pubkey, workchain, wallet_id), + std::ptr::null_mut + ); + TWString::from(state_init).into_ptr() +} + +// Constructs a TON Wallet V5R1 stateInit encoded as BoC (BagOfCells) for the given `public_key`. +/// +/// \param public_key wallet's public key. +/// \param workchain TON workchain to which the wallet belongs. Usually, base chain is used (0). +/// \param wallet_id wallet's ID allows to create multiple wallets for the same private key. +/// \return Pointer to a base64 encoded Bag Of Cells (BoC) StateInit. Null if invalid public key provided. +#[no_mangle] +pub unsafe extern "C" fn tw_ton_wallet_build_v5_r1_state_init( + public_key: *const TWPublicKey, + workchain: i32, + wallet_id: i32, +) -> *mut TWString { + let public_key = try_or_else!(TWPublicKey::from_ptr_as_ref(public_key), std::ptr::null_mut); + let ed_pubkey = try_or_else!(public_key.as_ref().to_ed25519(), std::ptr::null_mut).clone(); + + let state_init = try_or_else!( + WalletProvider::v5r1_state_init(ed_pubkey, workchain, wallet_id), + std::ptr::null_mut + ); + TWString::from(state_init).into_ptr() +} diff --git a/rust/wallet_core_rs/src/ffi/wallet/mod.rs b/rust/wallet_core_rs/src/ffi/wallet/mod.rs deleted file mode 100644 index 3a0788a1e2c..00000000000 --- a/rust/wallet_core_rs/src/ffi/wallet/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// -// Copyright © 2017 Trust Wallet. - -pub mod ton_wallet; diff --git a/rust/wallet_core_rs/src/ffi/wallet/ton_wallet.rs b/rust/wallet_core_rs/src/ffi/wallet/ton_wallet.rs deleted file mode 100644 index d367824ed81..00000000000 --- a/rust/wallet_core_rs/src/ffi/wallet/ton_wallet.rs +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// -// Copyright © 2017 Trust Wallet. - -#![allow(clippy::missing_safety_doc)] - -use tw_hd_wallet::ton::TonWallet; -use tw_keypair::ffi::privkey::TWPrivateKey; -use tw_keypair::ffi::pubkey::TWPublicKey; -use tw_keypair::traits::KeyPairTrait; -use tw_keypair::tw; -use tw_memory::ffi::tw_string::TWString; -use tw_memory::ffi::RawPtrTrait; -use tw_misc::{try_or_else, try_or_false}; -use tw_ton::modules::wallet_provider::WalletProvider; - -pub struct TWTONWallet(TonWallet); - -impl RawPtrTrait for TWTONWallet {} - -/// Determines whether the English mnemonic and passphrase are valid. -/// -/// \param mnemonic Non-null english mnemonic -/// \param passphrase Nullable optional passphrase -/// \note passphrase can be null or empty string if no passphrase required -/// \return whether the mnemonic and passphrase are valid (valid checksum) -#[no_mangle] -pub unsafe extern "C" fn tw_ton_wallet_is_valid_mnemonic( - mnemonic: *const TWString, - passphrase: *const TWString, -) -> bool { - let mnemonic = try_or_false!(TWString::from_ptr_as_ref(mnemonic)); - let mnemonic = try_or_false!(mnemonic.as_str()); - - let passphrase = TWString::from_ptr_as_ref(passphrase) - .and_then(TWString::as_str) - .map(|pass| pass.to_string()); - - TonWallet::new(mnemonic, passphrase).is_ok() -} - -/// Creates a `TONWallet` from a valid TON mnemonic and passphrase. -/// -/// \param mnemonic Non-null english mnemonic -/// \param passphrase Nullable optional passphrase -/// \note Null is returned on invalid mnemonic and passphrase -/// \note passphrase can be null or empty string if no passphrase required -/// \return Nullable TWTONWallet -#[no_mangle] -pub unsafe extern "C" fn tw_ton_wallet_create_with_mnemonic( - mnemonic: *const TWString, - passphrase: *const TWString, -) -> *mut TWTONWallet { - let mnemonic = try_or_else!(TWString::from_ptr_as_ref(mnemonic), std::ptr::null_mut); - let mnemonic = try_or_else!(mnemonic.as_str(), std::ptr::null_mut); - - let passphrase = TWString::from_ptr_as_ref(passphrase) - .and_then(TWString::as_str) - .map(|pass| pass.to_string()); - - let wallet = try_or_else!(TonWallet::new(mnemonic, passphrase), std::ptr::null_mut); - TWTONWallet(wallet).into_ptr() -} - -/// Delete the given TON mnemonic. -/// -/// \param wallet *non-null* pointer to TWTONMnemonic. -#[no_mangle] -pub unsafe extern "C" fn tw_ton_wallet_delete(wallet: *mut TWTONWallet) { - // Take the ownership back to rust and drop the owner. - let _ = TWTONWallet::from_ptr(wallet); -} - -/// Generates Ed25519 private key associated with the wallet. -/// -/// \param wallet non-null TWTONWallet -/// \note Returned object needs to be deleted with \TWPrivateKeyDelete -/// \return The Ed25519 private key -#[no_mangle] -pub unsafe extern "C" fn tw_ton_wallet_get_key(wallet: *const TWTONWallet) -> *mut TWPrivateKey { - let wallet = try_or_else!(TWTONWallet::from_ptr_as_ref(wallet), std::ptr::null_mut); - let key = wallet.0.to_key_pair().private().clone(); - TWPrivateKey(tw::PrivateKey::from(key)).into_ptr() -} - -/// Constructs a TON Wallet V4R2 stateInit encoded as BoC (BagOfCells) for the given `public_key`. -/// -/// \param public_key wallet's public key. -/// \param workchain TON workchain to which the wallet belongs. Usually, base chain is used (0). -/// \param wallet_id wallet's ID allows to create multiple wallets for the same private key. -/// \return Pointer to a base64 encoded Bag Of Cells (BoC) StateInit. Null if invalid public key provided. -#[no_mangle] -pub unsafe extern "C" fn tw_ton_wallet_build_v4_r2_state_init( - public_key: *const TWPublicKey, - workchain: i32, - wallet_id: i32, -) -> *mut TWString { - let public_key = try_or_else!(TWPublicKey::from_ptr_as_ref(public_key), std::ptr::null_mut); - let ed_pubkey = try_or_else!(public_key.as_ref().to_ed25519(), std::ptr::null_mut).clone(); - - let state_init = try_or_else!( - WalletProvider::v4r2_state_init(ed_pubkey, workchain, wallet_id), - std::ptr::null_mut - ); - TWString::from(state_init).into_ptr() -} - -// Constructs a TON Wallet V5R1 stateInit encoded as BoC (BagOfCells) for the given `public_key`. -/// -/// \param public_key wallet's public key. -/// \param workchain TON workchain to which the wallet belongs. Usually, base chain is used (0). -/// \param wallet_id wallet's ID allows to create multiple wallets for the same private key. -/// \return Pointer to a base64 encoded Bag Of Cells (BoC) StateInit. Null if invalid public key provided. -#[no_mangle] -pub unsafe extern "C" fn tw_ton_wallet_build_v5_r1_state_init( - public_key: *const TWPublicKey, - workchain: i32, - wallet_id: i32, -) -> *mut TWString { - let public_key = try_or_else!(TWPublicKey::from_ptr_as_ref(public_key), std::ptr::null_mut); - let ed_pubkey = try_or_else!(public_key.as_ref().to_ed25519(), std::ptr::null_mut).clone(); - - let state_init = try_or_else!( - WalletProvider::v5r1_state_init(ed_pubkey, workchain, wallet_id), - std::ptr::null_mut - ); - TWString::from(state_init).into_ptr() -} diff --git a/src/DerivationPath.cpp b/src/DerivationPath.cpp index c2d369ee413..dd54e28efbc 100644 --- a/src/DerivationPath.cpp +++ b/src/DerivationPath.cpp @@ -46,10 +46,6 @@ DerivationPath::DerivationPath(const std::string& string) { } std::string DerivationPath::string() const noexcept { - if (indices.empty()) { - return {}; - } - std::string result = "m/"; for (auto& index : indices) { result += index.string(); diff --git a/src/Keystore/StoredKey.cpp b/src/Keystore/StoredKey.cpp index 732e0953e37..b216461fe31 100644 --- a/src/Keystore/StoredKey.cpp +++ b/src/Keystore/StoredKey.cpp @@ -8,7 +8,6 @@ #include "HexCoding.h" #include "Mnemonic.h" #include "PrivateKey.h" -#include "TheOpenNetwork/TONWallet.h" #include #include @@ -68,24 +67,6 @@ StoredKey StoredKey::createWithPrivateKeyAddDefaultAddress(const std::string& na return key; } -StoredKey StoredKey::createWithTonMnemonic(const std::string& name, const Data& password, const std::string& tonMnemonic, TWStoredKeyEncryption encryption) { - if (!TheOpenNetwork::TONWallet::isValidMnemonic(tonMnemonic, std::nullopt)) { - throw std::invalid_argument("Invalid TON mnemonic"); - } - - Data mnemonicData = TW::Data(tonMnemonic.begin(), tonMnemonic.end()); - StoredKey key(StoredKeyType::tonMnemonicPhrase, name, password, mnemonicData, TWStoredKeyEncryptionLevelDefault, encryption); - memzero(mnemonicData.data(), mnemonicData.size()); - return key; -} - -StoredKey StoredKey::createWithTonMnemonicAddDefaultAddress(const std::string& name, const Data& password, TWCoinType coin, const std::string& tonMnemonic, TWStoredKeyEncryption encryption) { - StoredKey key = createWithTonMnemonic(name, password, tonMnemonic, encryption); - const auto tonWallet = key.tonWallet(password); - key.account(coin, TWDerivationDefault, tonWallet); - return key; -} - StoredKey::StoredKey(StoredKeyType type, std::string name, const Data& password, const Data& data, TWStoredKeyEncryptionLevel encryptionLevel, TWStoredKeyEncryption encryption) : type(type), id(), name(std::move(name)), accounts() { const auto encryptionParams = EncryptionParameters::getPreset(encryptionLevel, encryption); @@ -105,20 +86,6 @@ const HDWallet<> StoredKey::wallet(const Data& password) const { return HDWallet<>(mnemonic, ""); } -TheOpenNetwork::TONWallet StoredKey::tonWallet(const Data& password) const { - if (type != StoredKeyType::tonMnemonicPhrase) { - throw std::invalid_argument("Invalid account requested."); - } - const auto data = payload.decrypt(password); - const auto tonMnemonic = std::string(reinterpret_cast(data.data()), data.size()); - - auto maybeTonWallet = TheOpenNetwork::TONWallet::createWithMnemonic(tonMnemonic, std::nullopt); - if (!maybeTonWallet.has_value()) { - throw std::invalid_argument("Invalid TON mnemonic phrase."); - } - return std::move(*maybeTonWallet); -} - std::vector StoredKey::getAccounts(TWCoinType coin) const { std::vector result; for (auto& account : accounts) { @@ -176,12 +143,6 @@ std::optional StoredKey::getAccount(TWCoinType coin, TWDerivation deriv return getAccount(coin, address); } -std::optional StoredKey::getAccount(TWCoinType coin, TWDerivation derivation, const TheOpenNetwork::TONWallet& wallet) const { - // obtain address - const auto address = wallet.deriveAddress(coin, derivation); - return getAccount(coin, address); -} - Account StoredKey::fillAddressIfMissing(Account& account, const HDWallet<>* wallet) const { if (account.address.empty() && wallet != nullptr) { account.address = wallet->deriveAddress(account.coin, account.derivation); @@ -240,28 +201,6 @@ Account StoredKey::account(TWCoinType coin, TWDerivation derivation, const HDWal return accounts.back(); } -Account StoredKey::account(TWCoinType coin, TWDerivation derivation, const TheOpenNetwork::TONWallet& tonWallet) { - const auto coinAccount = getAccount(coin, derivation, tonWallet); - if (coinAccount.has_value()) { - // No need to use `fillAddressIfMissing` - // because `getAccount` searches for an account with both `coin` and `address` equal to expected. - // So `address` is always set. - return coinAccount.value(); - } - // Not found, add it. - - // No derivation path for TON wallet. Use default - const DerivationPath derivationPath {}; - const auto address = tonWallet.deriveAddress(coin, derivation); - // No extended public key for TON wallet. Use default - const std::string extendedPublicKey {}; - const auto pubKeyType = TW::publicKeyType(coin); - const auto pubKey = tonWallet.getKey(coin, derivation).getPublicKey(pubKeyType); - - addAccount(address, coin, derivation, derivationPath, hex(pubKey.bytes), extendedPublicKey); - return accounts.back(); -} - std::optional StoredKey::account(TWCoinType coin) const { return getDefaultAccountOrAny(coin, nullptr); } @@ -315,23 +254,14 @@ const PrivateKey StoredKey::privateKey(TWCoinType coin, const Data& password) { return privateKey(coin, TWDerivationDefault, password); } -const PrivateKey StoredKey::privateKey(TWCoinType coin, TWDerivation derivation, const Data& password) { - switch (type) { - case StoredKeyType::mnemonicPhrase: { - const auto wallet = this->wallet(password); - const Account account = this->account(coin, derivation, wallet); - return wallet.getKey(coin, account.derivationPath); - } - case StoredKeyType::privateKey: { - return PrivateKey(payload.decrypt(password)); - } - case StoredKeyType::tonMnemonicPhrase: { - const auto tonWallet = this->tonWallet(password); - return tonWallet.getKey(coin, derivation); - } - default: - throw std::invalid_argument("Unexpected StoredKey type"); +const PrivateKey StoredKey::privateKey(TWCoinType coin, [[maybe_unused]] TWDerivation derivation, const Data& password) { + if (type == StoredKeyType::mnemonicPhrase) { + const auto wallet = this->wallet(password); + const Account& account = this->account(coin, derivation, wallet); + return wallet.getKey(coin, account.derivationPath); } + // type == StoredKeyType::privateKey + return PrivateKey(payload.decrypt(password)); } void StoredKey::fixAddresses(const Data& password) { @@ -359,21 +289,6 @@ void StoredKey::fixAddresses(const Data& password) { updateAddressForAccount(key, account); } } break; - - case StoredKeyType::tonMnemonicPhrase: { - const auto tonWallet = this->tonWallet(password); - for (auto& account : accounts) { - if (!account.address.empty() && !account.publicKey.empty() && - TW::validateAddress(account.coin, account.address)) { - continue; - } - const auto key = tonWallet.getKey(account.coin, account.derivation); - updateAddressForAccount(key, account); - } - } break; - - default: - throw std::invalid_argument("Unexpected StoredKey type"); } } @@ -425,18 +340,12 @@ static const auto crypto = "Crypto"; namespace TypeString { static const auto privateKey = "private-key"; static const auto mnemonic = "mnemonic"; -static const auto tonMnemonic = "ton-mnemonic"; } // namespace TypeString void StoredKey::loadJson(const nlohmann::json& json) { - const auto isSKType = [](const nlohmann::json& json, const std::string& expected) -> bool { - return json.count(CodingKeys::SK::type) != 0 && json[CodingKeys::SK::type].get() == expected; - }; - - if (isSKType(json, TypeString::mnemonic)) { + if (json.count(CodingKeys::SK::type) != 0 && + json[CodingKeys::SK::type].get() == TypeString::mnemonic) { type = StoredKeyType::mnemonicPhrase; - } else if (isSKType(json, TypeString::tonMnemonic)) { - type = StoredKeyType::tonMnemonicPhrase; } else { type = StoredKeyType::privateKey; } @@ -487,9 +396,6 @@ nlohmann::json StoredKey::json() const { case StoredKeyType::mnemonicPhrase: j[CodingKeys::SK::type] = TypeString::mnemonic; break; - case StoredKeyType::tonMnemonicPhrase: - j[CodingKeys::SK::type] = TypeString::tonMnemonic; - break; } if (id) { diff --git a/src/Keystore/StoredKey.h b/src/Keystore/StoredKey.h index a98aace31df..12eaf5038f4 100644 --- a/src/Keystore/StoredKey.h +++ b/src/Keystore/StoredKey.h @@ -7,8 +7,7 @@ #include "Account.h" #include "EncryptionParameters.h" #include "Data.h" -#include "HDWallet.h" -#include "TheOpenNetwork/TONWallet.h" +#include "../HDWallet.h" #include #include @@ -21,13 +20,9 @@ namespace TW::Keystore { -/// An stored key can be either a private key, or a mnemonic phrase for a HD -/// wallet, or a TON-specific mnemonic phrase. -enum class StoredKeyType { - privateKey, - mnemonicPhrase, - tonMnemonicPhrase -}; +/// An stored key can be either a private key or a mnemonic phrase for a HD +/// wallet. +enum class StoredKeyType { privateKey, mnemonicPhrase }; /// Represents a key stored as an encrypted file. class StoredKey { @@ -67,16 +62,6 @@ class StoredKey { /// @throws std::invalid_argument if privateKeyData is not a valid private key static StoredKey createWithPrivateKeyAddDefaultAddress(const std::string& name, const Data& password, TWCoinType coin, const Data& privateKeyData, TWStoredKeyEncryption encryption = TWStoredKeyEncryptionAes128Ctr); - /// Create a new StoredKey, with the given name and TON specific mnemonic. - /// @throws std::invalid_argument if menmonic is invalid - /// @note mnemonic created with a passphrase is not supported yet - static StoredKey createWithTonMnemonic(const std::string& name, const Data& password, const std::string& tonMnemonic, TWStoredKeyEncryption encryption = TWStoredKeyEncryptionAes128Ctr); - - /// Create a new StoredKey, with the given name and TON specific mnemonic, and also add the default address for the given coin. - /// @throws std::invalid_argument if menmonic is invalid - /// @note mnemonic created with a passphrase is not supported yet - static StoredKey createWithTonMnemonicAddDefaultAddress(const std::string& name, const Data& password, TWCoinType coin, const std::string& tonMnemonic, TWStoredKeyEncryption encryption = TWStoredKeyEncryptionAes128Ctr); - /// Create a StoredKey from a JSON object. static StoredKey createWithJson(const nlohmann::json& json); @@ -85,31 +70,19 @@ class StoredKey { /// @throws std::invalid_argument if this key is of a type other than `mnemonicPhrase`. const HDWallet<> wallet(const Data& password) const; - /// Returns the TONWallet for this key. - /// - /// @throws std::invalid_argument if this key is of a type other than `tonMnemonicPhrase`. - TheOpenNetwork::TONWallet tonWallet(const Data& password) const; - /// Returns all the accounts for a specific coin: 0, 1, or more. std::vector getAccounts(TWCoinType coin) const; - /// If found, returns the account for a specific coin. - /// In case of multiple accounts, the default derivation is returned, or the first one is returned. + /// If found, returns the account for a specific coin. In case of muliple accounts, the default derivation is returned, or the first one is returned. /// If none exists, and wallet is not null, an account is created (with default derivation). std::optional account(TWCoinType coin, const HDWallet<>* wallet); - /// If found, returns the account for a specific coin and derivation. - /// In case of multiple accounts, the first one is returned. + /// If found, returns the account for a specific coin and derivation. In case of muliple accounts, the first one is returned. /// If none exists, an account is created. Account account(TWCoinType coin, TWDerivation derivation, const HDWallet<>& wallet); - /// If found, returns the account for a specific coin. - /// In case of multiple accounts, the first one is returned. - /// If none exists, an account is created. - Account account(TWCoinType coin, TWDerivation derivation, const TheOpenNetwork::TONWallet& tonWallet); - /// Returns the account for a specific coin if it exists. - /// In case of multiple accounts, the default derivation is returned, or the first one is returned. + /// In case of muliple accounts, the default derivation is returned, or the first one is returned. std::optional account(TWCoinType coin) const; /// Returns the account for a specific coin and derivation, if it exists. @@ -200,9 +173,6 @@ class StoredKey { /// Find account by coin+derivation (should be one, if multiple, first is returned) std::optional getAccount(TWCoinType coin, TWDerivation derivation, const HDWallet<>& wallet) const; - /// Find account by coin+derivation (should be one, if multiple, first is returned) - std::optional getAccount(TWCoinType coin, TWDerivation derivation, const TheOpenNetwork::TONWallet& wallet) const; - /// Re-derive account address if missing Account fillAddressIfMissing(Account& account, const HDWallet<>* wallet) const; diff --git a/src/TheOpenNetwork/TONWallet.cpp b/src/TheOpenNetwork/TONWallet.cpp deleted file mode 100644 index a4b4adc6c28..00000000000 --- a/src/TheOpenNetwork/TONWallet.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// -// Copyright © 2017 Trust Wallet. - -#include "TONWallet.h" -#include "Coin.h" - -namespace TW::TheOpenNetwork { - -bool TONWallet::isValidMnemonic(const std::string& mnemonic, const MaybePassphrase& passphrase) { - const Rust::TWStringWrapper mnemonicRust = mnemonic; - - if (passphrase.has_value()) { - const Rust::TWStringWrapper passphraseRust = passphrase.value(); - return Rust::tw_ton_wallet_is_valid_mnemonic(mnemonicRust.get(), passphraseRust.get()); - } else { - return Rust::tw_ton_wallet_is_valid_mnemonic(mnemonicRust.get(), nullptr); - } -} - -MaybeTONWallet TONWallet::createWithMnemonic(const std::string& mnemonic, const MaybePassphrase& passphrase) { - const Rust::TWStringWrapper mnemonicRust = mnemonic; - - Rust::TWTONWallet* walletPtr; - if (passphrase.has_value()) { - const Rust::TWStringWrapper passphraseRust = passphrase.value(); - walletPtr = Rust::tw_ton_wallet_create_with_mnemonic(mnemonicRust.get(), passphraseRust.get()); - } else { - walletPtr = Rust::tw_ton_wallet_create_with_mnemonic(mnemonicRust.get(), nullptr); - } - - if (!walletPtr) { - return std::nullopt; - } - - return TONWallet(TONWalletPtr(walletPtr, Rust::tw_ton_wallet_delete)); -} - -PrivateKey TONWallet::getKey(TWCoinType coin, TWDerivation derivation) const { - if (coin != TWCoinTypeTON || derivation != TWDerivationDefault) { - throw std::invalid_argument("'TONWallet' supports TON coin and Default derivation only"); - } - - const auto privateKeyRust = wrapTWPrivateKey(Rust::tw_ton_wallet_get_key(impl.get())); - const Rust::TWDataWrapper privateKeyBytes = Rust::tw_private_key_data(privateKeyRust.get()); - return PrivateKey(privateKeyBytes.toDataOrDefault()); -} - -std::string TONWallet::deriveAddress(TWCoinType coin, TWDerivation derivation) const { - const auto key = getKey(coin, derivation); - return TW::deriveAddress(coin, key, derivation); -} - -} // namespace TW::TheOpenNetwork diff --git a/src/TheOpenNetwork/TONWallet.h b/src/TheOpenNetwork/TONWallet.h deleted file mode 100644 index b6d80e1f0e2..00000000000 --- a/src/TheOpenNetwork/TONWallet.h +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// -// Copyright © 2017 Trust Wallet. - -#pragma once - -#include "PrivateKey.h" -#include "rust/Wrapper.h" - -#include "TrustWalletCore/TWCoinType.h" -#include "TrustWalletCore/TWDerivation.h" - -namespace TW::TheOpenNetwork { - -class TONWallet; - -using TONWalletPtr = std::shared_ptr; -using MaybePassphrase = std::optional; -using MaybeTONWallet = std::optional; - -class TONWallet { -public: - static bool isValidMnemonic(const std::string& mnemonic, const MaybePassphrase& passphrase); - - static MaybeTONWallet createWithMnemonic(const std::string& mnemonic, const MaybePassphrase& passphrase); - - /// Returns the private key with the given coin and derivation. - /// \throws std exception if `coin` or `derivation` aren't `TWCoinTypeTON` and `TWDerivationDefault` correspondingly. - PrivateKey getKey(TWCoinType coin = TWCoinTypeTON, TWDerivation derivation = TWDerivationDefault) const; - - /// Derives the address for the given coin and derivation. - /// \throws std exception if `coin` or `derivation` aren't `TWCoinTypeTON` and `TWDerivationDefault` correspondingly. - std::string deriveAddress(TWCoinType coin = TWCoinTypeTON, TWDerivation derivation = TWDerivationDefault) const; - -private: - explicit TONWallet(TONWalletPtr ptr): impl(std::move(ptr)) { - } - - TONWalletPtr impl; -}; - -} // namespace TW::TheOpenNetwork - -/// Wrapper for C interface. -struct TWTONWallet { - TW::TheOpenNetwork::TONWallet impl; -}; diff --git a/src/interface/TWStoredKey.cpp b/src/interface/TWStoredKey.cpp index 90c78c94e13..f756ce5e6b3 100644 --- a/src/interface/TWStoredKey.cpp +++ b/src/interface/TWStoredKey.cpp @@ -72,21 +72,6 @@ struct TWStoredKey* _Nullable TWStoredKeyImportHDWalletWithEncryption(TWString* } } -struct TWStoredKey* _Nullable TWStoredKeyImportTONWallet(TWString* _Nonnull tonMnemonic, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin) { - return TWStoredKeyImportTONWalletWithEncryption(tonMnemonic, name, password, coin, TWStoredKeyEncryptionAes128Ctr); -} - -struct TWStoredKey* _Nullable TWStoredKeyImportTONWalletWithEncryption(TWString* _Nonnull tonMnemonic, TWString* _Nonnull name, TWData* _Nonnull password, enum TWCoinType coin, enum TWStoredKeyEncryption encryption) { - try { - const auto& tonMnemonicString = *reinterpret_cast(tonMnemonic); - const auto& nameString = *reinterpret_cast(name); - const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password)); - return new TWStoredKey{ KeyStore::StoredKey::createWithTonMnemonicAddDefaultAddress(nameString, passwordData, coin, tonMnemonicString, encryption) }; - } catch (...) { - return nullptr; - } -} - struct TWStoredKey* _Nullable TWStoredKeyImportJSON(TWData* _Nonnull json) { try { const auto& d = *reinterpret_cast(json); @@ -116,10 +101,6 @@ bool TWStoredKeyIsMnemonic(struct TWStoredKey* _Nonnull key) { return key->impl.type == KeyStore::StoredKeyType::mnemonicPhrase; } -bool TWStoredKeyIsTONMnemonic(struct TWStoredKey* _Nonnull key) { - return key->impl.type == KeyStore::StoredKeyType::tonMnemonicPhrase; -} - size_t TWStoredKeyAccountCount(struct TWStoredKey* _Nonnull key) { return key->impl.accounts.size(); } @@ -210,13 +191,6 @@ TWString* _Nullable TWStoredKeyDecryptMnemonic(struct TWStoredKey* _Nonnull key, } } -TWString* _Nullable TWStoredKeyDecryptTONMnemonic(struct TWStoredKey* _Nonnull key, TWData* _Nonnull password) { - if (!TWStoredKeyIsTONMnemonic(key)) { - return nullptr; - } - return TWStoredKeyDecryptMnemonic(key, password); -} - struct TWPrivateKey* _Nullable TWStoredKeyPrivateKey(struct TWStoredKey* _Nonnull key, enum TWCoinType coin, TWData* _Nonnull password) { try { const auto passwordData = TW::data(TWDataBytes(password), TWDataSize(password)); diff --git a/src/interface/TWTONWallet.cpp b/src/interface/TWTONWallet.cpp index 137a672f2c1..7e6495491ab 100644 --- a/src/interface/TWTONWallet.cpp +++ b/src/interface/TWTONWallet.cpp @@ -3,46 +3,11 @@ // Copyright © 2017 Trust Wallet. #include "TrustWalletCore/TWTONWallet.h" -#include "TheOpenNetwork/TONWallet.h" #include "rust/Wrapper.h" #include "PublicKey.h" using namespace TW; -bool TWTONWalletIsValidMnemonic(TWString* _Nonnull mnemonic, TWString* _Nullable passphrase) { - const auto& mnemonicRef = *reinterpret_cast(mnemonic); - std::string passphraseObj; - if (passphrase) { - passphraseObj = std::string(TWStringUTF8Bytes(passphrase), TWStringSize(passphrase)); - } - - return TheOpenNetwork::TONWallet::isValidMnemonic(mnemonicRef, passphraseObj); -} - -struct TWTONWallet* _Nullable TWTONWalletCreateWithMnemonic(TWString* _Nonnull mnemonic, TWString* _Nullable passphrase) { - const auto& mnemonicRef = *reinterpret_cast(mnemonic); - std::string passphraseObj; - if (passphrase) { - passphraseObj = std::string(TWStringUTF8Bytes(passphrase), TWStringSize(passphrase)); - } - - const auto maybeWallet = TheOpenNetwork::TONWallet::createWithMnemonic(mnemonicRef, passphraseObj); - if (!maybeWallet.has_value()) { - return nullptr; - } - - return new TWTONWallet { .impl = *maybeWallet }; -} - -void TWTONWalletDelete(struct TWTONWallet* _Nonnull wallet) { - delete wallet; -} - -struct TWPrivateKey* _Nonnull TWTONWalletGetKey(struct TWTONWallet* _Nonnull wallet) { - const auto privateKey = wallet->impl.getKey(); - return new TWPrivateKey { .impl = privateKey }; -} - TWString *_Nullable TWTONWalletBuildV4R2StateInit(struct TWPublicKey *_Nonnull publicKey, int32_t workchain, int32_t walletId) { auto keyType = static_cast(TWPublicKeyKeyType(publicKey)); auto* publicKeyRustRaw = Rust::tw_public_key_create_with_data(publicKey->impl.bytes.data(), publicKey->impl.bytes.size(), keyType); diff --git a/src/rust/Wrapper.h b/src/rust/Wrapper.h index 1ac64605951..04d97a9104c 100644 --- a/src/rust/Wrapper.h +++ b/src/rust/Wrapper.h @@ -13,15 +13,11 @@ namespace TW::Rust { inline std::shared_ptr wrapTWAnyAddress(TWAnyAddress* anyAddress) { - return { anyAddress, tw_any_address_delete }; -} - -inline std::shared_ptr wrapTWPrivateKey(TWPrivateKey* privateKey) { - return { privateKey, tw_private_key_delete }; + return std::shared_ptr(anyAddress, tw_any_address_delete); } inline std::shared_ptr wrapTWPublicKey(TWPublicKey* publicKey) { - return { publicKey, tw_public_key_delete }; + return std::shared_ptr(publicKey, tw_public_key_delete); } struct TWDataVectorWrapper { diff --git a/swift/Sources/KeyStore.swift b/swift/Sources/KeyStore.swift index e1a6b7bfa8f..0b6c3368d77 100644 --- a/swift/Sources/KeyStore.swift +++ b/swift/Sources/KeyStore.swift @@ -6,12 +6,6 @@ import Foundation -private enum StoredKeyType { - case privateKey(PrivateKey) - case mnemonic(String) - case tonMnemonic(String) -} - /// Manages directories of key and wallet files and presents them as accounts. public final class KeyStore { static let watchesFileName = "watches.json" @@ -136,49 +130,25 @@ public final class KeyStore { guard let key = StoredKey.importJSON(json: json) else { throw Error.invalidJSON } - - switch try decryptSecret(key: key, password: Data(password.utf8)) { - case .privateKey(let privateKey): - return try self.import(privateKey: privateKey, name: name, password: newPassword, coin: coins.first ?? .ethereum) - case .mnemonic(let mnemonic): - return try self.import(mnemonic: mnemonic, name: name, encryptPassword: newPassword, coins: coins) - case .tonMnemonic(let tonMnemonic): - return try self.importTON(tonMnemonic: tonMnemonic, name: name, encryptPassword: newPassword, coin: coins.first ?? .ton) - } - } - - /// Decrypts an inner secret as a `privateKey`, `mnemonic` or another type. - /// - Returns: a `StoredKeyType` enum. - /// - Note: `StoredKey::type` is not always set, and mnemonic or private key can be stored encrypted without any tag. - private func decryptSecret(key: StoredKey, password: Data) throws -> StoredKeyType { - guard var secretData = key.decryptPrivateKey(password: password) else { + guard let data = key.decryptPrivateKey(password: Data(password.utf8)) else { throw Error.invalidPassword } - defer { - secretData.resetBytes(in: 0 ..< secretData.count) - } - // First, check whether the key is init with a TON mnemonic. - // That's because TON Wallet is a new feature, and `StoredKey::type` is always set for these kind of keys. - if key.isTONMnemonic { - guard let tonMnemonic = String(data: secretData, encoding: .ascii), TONWallet.isValidMnemonic(mnemonic: tonMnemonic, passphrase: nil) else { - throw Error.invalidMnemonic - } - return StoredKeyType.tonMnemonic(tonMnemonic) + if let mnemonic = checkMnemonic(data) { + return try self.import(mnemonic: mnemonic, name: name, encryptPassword: newPassword, coins: coins) } - // The next, we should try to convert the secret into a string and check whether it's a valid BIP39 mnemonic phrase. - if let mnemonic = String(data: secretData, encoding: .ascii), Mnemonic.isValid(mnemonic: mnemonic) { - return StoredKeyType.mnemonic(mnemonic) + guard let privateKey = PrivateKey(data: data) else { + throw Error.invalidKey } + return try self.import(privateKey: privateKey, name: name, password: newPassword, coin: coins.first ?? .ethereum) + } - // Otherwise, we consider the secret as a private key. - - if let privateKey = PrivateKey(data: secretData) { - return StoredKeyType.privateKey(privateKey) + private func checkMnemonic(_ data: Data) -> String? { + guard let mnemonic = String(data: data, encoding: .ascii), Mnemonic.isValid(mnemonic: mnemonic) else { + return nil } - - throw Error.invalidKey + return mnemonic } /// Imports a private key. @@ -223,31 +193,6 @@ public final class KeyStore { return wallet } - - /// Imports a TON wallet. - /// - /// - Parameters: - /// - tonMnemonic: TON wallet's mnemonic phrase - /// - encryptPassword: password to use for encrypting - /// - coin: coins to use for this wallet - /// - Returns: new account - public func `importTON`(tonMnemonic: String, name: String, encryptPassword: String, coin: CoinType, encryption: StoredKeyEncryption = .aes128Ctr) throws -> Wallet { - guard let newKey = StoredKey.importTONWalletWithEncryption(tonMnemonic: tonMnemonic, name: name, password: Data(encryptPassword.utf8), coin: coin, encryption: encryption) else { - throw Error.invalidKey - } - - let url = makeAccountURL() - let wallet = Wallet(keyURL: url, key: newKey) - // `StoredKey.importTONWalletWithEncryption` should create exactly one account only. - if wallet.accounts.count != 1 { - throw Error.invalidKey - } - wallets.append(wallet) - - try save(wallet: wallet) - - return wallet - } /// Exports a wallet as JSON data. /// @@ -257,29 +202,28 @@ public final class KeyStore { /// - newPassword: password to use for exported key /// - Returns: encrypted JSON key public func export(wallet: Wallet, password: String, newPassword: String, encryption: StoredKeyEncryption = .aes128Ctr) throws -> Data { - // TODO why `importHDWalletWithEncryption` is called with a single coin? - // I guess that's because we don't want other wallets to know all user accounts. + var privateKeyData = try exportPrivateKey(wallet: wallet, password: password) + defer { + privateKeyData.resetBytes(in: 0 ..< privateKeyData.count) + } + guard let coin = wallet.key.account(index: 0)?.coin else { throw Error.accountNotFound } - let secretType = try decryptSecret(key: wallet.key, password: Data(password.utf8)) - - let maybeNewKey: StoredKey? = switch secretType { - case .privateKey(let privateKey): - StoredKey.importPrivateKeyWithEncryption(privateKey: privateKey.data, name: "", password: Data(newPassword.utf8), coin: coin, encryption: encryption) - - case .mnemonic(let mnemonic): - StoredKey.importHDWalletWithEncryption(mnemonic: mnemonic, name: "", password: Data(newPassword.utf8), coin: coin, encryption: encryption) - - case .tonMnemonic(let tonMnemonic): - StoredKey.importTONWalletWithEncryption(tonMnemonic: tonMnemonic, name: "", password: Data(newPassword.utf8), coin: coin, encryption: encryption) + if let mnemonic = checkMnemonic(privateKeyData), let newKey = StoredKey.importHDWalletWithEncryption(mnemonic: mnemonic, name: "", password: Data(newPassword.utf8), coin: coin, encryption: encryption) { + guard let json = newKey.exportJSON() else { + throw Error.invalidKey + } + return json + } else if let newKey = StoredKey.importPrivateKeyWithEncryption(privateKey: privateKeyData, name: "", password: Data(newPassword.utf8), coin: coin, encryption: encryption) { + guard let json = newKey.exportJSON() else { + throw Error.invalidKey + } + return json } - guard let newKey = maybeNewKey, let json = newKey.exportJSON() else { - throw Error.invalidKey - } - return json + throw Error.invalidKey } /// Exports a wallet as private key data. @@ -288,7 +232,6 @@ public final class KeyStore { /// - wallet: wallet to export /// - password: account password /// - Returns: private key data for encrypted keys or mnemonic phrase for HD wallets - /// - Throws: `EncryptError.invalidPassword` if the password is incorrect. public func exportPrivateKey(wallet: Wallet, password: String) throws -> Data { guard let key = wallet.key.decryptPrivateKey(password: Data(password.utf8)) else { throw Error.invalidPassword @@ -302,27 +245,13 @@ public final class KeyStore { /// - wallet: wallet to export /// - password: account password /// - Returns: mnemonic phrase - /// - Throws: `EncryptError.invalidPassword` if the password is incorrect. + /// - Throws: `EncryptError.invalidMnemonic` if the account is not an HD wallet. public func exportMnemonic(wallet: Wallet, password: String) throws -> String { guard let mnemonic = wallet.key.decryptMnemonic(password: Data(password.utf8)) else { throw Error.invalidPassword } return mnemonic } - - /// Exports a wallet as a TON mnemonic phrase. - /// - /// - Parameters: - /// - wallet: wallet to export - /// - password: account password - /// - Returns: TON mnemonic phrase - /// - Throws: `EncryptError.invalidPassword` if the password is incorrect. - public func exportTONMnemonic(wallet: Wallet, password: String) throws -> String { - guard let tonMnemonic = wallet.key.decryptTONMnemonic(password: Data(password.utf8)) else { - throw Error.invalidPassword - } - return tonMnemonic - } /// Updates the password of an existing account. /// @@ -349,30 +278,28 @@ public final class KeyStore { fatalError("Missing wallet") } + guard var privateKeyData = wallet.key.decryptPrivateKey(password: Data(password.utf8)) else { + throw Error.invalidPassword + } + defer { + privateKeyData.resetBytes(in: 0 ..< privateKeyData.count) + } + let coins = wallet.accounts.map({ $0.coin }) guard !coins.isEmpty else { throw Error.accountNotFound } - let secretType = try decryptSecret(key: wallet.key, password: Data(password.utf8)) - - let maybeNewKey: StoredKey? = switch secretType { - case .privateKey(let privateKey): - StoredKey.importPrivateKeyWithEncryption( - privateKey: privateKey.data, name: newName, password: Data(newPassword.utf8), coin: coins[0], encryption: encryption) - - case .mnemonic(let mnemonic): - StoredKey.importHDWalletWithEncryption(mnemonic: mnemonic, name: newName, password: Data(newPassword.utf8), coin: coins[0], encryption: encryption) - - case .tonMnemonic(let tonMnemonic): - StoredKey.importTONWalletWithEncryption(tonMnemonic: tonMnemonic, name: newName, password: Data(newPassword.utf8), coin: coins[0], encryption: encryption) - } - - guard let newKey = maybeNewKey else { + if let mnemonic = checkMnemonic(privateKeyData), + let key = StoredKey.importHDWalletWithEncryption(mnemonic: mnemonic, name: newName, password: Data(newPassword.utf8), coin: coins[0], encryption: encryption) { + wallets[index].key = key + } else if let key = StoredKey.importPrivateKeyWithEncryption( + privateKey: privateKeyData, name: newName, password: Data(newPassword.utf8), coin: coins[0], encryption: encryption) { + wallets[index].key = key + } else { throw Error.invalidKey } - wallets[index].key = newKey _ = try wallets[index].getAccounts(password: newPassword, coins: coins) try save(wallet: wallets[index]) } diff --git a/swift/Sources/Wallet.swift b/swift/Sources/Wallet.swift index 0dc2ec1c6d3..04749b5d564 100644 --- a/swift/Sources/Wallet.swift +++ b/swift/Sources/Wallet.swift @@ -59,7 +59,7 @@ public final class Wallet: Hashable, Equatable { return account } - /// Returns the accounts for specific coins. + /// Returns the accounts for a specific coins. /// /// - Parameters: /// - password: wallet encryption password @@ -67,10 +67,6 @@ public final class Wallet: Hashable, Equatable { /// - Returns: the added accounts /// - Throws: `KeyStore.Error.invalidPassword` if the password is incorrect. public func getAccounts(password: String, coins: [CoinType]) throws -> [Account] { - if !key.isMnemonic { - return coins.compactMap({ key.accountForCoin(coin: $0, wallet: nil) }) - } - guard let wallet = key.wallet(password: Data(password.utf8)) else { throw KeyStore.Error.invalidPassword } diff --git a/swift/Tests/Keystore/Data/ton_wallet.json b/swift/Tests/Keystore/Data/ton_wallet.json deleted file mode 100644 index 3b744a4b01e..00000000000 --- a/swift/Tests/Keystore/Data/ton_wallet.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "activeAccounts": [ - { - "address": "UQBlm676c6vy6Q9Js732pvf3ivfmIkVc0MVDQy-F6NAFJd4k", - "coin": 607, - "derivationPath": "", - "publicKey": "9016f03f9cfa4e183707761f25407e0e1975194a33a56b3e8d2c26f2438fa3d1" - } - ], - "crypto": { - "cipher": "aes-128-ctr", - "cipherparams": { - "iv": "459bbf197fe8e1cdfb949fc516257238" - }, - "ciphertext": "efbda7237b41d2340a4b4c7f0ab6a103e31f7a2b8148137abc815a0d346c3ae851d842ad068ad0218ef9f81647f41e52f7b056d568a314433a0b7980601f96e8974a071b5ddedd50079eebdb9281a8d84a0b9d4649ef3125f6605e303a78c0a4ed67556e3cd4e88b78b120267544eb44a912c92516562acb9782e0ea989cb50bce5948e2dfa26107053caf838af096ce47357061a2b49654", - "kdf": "scrypt", - "kdfparams": { - "dklen": 32, - "n": 16384, - "p": 4, - "r": 8, - "salt": "" - }, - "mac": "be9e9a26076334683799c2dbe22bfb2d9f2ff92ad130aa61b4687b392e7b98e6" - }, - "id": "f7a2172e-fb7a-427a-8526-99779fc47c0a", - "name": "name", - "type": "ton-mnemonic", - "version": 3 -} diff --git a/swift/Tests/Keystore/KeyStoreTests.swift b/swift/Tests/Keystore/KeyStoreTests.swift index 4ce0748dd3d..99b2815b825 100755 --- a/swift/Tests/Keystore/KeyStoreTests.swift +++ b/swift/Tests/Keystore/KeyStoreTests.swift @@ -25,17 +25,12 @@ extension KeyStore { var bnbWallet: Wallet { return wallets.first(where: { $0.identifier == "bnb_wallet.json"})! } - - var tonWallet: Wallet? { - return wallets.first(where: { $0.identifier == "ton_wallet.json"}) - } } class KeyStoreTests: XCTestCase { let keyAddress = AnyAddress(string: "0x008AeEda4D805471dF9b2A5B0f38A0C3bCBA786b", coin: .ethereum)! let walletAddress = AnyAddress(string: "0x32dd55E0BCF509a35A3F5eEb8593fbEb244796b1", coin: .ethereum)! let mnemonic = "often tobacco bread scare imitate song kind common bar forest yard wisdom" - let tonMnemonic = "laundry myself fitness beyond prize piano match acid vacuum already abandon dance occur pause grocery company inject excuse weasel carpet fog grunt trick spike" let fileManager = FileManager.default var keyDirectory: URL! @@ -78,17 +73,11 @@ class KeyStoreTests: XCTestCase { try? fileManager.removeItem(at: bnbWalletDestination) try? fileManager.copyItem(at: bnbWalletURL, to: bnbWalletDestination) - - let tonWalletURL = Bundle(for: type(of: self)).url(forResource: "ton_wallet", withExtension: "json")! - let tonWalletDestination = keyDirectory.appendingPathComponent("ton_wallet.json") - - try? fileManager.removeItem(at: tonWalletDestination) - try? fileManager.copyItem(at: tonWalletURL, to: tonWalletDestination) } func testLoadKeyStore() { let keyStore = try! KeyStore(keyDirectory: keyDirectory) - XCTAssertEqual(keyStore.wallets.count, 5) + XCTAssertEqual(keyStore.wallets.count, 4) XCTAssertEqual(keyStore.watches.count, 1) } @@ -98,13 +87,13 @@ class KeyStoreTests: XCTestCase { let newWallet = try keyStore.createWallet(name: "name", password: "password", coins: coins) XCTAssertEqual(newWallet.accounts.count, 3) - XCTAssertEqual(keyStore.wallets.count, 6) + XCTAssertEqual(keyStore.wallets.count, 5) XCTAssertNoThrow(try newWallet.getAccount(password: "password", coin: .ethereum)) XCTAssertNoThrow(try newWallet.getAccount(password: "password", coin: .binance)) XCTAssertNoThrow(try newWallet.getAccount(password: "password", coin: .smartChain)) } - func testUpdatePassword() throws { + func testUpdateKey() throws { let keyStore = try KeyStore(keyDirectory: keyDirectory) let coins = [CoinType.ethereum, .callisto, .poanetwork] let wallet = try keyStore.createWallet(name: "name", password: "password", coins: coins) @@ -124,21 +113,6 @@ class KeyStoreTests: XCTestCase { XCTAssertEqual(savedWallet.key.name, "name") } - func testUpdatePasswordTON() throws { - let keyStore = try KeyStore(keyDirectory: keyDirectory) - - try keyStore.update(wallet: keyStore.tonWallet!, password: "password", newPassword: "testpassword") - - let savedKeyStore = try KeyStore(keyDirectory: keyDirectory) - let savedWallet = savedKeyStore.tonWallet! - - let tonMnemonic = savedWallet.key.decryptTONMnemonic(password: Data("testpassword".utf8))! - - XCTAssertEqual(savedWallet.accounts.count, 1) - XCTAssert(TONWallet.isValidMnemonic(mnemonic: tonMnemonic, passphrase: nil)) - XCTAssertEqual(savedWallet.key.name, "name") - } - func testUpdateName() throws { let keyStore = try KeyStore(keyDirectory: keyDirectory) let coins = [CoinType.ethereum, .callisto, .poanetwork] @@ -181,17 +155,6 @@ class KeyStoreTests: XCTestCase { XCTAssertEqual(savedWallet.accounts.count, 1) XCTAssertEqual(savedWallet.accounts[0].coin, coins.last) } - - func testRemoveTONAccounts() throws { - let keyStore = try KeyStore(keyDirectory: keyDirectory) - - _ = try keyStore.removeAccounts(wallet: keyStore.tonWallet!, coins: [.ton], password: "password") - - let savedKeyStore = try KeyStore(keyDirectory: keyDirectory) - let savedWallet = savedKeyStore.tonWallet! - // The only account should have been removed. - XCTAssertEqual(savedWallet.accounts.count, 0) - } func testDeleteKey() throws { let keyStore = try KeyStore(keyDirectory: keyDirectory) @@ -206,13 +169,6 @@ class KeyStoreTests: XCTestCase { try keyStore.delete(wallet: wallet, password: "password") XCTAssertNil(keyStore.hdWallet) } - - func testDeleteTONWallet() throws { - let keyStore = try KeyStore(keyDirectory: keyDirectory) - let wallet = keyStore.tonWallet! - try keyStore.delete(wallet: wallet, password: "password") - XCTAssertNil(keyStore.tonWallet) - } func testImportKey() throws { let keyStore = try KeyStore(keyDirectory: keyDirectory) @@ -276,60 +232,7 @@ class KeyStoreTests: XCTestCase { XCTAssertEqual(wallet.accounts.count, 1) XCTAssertNotNil(keyStore.hdWallet) } - - func testImportTONWallet() throws { - let keyStore = try KeyStore(keyDirectory: keyDirectory) - let wallet = try keyStore.importTON(tonMnemonic: tonMnemonic, name: "name", encryptPassword: "newPassword", coin: .ton, encryption: .aes128Ctr) - let storedData = wallet.key.decryptMnemonic(password: Data("newPassword".utf8)) - XCTAssertNotNil(storedData) - XCTAssertEqual(wallet.accounts.count, 1) - } - - func testImportTONWalletJSON() throws { - let json = """ - { - "activeAccounts": [ - { - "address": "UQByxuJBNpeC4QjGdgnfeO8oM4G9srUG1FyIGmqX3YnVQ4p1", - "coin": 607, - "derivationPath": "", - "publicKey": "3bab20a5f77e277e39443fc16c64e0479b4a9db542bf9e11c638598384c853f1" - } - ], - "crypto": { - "cipher": "aes-128-ctr", - "cipherparams": { - "iv": "d7fdc3fa7a09e1163094d14a557ed1b6" - }, - "ciphertext": "58017dfbee52c6f22fa1eed323cda21e3413de8da48083e09be9a826bc4f9c184f14e7a47ffcc5f539dc94435d1742dfdc0785e612d039c4858777da9dcd92960580cb9c755434832d94f88b8f562a23ad16f7b6165bbd709a701b3ec46efbe5f6aa858000ce19641abcb7d20475fa1e9cfed5f2f5dae7c76d6496d54bd6db593050617c85c0f6bc3cf8fac89b671d53924202037e1c0e1ecd521492e5", - "kdf": "scrypt", - "kdfparams": { - "dklen": 32, - "n": 16384, - "p": 4, - "r": 8, - "salt": "" - }, - "mac": "ddc49eecdec579021cd18526982ec9519a82f8c39ff20aa7d9aa7f02d5ebd36e" - }, - "id": "e11e5404-73d5-416c-b957-a65164fb0171", - "name": "name", - "type": "ton-mnemonic", - "version": 3 - } - """ - - let password = "password" - let keyStore = try KeyStore(keyDirectory: keyDirectory) - - let wallet = try keyStore.import(json: Data(json.utf8), name: "newName", password: "password", newPassword: "newPassword", coins: [.ton]) - XCTAssertEqual(wallet.accounts.first!.address, "UQByxuJBNpeC4QjGdgnfeO8oM4G9srUG1FyIGmqX3YnVQ4p1") - let actualMnemonic = try keyStore.exportTONMnemonic(wallet: wallet, password: "newPassword") - let expectedMnemonic = "slogan train glide measure mercy dizzy when satoshi vote change length pluck token walnut actress hollow guard soup solve rival summer vicious anxiety device" - XCTAssertEqual(actualMnemonic, expectedMnemonic) - } - func testImportJSON() throws { let expected = """ { @@ -429,14 +332,6 @@ class KeyStoreTests: XCTestCase { XCTAssertEqual(mnemonic, exported) } - - func testExportTONMnemonic() throws { - let keyStore = try KeyStore(keyDirectory: keyDirectory) - let wallet = try keyStore.importTON(tonMnemonic: tonMnemonic, name: "name", encryptPassword: "newPassword", coin: .ton) - let exported = try keyStore.exportTONMnemonic(wallet: wallet, password: "newPassword") - - XCTAssertEqual(tonMnemonic, exported) - } func testFileName() { let keyStore = try! KeyStore(keyDirectory: keyDirectory) diff --git a/swift/Tests/Keystore/WalletTests.swift b/swift/Tests/Keystore/WalletTests.swift index 48cf71436c5..00815ed0271 100755 --- a/swift/Tests/Keystore/WalletTests.swift +++ b/swift/Tests/Keystore/WalletTests.swift @@ -25,54 +25,4 @@ class WalletTests: XCTestCase { let wallet = Wallet(keyURL: url, key: key) XCTAssertEqual(wallet.identifier, "UTC--2018-07-23T15-42-07.380692005-42000--6E199F01-FA96-4ADF-9A4B-36EE4B1E08C7") } - - func testPrivateKeyGetAccount() throws { - let url = Bundle(for: type(of: self)).url(forResource: "key", withExtension: "json")! - let key = StoredKey.load(path: url.path)! - let wallet = Wallet(keyURL: url, key: key) - - // The wallet already contains `Ethereum` account. No exception expected. - let ethAccount = try wallet.getAccount(password: "testpassword", coin: .ethereum) - XCTAssertEqual(ethAccount.address, "0x008AeEda4D805471dF9b2A5B0f38A0C3bCBA786b") - - let accounts1 = try wallet.getAccounts(password: "testpassword", coins: [.ethereum]) - XCTAssertEqual(accounts1.count, 1) - - // Should fail because `getAccount` currently doesn't support creating a new account from PrivateKey. - XCTAssertThrowsError(try wallet.getAccount(password: "testpassword", coin: .bitcoin)) - - // Should return only `Ethereum` account. - let accounts2 = try wallet.getAccounts(password: "testpassword", coins: [.bitcoin, .ethereum]) - XCTAssertEqual(accounts2.count, 1) - } - - func testTONWalletGetAccount() throws { - let url = Bundle(for: type(of: self)).url(forResource: "ton_wallet", withExtension: "json")! - let key = StoredKey.load(path: url.path)! - let wallet = Wallet(keyURL: url, key: key) - - // The wallet already contains `TON` account. No exception expected. - let tonAccount = try wallet.getAccount(password: "password", coin: .ton) - XCTAssertEqual(tonAccount.address, "UQBlm676c6vy6Q9Js732pvf3ivfmIkVc0MVDQy-F6NAFJd4k") - - let accounts1 = try wallet.getAccounts(password: "password", coins: [.ton]) - XCTAssertEqual(accounts1.count, 1) - - // Should fail because `getAccount` currently doesn't support creating a new account from PrivateKey. - XCTAssertThrowsError(try wallet.getAccount(password: "password", coin: .ethereum)) - - // Should return only `TON` account. - let accounts2 = try wallet.getAccounts(password: "password", coins: [.bitcoin, .ton]) - XCTAssertEqual(accounts2.count, 1) - } - - func testTONWalletGetPrivateKey() throws { - let url = Bundle(for: type(of: self)).url(forResource: "ton_wallet", withExtension: "json")! - let key = StoredKey.load(path: url.path)! - let wallet = Wallet(keyURL: url, key: key) - - // The wallet already contains `TON` account. No exception expected. - let privateKey = try wallet.privateKey(password: "password", coin: .ton) - XCTAssertEqual(privateKey.data.hexString, "cdcea50b87d3f1ca859e7b2bdf9a5339b7b6804b5c70ac85198829f9607dc43b") - } } diff --git a/tests/chains/TheOpenNetwork/TWTONWalletTests.cpp b/tests/chains/TheOpenNetwork/TWTONWalletTests.cpp index b77b47773be..b346ee5568b 100644 --- a/tests/chains/TheOpenNetwork/TWTONWalletTests.cpp +++ b/tests/chains/TheOpenNetwork/TWTONWalletTests.cpp @@ -9,25 +9,6 @@ namespace TW::TheOpenNetwork::tests { -TEST(TWTONWallet, IsValidMnemonic) { - const auto mnemonic = STRING("sight shed side garbage illness clean health wet all win bench wide exist find galaxy drift task suggest portion fresh valve crime radar combine"); - const auto emptyPassphrase = STRING(""); - const auto invalidPassphrase = STRING("Expected empty passphrase"); - EXPECT_TRUE(TWTONWalletIsValidMnemonic(mnemonic.get(), nullptr)); - EXPECT_TRUE(TWTONWalletIsValidMnemonic(mnemonic.get(), emptyPassphrase.get())); - EXPECT_FALSE(TWTONWalletIsValidMnemonic(mnemonic.get(), invalidPassphrase.get())); -} - -TEST(TWTONWallet, MnemonicToPrivateKey) { - const auto mnemonic = STRING("sight shed side garbage illness clean health wet all win bench wide exist find galaxy drift task suggest portion fresh valve crime radar combine"); - const auto wallet = WRAP(TWTONWallet, TWTONWalletCreateWithMnemonic(mnemonic.get(), nullptr)); - EXPECT_TRUE(wallet); - const auto key = WRAP(TWPrivateKey, TWTONWalletGetKey(wallet.get())); - EXPECT_TRUE(key); - const auto keyBytes = WRAPD(TWPrivateKeyData(key.get())); - assertHexEqual(keyBytes, "b471884e691a9f5bb641b14f33bb9e555f759c24e368c4c0d997db3a60704220"); -} - TEST(TWTONWallet, BuildV4R2StateInit) { auto publicKeyBytes = DATA("f229a9371fa7c2108b3d90ea22c9be705ff5d0cfeaee9cbb9366ff0171579357"); auto publicKey = WRAP(TWPublicKey, TWPublicKeyCreateWithData(publicKeyBytes.get(), TWPublicKeyTypeED25519)); diff --git a/tests/common/Keystore/Data/ton-wallet.json b/tests/common/Keystore/Data/ton-wallet.json deleted file mode 100644 index 3ed1c08b087..00000000000 --- a/tests/common/Keystore/Data/ton-wallet.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "activeAccounts": [ - { - "address": "UQBlm676c6vy6Q9Js732pvf3ivfmIkVc0MVDQy-F6NAFJd4k", - "coin": 607, - "derivationPath": "", - "publicKey": "9016f03f9cfa4e183707761f25407e0e1975194a33a56b3e8d2c26f2438fa3d1" - } - ], - "crypto": { - "cipher": "aes-128-ctr", - "cipherparams": { - "iv": "459bbf197fe8e1cdfb949fc516257238" - }, - "ciphertext": "efbda7237b41d2340a4b4c7f0ab6a103e31f7a2b8148137abc815a0d346c3ae851d842ad068ad0218ef9f81647f41e52f7b056d568a314433a0b7980601f96e8974a071b5ddedd50079eebdb9281a8d84a0b9d4649ef3125f6605e303a78c0a4ed67556e3cd4e88b78b120267544eb44a912c92516562acb9782e0ea989cb50bce5948e2dfa26107053caf838af096ce47357061a2b49654", - "kdf": "scrypt", - "kdfparams": { - "dklen": 32, - "n": 16384, - "p": 4, - "r": 8, - "salt": "" - }, - "mac": "be9e9a26076334683799c2dbe22bfb2d9f2ff92ad130aa61b4687b392e7b98e6" - }, - "id": "f7a2172e-fb7a-427a-8526-99779fc47c0a", - "name": "Test TON Account", - "type": "ton-mnemonic", - "version": 3 -} diff --git a/tests/common/Keystore/StoredKeyConstants.h b/tests/common/Keystore/StoredKeyConstants.h deleted file mode 100644 index 93ce7404702..00000000000 --- a/tests/common/Keystore/StoredKeyConstants.h +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// -// Copyright © 2017 Trust Wallet. - -#pragma once - -extern std::string TESTS_ROOT; - -namespace TW::Keystore::tests { - -const auto gName = "name"; -const auto gPasswordString = "password"; -const auto gPassword = TW::data(std::string(gPasswordString)); - -inline std::string testDataPath(const char *subpath) { - return TESTS_ROOT + "/common/Keystore/Data/" + subpath; -} - -} // namespace TW::Keystore::tests diff --git a/tests/common/Keystore/StoredKeyTONTests.cpp b/tests/common/Keystore/StoredKeyTONTests.cpp deleted file mode 100644 index 6be77a508d3..00000000000 --- a/tests/common/Keystore/StoredKeyTONTests.cpp +++ /dev/null @@ -1,172 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// -// Copyright © 2017 Trust Wallet. - -#include "Keystore/StoredKey.h" - -#include "Coin.h" -#include "Data.h" -#include "HexCoding.h" -#include "StoredKeyConstants.h" - -#include -#include - -namespace TW::Keystore::tests { - -using namespace std; - -const auto gTONMnemonic = "protect drill sugar gallery note admit input wrist chicken swarm scheme hedgehog orbit ritual glove ski buddy slogan fragile sun delay toy lucky require"; -// The following TON mnemonic requires a passphrase to be used that we don't support right now. -const auto gTONInvalidMnemonic = "mimic close sibling chair shuffle goat fashion chunk increase tennis scene ceiling divert cross treat happy soccer sample umbrella oyster advance quality perfect call"; -const auto gTONPrivateKey = "cdcea50b87d3f1ca859e7b2bdf9a5339b7b6804b5c70ac85198829f9607dc43b"; -const auto gTONPublicKey = "9016f03f9cfa4e183707761f25407e0e1975194a33a56b3e8d2c26f2438fa3d1"; -const auto gBounceableAddress = "EQBlm676c6vy6Q9Js732pvf3ivfmIkVc0MVDQy-F6NAFJYPh"; -const auto gNonBounceableAddress = "UQBlm676c6vy6Q9Js732pvf3ivfmIkVc0MVDQy-F6NAFJd4k"; - -TEST(StoredKeyTON, CreateWithTonMnemonicAddDefault) { - auto key = StoredKey::createWithTonMnemonicAddDefaultAddress(gName, gPassword, TWCoinTypeTON, gTONMnemonic); - EXPECT_EQ(key.type, StoredKeyType::tonMnemonicPhrase); - const Data& mnemo2Data = key.payload.decrypt(gPassword); - EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(gTONMnemonic)); - EXPECT_EQ(key.accounts.size(), 1ul); - EXPECT_EQ(key.accounts[0].coin, TWCoinTypeTON); - EXPECT_EQ(key.accounts[0].address, "UQBlm676c6vy6Q9Js732pvf3ivfmIkVc0MVDQy-F6NAFJd4k"); - EXPECT_EQ(key.accounts[0].publicKey, gTONPublicKey); - EXPECT_EQ(key.accounts[0].extendedPublicKey, ""); - EXPECT_EQ(key.accounts[0].derivationPath.string(), ""); - EXPECT_EQ(key.accounts[0].derivation, TWDerivationDefault); - EXPECT_EQ(hex(key.privateKey(TWCoinTypeTON, gPassword).bytes), gTONPrivateKey); - EXPECT_EQ(key.payload.params.cipher(), "aes-128-ctr"); - - const auto json = key.json(); - EXPECT_EQ(json["name"], gName); - EXPECT_EQ(json["type"], "ton-mnemonic"); - EXPECT_EQ(json["version"], 3); -} - -TEST(StoredKeyTON, CreateWithTonMnemonicInvalid) { - EXPECT_THROW( - StoredKey::createWithTonMnemonicAddDefaultAddress(gName, gPassword, TWCoinTypeTON, gTONInvalidMnemonic), - std::invalid_argument - ); -} - -TEST(StoredKeyTON, CreateWithTonMnemonicInvalidCoinType) { - EXPECT_THROW( - StoredKey::createWithTonMnemonicAddDefaultAddress(gName, gPassword, TWCoinTypeBitcoin, gTONMnemonic), - std::invalid_argument - ); -} - -TEST(StoredKeyTON, CreateWithMnemonicAddDefaultAddressAes256) { - auto key = StoredKey::createWithTonMnemonicAddDefaultAddress(gName, gPassword, TWCoinTypeTON, gTONMnemonic, TWStoredKeyEncryptionAes256Ctr); - EXPECT_EQ(key.type, StoredKeyType::tonMnemonicPhrase); - const Data& mnemo2Data = key.payload.decrypt(gPassword); - EXPECT_EQ(string(mnemo2Data.begin(), mnemo2Data.end()), string(gTONMnemonic)); - EXPECT_EQ(key.accounts.size(), 1ul); - EXPECT_EQ(key.accounts[0].coin, TWCoinTypeTON); - EXPECT_EQ(key.accounts[0].address, "UQBlm676c6vy6Q9Js732pvf3ivfmIkVc0MVDQy-F6NAFJd4k"); - EXPECT_EQ(key.payload.params.cipher(), "aes-256-ctr"); -} - -TEST(StoredKeyTON, HDWalletNotSupported) { - auto key = StoredKey::createWithTonMnemonicAddDefaultAddress(gName, gPassword, TWCoinTypeTON, gTONMnemonic); - EXPECT_THROW(key.wallet(gPassword), std::invalid_argument); -} - -TEST(StoredKeyTON, AddRemoveAccount) { - auto key = StoredKey::createWithTonMnemonicAddDefaultAddress(gName, gPassword, TWCoinTypeTON, gTONMnemonic); - EXPECT_EQ(key.accounts.size(), 1ul); - - // Add another dummy (doesn't belong to the mnemonic) TON account. - { - const DerivationPath derivationPath {}; - const auto publicKey = "b191d35f81aa8b144aa91c90a6b887e0b165ad9c2933b1c5266eb5c4e8bea241"; - const auto extendedPublicKey = ""; - key.addAccount("UQDSRYDMMez8BdcOuPEiaR6aJZpO6EjlIwmOBFn14mMbnRah", TWCoinTypeTON, TWDerivationDefault, derivationPath, publicKey, extendedPublicKey); - EXPECT_EQ(key.accounts.size(), 2ul); - } - - key.removeAccount(TWCoinTypeTON, TWDerivationDefault); - EXPECT_EQ(key.accounts.size(), 0ul); -} - -TEST(StoredKeyTON, FixAddressHasNoEffect) { - // `StoredKey::createWithTonMnemonicAddDefaultAddress` derives the correct address. - auto key = StoredKey::createWithTonMnemonicAddDefaultAddress(gName, gPassword, TWCoinTypeTON, gTONMnemonic); - EXPECT_EQ(key.accounts.size(), 1ul); - - key.fixAddresses(gPassword); - EXPECT_EQ(key.accounts[0].address, gNonBounceableAddress); -} - -TEST(StoredKeyTON, FixAddress) { - auto key = StoredKey::createWithTonMnemonic(gName, gPassword, gTONMnemonic); - EXPECT_EQ(key.accounts.size(), 0ul); - - // Add an account with an invalid address manually. - { - const DerivationPath derivationPath {}; - const auto publicKey = gTONPublicKey; - const auto extendedPublicKey = ""; - const auto invalidAddress = "INVALID_ADDRESS"; - key.addAccount(invalidAddress, TWCoinTypeTON, TWDerivationDefault, derivationPath, publicKey, extendedPublicKey); - EXPECT_EQ(key.accounts.size(), 1ul); - } - - key.fixAddresses(gPassword); - EXPECT_EQ(key.accounts.size(), 1ul); - EXPECT_EQ(key.accounts[0].coin, TWCoinTypeTON); - // Address should be fixed to a valid non-bounceable address. - EXPECT_EQ(key.accounts[0].address, gNonBounceableAddress); -} - -TEST(StoredKeyTON, UpdateAddress) { - auto key = StoredKey::createWithTonMnemonic(gName, gPassword, gTONMnemonic); - EXPECT_EQ(key.accounts.size(), 0ul); - - // Add an account with a bounceable (EQ) address. - { - const DerivationPath derivationPath {}; - const auto publicKey = gTONPublicKey; - const auto extendedPublicKey = ""; - const auto invalidAddress = gBounceableAddress; - key.addAccount(invalidAddress, TWCoinTypeTON, TWDerivationDefault, derivationPath, publicKey, extendedPublicKey); - EXPECT_EQ(key.accounts.size(), 1ul); - } - - key.updateAddress(TWCoinTypeTON); - EXPECT_EQ(key.accounts.size(), 1ul); - EXPECT_EQ(key.accounts[0].coin, TWCoinTypeTON); - // Address should be fixed to a valid non-bounceable address. - EXPECT_EQ(key.accounts[0].address, gNonBounceableAddress); -} - -TEST(StoredKeyTON, LoadNonexistent) { - ASSERT_THROW(StoredKey::load(testDataPath("nonexistent.json")), invalid_argument); -} - -TEST(StoredKeyTON, LoadTonMnemonic) { - const auto key = StoredKey::load(testDataPath("ton-wallet.json")); - EXPECT_EQ(key.type, StoredKeyType::tonMnemonicPhrase); - EXPECT_EQ(key.id, "f7a2172e-fb7a-427a-8526-99779fc47c0a"); - EXPECT_EQ(key.name, "Test TON Account"); - - const auto data = key.payload.decrypt(gPassword); - const auto mnemonic = string(reinterpret_cast(data.data()), data.size()); - EXPECT_EQ(mnemonic, gTONMnemonic); - - EXPECT_EQ(key.accounts[0].coin, TWCoinTypeTON); - EXPECT_EQ(key.accounts[0].derivationPath.string(), ""); - EXPECT_EQ(key.accounts[0].address, gNonBounceableAddress); - EXPECT_EQ(key.accounts[0].publicKey, gTONPublicKey); -} - -TEST(StoredKeyTON, InvalidPassword) { - const auto key = StoredKey::load(testDataPath("ton-wallet.json")); - - ASSERT_THROW(key.payload.decrypt(TW::data("INVALID PASSWORD")), DecryptionError); -} - -} // namespace TW::Keystore diff --git a/tests/common/Keystore/StoredKeyTests.cpp b/tests/common/Keystore/StoredKeyTests.cpp index a0a98840cb4..02c9bed047b 100644 --- a/tests/common/Keystore/StoredKeyTests.cpp +++ b/tests/common/Keystore/StoredKeyTests.cpp @@ -10,21 +10,28 @@ #include "HexCoding.h" #include "Mnemonic.h" #include "PrivateKey.h" -#include "StoredKeyConstants.h" #include #include +extern std::string TESTS_ROOT; + namespace TW::Keystore::tests { using namespace std; -static const auto gMnemonic = "team engine square letter hero song dizzy scrub tornado fabric divert saddle"; -static const TWCoinType coinTypeBc = TWCoinTypeBitcoin; -static const TWCoinType coinTypeBnb = TWCoinTypeBinance; -static const TWCoinType coinTypeBsc = TWCoinTypeSmartChain; -static const TWCoinType coinTypeEth = TWCoinTypeEthereum; -static const TWCoinType coinTypeBscLegacy = TWCoinTypeSmartChainLegacy; +const auto passwordString = "password"; +const auto gPassword = TW::data(string(passwordString)); +const auto gMnemonic = "team engine square letter hero song dizzy scrub tornado fabric divert saddle"; +const TWCoinType coinTypeBc = TWCoinTypeBitcoin; +const TWCoinType coinTypeBnb = TWCoinTypeBinance; +const TWCoinType coinTypeBsc = TWCoinTypeSmartChain; +const TWCoinType coinTypeEth = TWCoinTypeEthereum; +const TWCoinType coinTypeBscLegacy = TWCoinTypeSmartChainLegacy; + +const std::string testDataPath(const char* subpath) { + return TESTS_ROOT + "/common/Keystore/Data/" + subpath; +} TEST(StoredKey, CreateWithMnemonic) { auto key = StoredKey::createWithMnemonic("name", gPassword, gMnemonic, TWStoredKeyEncryptionLevelDefault); @@ -350,7 +357,6 @@ TEST(StoredKey, LoadLegacyMnemonic) { EXPECT_EQ(key.id, "629aad29-0b22-488e-a0e7-b4219d4f311c"); const auto data = key.payload.decrypt(gPassword); - // In this case, the encrypted mnemonic contains `\0` value at the end. const auto mnemonic = string(reinterpret_cast(data.data())); EXPECT_EQ(mnemonic, "ripple scissors kick mammal hire column oak again sun offer wealth tomorrow wagon turn back"); diff --git a/tests/interface/TWStoredKeyTests.cpp b/tests/interface/TWStoredKeyTests.cpp index 2376972fa52..ee758923b47 100644 --- a/tests/interface/TWStoredKeyTests.cpp +++ b/tests/interface/TWStoredKeyTests.cpp @@ -38,32 +38,6 @@ struct std::shared_ptr createDefaultStoredKey(TWStoredKeyEncryption return createAStoredKey(TWCoinTypeBitcoin, password.get(), encryption); } -/// Return a StoredKey instance that can be used for further tests. Needs to be deleted at the end. -struct std::shared_ptr createTONStoredKey(TWData* password, TWStoredKeyEncryption encryption = TWStoredKeyEncryptionAes128Ctr) { - const auto mnemonic = WRAPS(TWStringCreateWithUTF8Bytes("slim holiday tiny pizza donor egg round three verify post chat social offer mix rack soft loud code option learn this pipe mouse mango")); - const auto name = WRAPS(TWStringCreateWithUTF8Bytes("name")); - const auto coin = TWCoinTypeTON; - - return WRAP(TWStoredKey, TWStoredKeyImportTONWalletWithEncryption(mnemonic.get(), name.get(), password, coin, encryption)); -} - -Data readFileData(const std::string& path) { - // read contents of file - ifstream ifs(path); - // get length of file: - ifs.seekg (0, ifs.end); - auto length = ifs.tellg(); - ifs.seekg (0, ifs.beg); - EXPECT_TRUE(length > 20); - - Data data(length); - size_t idx = 0; - // read the slow way, ifs.read gave some false warnings with codacy - while (!ifs.eof() && idx < static_cast(length)) { char c = ifs.get(); data[idx++] = (uint8_t)c; } - - return data; -} - TEST(TWStoredKey, loadPBKDF2Key) { const auto filename = WRAPS(TWStringCreateWithUTF8Bytes((TESTS_ROOT + "/common/Keystore/Data/pbkdf2.json").c_str())); const auto key = WRAP(TWStoredKey, TWStoredKeyLoad(filename.get())); @@ -153,36 +127,6 @@ TEST(TWStoredKey, importHDWalletAES256) { EXPECT_EQ(nokey.get(), nullptr); } -TEST(TWStoredKey, importTONWallet) { - const auto mnemonicStr = "slim holiday tiny pizza donor egg round three verify post chat social offer mix rack soft loud code option learn this pipe mouse mango"; - const auto mnemonic = WRAPS(TWStringCreateWithUTF8Bytes(mnemonicStr)); - const auto name = WRAPS(TWStringCreateWithUTF8Bytes("name")); - const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password")); - const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get()))); - const auto coin = TWCoinTypeTON; - const auto key = WRAP(TWStoredKey, TWStoredKeyImportTONWallet(mnemonic.get(), name.get(), password.get(), coin)); - EXPECT_FALSE(TWStoredKeyIsMnemonic(key.get())); - EXPECT_TRUE(TWStoredKeyIsTONMnemonic(key.get())); - - const auto actualMnemonic = WRAPS(TWStoredKeyDecryptTONMnemonic(key.get(), password.get())); - assertStringsEqual(actualMnemonic, mnemonicStr); - - // invalid mnemonic - const auto mnemonicInvalid = WRAPS(TWStringCreateWithUTF8Bytes("_THIS_IS_AN_INVALID_MNEMONIC_")); - const auto nokey = WRAP(TWStoredKey, TWStoredKeyImportTONWallet(mnemonicInvalid.get(), name.get(), password.get(), coin)); - EXPECT_EQ(nokey.get(), nullptr); -} - -TEST(TWStoredKey, importTONWalletAES256) { - const auto mnemonic = WRAPS(TWStringCreateWithUTF8Bytes("slim holiday tiny pizza donor egg round three verify post chat social offer mix rack soft loud code option learn this pipe mouse mango")); - const auto name = WRAPS(TWStringCreateWithUTF8Bytes("name")); - const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password")); - const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get()))); - const auto coin = TWCoinTypeTON; - const auto key = WRAP(TWStoredKey, TWStoredKeyImportTONWalletWithEncryption(mnemonic.get(), name.get(), password.get(), coin, TWStoredKeyEncryptionAes256Ctr)); - EXPECT_TRUE(TWStoredKeyIsTONMnemonic(key.get())); -} - TEST(TWStoredKey, addressAddRemove) { const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password")); const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get()))); @@ -218,15 +162,6 @@ TEST(TWStoredKey, addressAddRemove) { EXPECT_EQ(TWStoredKeyAccount(key.get(), 1001), nullptr); } -/// HDWallet cannot be created from a TON mnemonic. -TEST(TWStoredKey, TONWalletGetWalletNotSupported) { - const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password")); - const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get()))); - - const auto key = createTONStoredKey(password.get()); - EXPECT_EQ(TWStoredKeyWallet(key.get(), password.get()), nullptr); -} - TEST(TWStoredKey, addressAddRemoveDerivationPath) { const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password")); const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get()))); @@ -283,26 +218,25 @@ TEST(TWStoredKey, exportJSON) { EXPECT_EQ(TWDataGet(json.get(), 0), '{'); } -TEST(TWStoredKey, TONWalletExportJSON) { - const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password")); - const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get()))); - - const auto key = createTONStoredKey(password.get()); - - const auto jsonData = WRAPD(TWStoredKeyExportJSON(key.get())); - const auto jsonStr = WRAPS(TWStringCreateWithRawBytes(TWDataBytes(jsonData.get()), TWDataSize(jsonData.get()))); - const auto json = nlohmann::json::parse(string(TWStringUTF8Bytes(jsonStr.get()))); - EXPECT_EQ(json["type"], "ton-mnemonic"); - EXPECT_EQ(json["activeAccounts"].size(), 1ul); -} - TEST(TWStoredKey, storeAndImportJSONAES256) { const auto key = createDefaultStoredKey(TWStoredKeyEncryptionAes256Ctr); const auto outFileName = string(getTestTempDir() + "/TWStoredKey_store.json"); const auto outFileNameStr = WRAPS(TWStringCreateWithUTF8Bytes(outFileName.c_str())); EXPECT_TRUE(TWStoredKeyStore(key.get(), outFileNameStr.get())); - const auto json = readFileData(outFileName); + // read contents of file + ifstream ifs(outFileName); + // get length of file: + ifs.seekg (0, ifs.end); + auto length = ifs.tellg(); + ifs.seekg (0, ifs.beg); + EXPECT_TRUE(length > 20); + + Data json(length); + size_t idx = 0; + // read the slow way, ifs.read gave some false warnings with codacy + while (!ifs.eof() && idx < static_cast(length)) { char c = ifs.get(); json[idx++] = (uint8_t)c; } + const auto key2 = WRAP(TWStoredKey, TWStoredKeyImportJSON(WRAPD(TWDataCreateWithData(&json)).get())); const auto name2 = WRAPS(TWStoredKeyName(key2.get())); EXPECT_EQ(string(TWStringUTF8Bytes(name2.get())), "name"); @@ -313,28 +247,24 @@ TEST(TWStoredKey, storeAndImportJSON) { const auto outFileName = string(getTestTempDir() + "/TWStoredKey_store.json"); const auto outFileNameStr = WRAPS(TWStringCreateWithUTF8Bytes(outFileName.c_str())); EXPECT_TRUE(TWStoredKeyStore(key.get(), outFileNameStr.get())); + //EXPECT_TRUE(filesystem::exists(outFileName)); // some linker issues with filesystem + + // read contents of file + ifstream ifs(outFileName); + // get length of file: + ifs.seekg (0, ifs.end); + auto length = ifs.tellg(); + ifs.seekg (0, ifs.beg); + EXPECT_TRUE(length > 20); - const auto json = readFileData(outFileName); - const auto key2 = WRAP(TWStoredKey, TWStoredKeyImportJSON(WRAPD(TWDataCreateWithData(&json)).get())); - const auto name2 = WRAPS(TWStoredKeyName(key2.get())); - EXPECT_EQ(string(TWStringUTF8Bytes(name2.get())), "name"); - EXPECT_TRUE(TWStoredKeyIsMnemonic(key2.get())); -} - -TEST(TWStoredKey, TONWalletStoreAndImport) { - const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password")); - const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get()))); - - const auto key = createTONStoredKey(password.get()); - const auto outFileName = string(getTestTempDir() + "/TWStoredKey_storeTON.json"); - const auto outFileNameStr = WRAPS(TWStringCreateWithUTF8Bytes(outFileName.c_str())); - EXPECT_TRUE(TWStoredKeyStore(key.get(), outFileNameStr.get())); + Data json(length); + size_t idx = 0; + // read the slow way, ifs.read gave some false warnings with codacy + while (!ifs.eof() && idx < static_cast(length)) { char c = ifs.get(); json[idx++] = (uint8_t)c; } - const auto json = readFileData(outFileName); const auto key2 = WRAP(TWStoredKey, TWStoredKeyImportJSON(WRAPD(TWDataCreateWithData(&json)).get())); const auto name2 = WRAPS(TWStoredKeyName(key2.get())); EXPECT_EQ(string(TWStringUTF8Bytes(name2.get())), "name"); - EXPECT_TRUE(TWStoredKeyIsTONMnemonic(key2.get())); } TEST(TWStoredKey, importJsonInvalid) { @@ -466,10 +396,10 @@ TEST(TWStoredKey, getWalletPasswordInvalid) { const auto name = WRAPS(TWStringCreateWithUTF8Bytes("name")); const auto passwordString = WRAPS(TWStringCreateWithUTF8Bytes("password")); const auto password = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(passwordString.get())), TWStringSize(passwordString.get()))); - + const auto invalidString = WRAPS(TWStringCreateWithUTF8Bytes("_THIS_IS_INVALID_PASSWORD_")); const auto passwordInvalid = WRAPD(TWDataCreateWithBytes(reinterpret_cast(TWStringUTF8Bytes(invalidString.get())), TWStringSize(invalidString.get()))); - + auto key = WRAP(TWStoredKey, TWStoredKeyCreate(name.get(), password.get())); ASSERT_NE(WRAP(TWHDWallet, TWStoredKeyWallet(key.get(), password.get())).get(), nullptr); ASSERT_EQ(WRAP(TWHDWallet, TWStoredKeyWallet(key.get(), passwordInvalid.get())).get(), nullptr); diff --git a/wasm/src/keystore/default-impl.ts b/wasm/src/keystore/default-impl.ts index 04ecb4bae87..6da4ae6c57a 100644 --- a/wasm/src/keystore/default-impl.ts +++ b/wasm/src/keystore/default-impl.ts @@ -104,31 +104,6 @@ export class Default implements Types.IKeyStore { }); } - importTON( - tonMnemonic: string, - name: string, - password: string, - coin: CoinType, - encryption: StoredKeyEncryption - ): Promise { - return new Promise((resolve, reject) => { - const { StoredKey, TONWallet } = this.core; - - const passphrase = ""; - if (!TONWallet.isValidMnemonic(tonMnemonic, passphrase)) { - throw Types.Error.InvalidMnemonic; - } - - let pass = Buffer.from(password); - let storedKey = StoredKey.importTONWalletWithEncryption(tonMnemonic, name, pass, coin, encryption); - let wallet = this.mapWallet(storedKey); - storedKey.delete(); - this.importWallet(wallet) - .then(() => resolve(wallet)) - .catch((error) => reject(error)); - }); - } - addAccounts( id: string, password: string, @@ -154,23 +129,11 @@ export class Default implements Types.IKeyStore { ): Promise { return this.load(id).then((wallet) => { let storedKey = this.mapStoredKey(wallet); + let hdWallet = storedKey.wallet(Buffer.from(password)); let coin = (this.core.CoinType as any).values["" + account.coin]; - - let privateKey: PrivateKey; - switch (wallet.type) { - // In case of BIP39 mnemonic, we should use the custom derivation path. - case Types.WalletType.Mnemonic: - let hdWallet = storedKey.wallet(Buffer.from(password)); - privateKey = hdWallet.getKey(coin, account.derivationPath); - hdWallet.delete(); - break; - // Otherwise, use the default implementation. - default: - privateKey = storedKey.privateKey(coin, Buffer.from(password)); - break; - } - + let privateKey = hdWallet.getKey(coin, account.derivationPath); storedKey.delete(); + hdWallet.delete(); return privateKey; }); } @@ -186,9 +149,6 @@ export class Default implements Types.IKeyStore { case Types.WalletType.PrivateKey: value = storedKey.decryptPrivateKey(Buffer.from(password)); break; - case Types.WalletType.TonMnemonic: - value = storedKey.decryptTONMnemonic(Buffer.from(password)); - break; default: throw Types.Error.InvalidJSON; } diff --git a/wasm/src/keystore/types.ts b/wasm/src/keystore/types.ts index ecdd3280db1..bccb05ef58a 100644 --- a/wasm/src/keystore/types.ts +++ b/wasm/src/keystore/types.ts @@ -9,7 +9,6 @@ export enum WalletType { PrivateKey = "privateKey", WatchOnly = "watchOnly", Hardware = "hardware", - TonMnemonic = "ton-mnemonic" } export enum Error { @@ -69,15 +68,6 @@ export interface IKeyStore { // Import a Wallet object directly importWallet(wallet: Wallet): Promise; - // Import a TON wallet by 24-words mnemonic, name, password and initial active account (from coinType) - importTON( - tonMnemonic: string, - name: string, - password: string, - coin: CoinType, - encryption: StoredKeyEncryption - ): Promise; - // Add active accounts to a wallet by wallet id, password, coin addAccounts(id: string, password: string, coins: CoinType[]): Promise; @@ -88,7 +78,7 @@ export interface IKeyStore { account: ActiveAccount ): Promise; - // Delete a wallet by wallet id and password + // Delete a wallet by wallet id and password.aq1aq delete(id: string, password: string): Promise; // Export a wallet by wallet id and password, returns mnemonic or private key diff --git a/wasm/tests/KeyStore+extension.test.ts b/wasm/tests/KeyStore+extension.test.ts index a44b7cb3504..9cc1dcf5c22 100644 --- a/wasm/tests/KeyStore+extension.test.ts +++ b/wasm/tests/KeyStore+extension.test.ts @@ -64,51 +64,6 @@ describe("KeyStore", async () => { }); }).timeout(10000); - it("test ExtensionStorage TONWallet", async () => { - const { CoinType, HexCoding, StoredKeyEncryption } = globalThis.core; - const tonMnemonic = globalThis.tonMnemonic as string; - const password = globalThis.password as string; - - const walletIdsKey = "all-wallet-ids"; - const storage = new KeyStore.ExtensionStorage( - walletIdsKey, - new ChromeStorageMock() - ); - const keystore = new KeyStore.Default(globalThis.core, storage); - - const wallet = await keystore.importTON(tonMnemonic, "Coolton", password, CoinType.ton, StoredKeyEncryption.aes128Ctr); - - assert.equal(wallet.name, "Coolton"); - assert.equal(wallet.type, "ton-mnemonic"); - assert.equal(wallet.version, 3); - - const account = wallet.activeAccounts[0]; - const key = await keystore.getKey(wallet.id, password, account); - - assert.equal( - HexCoding.encode(key.data()), - "0x859cd74ab605afb7ce9f5316a1f6d59217a130b75b494efd249913be874c9d46" - ); - assert.equal(account.address, "UQDdB2lMwYM9Gxc-ln--Tu8cz-TYksQxYuUsMs2Pd4cHerYz"); - assert.isUndefined(account.extendedPublicKey); - assert.equal( - account.publicKey, - "c9af50596bd5c1c5a15fb32bef8d4f1ee5244b287aea1f49f6023a79f9b2f055" - ); - - assert.isTrue(await keystore.hasWallet(wallet.id)); - assert.isFalse(await keystore.hasWallet("invalid-id")); - - const exported = await keystore.export(wallet.id, password); - assert.equal(exported, tonMnemonic); - - const wallets = await keystore.loadAll(); - - await wallets.forEach((w) => { - keystore.delete(w.id, password); - }); - }).timeout(10000); - it("test ExtensionStorage AES256", async () => { const { CoinType, HexCoding, StoredKeyEncryption } = globalThis.core; const mnemonic = globalThis.mnemonic as string; diff --git a/wasm/tests/setup.test.ts b/wasm/tests/setup.test.ts index 98ede91486e..54d6664beee 100644 --- a/wasm/tests/setup.test.ts +++ b/wasm/tests/setup.test.ts @@ -4,8 +4,6 @@ import { initWasm } from "../dist"; before(async () => { globalThis.mnemonic = "team engine square letter hero song dizzy scrub tornado fabric divert saddle"; - globalThis.tonMnemonic = - "laundry myself fitness beyond prize piano match acid vacuum already abandon dance occur pause grocery company inject excuse weasel carpet fog grunt trick spike"; globalThis.password = "password"; globalThis.core = await initWasm(); });