From 0f17fe981627ad27dfc2f5dafe38a6c32e2913b5 Mon Sep 17 00:00:00 2001 From: Anton Paymyshev Date: Wed, 22 Jan 2025 16:42:40 +0700 Subject: [PATCH 1/2] wallet refactor --- components/brave_wallet/browser/BUILD.gn | 2 + components/brave_wallet/browser/DEPS | 2 +- .../account_discovery_manager_unittest.cc | 4 +- components/brave_wallet/browser/bip39.cc | 98 ++++++++ components/brave_wallet/browser/bip39.h | 41 ++++ .../brave_wallet/browser/bip39_unittest.cc | 218 ++++++++++++++++++ .../bitcoin/bitcoin_hd_keyring_unittest.cc | 4 +- .../bitcoin_knapsack_solver_unittest.cc | 9 +- .../bitcoin_max_send_solver_unittest.cc | 9 +- .../browser/bitcoin/bitcoin_test_utils.cc | 7 +- .../browser/brave_wallet_service.cc | 7 +- .../browser/brave_wallet_utils.cc | 109 --------- .../brave_wallet/browser/brave_wallet_utils.h | 18 -- .../browser/brave_wallet_utils_unittest.cc | 205 +--------------- .../browser/eip1559_transaction.cc | 19 +- .../browser/eip1559_transaction.h | 9 +- .../browser/eip1559_transaction_unittest.cc | 20 +- .../browser/eip2930_transaction.cc | 13 +- .../browser/eip2930_transaction.h | 11 +- .../browser/eip2930_transaction_unittest.cc | 9 +- .../brave_wallet/browser/eth_transaction.cc | 18 +- .../brave_wallet/browser/eth_transaction.h | 18 +- .../browser/eth_transaction_unittest.cc | 29 +-- .../brave_wallet/browser/eth_tx_manager.cc | 31 +-- .../brave_wallet/browser/ethereum_keyring.cc | 52 +++-- .../brave_wallet/browser/ethereum_keyring.h | 9 +- .../browser/ethereum_keyring_unittest.cc | 29 ++- .../browser/ethereum_provider_impl.cc | 11 +- .../brave_wallet/browser/fil_transaction.cc | 7 +- .../browser/filecoin_keyring_unittest.cc | 3 + components/brave_wallet/browser/hd_keyring.cc | 26 --- components/brave_wallet/browser/hd_keyring.h | 3 - .../brave_wallet/browser/internal/hd_key.cc | 43 ++-- .../brave_wallet/browser/internal/hd_key.h | 17 +- .../browser/internal/hd_key_unittest.cc | 40 ++-- .../browser/json_keystore_parser.cc | 10 +- .../brave_wallet/browser/keyring_service.cc | 55 ++--- .../brave_wallet/browser/keyring_service.h | 16 +- .../browser/keyring_service_migrations.cc | 24 +- .../browser/keyring_service_unittest.cc | 39 ++-- .../brave_wallet/browser/sns_resolver_task.cc | 5 +- .../brave_wallet/browser/solana_keyring.cc | 10 +- .../brave_wallet/browser/solana_keyring.h | 1 + .../browser/solana_keyring_unittest.cc | 4 +- components/brave_wallet/browser/test/BUILD.gn | 1 + .../browser/zcash/zcash_keyring_unittest.cc | 4 +- components/brave_wallet/common/eth_address.cc | 5 - components/brave_wallet/common/f4_jumble.cc | 44 +--- components/brave_wallet/common/fil_address.cc | 84 ++----- components/brave_wallet/common/fil_address.h | 4 +- .../common/fil_address_unittest.cc | 10 +- components/brave_wallet/common/hash_utils.cc | 35 ++- components/brave_wallet/common/hash_utils.h | 12 +- .../common/hash_utils_unittest.cc | 21 ++ 54 files changed, 730 insertions(+), 804 deletions(-) create mode 100644 components/brave_wallet/browser/bip39.cc create mode 100644 components/brave_wallet/browser/bip39.h create mode 100644 components/brave_wallet/browser/bip39_unittest.cc diff --git a/components/brave_wallet/browser/BUILD.gn b/components/brave_wallet/browser/BUILD.gn index 7bb1501ffd53..24692654d262 100644 --- a/components/brave_wallet/browser/BUILD.gn +++ b/components/brave_wallet/browser/BUILD.gn @@ -34,6 +34,8 @@ static_library("browser") { "asset_ratio_response_parser.h", "asset_ratio_service.cc", "asset_ratio_service.h", + "bip39.cc", + "bip39.h", "bitcoin/bitcoin_block_tracker.cc", "bitcoin/bitcoin_block_tracker.h", "bitcoin/bitcoin_discover_account_task.cc", diff --git a/components/brave_wallet/browser/DEPS b/components/brave_wallet/browser/DEPS index 2d56ab7e8a8a..3bde8afbd840 100644 --- a/components/brave_wallet/browser/DEPS +++ b/components/brave_wallet/browser/DEPS @@ -18,7 +18,7 @@ include_rules = [ ] specific_include_rules = { - "brave_wallet_utils\.cc": [ + "bip39\.cc": [ "+brave/third_party/bip39wally-core-native/include", ] } diff --git a/components/brave_wallet/browser/account_discovery_manager_unittest.cc b/components/brave_wallet/browser/account_discovery_manager_unittest.cc index 714dc1767b53..9f8e1f7aacbf 100644 --- a/components/brave_wallet/browser/account_discovery_manager_unittest.cc +++ b/components/brave_wallet/browser/account_discovery_manager_unittest.cc @@ -10,11 +10,11 @@ #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" +#include "brave/components/brave_wallet/browser/bip39.h" #include "brave/components/brave_wallet/browser/bitcoin/bitcoin_hd_keyring.h" #include "brave/components/brave_wallet/browser/bitcoin/bitcoin_test_utils.h" #include "brave/components/brave_wallet/browser/bitcoin/bitcoin_wallet_service.h" #include "brave/components/brave_wallet/browser/brave_wallet_prefs.h" -#include "brave/components/brave_wallet/browser/brave_wallet_utils.h" #include "brave/components/brave_wallet/browser/keyring_service.h" #include "brave/components/brave_wallet/browser/network_manager.h" #include "brave/components/brave_wallet/browser/test_utils.h" @@ -60,7 +60,7 @@ class AccountDiscoveryManagerUnitTest : public testing::Test { bitcoin_test_rpc_server_->SetUpBitcoinRpc(std::nullopt, std::nullopt); keyring_ = std::make_unique( - *MnemonicToSeed(kMnemonicDivideCruise), false); + *bip39::MnemonicToSeed(kMnemonicDivideCruise), false); } AccountUtils GetAccountUtils() { diff --git a/components/brave_wallet/browser/bip39.cc b/components/brave_wallet/browser/bip39.cc new file mode 100644 index 000000000000..a79b11145449 --- /dev/null +++ b/components/brave_wallet/browser/bip39.cc @@ -0,0 +1,98 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_wallet/browser/bip39.h" + +#include "base/containers/span.h" +#include "base/strings/strcat.h" +#include "brave/third_party/bip39wally-core-native/include/wally_bip39.h" +#include "third_party/boringssl/src/include/openssl/digest.h" +#include "third_party/boringssl/src/include/openssl/evp.h" + +namespace brave_wallet::bip39 { + +namespace { + +// https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#generating-the-mnemonic +inline constexpr uint32_t kMaxSupportedEntropySize = 32; + +// https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#from-mnemonic-to-seed +inline constexpr uint32_t kPBKDF2Iterations = 2048; +inline constexpr uint32_t kSeedSize = 64; + +std::optional GenerateMnemonicInternal( + base::span entropy) { + char* words = nullptr; + if (bip39_mnemonic_from_bytes(nullptr, entropy.data(), entropy.size(), + &words) != WALLY_OK) { + return std::nullopt; + } + std::string result(words); + wally_free_string(words); + return result; +} + +bool IsValidEntropySize(size_t entropy_size) { + // entropy size should be 128, 160, 192, 224, 256 bits + if (entropy_size < 16 || entropy_size > 32 || entropy_size % 4 != 0) { + return false; + } + return true; +} + +} // namespace + +std::optional GenerateMnemonic(base::span entropy) { + if (!IsValidEntropySize(entropy.size())) { + return std::nullopt; + } + return GenerateMnemonicInternal(entropy); +} + +std::optional> MnemonicToSeed( + std::string_view mnemonic, + std::string_view passphrase) { + if (!IsValidMnemonic(mnemonic)) { + return std::nullopt; + } + + std::vector seed(kSeedSize, 0); + const std::string salt = base::StrCat({"mnemonic", passphrase}); + if (PKCS5_PBKDF2_HMAC(mnemonic.data(), mnemonic.length(), + base::as_byte_span(salt).data(), salt.length(), + kPBKDF2Iterations, EVP_sha512(), seed.size(), + seed.data())) { + return seed; + } + + return std::nullopt; +} + +std::optional> MnemonicToEntropy( + std::string_view mnemonic) { + if (!IsValidMnemonic(mnemonic)) { + return std::nullopt; + } + + std::vector entropy(kMaxSupportedEntropySize, 0); + size_t written = 0; + if (bip39_mnemonic_to_bytes(nullptr, std::string(mnemonic).c_str(), + entropy.data(), entropy.size(), + &written) != WALLY_OK) { + return std::nullopt; + } + entropy.resize(written); + return entropy; +} + +bool IsValidMnemonic(std::string_view mnemonic) { + if (bip39_mnemonic_validate(nullptr, std::string(mnemonic).c_str()) != + WALLY_OK) { + return false; + } + return true; +} + +} // namespace brave_wallet::bip39 diff --git a/components/brave_wallet/browser/bip39.h b/components/brave_wallet/browser/bip39.h new file mode 100644 index 000000000000..429237e5ce94 --- /dev/null +++ b/components/brave_wallet/browser/bip39.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_BIP39_H_ +#define BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_BIP39_H_ + +#include +#include +#include +#include + +#include "base/containers/span.h" + +// Utility functions for BIP39 mnemonics support. +// https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki +namespace brave_wallet::bip39 { + +inline constexpr uint32_t kDefaultEntropySize = 16; +inline constexpr uint32_t kLegacyEthEntropySize = 32; + +// Generate mnemonic from entropy bytes following BIP39. +// If |entropy.size()| is not in 16, 20, 24, 28, 32 range or +// allocation failure, the std::nullopt will be returned. +std::optional GenerateMnemonic(base::span entropy); + +// Generate 64 bytes seed from mnemonic following BIP39. +std::optional> MnemonicToSeed( + std::string_view mnemonic, + std::string_view passphrase = ""); + +// This is mainly used for restoring legacy brave crypto wallet +std::optional> MnemonicToEntropy( + std::string_view mnemonic); + +bool IsValidMnemonic(std::string_view mnemonic); + +} // namespace brave_wallet::bip39 + +#endif // BRAVE_COMPONENTS_BRAVE_WALLET_BROWSER_BIP39_H_ diff --git a/components/brave_wallet/browser/bip39_unittest.cc b/components/brave_wallet/browser/bip39_unittest.cc new file mode 100644 index 000000000000..8abe5de2c3e1 --- /dev/null +++ b/components/brave_wallet/browser/bip39_unittest.cc @@ -0,0 +1,218 @@ +/* Copyright (c) 2025 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_wallet/browser/bip39.h" + +#include + +#include "base/rand_util.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "base/test/values_test_util.h" +#include "brave/components/brave_wallet/browser/test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::test::ParseJsonDict; +using testing::Contains; +using testing::ElementsAreArray; +using testing::Eq; +using testing::Not; + +namespace brave_wallet::bip39 { + +TEST(BraveWalletUtilsUnitTest, Mnemonic) { + const struct { + std::string_view entropy; + std::string_view mnemonic; + std::string_view seed; + } cases[] = { + {"00000000000000000000000000000000", kMnemonicAbandonAbandon, + "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a69" + "87" + "599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04"}, + {"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "yellow", + "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1" + "29" + "6106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607"}, + {"80808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage above", + "d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f1" + "2eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8"}, + {"ffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", + "ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a133325729" + "17f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069"}, + {"000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon agent", + "035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9" + "a565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa"}, + {"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal will", + "f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c3" + "92d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd"}, + {"808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter always", + "107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913f" + "fb796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "when", + "0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b43" + "348d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528"}, + {"0000000000000000000000000000000000000000000000000000000000000000", + "abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon abandon " + "abandon abandon abandon abandon abandon abandon abandon art", + "bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4" + "d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8"}, + {"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", + "legal winner thank year wave sausage worth useful legal winner thank " + "year wave sausage worth useful legal winner thank year wave sausage " + "worth title", + "bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146a" + "d717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87"}, + {"8080808080808080808080808080808080808080808080808080808080808080", + "letter advice cage absurd amount doctor acoustic avoid letter advice " + "cage absurd amount doctor acoustic avoid letter advice cage absurd " + "amount doctor acoustic bless", + "c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61a" + "f0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " + "zoo zoo zoo zoo zoo zoo vote", + "dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0" + "a5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad"}, + {"77c2b00716cec7213839159e404db50d", + "jelly better achieve collect unaware mountain thought cargo oxygen act " + "hood bridge", + "b5b6d0127db1a9d2226af0c3346031d77af31e918dba64287a1b44b8ebf63cdd52676f6" + "72a290aae502472cf2d602c051f3e6f18055e84e4c43897fc4e51a6ff"}, + {"b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", + "renew stay biology evidence goat welcome casual join adapt armor " + "shuffle fault little machine walk stumble urge swap", + "9248d83e06f4cd98debf5b6f010542760df925ce46cf38a1bdb4e4de7d21f5c39366941" + "c69e1bdbf2966e0f6e6dbece898a0e2f0a4c2b3e640953dfe8b7bbdc5"}, + {"3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", + "dignity pass list indicate nasty swamp pool script soccer toe leaf " + "photo multiply desk host tomato cradle drill spread actor shine " + "dismiss champion exotic", + "ff7f3184df8696d8bef94b6c03114dbee0ef89ff938712301d27ed8336ca89ef9635da2" + "0af07d4175f2bf5f3de130f39c9d9e8dd0472489c19b1a020a940da67"}, + {"0460ef47585604c5660618db2e6a7e7f", + "afford alter spike radar gate glance object seek swamp infant panel " + "yellow", + "65f93a9f36b6c85cbe634ffc1f99f2b82cbb10b31edc7f087b4f6cb9e976e9faf76ff41" + "f8f27c99afdf38f7a303ba1136ee48a4c1e7fcd3dba7aa876113a36e4"}, + {"72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", + "indicate race push merry suffer human cruise dwarf pole review arch " + "keep canvas theme poem divorce alter left", + "3bbf9daa0dfad8229786ace5ddb4e00fa98a044ae4c4975ffd5e094dba9e0bb289349db" + "e2091761f30f382d4e35c4a670ee8ab50758d2c55881be69e327117ba"}, + {"2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", + "clutch control vehicle tonight unusual clog visa ice plunge glimpse " + "recipe series open hour vintage deposit universe tip job dress radar " + "refuse motion taste", + "fe908f96f46668b2d5b37d82f558c77ed0d69dd0e7e043a5b0511c48c2f1064694a956f" + "86360c93dd04052a8899497ce9e985ebe0c8c52b955e6ae86d4ff4449"}, + {"eaebabb2383351fd31d703840b32e9e2", + "turtle front uncle idea crush write shrug there lottery flower risk " + "shell", + "bdfb76a0759f301b0b899a1e3985227e53b3f51e67e3f2a65363caedf3e32fde42a66c4" + "04f18d7b05818c95ef3ca1e5146646856c461c073169467511680876c"}, + {"7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", + "kiss carry display unusual confirm curtain upgrade antique rotate " + "hello void custom frequent obey nut hole price segment", + "ed56ff6c833c07982eb7119a8f48fd363c4a9b1601cd2de736b01045c5eb8ab4f57b079" + "403485d1c4924f0790dc10a971763337cb9f9c62226f64fff26397c79"}, + {"4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", + "exile ask congress lamp submit jacket era scheme attend cousin alcohol " + "catch course end lucky hurt sentence oven short ball bird grab wing " + "top", + "095ee6f817b4c2cb30a5a797360a81a40ab0f9a4e25ecd672a3f58a0b5ba0687c096a6b" + "14d2c0deb3bdefce4f61d01ae07417d502429352e27695163f7447a8c"}, + {"18ab19a9f54a9274f03e5209a2ac8a91", + "board flee heavy tunnel powder denial science ski answer betray cargo " + "cat", + "6eff1bb21562918509c73cb990260db07c0ce34ff0e3cc4a8cb3276129fbcb300bddfe0" + "05831350efd633909f476c45c88253276d9fd0df6ef48609e8bb7dca8"}, + {"18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", + "board blade invite damage undo sun mimic interest slam gaze truly " + "inherit resist great inject rocket museum chief", + "f84521c777a13b61564234bf8f8b62b3afce27fc4062b51bb5e62bdfecb23864ee6ecf0" + "7c1d5a97c0834307c5c852d8ceb88e7c97923c0a3b496bedd4e5f88a9"}, + {"15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", + "beyond stage sleep clip because twist token leaf atom beauty genius " + "food business side grid unable middle armed observe pair crouch " + "tonight away coconut", + "b15509eaa2d09d3efd3e006ef42151b30367dc6e3aa5e44caba3fe4d3e352e65101fbdb" + "86a96776b91946ff06f8eac594dc6ee1d3e82a42dfe1b40fef6bcc3fd"}, + }; + + for (const auto& entry : cases) { + std::vector bytes; + EXPECT_TRUE(base::HexStringToBytes(entry.entropy, &bytes)); + auto entropy = MnemonicToEntropy(entry.mnemonic); + EXPECT_EQ(base::ToLowerASCII(base::HexEncode(*entropy)), entry.entropy); + + EXPECT_EQ(GenerateMnemonic(bytes), entry.mnemonic); + auto seed = MnemonicToSeed(entry.mnemonic, "TREZOR"); + EXPECT_EQ(base::ToLowerASCII(base::HexEncode(*seed)), entry.seed); + } + + for (size_t i = 15; i <= 33; i += 2) { + EXPECT_FALSE(GenerateMnemonic(base::RandBytesAsVector(i))); + } + for (size_t i = 16; i <= 32; i += 4) { + auto result = GenerateMnemonic(base::RandBytesAsVector(i)); + ASSERT_TRUE(result); + auto words = base::SplitStringPiece(*result, " ", base::KEEP_WHITESPACE, + base::SPLIT_WANT_ALL); + // words count should be 12, 15, 18, 21, 24 + EXPECT_EQ(words.size(), (i / 4) * 3); + // Random generated entropy + EXPECT_NE(GenerateMnemonic(base::RandBytesAsVector(i)), + GenerateMnemonic(base::RandBytesAsVector(i))); + } +} + +TEST(BraveWalletUtilsUnitTest, MnemonicToSeedAndEntropy) { + const char valid_mnemonic[] = + "kingdom possible coast island six arrow fluid spell chunk loud glue " + "street"; + const char invalid_mnemonic1[] = + "lingdom possible coast island six arrow fluid spell chunk loud glue " + "street"; + const char invalid_mnemonic2[] = + "kingdom possible coast island six arrow fluid spell chunk loud glue"; + EXPECT_NE(MnemonicToSeed(valid_mnemonic, ""), std::nullopt); + EXPECT_NE(MnemonicToEntropy(valid_mnemonic), std::nullopt); + EXPECT_EQ(MnemonicToSeed(invalid_mnemonic1, ""), std::nullopt); + EXPECT_EQ(MnemonicToEntropy(invalid_mnemonic1), std::nullopt); + EXPECT_EQ(MnemonicToSeed(invalid_mnemonic2, ""), std::nullopt); + EXPECT_EQ(MnemonicToEntropy(invalid_mnemonic2), std::nullopt); + EXPECT_EQ(MnemonicToSeed("", ""), std::nullopt); + EXPECT_EQ(MnemonicToEntropy(""), std::nullopt); +} + +TEST(BraveWalletUtilsUnitTest, IsValidMnemonic) { + EXPECT_TRUE( + IsValidMnemonic("kingdom possible coast island six arrow fluid " + "spell chunk loud glue street")); + EXPECT_FALSE( + IsValidMnemonic("lingdom possible coast island six arrow fluid " + "spell chunk loud glue street")); + EXPECT_FALSE(IsValidMnemonic("kingdom possible coast island six arrow")); + EXPECT_FALSE(IsValidMnemonic("")); +} + +} // namespace brave_wallet::bip39 diff --git a/components/brave_wallet/browser/bitcoin/bitcoin_hd_keyring_unittest.cc b/components/brave_wallet/browser/bitcoin/bitcoin_hd_keyring_unittest.cc index b3b6f107f5ee..cf504fe627cc 100644 --- a/components/brave_wallet/browser/bitcoin/bitcoin_hd_keyring_unittest.cc +++ b/components/brave_wallet/browser/bitcoin/bitcoin_hd_keyring_unittest.cc @@ -10,11 +10,13 @@ #include #include "base/strings/string_number_conversions.h" -#include "brave/components/brave_wallet/browser/brave_wallet_utils.h" +#include "brave/components/brave_wallet/browser/bip39.h" #include "brave/components/brave_wallet/browser/test_utils.h" #include "testing/gtest/include/gtest/gtest.h" namespace brave_wallet { + +using bip39::MnemonicToSeed; using mojom::BitcoinKeyId; // https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki#test-vectors diff --git a/components/brave_wallet/browser/bitcoin/bitcoin_knapsack_solver_unittest.cc b/components/brave_wallet/browser/bitcoin/bitcoin_knapsack_solver_unittest.cc index 47a7d2eebeca..c170d1ef5c1c 100644 --- a/components/brave_wallet/browser/bitcoin/bitcoin_knapsack_solver_unittest.cc +++ b/components/brave_wallet/browser/bitcoin/bitcoin_knapsack_solver_unittest.cc @@ -10,13 +10,13 @@ #include "base/containers/span.h" #include "base/rand_util.h" #include "base/strings/string_number_conversions.h" +#include "brave/components/brave_wallet/browser/bip39.h" #include "brave/components/brave_wallet/browser/bitcoin/bitcoin_hd_keyring.h" #include "brave/components/brave_wallet/browser/bitcoin/bitcoin_serializer.h" -#include "brave/components/brave_wallet/browser/brave_wallet_utils.h" #include "brave/components/brave_wallet/browser/test_utils.h" #include "brave/components/brave_wallet/common/bitcoin_utils.h" #include "components/grit/brave_components_strings.h" -#include "crypto/sha2.h" +#include "crypto/hash.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/l10n/l10n_util.h" @@ -75,7 +75,7 @@ class BitcoinKnapsackSolverUnitTest : public testing::Test { tx_input.utxo_address = address; std::string txid_fake = address + base::NumberToString(amount); tx_input.utxo_outpoint.txid = - crypto::SHA256Hash(base::as_byte_span(txid_fake)); + crypto::hash::Sha256(base::as_byte_span(txid_fake)); tx_input.utxo_outpoint.index = tx_input.utxo_outpoint.txid.back(); tx_input.utxo_value = amount; @@ -87,7 +87,8 @@ class BitcoinKnapsackSolverUnitTest : public testing::Test { double longterm_fee_rate() const { return 3.0; } bool testnet_ = false; - BitcoinHDKeyring keyring_{*MnemonicToSeed(kMnemonicAbandonAbandon), testnet_}; + BitcoinHDKeyring keyring_{*bip39::MnemonicToSeed(kMnemonicAbandonAbandon), + testnet_}; }; TEST_F(BitcoinKnapsackSolverUnitTest, NoInputs) { diff --git a/components/brave_wallet/browser/bitcoin/bitcoin_max_send_solver_unittest.cc b/components/brave_wallet/browser/bitcoin/bitcoin_max_send_solver_unittest.cc index c8e763318624..7ea57f455c4d 100644 --- a/components/brave_wallet/browser/bitcoin/bitcoin_max_send_solver_unittest.cc +++ b/components/brave_wallet/browser/bitcoin/bitcoin_max_send_solver_unittest.cc @@ -9,13 +9,13 @@ #include "base/rand_util.h" #include "base/strings/string_number_conversions.h" +#include "brave/components/brave_wallet/browser/bip39.h" #include "brave/components/brave_wallet/browser/bitcoin/bitcoin_hd_keyring.h" #include "brave/components/brave_wallet/browser/bitcoin/bitcoin_serializer.h" -#include "brave/components/brave_wallet/browser/brave_wallet_utils.h" #include "brave/components/brave_wallet/browser/test_utils.h" #include "brave/components/brave_wallet/common/bitcoin_utils.h" #include "components/grit/brave_components_strings.h" -#include "crypto/sha2.h" +#include "crypto/hash.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/l10n/l10n_util.h" @@ -63,7 +63,7 @@ class BitcoinMaxSendSolverUnitTest : public testing::Test { tx_input.utxo_address = address; std::string txid_fake = address + base::NumberToString(amount); tx_input.utxo_outpoint.txid = - crypto::SHA256Hash(base::as_byte_span(txid_fake)); + crypto::hash::Sha256(base::as_byte_span(txid_fake)); tx_input.utxo_outpoint.index = tx_input.utxo_outpoint.txid.back(); tx_input.utxo_value = amount; @@ -74,7 +74,8 @@ class BitcoinMaxSendSolverUnitTest : public testing::Test { double longterm_fee_rate() const { return 3.0; } bool testnet_ = false; - BitcoinHDKeyring keyring_{*MnemonicToSeed(kMnemonicAbandonAbandon), testnet_}; + BitcoinHDKeyring keyring_{*bip39::MnemonicToSeed(kMnemonicAbandonAbandon), + testnet_}; }; TEST_F(BitcoinMaxSendSolverUnitTest, NoInputs) { diff --git a/components/brave_wallet/browser/bitcoin/bitcoin_test_utils.cc b/components/brave_wallet/browser/bitcoin/bitcoin_test_utils.cc index b204529ee773..954a7bd039db 100644 --- a/components/brave_wallet/browser/bitcoin/bitcoin_test_utils.cc +++ b/components/brave_wallet/browser/bitcoin/bitcoin_test_utils.cc @@ -14,14 +14,13 @@ #include "base/strings/string_split.h" #include "base/test/values_test_util.h" #include "base/values.h" +#include "brave/components/brave_wallet/browser/bip39.h" #include "brave/components/brave_wallet/browser/bitcoin/bitcoin_wallet_service.h" #include "brave/components/brave_wallet/browser/brave_wallet_utils.h" #include "brave/components/brave_wallet/browser/network_manager.h" #include "brave/components/brave_wallet/common/brave_wallet.mojom.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" using base::test::ParseJson; @@ -267,8 +266,8 @@ void BitcoinTestRpcServer::SetUpBitcoinRpc( account_index_ = account_index; if (mnemonic && account_index) { - keyring_ = - std::make_unique(*MnemonicToSeed(*mnemonic), false); + keyring_ = std::make_unique( + *bip39::MnemonicToSeed(*mnemonic), false); address_0_ = keyring_->GetAddress(*account_index_, *mojom::BitcoinKeyId::New(0, 0)) diff --git a/components/brave_wallet/browser/brave_wallet_service.cc b/components/brave_wallet/browser/brave_wallet_service.cc index 796f290fd913..7b588ff7bd02 100644 --- a/components/brave_wallet/browser/brave_wallet_service.cc +++ b/components/brave_wallet/browser/brave_wallet_service.cc @@ -32,6 +32,7 @@ #include "brave/components/brave_wallet/common/brave_wallet_types.h" #include "brave/components/brave_wallet/common/common_utils.h" #include "brave/components/brave_wallet/common/encoding_utils.h" +#include "brave/components/brave_wallet/common/eth_address.h" #include "brave/components/brave_wallet/common/fil_address.h" #include "brave/components/brave_wallet/common/solana_utils.h" #include "brave/components/brave_wallet/common/value_conversion_utils.h" @@ -1601,7 +1602,11 @@ void BraveWalletService::ConvertFEVMToFVMAddress( ConvertFEVMToFVMAddressCallback callback) { base::flat_map result; for (const auto& fevm_address : fevm_addresses) { - auto address = FilAddress::FromFEVMAddress(is_mainnet, fevm_address); + auto eth_address = EthAddress::FromHex(fevm_address); + if (!eth_address.IsValid()) { + continue; + } + auto address = FilAddress::FromFEVMAddress(is_mainnet, eth_address); DCHECK(result.find(fevm_address) == result.end()); if (!address.IsEmpty()) { result[fevm_address] = address.EncodeAsString(); diff --git a/components/brave_wallet/browser/brave_wallet_utils.cc b/components/brave_wallet/browser/brave_wallet_utils.cc index bea236ed3465..8f4ee64c0e78 100644 --- a/components/brave_wallet/browser/brave_wallet_utils.cc +++ b/components/brave_wallet/browser/brave_wallet_utils.cc @@ -12,11 +12,9 @@ #include "base/check.h" #include "base/containers/span.h" -#include "base/logging.h" #include "base/notreached.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/time/time.h" #include "base/values.h" @@ -33,12 +31,10 @@ #include "brave/components/brave_wallet/common/value_conversion_utils.h" #include "brave/components/constants/brave_services_key.h" #include "brave/components/version_info/version_info.h" -#include "brave/third_party/bip39wally-core-native/include/wally_bip39.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" #include "crypto/random.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" -#include "third_party/boringssl/src/include/openssl/evp.h" #include "ui/base/l10n/l10n_util.h" #include "url/gurl.h" @@ -46,27 +42,6 @@ namespace brave_wallet { namespace { -std::string GenerateMnemonicInternal(uint8_t* entropy, size_t size) { - char* words = nullptr; - std::string result; - if (bip39_mnemonic_from_bytes(nullptr, entropy, size, &words) != WALLY_OK) { - LOG(ERROR) << __func__ << ": bip39_mnemonic_from_bytes failed"; - return result; - } - result = words; - wally_free_string(words); - return result; -} - -bool IsValidEntropySize(size_t entropy_size) { - // entropy size should be 128, 160, 192, 224, 256 bits - if (entropy_size < 16 || entropy_size > 32 || entropy_size % 4 != 0) { - LOG(ERROR) << __func__ << ": Entropy should be 16, 20, 24, 28, 32 bytes"; - return false; - } - return true; -} - const base::flat_map kUnstoppableDomainsProxyReaderContractAddressMap = { // https://github.com/unstoppabledomains/uns/blob/abd9e12409094dd6ea8611ebffdade8db49c4b56/uns-config.json#L76 @@ -236,90 +211,6 @@ base::flat_map MakeBraveServicesKeyHeaders() { }; } -std::string GenerateMnemonic(size_t entropy_size) { - if (!IsValidEntropySize(entropy_size)) { - return ""; - } - - std::vector entropy(entropy_size); - crypto::RandBytes(entropy); - - return GenerateMnemonicInternal(entropy.data(), entropy.size()); -} - -std::string GenerateMnemonicForTest(const std::vector& entropy) { - return GenerateMnemonicInternal(const_cast(entropy.data()), - entropy.size()); -} - -std::unique_ptr> MnemonicToSeed( - base::cstring_view mnemonic, - std::string_view passphrase) { - if (!IsValidMnemonic(mnemonic)) { - return nullptr; - } - - std::unique_ptr> seed = - std::make_unique>(64); - const std::string salt = base::StrCat({"mnemonic", passphrase}); - int rv = PKCS5_PBKDF2_HMAC(mnemonic.data(), mnemonic.length(), - reinterpret_cast(salt.data()), - salt.length(), 2048, EVP_sha512(), seed->size(), - seed->data()); - return rv == 1 ? std::move(seed) : nullptr; -} - -std::unique_ptr> MnemonicToEntropy( - base::cstring_view mnemonic) { - if (!IsValidMnemonic(mnemonic)) { - return nullptr; - } - - const std::vector words = SplitString( - mnemonic, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - // size in bytes - size_t entropy_size = 0; - switch (words.size()) { - case 12: - entropy_size = 16; - break; - case 15: - entropy_size = 20; - break; - case 18: - entropy_size = 24; - break; - case 21: - entropy_size = 28; - break; - case 24: - entropy_size = 32; - break; - default: - return nullptr; - } - DCHECK(IsValidEntropySize(entropy_size)) << entropy_size; - - std::unique_ptr> entropy = - std::make_unique>(entropy_size); - - size_t written; - if (bip39_mnemonic_to_bytes(nullptr, mnemonic.c_str(), entropy->data(), - entropy->size(), &written) != WALLY_OK) { - LOG(ERROR) << "bip39_mnemonic_to_bytes failed"; - return nullptr; - } - return entropy; -} - -bool IsValidMnemonic(base::cstring_view mnemonic) { - if (bip39_mnemonic_validate(nullptr, mnemonic.c_str()) != WALLY_OK) { - LOG(ERROR) << __func__ << ": Invalid mnemonic: " << mnemonic; - return false; - } - return true; -} - bool EncodeString(std::string_view input, std::string* output) { if (!base::IsStringUTF8(input)) { return false; diff --git a/components/brave_wallet/browser/brave_wallet_utils.h b/components/brave_wallet/browser/brave_wallet_utils.h index 2c5f3b552569..6dd5a821730e 100644 --- a/components/brave_wallet/browser/brave_wallet_utils.h +++ b/components/brave_wallet/browser/brave_wallet_utils.h @@ -25,24 +25,6 @@ class GURL; namespace brave_wallet { -// Generate mnemonic from random entropy following BIP39. -// |entropy_size| should be specify in bytes -// If |entropy_size| is not in 16, 20, 24, 28, 32 range or allocation -// failure, the empty string will be returned. -std::string GenerateMnemonic(size_t entropy_size); -// Testing specific entropy -std::string GenerateMnemonicForTest(const std::vector& entropy); -// Generate seed from mnemonic following BIP39. -// If allocation failed, it would return nullptr. Otherwise 512 bits seed will -// be returned. -std::unique_ptr> MnemonicToSeed( - base::cstring_view mnemonic, - std::string_view passphrase = ""); -// This is mainly used for restoring legacy brave crypto wallet -std::unique_ptr> MnemonicToEntropy( - base::cstring_view mnemonic); -bool IsValidMnemonic(base::cstring_view mnemonic); - bool EncodeString(std::string_view input, std::string* output); bool EncodeStringArray(base::span input, std::string* output); diff --git a/components/brave_wallet/browser/brave_wallet_utils_unittest.cc b/components/brave_wallet/browser/brave_wallet_utils_unittest.cc index 502cb8f5243b..1e0b98d41f11 100644 --- a/components/brave_wallet/browser/brave_wallet_utils_unittest.cc +++ b/components/brave_wallet/browser/brave_wallet_utils_unittest.cc @@ -5,20 +5,17 @@ #include "brave/components/brave_wallet/browser/brave_wallet_utils.h" -#include -#include -#include #include #include #include -#include #include #include #include #include "base/containers/contains.h" -#include "base/containers/flat_set.h" +#include "base/rand_util.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/test/gtest_util.h" #include "base/test/scoped_feature_list.h" @@ -27,7 +24,6 @@ #include "brave/components/brave_wallet/browser/brave_wallet_constants.h" #include "brave/components/brave_wallet/browser/brave_wallet_prefs.h" #include "brave/components/brave_wallet/browser/network_manager.h" -#include "brave/components/brave_wallet/browser/pref_names.h" #include "brave/components/brave_wallet/browser/test_utils.h" #include "brave/components/brave_wallet/common/brave_wallet.mojom.h" #include "brave/components/brave_wallet/common/brave_wallet_types.h" @@ -36,9 +32,6 @@ #include "brave/components/brave_wallet/common/features.h" #include "brave/components/brave_wallet/common/test_utils.h" #include "brave/components/brave_wallet/common/value_conversion_utils.h" -#include "components/prefs/pref_registry_simple.h" -#include "components/prefs/scoped_user_pref_update.h" -#include "components/prefs/testing_pref_service.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -52,200 +45,6 @@ using testing::Not; namespace brave_wallet { -TEST(BraveWalletUtilsUnitTest, Mnemonic) { - const struct { - base::cstring_view entropy; - base::cstring_view mnemonic; - base::cstring_view seed; - } cases[] = { - {"00000000000000000000000000000000", kMnemonicAbandonAbandon, - "c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a69" - "87" - "599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04"}, - {"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank " - "yellow", - "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1" - "29" - "6106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607"}, - {"80808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice " - "cage above", - "d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f1" - "2eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8"}, - {"ffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", - "ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a133325729" - "17f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069"}, - {"000000000000000000000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon agent", - "035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9" - "a565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa"}, - {"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank " - "year wave sausage worth useful legal will", - "f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c3" - "92d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd"}, - {"808080808080808080808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice " - "cage absurd amount doctor acoustic avoid letter always", - "107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913f" - "fb796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65"}, - {"ffffffffffffffffffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " - "when", - "0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b43" - "348d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528"}, - {"0000000000000000000000000000000000000000000000000000000000000000", - "abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon abandon abandon abandon " - "abandon abandon abandon abandon abandon abandon abandon art", - "bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4" - "d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8"}, - {"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f", - "legal winner thank year wave sausage worth useful legal winner thank " - "year wave sausage worth useful legal winner thank year wave sausage " - "worth title", - "bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146a" - "d717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87"}, - {"8080808080808080808080808080808080808080808080808080808080808080", - "letter advice cage absurd amount doctor acoustic avoid letter advice " - "cage absurd amount doctor acoustic avoid letter advice cage absurd " - "amount doctor acoustic bless", - "c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61a" - "f0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f"}, - {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo " - "zoo zoo zoo zoo zoo zoo vote", - "dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0" - "a5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad"}, - {"77c2b00716cec7213839159e404db50d", - "jelly better achieve collect unaware mountain thought cargo oxygen act " - "hood bridge", - "b5b6d0127db1a9d2226af0c3346031d77af31e918dba64287a1b44b8ebf63cdd52676f6" - "72a290aae502472cf2d602c051f3e6f18055e84e4c43897fc4e51a6ff"}, - {"b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b", - "renew stay biology evidence goat welcome casual join adapt armor " - "shuffle fault little machine walk stumble urge swap", - "9248d83e06f4cd98debf5b6f010542760df925ce46cf38a1bdb4e4de7d21f5c39366941" - "c69e1bdbf2966e0f6e6dbece898a0e2f0a4c2b3e640953dfe8b7bbdc5"}, - {"3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982", - "dignity pass list indicate nasty swamp pool script soccer toe leaf " - "photo multiply desk host tomato cradle drill spread actor shine " - "dismiss champion exotic", - "ff7f3184df8696d8bef94b6c03114dbee0ef89ff938712301d27ed8336ca89ef9635da2" - "0af07d4175f2bf5f3de130f39c9d9e8dd0472489c19b1a020a940da67"}, - {"0460ef47585604c5660618db2e6a7e7f", - "afford alter spike radar gate glance object seek swamp infant panel " - "yellow", - "65f93a9f36b6c85cbe634ffc1f99f2b82cbb10b31edc7f087b4f6cb9e976e9faf76ff41" - "f8f27c99afdf38f7a303ba1136ee48a4c1e7fcd3dba7aa876113a36e4"}, - {"72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f", - "indicate race push merry suffer human cruise dwarf pole review arch " - "keep canvas theme poem divorce alter left", - "3bbf9daa0dfad8229786ace5ddb4e00fa98a044ae4c4975ffd5e094dba9e0bb289349db" - "e2091761f30f382d4e35c4a670ee8ab50758d2c55881be69e327117ba"}, - {"2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416", - "clutch control vehicle tonight unusual clog visa ice plunge glimpse " - "recipe series open hour vintage deposit universe tip job dress radar " - "refuse motion taste", - "fe908f96f46668b2d5b37d82f558c77ed0d69dd0e7e043a5b0511c48c2f1064694a956f" - "86360c93dd04052a8899497ce9e985ebe0c8c52b955e6ae86d4ff4449"}, - {"eaebabb2383351fd31d703840b32e9e2", - "turtle front uncle idea crush write shrug there lottery flower risk " - "shell", - "bdfb76a0759f301b0b899a1e3985227e53b3f51e67e3f2a65363caedf3e32fde42a66c4" - "04f18d7b05818c95ef3ca1e5146646856c461c073169467511680876c"}, - {"7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78", - "kiss carry display unusual confirm curtain upgrade antique rotate " - "hello void custom frequent obey nut hole price segment", - "ed56ff6c833c07982eb7119a8f48fd363c4a9b1601cd2de736b01045c5eb8ab4f57b079" - "403485d1c4924f0790dc10a971763337cb9f9c62226f64fff26397c79"}, - {"4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef", - "exile ask congress lamp submit jacket era scheme attend cousin alcohol " - "catch course end lucky hurt sentence oven short ball bird grab wing " - "top", - "095ee6f817b4c2cb30a5a797360a81a40ab0f9a4e25ecd672a3f58a0b5ba0687c096a6b" - "14d2c0deb3bdefce4f61d01ae07417d502429352e27695163f7447a8c"}, - {"18ab19a9f54a9274f03e5209a2ac8a91", - "board flee heavy tunnel powder denial science ski answer betray cargo " - "cat", - "6eff1bb21562918509c73cb990260db07c0ce34ff0e3cc4a8cb3276129fbcb300bddfe0" - "05831350efd633909f476c45c88253276d9fd0df6ef48609e8bb7dca8"}, - {"18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4", - "board blade invite damage undo sun mimic interest slam gaze truly " - "inherit resist great inject rocket museum chief", - "f84521c777a13b61564234bf8f8b62b3afce27fc4062b51bb5e62bdfecb23864ee6ecf0" - "7c1d5a97c0834307c5c852d8ceb88e7c97923c0a3b496bedd4e5f88a9"}, - {"15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419", - "beyond stage sleep clip because twist token leaf atom beauty genius " - "food business side grid unable middle armed observe pair crouch " - "tonight away coconut", - "b15509eaa2d09d3efd3e006ef42151b30367dc6e3aa5e44caba3fe4d3e352e65101fbdb" - "86a96776b91946ff06f8eac594dc6ee1d3e82a42dfe1b40fef6bcc3fd"}, - }; - - for (const auto& entry : cases) { - std::vector bytes; - EXPECT_TRUE(base::HexStringToBytes(entry.entropy, &bytes)); - std::unique_ptr> entropy = - MnemonicToEntropy(entry.mnemonic); - EXPECT_EQ(base::ToLowerASCII(base::HexEncode(*entropy)), entry.entropy); - - EXPECT_EQ(GenerateMnemonicForTest(bytes), entry.mnemonic); - std::unique_ptr> seed = - MnemonicToSeed(entry.mnemonic, "TREZOR"); - EXPECT_EQ(base::ToLowerASCII(base::HexEncode(*seed)), entry.seed); - } - - for (size_t i = 15; i <= 33; i += 2) { - EXPECT_EQ(GenerateMnemonic(i), ""); - } - for (size_t i = 16; i <= 32; i += 4) { - std::string result = GenerateMnemonic(i); - EXPECT_NE(result, ""); - std::istringstream buf(result); - std::istream_iterator begin(buf), end; - std::vector words(begin, end); - // words count should be 12, 15, 18, 21, 24 - EXPECT_EQ(words.size(), (i / 4) * 3); - // Random generated entropy - EXPECT_NE(GenerateMnemonic(i), GenerateMnemonic(i)); - } -} - -TEST(BraveWalletUtilsUnitTest, MnemonicToSeedAndEntropy) { - const char valid_mnemonic[] = - "kingdom possible coast island six arrow fluid spell chunk loud glue " - "street"; - const char invalid_mnemonic1[] = - "lingdom possible coast island six arrow fluid spell chunk loud glue " - "street"; - const char invalid_mnemonic2[] = - "kingdom possible coast island six arrow fluid spell chunk loud glue"; - EXPECT_NE(MnemonicToSeed(valid_mnemonic, ""), nullptr); - EXPECT_NE(MnemonicToEntropy(valid_mnemonic), nullptr); - EXPECT_EQ(MnemonicToSeed(invalid_mnemonic1, ""), nullptr); - EXPECT_EQ(MnemonicToEntropy(invalid_mnemonic1), nullptr); - EXPECT_EQ(MnemonicToSeed(invalid_mnemonic2, ""), nullptr); - EXPECT_EQ(MnemonicToEntropy(invalid_mnemonic2), nullptr); - EXPECT_EQ(MnemonicToSeed("", ""), nullptr); - EXPECT_EQ(MnemonicToEntropy(""), nullptr); -} - -TEST(BraveWalletUtilsUnitTest, IsValidMnemonic) { - EXPECT_TRUE( - IsValidMnemonic("kingdom possible coast island six arrow fluid " - "spell chunk loud glue street")); - EXPECT_FALSE( - IsValidMnemonic("lingdom possible coast island six arrow fluid " - "spell chunk loud glue street")); - EXPECT_FALSE(IsValidMnemonic("kingdom possible coast island six arrow")); - EXPECT_FALSE(IsValidMnemonic("")); -} - TEST(BraveWalletUtilsUnitTest, EncodeString) { std::string output; EXPECT_TRUE(EncodeString("one", &output)); diff --git a/components/brave_wallet/browser/eip1559_transaction.cc b/components/brave_wallet/browser/eip1559_transaction.cc index 8e18c12dfbd2..24f04df7de8e 100644 --- a/components/brave_wallet/browser/eip1559_transaction.cc +++ b/components/brave_wallet/browser/eip1559_transaction.cc @@ -10,7 +10,6 @@ #include #include "base/containers/extend.h" -#include "base/containers/to_vector.h" #include "base/values.h" #include "brave/components/brave_wallet/browser/rlp_encode.h" #include "brave/components/brave_wallet/common/hash_utils.h" @@ -272,11 +271,9 @@ std::optional Eip1559Transaction::FromValue( return tx; } -std::vector Eip1559Transaction::GetMessageToSign(uint256_t chain_id, - bool hash) const { +std::vector Eip1559Transaction::GetMessageToSign( + uint256_t chain_id) const { DCHECK(nonce_); - std::vector result; - result.push_back(type_); base::Value::List list; list.Append(RLPUint256ToBlob(chain_id_)); @@ -289,8 +286,10 @@ std::vector Eip1559Transaction::GetMessageToSign(uint256_t chain_id, list.Append(base::Value(data_)); list.Append(base::Value(AccessListToValue(access_list_))); + std::vector result; + result.push_back(type_); base::Extend(result, RLPEncode(list)); - return hash ? base::ToVector(KeccakHash(result)) : result; + return result; } std::string Eip1559Transaction::GetSignedTransaction() const { @@ -337,14 +336,6 @@ base::Value::Dict Eip1559Transaction::ToValue() const { return tx; } -uint256_t Eip1559Transaction::GetUpfrontCost(uint256_t block_base_fee) const { - uint256_t inclusion_fee_per_gas = - std::min(max_priority_fee_per_gas_, max_fee_per_gas_ - block_base_fee); - uint256_t gas_price = inclusion_fee_per_gas + block_base_fee; - - return gas_limit_ * gas_price + value_; -} - std::vector Eip1559Transaction::Serialize() const { base::Value::List list; list.Append(RLPUint256ToBlob(chain_id_)); diff --git a/components/brave_wallet/browser/eip1559_transaction.h b/components/brave_wallet/browser/eip1559_transaction.h index a58c6d3b2fd7..921f10b9f53e 100644 --- a/components/brave_wallet/browser/eip1559_transaction.h +++ b/components/brave_wallet/browser/eip1559_transaction.h @@ -63,10 +63,9 @@ class Eip1559Transaction : public Eip2930Transaction { gas_estimation_ = estimation; } - // keccak256(0x02 || rlp([chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, - // gasLimit, destination, value, data, access_list])) - std::vector GetMessageToSign(uint256_t chain_id = 0, - bool hash = true) const override; + // 0x02 || rlp([chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, + // gasLimit, destination, value, data, access_list]) + std::vector GetMessageToSign(uint256_t chain_id) const override; // 0x02 || rlp([chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, // destination, value, data, accessList, signatureYParity, signatureR, @@ -80,8 +79,6 @@ class Eip1559Transaction : public Eip2930Transaction { base::Value::Dict ToValue() const override; - uint256_t GetUpfrontCost(uint256_t block_base_fee = 0) const override; - protected: Eip1559Transaction(std::optional nonce, uint256_t gas_price, diff --git a/components/brave_wallet/browser/eip1559_transaction_unittest.cc b/components/brave_wallet/browser/eip1559_transaction_unittest.cc index 841f324cc4d5..0571d81485fc 100644 --- a/components/brave_wallet/browser/eip1559_transaction_unittest.cc +++ b/components/brave_wallet/browser/eip1559_transaction_unittest.cc @@ -49,7 +49,7 @@ TEST(Eip1559TransactionUnitTest, GetMessageToSign) { access_list->push_back(item); - EXPECT_EQ(base::ToLowerASCII(base::HexEncode(tx.GetMessageToSign())), + EXPECT_EQ(base::ToLowerASCII(base::HexEncode(tx.GetHashedMessageToSign(0))), "fa81814f7dd57bad435657a05eabdba2815f41e3f15ddd6139027e7db56b0dea"); } @@ -142,27 +142,13 @@ TEST(Eip1559TransactionUnitTest, GetSignedTransactionAndHash) { nullptr)); int recid; - const std::vector signature = - key.SignCompact(tx.GetMessageToSign(), &recid); - tx.ProcessSignature(signature, recid); + auto signature = *key.SignCompact(tx.GetHashedMessageToSign(0), &recid); + tx.ProcessSignature(signature, recid, 0); EXPECT_EQ(tx.GetSignedTransaction(), entry.signed_tx); EXPECT_EQ(tx.GetTransactionHash(), entry.hash); } } -TEST(Eip1559TransactionUnitTest, GetUpfrontCost) { - Eip1559Transaction tx = - *Eip1559Transaction::FromTxData(mojom::TxData1559::New( - mojom::TxData::New("0x00", "0x00", "0x64", - "0x0101010101010101010101010101010101010101", - "0x06", std::vector(), false, - std::nullopt), - "0x04", "0x8", "0xA", nullptr)); - EXPECT_EQ(tx.GetUpfrontCost(), uint256_t(806)); - EXPECT_EQ(tx.GetUpfrontCost(0), uint256_t(806)); - EXPECT_EQ(tx.GetUpfrontCost(4), uint256_t(1006)); -} - TEST(Eip1559TransactionUnitTest, Serialization) { Eip1559Transaction tx = *Eip1559Transaction::FromTxData(mojom::TxData1559::New( diff --git a/components/brave_wallet/browser/eip2930_transaction.cc b/components/brave_wallet/browser/eip2930_transaction.cc index 83e5d560b83f..509a29876785 100644 --- a/components/brave_wallet/browser/eip2930_transaction.cc +++ b/components/brave_wallet/browser/eip2930_transaction.cc @@ -9,7 +9,6 @@ #include #include "base/containers/extend.h" -#include "base/containers/to_vector.h" #include "base/values.h" #include "brave/components/brave_wallet/browser/rlp_encode.h" #include "brave/components/brave_wallet/common/eth_address.h" @@ -163,11 +162,9 @@ Eip2930Transaction::ValueToAccessList(const base::Value::List& value) { return access_list; } -std::vector Eip2930Transaction::GetMessageToSign(uint256_t chain_id, - bool hash) const { +std::vector Eip2930Transaction::GetMessageToSign( + uint256_t chain_id) const { DCHECK(nonce_); - std::vector result; - result.push_back(type_); base::Value::List list; list.Append(RLPUint256ToBlob(chain_id_)); @@ -179,8 +176,10 @@ std::vector Eip2930Transaction::GetMessageToSign(uint256_t chain_id, list.Append(base::Value(data_)); list.Append(base::Value(AccessListToValue(access_list_))); + std::vector result; + result.push_back(type_); base::Extend(result, RLPEncode(list)); - return hash ? base::ToVector(KeccakHash(result)) : result; + return result; } std::string Eip2930Transaction::GetSignedTransaction() const { @@ -197,7 +196,7 @@ std::string Eip2930Transaction::GetTransactionHash() const { return ToHex(KeccakHash(Serialize())); } -void Eip2930Transaction::ProcessSignature(const std::vector signature, +void Eip2930Transaction::ProcessSignature(base::span signature, int recid, uint256_t chain_id) { EthTransaction::ProcessSignature(signature, recid, chain_id_); diff --git a/components/brave_wallet/browser/eip2930_transaction.h b/components/brave_wallet/browser/eip2930_transaction.h index e02fadb5998f..f197edb60458 100644 --- a/components/brave_wallet/browser/eip2930_transaction.h +++ b/components/brave_wallet/browser/eip2930_transaction.h @@ -50,10 +50,9 @@ class Eip2930Transaction : public EthTransaction { const AccessList* access_list() const { return &access_list_; } AccessList* access_list() { return &access_list_; } - // keccak256(0x01 || rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, - // accessList])) - std::vector GetMessageToSign(uint256_t chain_id = 0, - bool hash = true) const override; + // 0x01 || rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, + // accessList]) + std::vector GetMessageToSign(uint256_t chain_id) const override; // 0x01 || rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, // accessList, signatureYParity, signatureR, signatureS]) @@ -63,9 +62,9 @@ class Eip2930Transaction : public EthTransaction { // accessList, signatureYParity, signatureR, signatureS])) std::string GetTransactionHash() const override; - void ProcessSignature(const std::vector signature, + void ProcessSignature(base::span signature, int recid, - uint256_t chain_id = 0) override; + uint256_t chain_id) override; bool IsSigned() const override; diff --git a/components/brave_wallet/browser/eip2930_transaction_unittest.cc b/components/brave_wallet/browser/eip2930_transaction_unittest.cc index 4237179fa429..468015c60bc5 100644 --- a/components/brave_wallet/browser/eip2930_transaction_unittest.cc +++ b/components/brave_wallet/browser/eip2930_transaction_unittest.cc @@ -74,7 +74,7 @@ TEST(Eip2930TransactionUnitTest, AccessListAndValue) { EXPECT_EQ(*access_list_from_value, access_list); } -TEST(Eip2930TransactionUnitTest, GetMessageToSign) { +TEST(Eip2930TransactionUnitTest, GetHashedMessageToSign) { std::vector data; EXPECT_TRUE(base::HexStringToBytes("010200", &data)); Eip2930Transaction tx = *Eip2930Transaction::FromTxData( @@ -93,7 +93,7 @@ TEST(Eip2930TransactionUnitTest, GetMessageToSign) { access_list->push_back(item); - EXPECT_EQ(base::ToLowerASCII(base::HexEncode(tx.GetMessageToSign())), + EXPECT_EQ(base::ToLowerASCII(base::HexEncode(tx.GetHashedMessageToSign(0))), "78528e2724aa359c58c13e43a7c467eb721ce8d410c2a12ee62943a3aaefb60b"); } @@ -125,11 +125,10 @@ TEST(Eip2930TransactionUnitTest, GetSignedTransactionAndHash) { HDKey key; key.SetPrivateKey(private_key); int recid; - const std::vector signature = - key.SignCompact(tx.GetMessageToSign(), &recid); + auto signature = *key.SignCompact(tx.GetHashedMessageToSign(0), &recid); ASSERT_FALSE(tx.IsSigned()); - tx.ProcessSignature(signature, recid); + tx.ProcessSignature(signature, recid, 0); ASSERT_TRUE(tx.IsSigned()); EXPECT_EQ( tx.GetSignedTransaction(), diff --git a/components/brave_wallet/browser/eth_transaction.cc b/components/brave_wallet/browser/eth_transaction.cc index cc172974c1fa..9848e8390e93 100644 --- a/components/brave_wallet/browser/eth_transaction.cc +++ b/components/brave_wallet/browser/eth_transaction.cc @@ -172,8 +172,8 @@ std::optional EthTransaction::FromValue( return tx; } -std::vector EthTransaction::GetMessageToSign(uint256_t chain_id, - bool hash) const { +std::vector EthTransaction::GetMessageToSign( + uint256_t chain_id) const { DCHECK(nonce_); base::Value::List list; list.Append(RLPUint256ToBlob(nonce_.value())); @@ -188,8 +188,12 @@ std::vector EthTransaction::GetMessageToSign(uint256_t chain_id, list.Append(RLPUint256ToBlob(0)); } - auto result = RLPEncode(list); - return hash ? base::ToVector(KeccakHash(result)) : result; + return RLPEncode(list); +} + +KeccakHashArray EthTransaction::GetHashedMessageToSign( + uint256_t chain_id) const { + return KeccakHash(GetMessageToSign(chain_id)); } std::string EthTransaction::GetSignedTransaction() const { @@ -223,7 +227,7 @@ bool EthTransaction::ProcessVRS(const std::vector& v, } // signature and recid will be used to produce v, r, s -void EthTransaction::ProcessSignature(const std::vector signature, +void EthTransaction::ProcessSignature(base::span signature, int recid, uint256_t chain_id) { if (signature.size() != 64) { @@ -281,10 +285,6 @@ uint256_t EthTransaction::GetDataFee() const { return cost; } -uint256_t EthTransaction::GetUpfrontCost(uint256_t block_base_fee) const { - return gas_limit_ * gas_price_ + value_; -} - base::Value EthTransaction::Serialize() const { base::Value::List list; list.Append(RLPUint256ToBlob(nonce_.value())); diff --git a/components/brave_wallet/browser/eth_transaction.h b/components/brave_wallet/browser/eth_transaction.h index 126e8d2b435c..9c1519adcc21 100644 --- a/components/brave_wallet/browser/eth_transaction.h +++ b/components/brave_wallet/browser/eth_transaction.h @@ -14,6 +14,7 @@ #include "brave/components/brave_wallet/common/brave_wallet.mojom.h" #include "brave/components/brave_wallet/common/brave_wallet_types.h" #include "brave/components/brave_wallet/common/eth_address.h" +#include "brave/components/brave_wallet/common/hash_utils.h" namespace base { class Value; @@ -68,14 +69,12 @@ class EthTransaction { const std::vector& s); bool IsToCreationAddress() const { return to_.IsEmpty(); } - // return - // if hash == true: - // keccack(rlp([nonce, gasPrice, gasLimit, to, value, data, chainID, 0, 0])) - // else: - // rlp([nonce, gasPrice, gasLimit, to, value, data, chainID, 0, 0]) + // return rlp([nonce, gasPrice, gasLimit, to, value, data, chainID, 0, 0]) // Support EIP-155 chain id - virtual std::vector GetMessageToSign(uint256_t chain_id, - bool hash = true) const; + virtual std::vector GetMessageToSign(uint256_t chain_id) const; + + // keccak(GetMessageToSign(chain_id)) + KeccakHashArray GetHashedMessageToSign(uint256_t chain_id) const; // return rlp([nonce, gasPrice, gasLimit, to, value, data, v, r, s]) virtual std::string GetSignedTransaction() const; @@ -85,7 +84,7 @@ class EthTransaction { // signature and recid will be used to produce v, r, s // Support EIP-155 chain id - virtual void ProcessSignature(const std::vector signature, + virtual void ProcessSignature(base::span signature, int recid, uint256_t chain_id); @@ -97,9 +96,6 @@ class EthTransaction { uint256_t GetBaseFee() const; // Gas paid for the data. virtual uint256_t GetDataFee() const; - // The up front amount that an account must have for this transaction to be - // valid - virtual uint256_t GetUpfrontCost(uint256_t block_base_fee = 0) const; protected: // type 0 would be LegacyTransaction diff --git a/components/brave_wallet/browser/eth_transaction_unittest.cc b/components/brave_wallet/browser/eth_transaction_unittest.cc index c9a1da94a178..b59c40ca0cd4 100644 --- a/components/brave_wallet/browser/eth_transaction_unittest.cc +++ b/components/brave_wallet/browser/eth_transaction_unittest.cc @@ -40,11 +40,12 @@ TEST(EthTransactionUnitTest, GetMessageToSign) { "0xbe862ad9abfe6f22bcb087716c7d89a26051f74c", "0x016345785d8a0000", data, false, std::nullopt)); - EXPECT_EQ(base::ToLowerASCII(base::HexEncode(tx1.GetMessageToSign(0))), + EXPECT_EQ(base::ToLowerASCII(base::HexEncode(tx1.GetHashedMessageToSign(0))), "61e1ec33764304dddb55348e7883d4437426f44ab3ef65e6da1e025734c03ff0"); - EXPECT_EQ(base::ToLowerASCII(base::HexEncode(tx1.GetMessageToSign(1337))), - "9ad82175b6921c5525fc52ebc08b97118cc9709952a16b2249a3f42d44614721"); + EXPECT_EQ( + base::ToLowerASCII(base::HexEncode(tx1.GetHashedMessageToSign(1337))), + "9ad82175b6921c5525fc52ebc08b97118cc9709952a16b2249a3f42d44614721"); data.clear(); EthTransaction tx2 = *EthTransaction::FromTxData( @@ -53,11 +54,11 @@ TEST(EthTransactionUnitTest, GetMessageToSign) { "0x2386f26fc10000", data, false, std::nullopt)); // with chain id (mainnet) - EXPECT_EQ(base::ToLowerASCII(base::HexEncode(tx2.GetMessageToSign(1))), + EXPECT_EQ(base::ToLowerASCII(base::HexEncode(tx2.GetHashedMessageToSign(1))), "f97c73fdca079da7652dbc61a46cd5aeef804008e057be3e712c43eac389aaf0"); EXPECT_EQ( - base::ToLowerASCII(base::HexEncode(tx2.GetMessageToSign(1, false))), + base::ToLowerASCII(base::HexEncode(tx2.GetMessageToSign(1))), "eb0b85051f4d5c0082520894656e929d6fc0cac52d3d9526d288fe02dcd56fbd872386f" "26fc1000080018080"); @@ -107,7 +108,7 @@ TEST(EthTransactionUnitTest, GetMessageToSign) { entry.nonce, entry.gas_price, entry.gas_limit, entry.to, entry.value, std::vector(), false, std::nullopt)); // with chain id (mainnet) - EXPECT_EQ(base::ToLowerASCII(base::HexEncode(tx.GetMessageToSign(1))), + EXPECT_EQ(base::ToLowerASCII(base::HexEncode(tx.GetHashedMessageToSign(1))), entry.hash); } } @@ -125,12 +126,12 @@ TEST(EthTransactionUnitTest, GetSignedTransactionAndHash) { "0x3535353535353535353535353535353535353535", "0x0de0b6b3a7640000", std::vector(), false, std::nullopt)); - const std::vector message = tx.GetMessageToSign(1); + auto message = tx.GetHashedMessageToSign(1); EXPECT_EQ(base::ToLowerASCII(base::HexEncode(message)), "daf5a779ae972f972197303d7b574746c7ef83eadac0f2791ad23db92e4c8e53"); int recid; - const std::vector signature = key.SignCompact(message, &recid); + auto signature = *key.SignCompact(message, &recid); // invalid tx.ProcessSignature(std::vector(63), recid, 1); @@ -165,12 +166,11 @@ TEST(EthTransactionUnitTest, GetSignedTransactionAndHash) { "67CBE9D8997F761AECB703304B3800CCF555C9F3DC64214B297FB1966A3B6D83"); // Bigger chain_id - const std::vector message1337 = tx.GetMessageToSign(1337); + auto message1337 = tx.GetHashedMessageToSign(1337); EXPECT_EQ(base::ToLowerASCII(base::HexEncode(message1337)), "9df81edc908cd622cbbab86525a4588fdcbaf6c88757f39b42b1f8f58fd617c2"); recid = 0; - const std::vector signature1337 = - key.SignCompact(message1337, &recid); + auto signature1337 = *key.SignCompact(message1337, &recid); tx.ProcessSignature(signature1337, recid, 1337); EXPECT_EQ(tx.GetSignedTransaction(), "0xf86e098504a817c8008252089435353535353535353535353535353535353535" @@ -229,13 +229,6 @@ TEST(EthTransactionUnitTest, GetDataFee) { EXPECT_EQ(tx2.GetDataFee(), uint256_t(1716)); } -TEST(EthTransactionUnitTest, GetUpFrontCost) { - EthTransaction tx = *EthTransaction::FromTxData(mojom::TxData::New( - "0x00", "0x3E8", "0x989680", "0x3535353535353535353535353535353535353535", - "0x2A", std::vector(), false, std::nullopt)); - EXPECT_EQ(tx.GetUpfrontCost(), uint256_t(10000000042)); -} - TEST(EthTransactionUnitTest, FromTxData) { auto tx = EthTransaction::FromTxData(mojom::TxData::New( "0x01", "0x3E8", "0x989680", "0x3535353535353535353535353535353535353535", diff --git a/components/brave_wallet/browser/eth_tx_manager.cc b/components/brave_wallet/browser/eth_tx_manager.cc index 219988fb722b..c3a60c848c48 100644 --- a/components/brave_wallet/browser/eth_tx_manager.cc +++ b/components/brave_wallet/browser/eth_tx_manager.cc @@ -14,7 +14,6 @@ #include #include "base/functional/bind.h" -#include "base/logging.h" #include "brave/components/brave_wallet/browser/account_resolver_delegate.h" #include "brave/components/brave_wallet/browser/blockchain_registry.h" #include "brave/components/brave_wallet/browser/brave_wallet_constants.h" @@ -413,7 +412,6 @@ void EthTxManager::GetNonceForHardwareTransaction( GetNonceForHardwareTransactionCallback callback) { std::unique_ptr meta = GetEthTxStateManager().GetEthTx(tx_meta_id); if (!meta) { - LOG(ERROR) << "No transaction found"; std::move(callback).Run(std::nullopt); return; } @@ -437,7 +435,6 @@ void EthTxManager::GetEthTransactionMessageToSign( GetEthTransactionMessageToSignCallback callback) { std::unique_ptr meta = GetEthTxStateManager().GetEthTx(tx_meta_id); if (!meta) { - VLOG(1) << __FUNCTION__ << "No transaction found with id:" << tx_meta_id; std::move(callback).Run(std::nullopt); return; } @@ -447,7 +444,7 @@ void EthTxManager::GetEthTransactionMessageToSign( return; } std::move(callback).Run(base::ToLowerASCII( - base::HexEncode(meta->tx()->GetMessageToSign(chain_id, false)))); + base::HexEncode(meta->tx()->GetMessageToSign(chain_id)))); } mojom::CoinType EthTxManager::GetCoinType() const { @@ -462,8 +459,6 @@ void EthTxManager::OnGetNextNonceForHardware( if (!success) { meta->set_status(mojom::TransactionStatus::Error); tx_state_manager().AddOrUpdateTx(*meta); - VLOG(1) << __FUNCTION__ - << "GetNextNonce failed for tx with meta:" << meta->id(); std::move(callback).Run(std::nullopt); return; } @@ -481,7 +476,6 @@ void EthTxManager::ProcessEthHardwareSignature( ProcessEthHardwareSignatureCallback callback) { std::unique_ptr meta = GetEthTxStateManager().GetEthTx(tx_meta_id); if (!meta) { - VLOG(1) << __FUNCTION__ << "No transaction found with id" << tx_meta_id; std::move(callback).Run( false, mojom::ProviderError::kResourceNotFound, l10n_util::GetStringUTF8(IDS_BRAVE_WALLET_TRANSACTION_NOT_FOUND)); @@ -489,9 +483,6 @@ void EthTxManager::ProcessEthHardwareSignature( } if (!meta->tx()->ProcessVRS(hw_signature->v_bytes, hw_signature->r_bytes, hw_signature->s_bytes)) { - VLOG(1) << __FUNCTION__ - << "Could not initialize a transaction with v,r,s for id:" - << tx_meta_id; meta->set_status(mojom::TransactionStatus::Error); tx_state_manager().AddOrUpdateTx(*meta); std::move(callback).Run( @@ -531,7 +522,6 @@ void EthTxManager::ApproveTransaction(const std::string& tx_meta_id, ApproveTransactionCallback callback) { std::unique_ptr meta = GetEthTxStateManager().GetEthTx(tx_meta_id); if (!meta) { - LOG(ERROR) << "No transaction found"; std::move(callback).Run( false, mojom::ProviderErrorUnion::NewProviderError( @@ -561,7 +551,6 @@ void EthTxManager::OnGetNextNonce(std::unique_ptr meta, if (!success) { meta->set_status(mojom::TransactionStatus::Error); tx_state_manager().AddOrUpdateTx(*meta); - LOG(ERROR) << "GetNextNonce failed"; std::move(callback).Run( false, mojom::ProviderErrorUnion::NewProviderError( @@ -572,7 +561,6 @@ void EthTxManager::OnGetNextNonce(std::unique_ptr meta, uint256_t chain_id = 0; if (!HexValueToUint256(meta->chain_id(), &chain_id)) { - LOG(ERROR) << "Could not convert chain ID"; std::move(callback).Run( false, mojom::ProviderErrorUnion::NewProviderError( @@ -604,7 +592,6 @@ void EthTxManager::OnGetNextNonce(std::unique_ptr meta, return; } if (!meta->tx()->IsSigned()) { - LOG(ERROR) << "Transaction must be signed first"; std::move(callback).Run( false, mojom::ProviderErrorUnion::NewProviderError( @@ -654,7 +641,6 @@ void EthTxManager::OnPublishTransaction(const std::string& chain_id, const std::string& error_message) { std::unique_ptr meta = tx_state_manager().GetTx(tx_meta_id); if (!meta) { - LOG(ERROR) << "Transaction should be found"; std::move(callback).Run( false, mojom::ProviderErrorUnion::NewProviderError( @@ -695,7 +681,6 @@ void EthTxManager::MakeFilForwarderTransferData( std::optional> data = filforwarder::Forward(fil_address); if (!data) { - LOG(ERROR) << "Could not make transfer data"; std::move(callback).Run(false, std::vector()); return; } @@ -714,21 +699,18 @@ void EthTxManager::MakeERC20TransferData( uint256_t amount_uint = 0; if (!HexValueToUint256(amount, &amount_uint)) { - LOG(ERROR) << "Could not convert amount"; std::move(callback).Run(false, std::vector()); return; } std::string data; if (!erc20::Transfer(to_address, amount_uint, &data)) { - LOG(ERROR) << "Could not make transfer data"; std::move(callback).Run(false, std::vector()); return; } std::vector data_decoded; if (!PrefixedHexStringToBytes(data, &data_decoded)) { - LOG(ERROR) << "Could not decode data"; std::move(callback).Run(false, std::vector()); return; } @@ -746,21 +728,18 @@ void EthTxManager::MakeERC20ApproveData(const std::string& spender_address, uint256_t amount_uint = 0; if (!HexValueToUint256(amount, &amount_uint)) { - LOG(ERROR) << "Could not convert amount"; std::move(callback).Run(false, std::vector()); return; } std::string data; if (!erc20::Approve(spender_address, amount_uint, &data)) { - LOG(ERROR) << "Could not make transfer data"; std::move(callback).Run(false, std::vector()); return; } std::vector data_decoded; if (!PrefixedHexStringToBytes(data.data(), &data_decoded)) { - LOG(ERROR) << "Could not decode data"; std::move(callback).Run(false, std::vector()); return; } @@ -781,7 +760,6 @@ void EthTxManager::MakeERC721TransferFromData( uint256_t token_id_uint = 0; if (!HexValueToUint256(token_id, &token_id_uint)) { - VLOG(1) << __FUNCTION__ << ": Could not convert token_id"; std::move(callback).Run(false, std::vector()); return; } @@ -807,15 +785,12 @@ void EthTxManager::ContinueMakeERC721TransferFromData( std::string data; if (!erc721::TransferFromOrSafeTransferFrom(is_safe_transfer_from_supported, from, to, token_id, &data)) { - VLOG(1) << __FUNCTION__ - << ": Could not make transferFrom/safeTransferFrom data"; std::move(callback).Run(false, std::vector()); return; } std::vector data_decoded; if (!PrefixedHexStringToBytes(data, &data_decoded)) { - VLOG(1) << __FUNCTION__ << ": Could not decode data"; std::move(callback).Run(false, std::vector()); return; } @@ -837,28 +812,24 @@ void EthTxManager::MakeERC1155TransferFromData( uint256_t token_id_uint = 0; if (!HexValueToUint256(token_id, &token_id_uint)) { - VLOG(1) << __FUNCTION__ << ": Could not convert token_id"; std::move(callback).Run(false, std::vector()); return; } uint256_t value_uint = 0; if (!HexValueToUint256(value, &value_uint) || (value_uint == 0)) { - VLOG(1) << __FUNCTION__ << ": Could not convert value"; std::move(callback).Run(false, std::vector()); return; } std::string data; if (!erc1155::SafeTransferFrom(from, to, token_id_uint, value_uint, &data)) { - VLOG(1) << __FUNCTION__ << ": Could not make safeTransferFrom data"; std::move(callback).Run(false, std::vector()); return; } std::vector data_decoded; if (!PrefixedHexStringToBytes(data, &data_decoded)) { - VLOG(1) << __FUNCTION__ << ": Could not decode data"; std::move(callback).Run(false, std::vector()); return; } diff --git a/components/brave_wallet/browser/ethereum_keyring.cc b/components/brave_wallet/browser/ethereum_keyring.cc index 44df448d3030..fc93d13461ad 100644 --- a/components/brave_wallet/browser/ethereum_keyring.cc +++ b/components/brave_wallet/browser/ethereum_keyring.cc @@ -23,12 +23,12 @@ namespace brave_wallet { namespace { // Get the 32 byte message hash -std::vector GetMessageHash(base::span message) { +KeccakHashArray GetMessageHash(base::span message) { std::string prefix = base::StrCat({"\x19", "Ethereum Signed Message:\n", base::NumberToString(message.size())}); std::vector hash_input(prefix.begin(), prefix.end()); base::Extend(hash_input, message); - return base::ToVector(KeccakHash(hash_input)); + return KeccakHash(hash_input); } std::unique_ptr ConstructAccountsRootKey( @@ -56,12 +56,12 @@ std::optional EthereumKeyring::RecoverAddress( base::span message, base::span signature) { // A compact ECDSA signature (recovery id byte + 64 bytes). - if (signature.size() != kCompactSignatureSize + 1) { + auto signature_span = signature.to_fixed_extent(); + if (!signature_span) { return std::nullopt; } - std::vector signature_only(signature.begin(), signature.end()); - uint8_t v = signature_only.back(); + uint8_t v = signature_span->back(); if (v < 27) { VLOG(1) << "v should be >= 27"; return std::nullopt; @@ -70,8 +70,6 @@ std::optional EthereumKeyring::RecoverAddress( // v = chain_id ? recid + chain_id * 2 + 35 : recid + 27; // So recid = v - 27 when chain_id is 0 uint8_t recid = v - 27; - signature_only.pop_back(); - std::vector hash = GetMessageHash(message); // Public keys (in scripts) are given as 04 where x and y are 32 // byte big-endian integers representing the coordinates of a point on the @@ -79,7 +77,8 @@ std::optional EthereumKeyring::RecoverAddress( // y is even and 0x03 if y is odd. HDKey key; std::vector public_key = - key.RecoverCompact(false, hash, signature_only, recid); + key.RecoverCompact(false, GetMessageHash(message), + signature_span->first(), recid); if (public_key.size() != 65) { VLOG(1) << "public key should be 65 bytes"; return std::nullopt; @@ -96,35 +95,39 @@ std::optional EthereumKeyring::RecoverAddress( return addr.ToChecksumAddress(); } -std::vector EthereumKeyring::SignMessage( +std::optional> EthereumKeyring::SignMessage( const std::string& address, base::span message, uint256_t chain_id, bool is_eip712) { HDKey* hd_key = GetHDKeyFromAddress(address); if (!hd_key) { - return std::vector(); + return std::nullopt; } - std::vector hash; + std::array hashed_message = {}; if (!is_eip712) { - hash = GetMessageHash(message); + hashed_message = GetMessageHash(message); } else { // eip712 hash is Keccak if (message.size() != 32) { - return std::vector(); + return std::nullopt; } - hash.assign(message.begin(), message.end()); + base::span(hashed_message).copy_from(message); + } + + int recid = 0; + auto signature = hd_key->SignCompact(hashed_message, &recid); + if (!signature) { + return std::nullopt; } - int recid; - std::vector signature = hd_key->SignCompact(hash, &recid); uint8_t v = static_cast(chain_id ? recid + chain_id * 2 + 35 : recid + 27); - signature.push_back(v); - - return signature; + auto result = base::ToVector(*signature); + result.push_back(v); + return result; } void EthereumKeyring::SignTransaction(const std::string& address, @@ -135,10 +138,13 @@ void EthereumKeyring::SignTransaction(const std::string& address, return; } - const std::vector message = tx->GetMessageToSign(chain_id); - int recid; - const std::vector signature = hd_key->SignCompact(message, &recid); - tx->ProcessSignature(signature, recid, chain_id); + int recid = 0; + auto signature = + hd_key->SignCompact(tx->GetHashedMessageToSign(chain_id), &recid); + if (!signature) { + return; + } + tx->ProcessSignature(*signature, recid, chain_id); } std::string EthereumKeyring::GetAddressInternal(const HDKey& hd_key) const { diff --git a/components/brave_wallet/browser/ethereum_keyring.h b/components/brave_wallet/browser/ethereum_keyring.h index a094a44b1a4b..316c9bc1f370 100644 --- a/components/brave_wallet/browser/ethereum_keyring.h +++ b/components/brave_wallet/browser/ethereum_keyring.h @@ -34,10 +34,11 @@ class EthereumKeyring : public Secp256k1HDKeyring { base::span message, base::span signature); - std::vector SignMessage(const std::string& address, - base::span message, - uint256_t chain_id, - bool is_eip712); + std::optional> SignMessage( + const std::string& address, + base::span message, + uint256_t chain_id, + bool is_eip712); void SignTransaction(const std::string& address, EthTransaction* tx, diff --git a/components/brave_wallet/browser/ethereum_keyring_unittest.cc b/components/brave_wallet/browser/ethereum_keyring_unittest.cc index 338a680b6d46..789eef1bb089 100644 --- a/components/brave_wallet/browser/ethereum_keyring_unittest.cc +++ b/components/brave_wallet/browser/ethereum_keyring_unittest.cc @@ -12,6 +12,7 @@ #include "base/base64.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" +#include "brave/components/brave_wallet/browser/bip39.h" #include "brave/components/brave_wallet/browser/brave_wallet_utils.h" #include "brave/components/brave_wallet/browser/eth_transaction.h" #include "testing/gmock/include/gmock/gmock.h" @@ -27,6 +28,8 @@ constexpr char kMnemonic[] = namespace brave_wallet { +using bip39::MnemonicToSeed; + TEST(EthereumKeyringUnitTest, ConstructRootHDKey) { std::vector seed; EXPECT_TRUE(base::HexStringToBytes( @@ -126,36 +129,34 @@ TEST(EthereumKeyringUnitTest, SignMessage) { std::vector message; EXPECT_TRUE(base::HexStringToBytes("deadbeef", &message)); - std::vector sig = keyring.SignMessage(address, message, 0, false); + auto sig = *keyring.SignMessage(address, message, 0, false); EXPECT_EQ(base::ToLowerASCII(base::HexEncode(sig)), "a77440e5c84e5f16ca3636c7af5857c828d2a8f1afbc0a6945d33d4fc45f216e" "3eefd69ccc5b3cee000fdaa564d8f1512789af8fe62f2907f5a8c87885b508fa" "1b"); - sig = keyring.SignMessage(address, message, 3, false); + sig = *keyring.SignMessage(address, message, 3, false); EXPECT_EQ(base::ToLowerASCII(base::HexEncode(sig)), "a77440e5c84e5f16ca3636c7af5857c828d2a8f1afbc0a6945d33d4fc45f216e" "3eefd69ccc5b3cee000fdaa564d8f1512789af8fe62f2907f5a8c87885b508fa" "29"); - sig = keyring.SignMessage(address, message, 300, false); + sig = *keyring.SignMessage(address, message, 300, false); EXPECT_EQ(base::ToLowerASCII(base::HexEncode(sig)), "a77440e5c84e5f16ca3636c7af5857c828d2a8f1afbc0a6945d33d4fc45f216e" "3eefd69ccc5b3cee000fdaa564d8f1512789af8fe62f2907f5a8c87885b508fa" "7b"); - EXPECT_TRUE(keyring - .SignMessage("0xDEADBEEFdeadbeefdeadbeefdeadbeefDEADBEEF", - message, 0, false) - .empty()); + EXPECT_FALSE(keyring.SignMessage("0xDEADBEEFdeadbeefdeadbeefdeadbeefDEADBEEF", + message, 0, false)); // when message is not Keccak hash - EXPECT_TRUE(keyring.SignMessage(address, message, 0, true).empty()); + EXPECT_FALSE(keyring.SignMessage(address, message, 0, true)); message.clear(); EXPECT_TRUE(base::HexStringToBytes( "be609aee343fb3c4b28e1df9e632fca64fcfaede20f02e86244efddf30957bd2", &message)); - sig = keyring.SignMessage(address, message, 3, true); + sig = *keyring.SignMessage(address, message, 3, true); EXPECT_EQ(base::ToLowerASCII(base::HexEncode(sig)), "789c0e9025bbf9410b58c2ca43ea1add3c6cfed66001300b9c102f78022cf6e21b" "bf3780d68ff28e72c0ccb4f515b3d527c585abf59bc03531f5047b0357ef3329"); @@ -199,8 +200,8 @@ TEST(EthereumKeyringUnitTest, ImportedAccounts) { // SignMessage std::vector message; EXPECT_TRUE(base::HexStringToBytes("68656c6c6f20776f726c64", &message)); - const std::vector sig = keyring.SignMessage( - "0xbE93f9BacBcFFC8ee6663f2647917ed7A20a57BB", message, 0, false); + auto sig = *keyring.SignMessage("0xbE93f9BacBcFFC8ee6663f2647917ed7A20a57BB", + message, 0, false); EXPECT_EQ(base::ToLowerASCII(base::HexEncode(sig)), "ce909e8ea6851bc36c007a0072d0524b07a3ff8d4e623aca4c71ca8e57250c4d0a" "3fc38fa8fbaaa81ead4b9f6bd03356b6f8bf18bccad167d78891636e1d69561b"); @@ -213,10 +214,8 @@ TEST(EthereumKeyringUnitTest, ImportedAccounts) { "0xbE93f9BacBcFFC8ee6663f2647917ed7A20a57BB")); EXPECT_FALSE(keyring.RemoveImportedAccount("")); EXPECT_FALSE(keyring.RemoveImportedAccount("*****0x*****")); - EXPECT_TRUE(keyring - .SignMessage("0xbE93f9BacBcFFC8ee6663f2647917ed7A20a57BB", - message, 0, false) - .empty()); + EXPECT_FALSE(keyring.SignMessage("0xbE93f9BacBcFFC8ee6663f2647917ed7A20a57BB", + message, 0, false)); // Sign Transaction EthTransaction tx = *EthTransaction::FromTxData(mojom::TxData::New( diff --git a/components/brave_wallet/browser/ethereum_provider_impl.cc b/components/brave_wallet/browser/ethereum_provider_impl.cc index 587c7c11b2cb..bfe07e3d7fc1 100644 --- a/components/brave_wallet/browser/ethereum_provider_impl.cc +++ b/components/brave_wallet/browser/ethereum_provider_impl.cc @@ -743,15 +743,14 @@ void EthereumProviderImpl::OnSignMessageRequestProcessed( base::Value formed_response; if (account_id->kind != mojom::AccountKind::kHardware) { - auto signature_with_err = keyring_service_->SignMessageByDefaultKeyring( + auto signature = keyring_service_->SignMessageByDefaultKeyring( account_id, message, is_eip712); - if (!signature_with_err.signature) { - formed_response = - GetProviderErrorDictionary(mojom::ProviderError::kInternalError, - signature_with_err.error_message); + if (!signature.has_value()) { + formed_response = GetProviderErrorDictionary( + mojom::ProviderError::kInternalError, signature.error()); reject = true; } else { - formed_response = base::Value(ToHex(*signature_with_err.signature)); + formed_response = base::Value(ToHex(signature.value())); } } else { if (!hw_signature) { // Missing hardware signature. diff --git a/components/brave_wallet/browser/fil_transaction.cc b/components/brave_wallet/browser/fil_transaction.cc index d83bcf204799..dba6b3b312e8 100644 --- a/components/brave_wallet/browser/fil_transaction.cc +++ b/components/brave_wallet/browser/fil_transaction.cc @@ -15,6 +15,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/values.h" +#include "brave/components/brave_wallet/common/eth_address.h" #include "brave/components/filecoin/rs/src/lib.rs.h" #include "brave/components/json/json_helper.h" @@ -78,7 +79,11 @@ std::optional FilTransaction::FromTxData( auto address = FilAddress::FromAddress(tx_data->to); if (address.IsEmpty()) { - address = FilAddress::FromFEVMAddress(is_mainnet, tx_data->to); + auto eth_address = EthAddress::FromHex(tx_data->to); + if (!eth_address.IsValid()) { + return std::nullopt; + } + address = FilAddress::FromFEVMAddress(is_mainnet, eth_address); if (address.IsEmpty()) { return std::nullopt; } diff --git a/components/brave_wallet/browser/filecoin_keyring_unittest.cc b/components/brave_wallet/browser/filecoin_keyring_unittest.cc index 6d4df56e2ada..62d8b8321943 100644 --- a/components/brave_wallet/browser/filecoin_keyring_unittest.cc +++ b/components/brave_wallet/browser/filecoin_keyring_unittest.cc @@ -7,6 +7,7 @@ #include "base/base64.h" #include "base/strings/string_number_conversions.h" +#include "brave/components/brave_wallet/browser/bip39.h" #include "brave/components/brave_wallet/browser/brave_wallet_utils.h" #include "brave/components/brave_wallet/browser/keyring_service.h" #include "brave/components/brave_wallet/browser/test_utils.h" @@ -18,6 +19,8 @@ using testing::ElementsAre; namespace brave_wallet { +using bip39::MnemonicToSeed; + namespace { std::vector GetPublicKey(const std::string& private_key_hex) { std::vector private_key; diff --git a/components/brave_wallet/browser/hd_keyring.cc b/components/brave_wallet/browser/hd_keyring.cc index aa6f16d53ee3..44e0d20be29e 100644 --- a/components/brave_wallet/browser/hd_keyring.cc +++ b/components/brave_wallet/browser/hd_keyring.cc @@ -5,35 +5,9 @@ #include "brave/components/brave_wallet/browser/hd_keyring.h" -#include "base/notreached.h" -#include "brave/components/brave_wallet/common/brave_wallet.mojom.h" - namespace brave_wallet { HDKeyring::HDKeyring() = default; HDKeyring::~HDKeyring() = default; -// static -std::string HDKeyring::GetRootPath(mojom::KeyringId keyring_id) { - if (keyring_id == mojom::KeyringId::kDefault) { - return "m/44'/60'/0'/0"; - } else if (keyring_id == mojom::KeyringId::kSolana) { - return "m/44'/501'"; - } else if (keyring_id == mojom::KeyringId::kFilecoin) { - return "m/44'/461'/0'/0"; - } else if (keyring_id == mojom::KeyringId::kFilecoinTestnet) { - return "m/44'/1'/0'/0"; - } else if (keyring_id == mojom::KeyringId::kBitcoin84) { - return "m/84'/0'"; - } else if (keyring_id == mojom::KeyringId::kBitcoin84Testnet) { - return "m/84'/1'"; - } else if (keyring_id == mojom::KeyringId::kZCashMainnet) { - return "m/44'/133'"; - } else if (keyring_id == mojom::KeyringId::kZCashTestnet) { - return "m/44'/1'"; - } - - NOTREACHED() << keyring_id; -} - } // namespace brave_wallet diff --git a/components/brave_wallet/browser/hd_keyring.h b/components/brave_wallet/browser/hd_keyring.h index c7a1bcc05c8e..c2007f3c1975 100644 --- a/components/brave_wallet/browser/hd_keyring.h +++ b/components/brave_wallet/browser/hd_keyring.h @@ -11,7 +11,6 @@ #include #include "base/containers/span.h" -#include "brave/components/brave_wallet/common/brave_wallet.mojom.h" namespace brave_wallet { @@ -27,8 +26,6 @@ class HDKeyring { HDKeyring(const HDKeyring&) = delete; HDKeyring& operator=(const HDKeyring&) = delete; - static std::string GetRootPath(mojom::KeyringId keyring_id); - virtual std::optional AddNewHDAccount() = 0; virtual void RemoveLastHDAccount() = 0; diff --git a/components/brave_wallet/browser/internal/hd_key.cc b/components/brave_wallet/browser/internal/hd_key.cc index b6b15f3305ef..db7303b0b353 100644 --- a/components/brave_wallet/browser/internal/hd_key.cc +++ b/components/brave_wallet/browser/internal/hd_key.cc @@ -345,54 +345,43 @@ std::unique_ptr HDKey::DeriveChildFromPath( return hd_key; } -std::vector HDKey::SignCompact(base::span msg, - int* recid) { - std::vector sig(kCompactSignatureSize); - if (msg.size() != 32) { - LOG(ERROR) << __func__ << ": message length should be 32"; - return sig; - } +std::optional> HDKey::SignCompact( + Secp256k1SignMsgSpan msg, + int* recid) { + std::array sig = {}; if (!recid) { secp256k1_ecdsa_signature ecdsa_sig; if (!secp256k1_ecdsa_sign(GetSecp256k1Ctx(), &ecdsa_sig, msg.data(), private_key_.data(), secp256k1_nonce_function_rfc6979, nullptr)) { - LOG(ERROR) << __func__ << ": secp256k1_ecdsa_sign failed"; - return sig; + return std::nullopt; } if (!secp256k1_ecdsa_signature_serialize_compact(GetSecp256k1Ctx(), sig.data(), &ecdsa_sig)) { - LOG(ERROR) << __func__ - << ": secp256k1_ecdsa_signature_serialize_compact failed"; + return std::nullopt; } } else { secp256k1_ecdsa_recoverable_signature ecdsa_sig; if (!secp256k1_ecdsa_sign_recoverable( GetSecp256k1Ctx(), &ecdsa_sig, msg.data(), private_key_.data(), secp256k1_nonce_function_rfc6979, nullptr)) { - LOG(ERROR) << __func__ << ": secp256k1_ecdsa_sign_recoverable failed"; - return sig; + return std::nullopt; } if (!secp256k1_ecdsa_recoverable_signature_serialize_compact( GetSecp256k1Ctx(), sig.data(), recid, &ecdsa_sig)) { - LOG(ERROR) - << __func__ - << ": secp256k1_ecdsa_recoverable_signature_serialize_compact failed"; + return std::nullopt; } } return sig; } -std::optional> HDKey::SignDer( - base::span msg) { - unsigned char extra_entropy[32] = {0}; +std::optional> HDKey::SignDer(Secp256k1SignMsgSpan msg) { secp256k1_ecdsa_signature ecdsa_sig; if (!secp256k1_ecdsa_sign(GetSecp256k1Ctx(), &ecdsa_sig, msg.data(), private_key_.data(), secp256k1_nonce_function_rfc6979, nullptr)) { - LOG(ERROR) << __func__ << ": secp256k1_ecdsa_sign failed"; return std::nullopt; } @@ -405,6 +394,7 @@ std::optional> HDKey::SignDer( }; // Grind R https://github.com/bitcoin/bitcoin/pull/13666 + unsigned char extra_entropy[32] = {0}; uint32_t extra_entropy_counter = 0; while (!sig_has_low_r(GetSecp256k1Ctx(), &ecdsa_sig)) { base::as_writable_byte_span(extra_entropy) @@ -433,13 +423,8 @@ std::optional> HDKey::SignDer( return sig_der; } -bool HDKey::VerifyForTesting(base::span msg, - base::span sig) { - if (msg.size() != 32 || sig.size() != kCompactSignatureSize) { - LOG(ERROR) << __func__ << ": message or signature length is invalid"; - return false; - } - +bool HDKey::VerifyForTesting(Secp256k1SignMsgSpan msg, + CompactSignatureSpan sig) { secp256k1_ecdsa_signature ecdsa_sig; if (!secp256k1_ecdsa_signature_parse_compact(GetSecp256k1Ctx(), &ecdsa_sig, sig.data())) { @@ -474,8 +459,8 @@ std::array HDKey::GetFingerprint() const { } std::vector HDKey::RecoverCompact(bool compressed, - base::span msg, - base::span sig, + Secp256k1SignMsgSpan msg, + CompactSignatureSpan sig, int recid) { size_t public_key_len = compressed ? 33 : 65; std::vector public_key(public_key_len); diff --git a/components/brave_wallet/browser/internal/hd_key.h b/components/brave_wallet/browser/internal/hd_key.h index 414f7419aa94..9b91f8c97686 100644 --- a/components/brave_wallet/browser/internal/hd_key.h +++ b/components/brave_wallet/browser/internal/hd_key.h @@ -24,7 +24,10 @@ inline constexpr size_t kSecp256k1ChainCodeSize = 32; inline constexpr size_t kSecp256k1PubkeySize = 33; inline constexpr size_t kSecp256k1IdentifierSize = 20; inline constexpr size_t kSecp256k1FingerprintSize = 4; +inline constexpr size_t kSecp256k1SignMsgSize = 32; +using Secp256k1SignMsgSpan = base::span; +using CompactSignatureSpan = base::span; using SecureVector = std::vector>; enum class ExtendedKeyVersion : uint32_t { @@ -94,24 +97,24 @@ class HDKey { // Sign the message using private key. The msg has to be exactly 32 bytes // Return 64 bytes ECDSA signature when succeed, otherwise empty vector // if recid is not null, recovery id will be filled. - std::vector SignCompact(base::span msg, int* recid); + std::optional> SignCompact( + Secp256k1SignMsgSpan msg, + int* recid); // Sign the message using private key and return it in DER format. - std::optional> SignDer( - base::span msg); + std::optional> SignDer(Secp256k1SignMsgSpan msg); // Verify the ECDSA signature using public key. The msg has to be exactly 32 // bytes and the sig has to be 64 bytes. // Return true when successfully verified, false otherwise. - bool VerifyForTesting(base::span msg, - base::span sig); + bool VerifyForTesting(Secp256k1SignMsgSpan msg, CompactSignatureSpan sig); // Recover public key from signature and message. The msg has to be exactly 32 // bytes and the sig has to be 64 bytes. // Return valid public key when succeed, all zero vector otherwise std::vector RecoverCompact(bool compressed, - base::span msg, - base::span sig, + Secp256k1SignMsgSpan msg, + CompactSignatureSpan sig, int recid); // Key identifier - hash of pubkey. diff --git a/components/brave_wallet/browser/internal/hd_key_unittest.cc b/components/brave_wallet/browser/internal/hd_key_unittest.cc index 2ef38c6237e0..02be649f1b65 100644 --- a/components/brave_wallet/browser/internal/hd_key_unittest.cc +++ b/components/brave_wallet/browser/internal/hd_key_unittest.cc @@ -14,8 +14,8 @@ #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/types/cxx23_to_underlying.h" +#include "brave/components/brave_wallet/browser/bip39.h" #include "brave/components/brave_wallet/browser/bitcoin/bitcoin_test_utils.h" -#include "brave/components/brave_wallet/browser/brave_wallet_utils.h" #include "brave/components/brave_wallet/browser/internal/hd_key_common.h" #include "brave/components/brave_wallet/browser/test_utils.h" #include "brave/components/brave_wallet/common/bitcoin_utils.h" @@ -27,6 +27,8 @@ namespace brave_wallet { +using bip39::MnemonicToSeed; + namespace { bool IsPublicKeyEmpty(const std::vector& public_key) { for (const uint8_t& byte : public_key) { @@ -398,12 +400,13 @@ TEST(HDKeyUnitTest, GenerateFromPrivateKey) { std::unique_ptr key = HDKey::GenerateFromPrivateKey(private_key); EXPECT_NE(key, nullptr); - const std::vector msg_a(32, 0x00); - const std::vector msg_b(32, 0x08); + std::array msg_a = {}; + std::array msg_b = {}; + msg_b.fill(0x08); int recid_a = -1; int recid_b = -1; - const std::vector sig_a = key->SignCompact(msg_a, &recid_a); - const std::vector sig_b = key->SignCompact(msg_b, &recid_b); + auto sig_a = *key->SignCompact(msg_a, &recid_a); + auto sig_b = *key->SignCompact(msg_b, &recid_b); EXPECT_NE(recid_a, -1); EXPECT_NE(recid_b, -1); EXPECT_EQ(base::ToLowerASCII(base::HexEncode(sig_a)), @@ -422,12 +425,13 @@ TEST(HDKeyUnitTest, SignAndVerifyAndRecover) { "GfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"); auto* key = parsed_xprv->hdkey.get(); - const std::vector msg_a(32, 0x00); - const std::vector msg_b(32, 0x08); + std::array msg_a = {}; + std::array msg_b = {}; + msg_b.fill(0x08); int recid_a = -1; int recid_b = -1; - const std::vector sig_a = key->SignCompact(msg_a, &recid_a); - const std::vector sig_b = key->SignCompact(msg_b, &recid_b); + auto sig_a = *key->SignCompact(msg_a, &recid_a); + auto sig_b = *key->SignCompact(msg_b, &recid_b); EXPECT_NE(recid_a, -1); EXPECT_NE(recid_b, -1); EXPECT_EQ(base::ToLowerASCII(base::HexEncode(sig_a)), @@ -453,25 +457,11 @@ TEST(HDKeyUnitTest, SignAndVerifyAndRecover) { EXPECT_EQ(base::HexEncode(uncompressed_public_key_b), base::HexEncode(key->GetUncompressedPublicKey())); - EXPECT_FALSE(key->VerifyForTesting(std::vector(32), - std::vector(64))); + EXPECT_FALSE(key->VerifyForTesting(std::array{}, + std::array{})); EXPECT_FALSE(key->VerifyForTesting(msg_a, sig_b)); EXPECT_FALSE(key->VerifyForTesting(msg_b, sig_a)); - EXPECT_FALSE(key->VerifyForTesting(std::vector(31), sig_a)); - EXPECT_FALSE(key->VerifyForTesting(std::vector(33), sig_a)); - - EXPECT_FALSE(key->VerifyForTesting(msg_a, std::vector(63))); - EXPECT_FALSE(key->VerifyForTesting(msg_a, std::vector(65))); - - EXPECT_TRUE(IsPublicKeyEmpty( - key->RecoverCompact(true, std::vector(31), sig_a, recid_a))); - EXPECT_TRUE(IsPublicKeyEmpty( - key->RecoverCompact(true, std::vector(33), sig_a, recid_a))); - EXPECT_TRUE(IsPublicKeyEmpty( - key->RecoverCompact(true, msg_a, std::vector(31), recid_a))); - EXPECT_TRUE(IsPublicKeyEmpty( - key->RecoverCompact(true, msg_a, std::vector(33), recid_a))); EXPECT_TRUE(IsPublicKeyEmpty(key->RecoverCompact(true, msg_a, sig_a, -1))); EXPECT_TRUE(IsPublicKeyEmpty(key->RecoverCompact(true, msg_a, sig_a, 4))); EXPECT_TRUE(IsPublicKeyEmpty(key->RecoverCompact(false, msg_a, sig_a, -1))); diff --git a/components/brave_wallet/browser/json_keystore_parser.cc b/components/brave_wallet/browser/json_keystore_parser.cc index 3782fc0ec9be..9af4cd5935ca 100644 --- a/components/brave_wallet/browser/json_keystore_parser.cc +++ b/components/brave_wallet/browser/json_keystore_parser.cc @@ -129,12 +129,12 @@ std::optional> DecryptPrivateKeyFromJsonKeystore( return std::nullopt; } - crypto::kdf::Pbkdf2HmacSha256Params params = { - .iterations = *c, - }; if (!crypto::kdf::DeriveKeyPbkdf2HmacSha256( - params, base::as_byte_span(password), - base::as_byte_span(salt_bytes), derived_key)) { + { + .iterations = *c, + }, + base::as_byte_span(password), base::as_byte_span(salt_bytes), + derived_key)) { return std::nullopt; } } else if (*kdf == "scrypt") { diff --git a/components/brave_wallet/browser/keyring_service.cc b/components/brave_wallet/browser/keyring_service.cc index 2005f42f4aab..8a50bbdff533 100644 --- a/components/brave_wallet/browser/keyring_service.cc +++ b/components/brave_wallet/browser/keyring_service.cc @@ -20,12 +20,14 @@ #include "base/logging.h" #include "base/notreached.h" #include "base/numerics/safe_conversions.h" +#include "base/rand_util.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/value_iterators.h" #include "base/values.h" +#include "brave/components/brave_wallet/browser/bip39.h" #include "brave/components/brave_wallet/browser/bitcoin/bitcoin_hardware_keyring.h" #include "brave/components/brave_wallet/browser/bitcoin/bitcoin_hd_keyring.h" #include "brave/components/brave_wallet/browser/bitcoin/bitcoin_import_keyring.h" @@ -590,7 +592,7 @@ std::optional MakeSeedFromMnemonic( const std::string& mnemonic, bool use_legacy_eth_seed_format) { KeyringSeed result; - const auto seed = MnemonicToSeed(mnemonic, ""); + const auto seed = bip39::MnemonicToSeed(mnemonic, ""); if (!seed) { return std::nullopt; } @@ -598,14 +600,11 @@ std::optional MakeSeedFromMnemonic( result.seed = std::move(*seed); if (use_legacy_eth_seed_format) { - const auto eth_seed = MnemonicToEntropy(mnemonic); + const auto eth_seed = bip39::MnemonicToEntropy(mnemonic); if (!eth_seed) { return std::nullopt; } - if (eth_seed->size() != 32) { - VLOG(1) << __func__ - << "mnemonic for legacy brave wallet must be 24 words which will " - "produce 32 bytes seed"; + if (eth_seed->size() != bip39::kLegacyEthEntropySize) { return std::nullopt; } result.eth_seed = std::move(*eth_seed); @@ -674,14 +673,19 @@ bool KeyringService::IsWalletCreatedSync() { void KeyringService::CreateWallet(const std::string& password, CreateWalletCallback callback) { - const std::string mnemonic = GenerateMnemonic(16); - if (CreateWalletInternal(mnemonic, password, false, false)) { + const auto mnemonic = bip39::GenerateMnemonic( + base::RandBytesAsVector(bip39::kDefaultEntropySize)); + if (!mnemonic) { + std::move(callback).Run(std::nullopt); + return; + } + if (CreateWalletInternal(*mnemonic, password, false, false)) { WalletDataFilesInstaller::GetInstance() .MaybeRegisterWalletDataFilesComponentOnDemand(base::BindOnce( [](const std::string& mnemonic, CreateWalletCallback callback) { std::move(callback).Run(mnemonic); }, - mnemonic, std::move(callback))); + *mnemonic, std::move(callback))); } else { std::move(callback).Run(std::nullopt); } @@ -853,7 +857,6 @@ void KeyringService::RestoreWallet(const std::string& mnemonic, } // Only register the component if restore is successful. - CHECK(is_valid_mnemonic); WalletDataFilesInstaller::GetInstance() .MaybeRegisterWalletDataFilesComponentOnDemand(base::BindOnce( [](RestoreWalletCallback callback) { std::move(callback).Run(true); }, @@ -1605,41 +1608,27 @@ void KeyringService::SignTransactionByDefaultKeyring( keyring->SignTransaction(account_id.address, tx, chain_id); } -KeyringService::SignatureWithError::SignatureWithError() = default; -KeyringService::SignatureWithError::SignatureWithError( - SignatureWithError&& other) = default; -KeyringService::SignatureWithError& -KeyringService::SignatureWithError::operator=(SignatureWithError&& other) = - default; -KeyringService::SignatureWithError::~SignatureWithError() = default; - -KeyringService::SignatureWithError KeyringService::SignMessageByDefaultKeyring( +base::expected, std::string> +KeyringService::SignMessageByDefaultKeyring( const mojom::AccountIdPtr& account_id, base::span message, bool is_eip712) { CHECK(account_id); - SignatureWithError ret; auto* keyring = GetEthereumKeyring(); if (!keyring || account_id->keyring_id != mojom::kDefaultKeyringId) { - ret.signature = std::nullopt; - ret.error_message = - l10n_util::GetStringUTF8(IDS_BRAVE_WALLET_SIGN_MESSAGE_UNLOCK_FIRST); - return ret; + return base::unexpected( + l10n_util::GetStringUTF8(IDS_BRAVE_WALLET_SIGN_MESSAGE_UNLOCK_FIRST)); } auto address = account_id->address; // MM currently doesn't provide chain_id when signing message - std::vector signature = - keyring->SignMessage(address, message, 0, is_eip712); - if (signature.empty()) { - ret.signature = std::nullopt; - ret.error_message = + auto signature = keyring->SignMessage(address, message, 0, is_eip712); + if (!signature) { + return base::unexpected( l10n_util::GetStringFUTF8(IDS_BRAVE_WALLET_SIGN_MESSAGE_INVALID_ADDRESS, - base::ASCIIToUTF16(address)); - return ret; + base::ASCIIToUTF16(address))); } - ret.signature = std::move(signature); - return ret; + return base::ok(*signature); } std::optional KeyringService::RecoverAddressByDefaultKeyring( diff --git a/components/brave_wallet/browser/keyring_service.h b/components/brave_wallet/browser/keyring_service.h index 63895955a257..ca45d6811a24 100644 --- a/components/brave_wallet/browser/keyring_service.h +++ b/components/brave_wallet/browser/keyring_service.h @@ -13,6 +13,7 @@ #include "base/gtest_prod_util.h" #include "base/memory/raw_ptr.h" +#include "base/types/expected.h" #include "brave/components/brave_wallet/common/brave_wallet.mojom.h" #include "brave/components/brave_wallet/common/brave_wallet_types.h" #include "brave/components/brave_wallet/common/buildflags.h" @@ -137,21 +138,10 @@ class KeyringService : public mojom::KeyringService { std::optional GetDiscoveryAddress(mojom::KeyringId keyring_id, int index); - struct SignatureWithError { - SignatureWithError(); - SignatureWithError(SignatureWithError&& other); - SignatureWithError& operator=(SignatureWithError&& other); - SignatureWithError(const SignatureWithError&) = delete; - SignatureWithError& operator=(const SignatureWithError&) = delete; - ~SignatureWithError(); - - std::optional> signature; - std::string error_message; - }; - SignatureWithError SignMessageByDefaultKeyring( + base::expected, std::string> SignMessageByDefaultKeyring( const mojom::AccountIdPtr& account_id, base::span message, - bool is_eip712 = false); + bool is_eip712); std::vector SignMessageBySolanaKeyring( const mojom::AccountIdPtr& account_id, diff --git a/components/brave_wallet/browser/keyring_service_migrations.cc b/components/brave_wallet/browser/keyring_service_migrations.cc index 4e90f4c9e54c..b8929be163df 100644 --- a/components/brave_wallet/browser/keyring_service_migrations.cc +++ b/components/brave_wallet/browser/keyring_service_migrations.cc @@ -45,6 +45,28 @@ constexpr char kEncryptedMnemonicDeprecated[] = "encrypted_mnemonic"; constexpr char kImportedAccountCoinTypeDeprecated[] = "coin_type"; constexpr char kSelectedAccountDeprecated[] = "selected_account"; +std::string GetRootPath(mojom::KeyringId keyring_id) { + if (keyring_id == mojom::KeyringId::kDefault) { + return "m/44'/60'/0'/0"; + } else if (keyring_id == mojom::KeyringId::kSolana) { + return "m/44'/501'"; + } else if (keyring_id == mojom::KeyringId::kFilecoin) { + return "m/44'/461'/0'/0"; + } else if (keyring_id == mojom::KeyringId::kFilecoinTestnet) { + return "m/44'/1'/0'/0"; + } else if (keyring_id == mojom::KeyringId::kBitcoin84) { + return "m/84'/0'"; + } else if (keyring_id == mojom::KeyringId::kBitcoin84Testnet) { + return "m/84'/1'"; + } else if (keyring_id == mojom::KeyringId::kZCashMainnet) { + return "m/44'/133'"; + } else if (keyring_id == mojom::KeyringId::kZCashTestnet) { + return "m/44'/1'"; + } + + NOTREACHED() << keyring_id; +} + std::optional ExtractAccountIndex(mojom::KeyringId keyring_id, const std::string& path) { CHECK(keyring_id == mojom::KeyringId::kDefault || @@ -60,7 +82,7 @@ std::optional ExtractAccountIndex(mojom::KeyringId keyring_id, // For all types remove root path and slash. For Solana also remove '/0'. auto account_index = std::string_view(path); - auto root_path = HDKeyring::GetRootPath(keyring_id); + auto root_path = GetRootPath(keyring_id); if (!account_index.starts_with(root_path)) { return std::nullopt; } diff --git a/components/brave_wallet/browser/keyring_service_unittest.cc b/components/brave_wallet/browser/keyring_service_unittest.cc index 0c26c22ccf5d..1804bd260f4c 100644 --- a/components/brave_wallet/browser/keyring_service_unittest.cc +++ b/components/brave_wallet/browser/keyring_service_unittest.cc @@ -19,6 +19,7 @@ #include "base/test/mock_callback.h" #include "base/test/scoped_feature_list.h" #include "base/test/values_test_util.h" +#include "brave/components/brave_wallet/browser/bip39.h" #include "brave/components/brave_wallet/browser/bitcoin/bitcoin_hd_keyring.h" #include "brave/components/brave_wallet/browser/bitcoin/bitcoin_test_utils.h" #include "brave/components/brave_wallet/browser/brave_wallet_constants.h" @@ -46,6 +47,7 @@ #include "components/prefs/scoped_user_pref_update.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/test/browser_task_environment.h" +#include "crypto/random.h" #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "services/network/test/test_url_loader_factory.h" @@ -481,7 +483,7 @@ TEST_F(KeyringServiceUnitTest, CreateWallet_DoubleCall) { EXPECT_CALL(callback1, Run(Truly([](const std::optional& mnemonic) { EXPECT_TRUE(mnemonic); - return IsValidMnemonic(*mnemonic); + return bip39::IsValidMnemonic(*mnemonic); }))); service.CreateWallet(kTestWalletPassword, callback1.Get()); @@ -641,7 +643,9 @@ TEST_F(KeyringServiceUnitTest, LockAndUnlock) { { KeyringService service(json_rpc_service(), GetPrefs(), GetLocalState()); NiceMock observer(service, task_environment_); - AccountUtils(&service).CreateWallet(GenerateMnemonic(16), kPasswordBrave); + AccountUtils(&service).CreateWallet( + *bip39::GenerateMnemonic(crypto::RandBytesAsVector(16)), + kPasswordBrave); ASSERT_TRUE(AddAccount(&service, mojom::CoinType::ETH, mojom::kDefaultKeyringId, "ETH Account 1")); EXPECT_FALSE(service.IsLockedSync()); @@ -2231,33 +2235,27 @@ TEST_F(KeyringServiceUnitTest, SignMessageByDefaultKeyring) { auto account1 = GetAccountUtils(&service).EthAccountId(0); const std::vector message = {0xde, 0xad, 0xbe, 0xef}; - auto sig_with_err = service.SignMessageByDefaultKeyring(account1, message); - EXPECT_NE(sig_with_err.signature, std::nullopt); - EXPECT_FALSE(sig_with_err.signature->empty()); - EXPECT_TRUE(sig_with_err.error_message.empty()); + EXPECT_TRUE(service.SignMessageByDefaultKeyring(account1, message, false) + .has_value()); // message is 0x - sig_with_err = - service.SignMessageByDefaultKeyring(account1, std::vector()); - EXPECT_NE(sig_with_err.signature, std::nullopt); - EXPECT_FALSE(sig_with_err.signature->empty()); - EXPECT_TRUE(sig_with_err.error_message.empty()); + EXPECT_TRUE( + service + .SignMessageByDefaultKeyring(account1, std::vector(), false) + .has_value()); // not a valid account in this wallet auto invalid_account = GetAccountUtils(&service).EthUnkownAccountId(); - sig_with_err = service.SignMessageByDefaultKeyring(invalid_account, message); - EXPECT_EQ(sig_with_err.signature, std::nullopt); EXPECT_EQ( - sig_with_err.error_message, + service.SignMessageByDefaultKeyring(invalid_account, message, false) + .error(), l10n_util::GetStringFUTF8(IDS_BRAVE_WALLET_SIGN_MESSAGE_INVALID_ADDRESS, base::ASCIIToUTF16(invalid_account->address))); // Cannot sign message when locked service.Lock(); - sig_with_err = service.SignMessageByDefaultKeyring(account1, message); - EXPECT_EQ(sig_with_err.signature, std::nullopt); EXPECT_EQ( - sig_with_err.error_message, + service.SignMessageByDefaultKeyring(account1, message, false).error(), l10n_util::GetStringUTF8(IDS_BRAVE_WALLET_SIGN_MESSAGE_UNLOCK_FIRST)); } @@ -3241,9 +3239,10 @@ TEST_F(KeyringServiceUnitTest, BitcoinDiscovery) { *brave_wallet_service.GetBitcoinWalletService()); bitcoin_test_rpc_server.SetUpBitcoinRpc(std::nullopt, std::nullopt); - BitcoinHDKeyring keyring_84(*MnemonicToSeed(kMnemonicAbandonAbandon), false); - BitcoinHDKeyring keyring_84_test(*MnemonicToSeed(kMnemonicAbandonAbandon), - true); + BitcoinHDKeyring keyring_84(*bip39::MnemonicToSeed(kMnemonicAbandonAbandon), + false); + BitcoinHDKeyring keyring_84_test( + *bip39::MnemonicToSeed(kMnemonicAbandonAbandon), true); // Account 0 bitcoin_test_rpc_server.AddTransactedAddress( diff --git a/components/brave_wallet/browser/sns_resolver_task.cc b/components/brave_wallet/browser/sns_resolver_task.cc index 1814cb8718cd..6b5275b28a22 100644 --- a/components/brave_wallet/browser/sns_resolver_task.cc +++ b/components/brave_wallet/browser/sns_resolver_task.cc @@ -19,7 +19,6 @@ #include "base/ranges/algorithm.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" -#include "base/sys_byteorder.h" #include "base/values.h" #include "brave/components/api_request_helper/api_request_helper.h" #include "brave/components/brave_wallet/browser/json_rpc_requests_helper.h" @@ -32,7 +31,7 @@ #include "brave/components/brave_wallet/common/solana_address.h" #include "brave/components/ipfs/ipfs_utils.h" #include "build/build_config.h" -#include "crypto/sha2.h" +#include "crypto/hash.h" #include "third_party/abseil-cpp/absl/cleanup/cleanup.h" #include "third_party/boringssl/src/include/openssl/curve25519.h" @@ -499,7 +498,7 @@ SnsNamehash GetHashedName(const std::string& prefix, const std::string& name) { // https://github.com/Bonfida/solana-program-library/blob/6e3be3eedad3a7f4a83c1b7cd5f17f89231e0bca/name-service/js/src/constants.ts#L13 constexpr char kHashPrefix[] = "SPL Name Service"; const std::string input = kHashPrefix + prefix + name; - return crypto::SHA256Hash(base::as_byte_span(input)); + return crypto::hash::Sha256(base::as_byte_span(input)); } // https://github.com/Bonfida/name-tokenizer#mint diff --git a/components/brave_wallet/browser/solana_keyring.cc b/components/brave_wallet/browser/solana_keyring.cc index 617f161d4a07..8435eefa2171 100644 --- a/components/brave_wallet/browser/solana_keyring.cc +++ b/components/brave_wallet/browser/solana_keyring.cc @@ -15,12 +15,11 @@ #include "base/containers/span_rust.h" #include "base/ranges/algorithm.h" #include "brave/components/brave_wallet/browser/brave_wallet_utils.h" -#include "brave/components/brave_wallet/common/brave_wallet.mojom.h" #include "brave/components/brave_wallet/common/brave_wallet_constants.h" #include "brave/components/brave_wallet/common/encoding_utils.h" #include "brave/components/brave_wallet/common/solana_utils.h" #include "brave/components/brave_wallet/rust/lib.rs.h" -#include "crypto/sha2.h" +#include "crypto/hash.h" namespace brave_wallet { @@ -187,15 +186,14 @@ std::optional SolanaKeyring::CreateProgramDerivedAddress( buffer.insert(buffer.end(), program_id_bytes.begin(), program_id_bytes.end()); buffer.insert(buffer.end(), pda_marker.begin(), pda_marker.end()); - auto hash_array = crypto::SHA256Hash(buffer); - std::vector hash_vec(hash_array.begin(), hash_array.end()); + auto hash_array = crypto::hash::Sha256(buffer); // Invalid because program derived addresses have to be off-curve. - if (bytes_are_curve25519_point(base::SpanToRustSlice(hash_vec))) { + if (bytes_are_curve25519_point(base::SpanToRustSlice(hash_array))) { return std::nullopt; } - return Base58Encode(hash_vec); + return Base58Encode(hash_array); } // Find a valid program derived address and its corresponding bump seed. diff --git a/components/brave_wallet/browser/solana_keyring.h b/components/brave_wallet/browser/solana_keyring.h index 29b1a6b482a1..7c4d5c1ef980 100644 --- a/components/brave_wallet/browser/solana_keyring.h +++ b/components/brave_wallet/browser/solana_keyring.h @@ -15,6 +15,7 @@ #include "base/containers/span.h" #include "brave/components/brave_wallet/browser/hd_keyring.h" #include "brave/components/brave_wallet/browser/internal/hd_key_ed25519.h" +#include "brave/components/brave_wallet/common/brave_wallet.mojom.h" namespace brave_wallet { diff --git a/components/brave_wallet/browser/solana_keyring_unittest.cc b/components/brave_wallet/browser/solana_keyring_unittest.cc index e85c4887685b..f2be13ba0eb5 100644 --- a/components/brave_wallet/browser/solana_keyring_unittest.cc +++ b/components/brave_wallet/browser/solana_keyring_unittest.cc @@ -8,7 +8,7 @@ #include #include "base/strings/string_number_conversions.h" -#include "brave/components/brave_wallet/browser/brave_wallet_utils.h" +#include "brave/components/brave_wallet/browser/bip39.h" #include "brave/components/brave_wallet/browser/test_utils.h" #include "brave/components/brave_wallet/common/brave_wallet.mojom.h" #include "brave/components/brave_wallet/common/brave_wallet_constants.h" @@ -21,6 +21,8 @@ using testing::ElementsAre; namespace brave_wallet { +using bip39::MnemonicToSeed; + TEST(SolanaKeyringUnitTest, ConstructRootHDKey) { SolanaKeyring keyring(*MnemonicToSeed(kMnemonicScarePiece)); diff --git a/components/brave_wallet/browser/test/BUILD.gn b/components/brave_wallet/browser/test/BUILD.gn index d38b761a6367..835244b6f1e7 100644 --- a/components/brave_wallet/browser/test/BUILD.gn +++ b/components/brave_wallet/browser/test/BUILD.gn @@ -14,6 +14,7 @@ source_set("brave_wallet_unit_tests") { "//brave/components/brave_wallet/browser/account_resolver_delegate_impl_unittest.cc", "//brave/components/brave_wallet/browser/asset_ratio_response_parser_unittest.cc", "//brave/components/brave_wallet/browser/asset_ratio_service_unittest.cc", + "//brave/components/brave_wallet/browser/bip39_unittest.cc", "//brave/components/brave_wallet/browser/bitcoin/bitcoin_block_tracker_unittest.cc", "//brave/components/brave_wallet/browser/bitcoin/bitcoin_hardware_keyring_unittest.cc", "//brave/components/brave_wallet/browser/bitcoin/bitcoin_hd_keyring_unittest.cc", diff --git a/components/brave_wallet/browser/zcash/zcash_keyring_unittest.cc b/components/brave_wallet/browser/zcash/zcash_keyring_unittest.cc index bc54aaf9f1a2..5a7d028a4547 100644 --- a/components/brave_wallet/browser/zcash/zcash_keyring_unittest.cc +++ b/components/brave_wallet/browser/zcash/zcash_keyring_unittest.cc @@ -10,7 +10,7 @@ #include "base/strings/string_number_conversions.h" #include "base/test/scoped_feature_list.h" -#include "brave/components/brave_wallet/browser/brave_wallet_utils.h" +#include "brave/components/brave_wallet/browser/bip39.h" #include "brave/components/brave_wallet/common/buildflags.h" #include "brave/components/brave_wallet/common/encoding_utils.h" #include "brave/components/brave_wallet/common/features.h" @@ -30,6 +30,8 @@ constexpr char kDeputyVisaTestMnemonic[] = } // namespace namespace brave_wallet { + +using bip39::MnemonicToSeed; using mojom::ZCashKeyId; TEST(ZCashKeyringUnitTest, GetPubKey) { diff --git a/components/brave_wallet/common/eth_address.cc b/components/brave_wallet/common/eth_address.cc index 4409803c63cc..da9aa60367fd 100644 --- a/components/brave_wallet/common/eth_address.cc +++ b/components/brave_wallet/common/eth_address.cc @@ -8,7 +8,6 @@ #include #include "base/containers/span.h" -#include "base/logging.h" #include "base/ranges/algorithm.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" @@ -37,7 +36,6 @@ bool EthAddress::operator!=(const EthAddress& other) const { EthAddress EthAddress::FromPublicKey(base::span public_key) { // TODO(apaymyshev): should be a fixed-size span. if (public_key.size() != 64) { - VLOG(1) << __func__ << ": public key size should be 64 bytes"; return EthAddress(); } @@ -53,7 +51,6 @@ EthAddress EthAddress::FromHex(std::string_view input) { std::vector bytes; if (!PrefixedHexStringToBytes(input, &bytes)) { - VLOG(1) << __func__ << ": PrefixedHexStringToBytes failed"; return EthAddress(); } @@ -76,11 +73,9 @@ EthAddress EthAddress::ZeroAddress() { // static bool EthAddress::IsValidAddress(std::string_view input) { if (!IsValidHexString(input)) { - VLOG(1) << __func__ << ": input is not a valid hex representation"; return false; } if (input.size() - 2 != kEthAddressLength * 2) { - VLOG(1) << __func__ << ": input should be 20 bytes long"; return false; } return true; diff --git a/components/brave_wallet/common/f4_jumble.cc b/components/brave_wallet/common/f4_jumble.cc index 07b1317758ea..64f99c13474b 100644 --- a/components/brave_wallet/common/f4_jumble.cc +++ b/components/brave_wallet/common/f4_jumble.cc @@ -6,23 +6,21 @@ #include "brave/components/brave_wallet/common/f4_jumble.h" #include -#include -#include -#include "base/notreached.h" -#include "brave/third_party/argon2/src/src/blake2/blake2.h" +#include "base/containers/extend.h" +#include "brave/components/brave_wallet/common/hash_utils.h" namespace brave_wallet { namespace { -using Blake2bPersonalBytes = std::array; +using Blake2bPersonalBytes = std::array; // Sizes for Blake2b are defined here https://zips.z.cash/zip-0316#solution constexpr size_t kMinMessageSize = 48u; constexpr size_t kMaxMessageSize = 4184368u; constexpr size_t kLeftSize = 64u; -static_assert(kLeftSize <= BLAKE2B_OUTBYTES); +static_assert(kLeftSize <= kBlake2bMaxLength); Blake2bPersonalBytes GetHPersonalizer(uint8_t i) { return {85, 65, 95, 70, 52, 74, 117, 109, 98, 108, 101, 95, 72, i, 0, 0}; @@ -47,32 +45,6 @@ Blake2bPersonalBytes GetGPersonalizer(uint8_t i, uint16_t j) { static_cast(j >> 8)}; } -void FillBlake2bParamPersonal(const Blake2bPersonalBytes& personalizer, - blake2b_param& params) { - CHECK_EQ(personalizer.size(), sizeof(params.personal)); - memcpy(params.personal, personalizer.data(), sizeof(params.personal)); -} - -std::vector Blake2b(base::span payload, - const Blake2bPersonalBytes& personalizer, - size_t digest_len) { - CHECK(digest_len >= 1 && digest_len <= BLAKE2B_OUTBYTES); - blake2b_state blake_state = {}; - blake2b_param params = {}; - - params.digest_length = digest_len; - params.fanout = 1; - params.depth = 1; - - FillBlake2bParamPersonal(personalizer, params); - - CHECK_EQ(blake2b_init_param(&blake_state, ¶ms), 0); - CHECK_EQ(blake2b_update(&blake_state, payload.data(), payload.size()), 0); - std::vector result(digest_len); - CHECK_EQ(blake2b_final(&blake_state, result.data(), digest_len), 0); - return result; -} - size_t GetLeftSize(base::span message) { return std::min(kLeftSize, message.size() / 2); } @@ -88,7 +60,7 @@ std::vector GetRight(base::span message) { std::vector HRound(uint8_t iter, base::span left, base::span right) { - auto hash = Blake2b(right, GetHPersonalizer(iter), left.size()); + auto hash = Blake2bHash(right, left.size(), GetHPersonalizer(iter)); CHECK_EQ(hash.size(), left.size()); std::vector result; result.reserve(left.size()); @@ -105,7 +77,7 @@ std::vector GRound(uint8_t i, std::vector result; result.reserve(right.size()); for (size_t j = 0; j < blocks_count; j++) { - auto hash = Blake2b(left, GetGPersonalizer(i, j), kLeftSize); + auto hash = Blake2bHash(left, kLeftSize, GetGPersonalizer(i, j)); CHECK_EQ(hash.size(), kLeftSize); for (size_t k = 0; k < hash.size() && (j * kLeftSize + k < right.size()); k++) { @@ -131,7 +103,7 @@ std::optional> ApplyF4Jumble( right = GRound(1, left, right); left = HRound(1, left, right); - left.insert(left.end(), right.begin(), right.end()); + base::Extend(left, right); return left; } @@ -150,7 +122,7 @@ std::optional> RevertF4Jumble( left = HRound(0, left, right); right = GRound(0, left, right); - left.insert(left.end(), right.begin(), right.end()); + base::Extend(left, right); return left; } diff --git a/components/brave_wallet/common/fil_address.cc b/components/brave_wallet/common/fil_address.cc index f98641ada2df..07ba8d4a417a 100644 --- a/components/brave_wallet/common/fil_address.cc +++ b/components/brave_wallet/common/fil_address.cc @@ -7,12 +7,12 @@ #include -#include "base/logging.h" +#include "base/containers/extend.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "brave/components/brave_wallet/common/brave_wallet.mojom.h" #include "brave/components/brave_wallet/common/eth_address.h" -#include "brave/third_party/argon2/src/src/blake2/blake2.h" +#include "brave/components/brave_wallet/common/hash_utils.h" #include "components/base32/base32.h" namespace brave_wallet { @@ -28,26 +28,6 @@ constexpr size_t kAddressSizeBLS = 86; constexpr size_t kAddressSizeDelegatedF410 = 44; constexpr size_t kPayloadSizeDelegatedF410 = 20; -std::optional> BlakeHash( - const std::vector& payload, - size_t length) { - blake2b_state blakeState; - if (blake2b_init(&blakeState, length) != 0) { - VLOG(0) << __func__ << ": blake2b_init failed"; - return std::nullopt; - } - if (blake2b_update(&blakeState, payload.data(), payload.size()) != 0) { - VLOG(0) << __func__ << ": blake2b_update failed"; - return std::nullopt; - } - std::vector result(length, 0); - if (blake2b_final(&blakeState, result.data(), length) != 0) { - VLOG(0) << __func__ << ": blake2b_final failed"; - return std::nullopt; - } - return result; -} - bool IsValidNetwork(const std::string& network) { return network == mojom::kFilecoinTestnet || network == mojom::kFilecoinMainnet; @@ -192,42 +172,22 @@ FilAddress FilAddress::FromUncompressedPublicKey( if (uncompressed_public_key.empty()) { return FilAddress(); } - auto payload = BlakeHash(uncompressed_public_key, kHashLengthSecp256K); - if (!payload || payload->empty()) { - return FilAddress(); - } - return FromPayload(*payload, protocol, network); + auto payload = Blake2bHash(uncompressed_public_key, kHashLengthSecp256K); + return FromPayload(payload, protocol, network); } // static FilAddress FilAddress::FromFEVMAddress(bool is_mainnet, - const std::string& fevm_address) { - if (!EthAddress::IsValidAddress(fevm_address)) { - return FilAddress(); - } - std::vector payload; - base::HexStringToBytes(fevm_address.substr(2), &payload); - std::vector prefix = {4, 10}; - - blake2b_state blakeState; - if (blake2b_init(&blakeState, 4) != 0) { - return FilAddress(); - } - - if (blake2b_update(&blakeState, prefix.data(), prefix.size()) != 0) { - return FilAddress(); - } - - if (blake2b_update(&blakeState, payload.data(), payload.size()) != 0) { - return FilAddress(); - } - - std::vector checksum(4, 0); - if (blake2b_final(&blakeState, checksum.data(), checksum.size()) != 0) { + const EthAddress& fevm_address) { + if (!fevm_address.IsValid()) { return FilAddress(); } + std::vector to_hash = {4, 10}; + base::Extend(to_hash, fevm_address.bytes()); + auto checksum = Blake2bHash(to_hash, kChecksumSize); - payload.insert(payload.end(), checksum.begin(), checksum.end()); + auto payload = fevm_address.bytes(); + base::Extend(payload, checksum); std::string encoded = base32::Base32Encode(payload, base32::Base32EncodePolicy::OMIT_PADDING); @@ -284,7 +244,7 @@ bool FilAddress::IsValidAddress(const std::string& address) { // Protocol value 3: addresses represent BLS public encryption keys. // The payload field contains 48 byte BLS PubKey public key. All payloads // except the payload of the ID protocol are base32 encoded using the lowercase -// alphabet when seralized to their human readable format. +// alphabet when serialized to their human readable format. // Protocol value 4: addresses represent a combination of agent id and agent // namespace addresses. // https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0048.md @@ -296,18 +256,18 @@ std::string FilAddress::EncodeAsString() const { if (bytes_.empty()) { return std::string(); } - std::vector payload_hash(bytes_); - std::vector checksum(bytes_); + + std::vector checksum_payload; + checksum_payload.push_back(static_cast(protocol_)); if (protocol_ == mojom::FilecoinAddressProtocol::DELEGATED) { - checksum.insert(checksum.begin(), 0x0A /* Agent id is 10*/); - } - checksum.insert(checksum.begin(), static_cast(protocol_)); - auto checksum_hash = BlakeHash(checksum, kChecksumSize); - if (!checksum_hash) { - return std::string(); + checksum_payload.push_back(0x0A /* Agent id is 10*/); } - payload_hash.insert(payload_hash.end(), checksum_hash->begin(), - checksum_hash->end()); + base::Extend(checksum_payload, bytes_); + auto checksum_hash = Blake2bHash(checksum_payload, kChecksumSize); + + std::vector payload_hash(bytes_); + base::Extend(payload_hash, checksum_hash); + // Encoding as lower case base32 without padding according to // https://spec.filecoin.io/appendix/address/#section-appendix.address.payload // and https://github.com/multiformats/multibase/blob/master/multibase.csv diff --git a/components/brave_wallet/common/fil_address.h b/components/brave_wallet/common/fil_address.h index 344805661a30..4fd2e6cd21e6 100644 --- a/components/brave_wallet/common/fil_address.h +++ b/components/brave_wallet/common/fil_address.h @@ -13,6 +13,8 @@ namespace brave_wallet { +class EthAddress; + class FilAddress { public: static std::optional GetProtocolFromAddress( @@ -30,7 +32,7 @@ class FilAddress { static FilAddress FromBytes(const std::string& chain_id, const std::vector& bytes); static FilAddress FromFEVMAddress(bool is_mainnet, - const std::string& fevm_address); + const EthAddress& fevm_address); static bool IsValidAddress(const std::string& input); FilAddress(); diff --git a/components/brave_wallet/common/fil_address_unittest.cc b/components/brave_wallet/common/fil_address_unittest.cc index 2a69fdbb2575..c424247f68f5 100644 --- a/components/brave_wallet/common/fil_address_unittest.cc +++ b/components/brave_wallet/common/fil_address_unittest.cc @@ -11,6 +11,7 @@ #include "base/containers/span.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" +#include "brave/components/brave_wallet/common/eth_address.h" #include "brave/components/brave_wallet/common/hex_utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -343,16 +344,19 @@ TEST(FilAddressUnitTest, FromBytes) { TEST(FilAddressUnitTest, ConvertFEVMtoFVM) { EXPECT_EQ("f410frrqkhkktbxosf5cmboocdhsv42jtgw2rddjac2y", FilAddress::FromFEVMAddress( - true, "0x8C60a3A9530dDD22F44C0B9c219E55E693335b51") + true, EthAddress::FromHex( + "0x8C60a3A9530dDD22F44C0B9c219E55E693335b51")) .EncodeAsString()); EXPECT_EQ("t410frrqkhkktbxosf5cmboocdhsv42jtgw2rddjac2y", FilAddress::FromFEVMAddress( - false, "0x8C60a3A9530dDD22F44C0B9c219E55E693335b51") + false, EthAddress::FromHex( + "0x8C60a3A9530dDD22F44C0B9c219E55E693335b51")) .EncodeAsString()); EXPECT_TRUE(FilAddress::FromFEVMAddress( - false, "8C60a3A9530dDD22F44C0B9c219E55E693335b51") + false, EthAddress::FromHex( + "8C60a3A9530dDD22F44C0B9c219E55E693335b51")) .IsEmpty()); } diff --git a/components/brave_wallet/common/hash_utils.cc b/components/brave_wallet/common/hash_utils.cc index 23401eb328cd..164aacf23666 100644 --- a/components/brave_wallet/common/hash_utils.cc +++ b/components/brave_wallet/common/hash_utils.cc @@ -14,11 +14,15 @@ #include "base/strings/string_split.h" #include "brave/components/brave_wallet/common/eth_abi_utils.h" #include "brave/components/brave_wallet/common/hex_utils.h" +#include "brave/third_party/argon2/src/src/blake2/blake2.h" #include "brave/third_party/bitcoin-core/src/src/crypto/ripemd160.h" #include "brave/third_party/ethash/src/include/ethash/keccak.h" -#include "crypto/sha2.h" +#include "crypto/hash.h" namespace brave_wallet { +static_assert(kBlake2bMaxLength == BLAKE2B_OUTBYTES); +static_assert(kBlake2bPersonalizerLength == BLAKE2B_PERSONALBYTES); + namespace { std::array ConcatArrays(const std::array& arr1, const std::array& arr2) { @@ -62,17 +66,42 @@ eth_abi::Bytes32 Namehash(std::string_view name) { } SHA256HashArray DoubleSHA256Hash(base::span input) { - return crypto::SHA256Hash(crypto::SHA256Hash(input)); + return crypto::hash::Sha256(crypto::hash::Sha256(input)); } Ripemd160HashArray Hash160(base::span input) { Ripemd160HashArray result = {}; CRIPEMD160() - .Write(crypto::SHA256Hash(input).data(), crypto::kSHA256Length) + .Write(crypto::hash::Sha256(input).data(), crypto::hash::kSha256Size) .Finalize(result.data()); return result; } +std::vector Blake2bHash( + base::span payload, + size_t length, + std::optional> + personalizer /* = std::nullopt */) { + CHECK_GT(length, 0u); + CHECK_LE(length, kBlake2bMaxLength); + + blake2b_param param = {}; + param.digest_length = length; + param.fanout = 1; + param.depth = 1; + if (personalizer) { + base::span(param.personal).copy_from(*personalizer); + } + + blake2b_state state = {}; + CHECK_EQ(0, blake2b_init_param(&state, ¶m)); + CHECK_EQ(0, blake2b_update(&state, payload.data(), payload.size())); + + std::vector result(length, 0); + CHECK_EQ(0, blake2b_final(&state, result.data(), result.size())); + return result; +} + } // namespace brave_wallet diff --git a/components/brave_wallet/common/hash_utils.h b/components/brave_wallet/common/hash_utils.h index f445edca8a3b..8a3094a9b550 100644 --- a/components/brave_wallet/common/hash_utils.h +++ b/components/brave_wallet/common/hash_utils.h @@ -11,15 +11,17 @@ #include #include "brave/components/brave_wallet/common/eth_abi_utils.h" -#include "crypto/sha2.h" +#include "crypto/hash.h" namespace brave_wallet { inline constexpr size_t kKeccakHashLength = 32; inline constexpr size_t kRipemd160HashLength = 20; +inline constexpr size_t kBlake2bPersonalizerLength = 16; +inline constexpr size_t kBlake2bMaxLength = 64; using KeccakHashArray = std::array; -using SHA256HashArray = std::array; +using SHA256HashArray = std::array; using Ripemd160HashArray = std::array; KeccakHashArray KeccakHash(base::span input); @@ -40,6 +42,12 @@ SHA256HashArray DoubleSHA256Hash(base::span input); // ripemd160(sha256(input)) Ripemd160HashArray Hash160(base::span input); +// blake2b-length(input, length, personalizer?) +std::vector Blake2bHash( + base::span payload, + size_t length, + std::optional> + personalizer = std::nullopt); } // namespace brave_wallet #endif // BRAVE_COMPONENTS_BRAVE_WALLET_COMMON_HASH_UTILS_H_ diff --git a/components/brave_wallet/common/hash_utils_unittest.cc b/components/brave_wallet/common/hash_utils_unittest.cc index 587b4740a162..d5bc945cf74c 100644 --- a/components/brave_wallet/common/hash_utils_unittest.cc +++ b/components/brave_wallet/common/hash_utils_unittest.cc @@ -5,6 +5,8 @@ #include "brave/components/brave_wallet/common/hash_utils.h" +#include +#include #include #include "base/containers/span.h" @@ -79,4 +81,23 @@ TEST(HashUtilsUnitTest, Hash160) { "b472a266d0bd89c13706a4132ccfb16f7c3b9fcb"); } +TEST(HashUtilsUnitTest, Blake2bHash) { + // https://datatracker.ietf.org/doc/html/rfc7693#appendix-A + EXPECT_EQ( + base::HexEncode(Blake2bHash(base::byte_span_from_cstring("abc"), 64)), + "BA80A53F981C4D0D6A2797B69F12F6E9" + "4C212F14685AC4B74B12BB6FDBFFA2D1" + "7D87C5392AAB792DC252D5DE4533CC95" + "18D38AA8DBF1925AB92386EDD4009923"); + + auto personalizer = + std::to_array({1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}); + EXPECT_EQ(base::HexEncode(Blake2bHash(base::byte_span_from_cstring("abc"), 64, + personalizer)), + "D969E8AFD6AD50262CA3391E492191E2" + "70A4AB7A7CBDE0766E2174263DC28286" + "39EE37F542A54015DA432264C2585F48" + "FFE06DEF21A179B3758FD7174D76E03E"); +} + } // namespace brave_wallet From 461ca5107b10e55a2bed89179d3007d67313bbac Mon Sep 17 00:00:00 2001 From: Anton Paymyshev Date: Thu, 23 Jan 2025 22:25:02 +0700 Subject: [PATCH 2/2] fix review --- components/brave_wallet/browser/BUILD.gn | 1 - components/brave_wallet/browser/zcash/DEPS | 6 -- .../browser/zcash/zcash_serializer.cc | 59 +++++++------------ components/brave_wallet/common/DEPS | 2 +- components/brave_wallet/common/f4_jumble.cc | 8 +-- components/brave_wallet/common/fil_address.cc | 26 ++++---- components/brave_wallet/common/fil_address.h | 8 +-- components/brave_wallet/common/hash_utils.cc | 15 ++--- components/brave_wallet/common/hash_utils.h | 17 +++++- .../common/hash_utils_unittest.cc | 14 ++++- 10 files changed, 73 insertions(+), 83 deletions(-) diff --git a/components/brave_wallet/browser/BUILD.gn b/components/brave_wallet/browser/BUILD.gn index 24692654d262..419e79767ee5 100644 --- a/components/brave_wallet/browser/BUILD.gn +++ b/components/brave_wallet/browser/BUILD.gn @@ -295,7 +295,6 @@ static_library("browser") { "//brave/components/services/brave_wallet/public/mojom", "//brave/components/services/brave_wallet/public/proto:zcash_proto", "//brave/net/base:utils", - "//brave/third_party/argon2", "//components/component_updater", "//components/content_settings/core/browser", "//components/country_codes", diff --git a/components/brave_wallet/browser/zcash/DEPS b/components/brave_wallet/browser/zcash/DEPS index 693bfa6e5d85..e7cf2c6ff61a 100644 --- a/components/brave_wallet/browser/zcash/DEPS +++ b/components/brave_wallet/browser/zcash/DEPS @@ -1,9 +1,3 @@ include_rules = [ "+ui/base", ] - -specific_include_rules = { - "zcash_serializer\.cc": [ - "+brave/third_party/argon2", - ], -} diff --git a/components/brave_wallet/browser/zcash/zcash_serializer.cc b/components/brave_wallet/browser/zcash/zcash_serializer.cc index db5777be7235..55ecc531ca9d 100644 --- a/components/brave_wallet/browser/zcash/zcash_serializer.cc +++ b/components/brave_wallet/browser/zcash/zcash_serializer.cc @@ -11,10 +11,7 @@ #include "base/containers/span.h" #include "base/containers/span_writer.h" -#include "base/numerics/byte_conversions.h" #include "brave/components/brave_wallet/common/btc_like_serializer_stream.h" -#include "brave/components/brave_wallet/common/hex_utils.h" -#include "brave/third_party/argon2/src/src/blake2/blake2.h" namespace brave_wallet { @@ -31,24 +28,11 @@ constexpr char kTxHashPersonalizerPrefix[] = "ZcashTxHash_"; constexpr uint32_t kV5TxVersion = 5 | 1 << 31 /* overwintered bit */; // https://zips.z.cash/protocol/protocol.pdf#txnconsensus constexpr uint32_t kV5VersionGroupId = 0x26A7270A; -constexpr size_t kBlake2bPersonalizationSize = 16; - -std::array blake2b256( - const std::vector& payload, - base::span personalizer) { - blake2b_state blake_state = {}; - blake2b_param params = {}; - - params.digest_length = kZCashDigestSize; - params.fanout = 1; - params.depth = 1; - base::span(params.personal).copy_from(personalizer); - CHECK(blake2b_init_param(&blake_state, ¶ms) == 0); - CHECK(blake2b_update(&blake_state, payload.data(), payload.size()) == 0); - std::array result; - CHECK(blake2b_final(&blake_state, result.data(), result.size()) == 0); - return result; +std::array Blake2b256( + base::span payload, + base::span personalizer) { + return Blake2bHash(payload, personalizer); } void PushHeader(const ZCashTransaction& tx, BtcLikeSerializerStream& stream) { @@ -78,7 +62,7 @@ std::array HashAmounts(const ZCashTransaction& tx) { for (const auto& input : tx.transparent_part().inputs) { stream.Push64(input.utxo_value); } - return blake2b256(data, base::byte_span_from_cstring("ZTxTrAmountsHash")); + return Blake2b256(data, base::byte_span_from_cstring("ZTxTrAmountsHash")); } // https://zips.z.cash/zip-0244#s-2d-scriptpubkeys-sig-digest @@ -88,12 +72,12 @@ std::array HashScriptPubKeys(const ZCashTransaction& tx) { for (const auto& input : tx.transparent_part().inputs) { stream.PushSizeAndBytes(input.script_pub_key); } - return blake2b256(data, base::byte_span_from_cstring("ZTxTrScriptsHash")); + return Blake2b256(data, base::byte_span_from_cstring("ZTxTrScriptsHash")); } -std::array GetHashPersonalizer( +std::array GetHashPersonalizer( const ZCashTransaction& tx) { - std::array result; + std::array result; auto span_writer = base::SpanWriter(base::span(result)); span_writer.Write(base::byte_span_from_cstring(kTxHashPersonalizerPrefix)); span_writer.WriteU32LittleEndian(tx.consensus_brach_id()); @@ -133,7 +117,7 @@ std::array ZCashSerializer::HashTxIn( stream.Push32(tx_in->n_sequence); } - return blake2b256(data, base::byte_span_from_cstring("Zcash___TxInHash")); + return Blake2b256(data, base::byte_span_from_cstring("Zcash___TxInHash")); } // static @@ -191,7 +175,7 @@ std::array ZCashSerializer::HashPrevouts( for (const auto& input : tx.transparent_part().inputs) { PushOutpoint(input.utxo_outpoint, stream); } - return blake2b256(data, base::byte_span_from_cstring("ZTxIdPrevoutHash")); + return Blake2b256(data, base::byte_span_from_cstring("ZTxIdPrevoutHash")); } // static @@ -203,7 +187,7 @@ std::array ZCashSerializer::HashSequences( for (const auto& input : tx.transparent_part().inputs) { stream.Push32(input.n_sequence); } - return blake2b256(data, base::byte_span_from_cstring("ZTxIdSequencHash")); + return Blake2b256(data, base::byte_span_from_cstring("ZTxIdSequencHash")); } // static @@ -215,7 +199,7 @@ std::array ZCashSerializer::HashOutputs( for (const auto& output : tx.transparent_part().outputs) { PushOutput(output, stream); } - return blake2b256(data, base::byte_span_from_cstring("ZTxIdOutputsHash")); + return Blake2b256(data, base::byte_span_from_cstring("ZTxIdOutputsHash")); } // static @@ -225,7 +209,7 @@ std::array ZCashSerializer::HashHeader( std::vector data; BtcLikeSerializerStream stream(&data); PushHeader(tx, stream); - return blake2b256(data, base::byte_span_from_cstring("ZTxIdHeadersHash")); + return Blake2b256(data, base::byte_span_from_cstring("ZTxIdHeadersHash")); } // static @@ -244,21 +228,20 @@ std::array ZCashSerializer::CalculateTxIdDigest( stream.PushBytes(ZCashSerializer::HashSequences(zcash_transaction)); stream.PushBytes(ZCashSerializer::HashOutputs(zcash_transaction)); } - transparent_hash = blake2b256( + transparent_hash = Blake2b256( data, base::byte_span_from_cstring(kTransparentHashPersonalizer)); } std::array sapling_hash; { sapling_hash = - blake2b256({}, base::byte_span_from_cstring(kSaplingHashPersonalizer)); + Blake2b256({}, base::byte_span_from_cstring(kSaplingHashPersonalizer)); } std::array orchard_hash; { orchard_hash = zcash_transaction.orchard_part().digest.value_or( - blake2b256(std::vector(), - base::byte_span_from_cstring(kOrchardHashPersonalizer))); + Blake2b256({}, base::byte_span_from_cstring(kOrchardHashPersonalizer))); } std::array digest_hash; @@ -270,7 +253,7 @@ std::array ZCashSerializer::CalculateTxIdDigest( stream.PushBytes(sapling_hash); stream.PushBytes(orchard_hash); - digest_hash = blake2b256(data, GetHashPersonalizer(zcash_transaction)); + digest_hash = Blake2b256(data, GetHashPersonalizer(zcash_transaction)); } std::reverse(digest_hash.begin(), digest_hash.end()); @@ -302,20 +285,20 @@ std::array ZCashSerializer::CalculateSignatureDigest( stream.PushBytes(HashTxIn(input)); } - transparent_hash = blake2b256( + transparent_hash = Blake2b256( data, base::byte_span_from_cstring(kTransparentHashPersonalizer)); } std::array sapling_hash; { sapling_hash = - blake2b256({}, base::byte_span_from_cstring(kSaplingHashPersonalizer)); + Blake2b256({}, base::byte_span_from_cstring(kSaplingHashPersonalizer)); } std::array orchard_hash; { orchard_hash = zcash_transaction.orchard_part().digest.value_or( - blake2b256({}, base::byte_span_from_cstring(kOrchardHashPersonalizer))); + Blake2b256({}, base::byte_span_from_cstring(kOrchardHashPersonalizer))); } std::array digest_hash; @@ -327,7 +310,7 @@ std::array ZCashSerializer::CalculateSignatureDigest( stream.PushBytes(sapling_hash); stream.PushBytes(orchard_hash); - digest_hash = blake2b256(data, GetHashPersonalizer(zcash_transaction)); + digest_hash = Blake2b256(data, GetHashPersonalizer(zcash_transaction)); } return digest_hash; diff --git a/components/brave_wallet/common/DEPS b/components/brave_wallet/common/DEPS index 459722a85a3f..61c2196fd39f 100644 --- a/components/brave_wallet/common/DEPS +++ b/components/brave_wallet/common/DEPS @@ -1,5 +1,4 @@ include_rules = [ - "+brave/third_party/argon2", "+crypto", "+brave/net/base", ] @@ -14,6 +13,7 @@ specific_include_rules = { "+brave/third_party/bitcoin-core/src/src/base58.h", ], "hash_utils\.cc": [ + "+brave/third_party/argon2", "+brave/third_party/bitcoin-core/src/src/crypto/ripemd160.h", "!brave/third_party/ethash/src/include/ethash/keccak.h", ], diff --git a/components/brave_wallet/common/f4_jumble.cc b/components/brave_wallet/common/f4_jumble.cc index 64f99c13474b..5386afdbc9cf 100644 --- a/components/brave_wallet/common/f4_jumble.cc +++ b/components/brave_wallet/common/f4_jumble.cc @@ -60,8 +60,9 @@ std::vector GetRight(base::span message) { std::vector HRound(uint8_t iter, base::span left, base::span right) { - auto hash = Blake2bHash(right, left.size(), GetHPersonalizer(iter)); - CHECK_EQ(hash.size(), left.size()); + std::vector hash(left.size()); + Blake2bHash(right, hash, GetHPersonalizer(iter)); + std::vector result; result.reserve(left.size()); for (size_t i = 0; i < left.size(); i++) { @@ -77,8 +78,7 @@ std::vector GRound(uint8_t i, std::vector result; result.reserve(right.size()); for (size_t j = 0; j < blocks_count; j++) { - auto hash = Blake2bHash(left, kLeftSize, GetGPersonalizer(i, j)); - CHECK_EQ(hash.size(), kLeftSize); + auto hash = Blake2bHash(left, GetGPersonalizer(i, j)); for (size_t k = 0; k < hash.size() && (j * kLeftSize + k < right.size()); k++) { result.push_back(right[j * kLeftSize + k] ^ hash[k]); diff --git a/components/brave_wallet/common/fil_address.cc b/components/brave_wallet/common/fil_address.cc index 07ba8d4a417a..ea8ff00176ed 100644 --- a/components/brave_wallet/common/fil_address.cc +++ b/components/brave_wallet/common/fil_address.cc @@ -8,6 +8,7 @@ #include #include "base/containers/extend.h" +#include "base/containers/to_vector.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "brave/components/brave_wallet/common/brave_wallet.mojom.h" @@ -48,10 +49,10 @@ std::optional ToProtocol(char input) { } // namespace -FilAddress::FilAddress(const std::vector& bytes, +FilAddress::FilAddress(base::span bytes, mojom::FilecoinAddressProtocol protocol, const std::string& network) - : protocol_(protocol), network_(network), bytes_(bytes) { + : protocol_(protocol), network_(network), bytes_(base::ToVector(bytes)) { DCHECK(IsValidNetwork(network)); } FilAddress::FilAddress() = default; @@ -144,7 +145,7 @@ FilAddress FilAddress::FromAddress(const std::string& address) { // static FilAddress FilAddress::FromBytes(const std::string& chain_id, - const std::vector& bytes) { + base::span bytes) { if (!IsValidNetwork(chain_id)) { return FilAddress(); } @@ -152,10 +153,9 @@ FilAddress FilAddress::FromBytes(const std::string& chain_id, return FilAddress(); } mojom::FilecoinAddressProtocol protocol = - static_cast(bytes.at(0)); - std::vector payload(bytes.begin() + 1, bytes.end()); + static_cast(bytes.front()); - return FilAddress::FromPayload(payload, protocol, chain_id); + return FilAddress::FromPayload(bytes.subspan(1), protocol, chain_id); } // Creates FilAddress from SECP256K uncompressed public key @@ -163,7 +163,7 @@ FilAddress FilAddress::FromBytes(const std::string& chain_id, // https://spec.filecoin.io/appendix/address/#section-appendix.address.string // static FilAddress FilAddress::FromUncompressedPublicKey( - const std::vector& uncompressed_public_key, + base::span uncompressed_public_key, mojom::FilecoinAddressProtocol protocol, const std::string& network) { if (protocol != mojom::FilecoinAddressProtocol::SECP256K1) { @@ -172,8 +172,8 @@ FilAddress FilAddress::FromUncompressedPublicKey( if (uncompressed_public_key.empty()) { return FilAddress(); } - auto payload = Blake2bHash(uncompressed_public_key, kHashLengthSecp256K); - return FromPayload(payload, protocol, network); + return FromPayload(Blake2bHash(uncompressed_public_key), + protocol, network); } // static @@ -184,10 +184,9 @@ FilAddress FilAddress::FromFEVMAddress(bool is_mainnet, } std::vector to_hash = {4, 10}; base::Extend(to_hash, fevm_address.bytes()); - auto checksum = Blake2bHash(to_hash, kChecksumSize); auto payload = fevm_address.bytes(); - base::Extend(payload, checksum); + base::Extend(payload, Blake2bHash(to_hash)); std::string encoded = base32::Base32Encode(payload, base32::Base32EncodePolicy::OMIT_PADDING); @@ -198,7 +197,7 @@ FilAddress FilAddress::FromFEVMAddress(bool is_mainnet, // with specified protocol and network. // https://spec.filecoin.io/appendix/address/#section-appendix.address.string // static -FilAddress FilAddress::FromPayload(const std::vector& payload, +FilAddress FilAddress::FromPayload(base::span payload, mojom::FilecoinAddressProtocol protocol, const std::string& network) { if (!IsValidNetwork(network)) { @@ -263,10 +262,9 @@ std::string FilAddress::EncodeAsString() const { checksum_payload.push_back(0x0A /* Agent id is 10*/); } base::Extend(checksum_payload, bytes_); - auto checksum_hash = Blake2bHash(checksum_payload, kChecksumSize); std::vector payload_hash(bytes_); - base::Extend(payload_hash, checksum_hash); + base::Extend(payload_hash, Blake2bHash(checksum_payload)); // Encoding as lower case base32 without padding according to // https://spec.filecoin.io/appendix/address/#section-appendix.address.payload diff --git a/components/brave_wallet/common/fil_address.h b/components/brave_wallet/common/fil_address.h index 4fd2e6cd21e6..f7734239e4ad 100644 --- a/components/brave_wallet/common/fil_address.h +++ b/components/brave_wallet/common/fil_address.h @@ -21,16 +21,16 @@ class FilAddress { const std::string& address); static FilAddress FromUncompressedPublicKey( - const std::vector& public_key, + base::span public_key, mojom::FilecoinAddressProtocol protocol, const std::string& network); - static FilAddress FromPayload(const std::vector& payload, + static FilAddress FromPayload(base::span payload, mojom::FilecoinAddressProtocol protocol, const std::string& network); static FilAddress FromAddress(const std::string& address); static FilAddress FromBytes(const std::string& chain_id, - const std::vector& bytes); + base::span bytes); static FilAddress FromFEVMAddress(bool is_mainnet, const EthAddress& fevm_address); @@ -52,7 +52,7 @@ class FilAddress { private: bool IsEqual(const FilAddress& other) const; - explicit FilAddress(const std::vector& bytes, + explicit FilAddress(base::span bytes, mojom::FilecoinAddressProtocol protocol, const std::string& network); diff --git a/components/brave_wallet/common/hash_utils.cc b/components/brave_wallet/common/hash_utils.cc index 164aacf23666..d36b3c433d2a 100644 --- a/components/brave_wallet/common/hash_utils.cc +++ b/components/brave_wallet/common/hash_utils.cc @@ -79,16 +79,16 @@ Ripemd160HashArray Hash160(base::span input) { return result; } -std::vector Blake2bHash( +void Blake2bHash( base::span payload, - size_t length, + base::span hash_out, std::optional> personalizer /* = std::nullopt */) { - CHECK_GT(length, 0u); - CHECK_LE(length, kBlake2bMaxLength); + CHECK_GT(hash_out.size(), 0u); + CHECK_LE(hash_out.size(), kBlake2bMaxLength); blake2b_param param = {}; - param.digest_length = length; + param.digest_length = hash_out.size(); param.fanout = 1; param.depth = 1; if (personalizer) { @@ -98,10 +98,7 @@ std::vector Blake2bHash( blake2b_state state = {}; CHECK_EQ(0, blake2b_init_param(&state, ¶m)); CHECK_EQ(0, blake2b_update(&state, payload.data(), payload.size())); - - std::vector result(length, 0); - CHECK_EQ(0, blake2b_final(&state, result.data(), result.size())); - return result; + CHECK_EQ(0, blake2b_final(&state, hash_out.data(), hash_out.size())); } } // namespace brave_wallet diff --git a/components/brave_wallet/common/hash_utils.h b/components/brave_wallet/common/hash_utils.h index 8a3094a9b550..f17eb09554c6 100644 --- a/components/brave_wallet/common/hash_utils.h +++ b/components/brave_wallet/common/hash_utils.h @@ -42,12 +42,23 @@ SHA256HashArray DoubleSHA256Hash(base::span input); // ripemd160(sha256(input)) Ripemd160HashArray Hash160(base::span input); -// blake2b-length(input, length, personalizer?) -std::vector Blake2bHash( +void Blake2bHash( base::span payload, - size_t length, + base::span hash_out, std::optional> personalizer = std::nullopt); + +template + requires(T > 0 && T <= kBlake2bMaxLength) +std::array Blake2bHash( + base::span payload, + std::optional> + personalizer = std::nullopt) { + std::array result; + Blake2bHash(payload, result, personalizer); + return result; +} + } // namespace brave_wallet #endif // BRAVE_COMPONENTS_BRAVE_WALLET_COMMON_HASH_UTILS_H_ diff --git a/components/brave_wallet/common/hash_utils_unittest.cc b/components/brave_wallet/common/hash_utils_unittest.cc index d5bc945cf74c..6ecebffc480a 100644 --- a/components/brave_wallet/common/hash_utils_unittest.cc +++ b/components/brave_wallet/common/hash_utils_unittest.cc @@ -84,7 +84,7 @@ TEST(HashUtilsUnitTest, Hash160) { TEST(HashUtilsUnitTest, Blake2bHash) { // https://datatracker.ietf.org/doc/html/rfc7693#appendix-A EXPECT_EQ( - base::HexEncode(Blake2bHash(base::byte_span_from_cstring("abc"), 64)), + base::HexEncode(Blake2bHash<64>(base::byte_span_from_cstring("abc"))), "BA80A53F981C4D0D6A2797B69F12F6E9" "4C212F14685AC4B74B12BB6FDBFFA2D1" "7D87C5392AAB792DC252D5DE4533CC95" @@ -92,12 +92,20 @@ TEST(HashUtilsUnitTest, Blake2bHash) { auto personalizer = std::to_array({1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}); - EXPECT_EQ(base::HexEncode(Blake2bHash(base::byte_span_from_cstring("abc"), 64, - personalizer)), + EXPECT_EQ(base::HexEncode(Blake2bHash<64>(base::byte_span_from_cstring("abc"), + personalizer)), "D969E8AFD6AD50262CA3391E492191E2" "70A4AB7A7CBDE0766E2174263DC28286" "39EE37F542A54015DA432264C2585F48" "FFE06DEF21A179B3758FD7174D76E03E"); + + EXPECT_EQ( + base::HexEncode(Blake2bHash<4>(base::byte_span_from_cstring("abc"))), + "63906248"); + + std::array result; + Blake2bHash(base::byte_span_from_cstring("abc"), result); + EXPECT_EQ(base::HexEncode(result), "63906248"); } } // namespace brave_wallet