From 4758598855780fe6d43b03f54e5386ab4e500427 Mon Sep 17 00:00:00 2001 From: Anton Paymyshev Date: Mon, 11 Nov 2024 14:27:11 +0700 Subject: [PATCH] Fix UNSAFE_TODO for wallet --- .../browser/eip1559_transaction.cc | 2 +- .../browser/eip2930_transaction.cc | 2 +- .../browser/eth_allowance_manager.cc | 3 +- .../browser/eth_topics_builder.cc | 3 +- .../brave_wallet/browser/eth_transaction.cc | 4 +- .../brave_wallet/browser/ethereum_keyring.cc | 11 +- .../browser/ethereum_provider_impl.cc | 7 +- .../brave_wallet/browser/internal/hd_key.cc | 10 +- .../browser/zcash/zcash_keyring.cc | 3 +- components/brave_wallet/common/eth_address.cc | 32 ++-- .../brave_wallet/common/eth_request_helper.cc | 6 +- .../common/eth_sign_typed_data_helper.cc | 152 +++++++++--------- .../common/eth_sign_typed_data_helper.h | 17 +- components/brave_wallet/common/hash_utils.cc | 49 ++---- components/brave_wallet/common/hash_utils.h | 18 ++- .../common/hash_utils_unittest.cc | 5 +- components/brave_wallet/common/zcash_utils.cc | 18 +-- 17 files changed, 163 insertions(+), 179 deletions(-) diff --git a/components/brave_wallet/browser/eip1559_transaction.cc b/components/brave_wallet/browser/eip1559_transaction.cc index 9541436c8e2d..9845108db522 100644 --- a/components/brave_wallet/browser/eip1559_transaction.cc +++ b/components/brave_wallet/browser/eip1559_transaction.cc @@ -289,7 +289,7 @@ std::vector Eip1559Transaction::GetMessageToSign(uint256_t chain_id, const std::string rlp_msg = RLPEncode(base::Value(std::move(list))); result.insert(result.end(), rlp_msg.begin(), rlp_msg.end()); - return hash ? KeccakHash(result) : result; + return hash ? KeccakHashToVector(result) : result; } std::string Eip1559Transaction::GetSignedTransaction() const { diff --git a/components/brave_wallet/browser/eip2930_transaction.cc b/components/brave_wallet/browser/eip2930_transaction.cc index e3b4e6440691..05581ce68095 100644 --- a/components/brave_wallet/browser/eip2930_transaction.cc +++ b/components/brave_wallet/browser/eip2930_transaction.cc @@ -179,7 +179,7 @@ std::vector Eip2930Transaction::GetMessageToSign(uint256_t chain_id, const std::string rlp_msg = RLPEncode(base::Value(std::move(list))); result.insert(result.end(), rlp_msg.begin(), rlp_msg.end()); - return hash ? KeccakHash(result) : result; + return hash ? KeccakHashToVector(result) : result; } std::string Eip2930Transaction::GetSignedTransaction() const { diff --git a/components/brave_wallet/browser/eth_allowance_manager.cc b/components/brave_wallet/browser/eth_allowance_manager.cc index 78693c31b7fb..c29bffb06f47 100644 --- a/components/brave_wallet/browser/eth_allowance_manager.cc +++ b/components/brave_wallet/browser/eth_allowance_manager.cc @@ -164,7 +164,8 @@ void EthAllowanceManager::OnGetCurrentBlock( return; } - const auto approval_topic_hash = KeccakHash(kApprovalTopicFunctionSignature); + const auto approval_topic_hash = ToHex(KeccakHash( + base::byte_span_from_cstring(kApprovalTopicFunctionSignature))); for (const auto& account_address : account_addresses) { std::string account_address_hex; if (!PadHexEncodedParameter(account_address, &account_address_hex)) { diff --git a/components/brave_wallet/browser/eth_topics_builder.cc b/components/brave_wallet/browser/eth_topics_builder.cc index eb39c88ac80e..3d2fc3c18bf6 100644 --- a/components/brave_wallet/browser/eth_topics_builder.cc +++ b/components/brave_wallet/browser/eth_topics_builder.cc @@ -17,7 +17,8 @@ bool MakeAssetDiscoveryTopics( const std::vector& to_account_addresses, base::Value::List* topics) { // First topic matches full keccak hash of the erc20::Transfer event signature - topics->Append(brave_wallet::KeccakHash("Transfer(address,address,uint256)")); + topics->Append(ToHex(KeccakHash( + base::byte_span_from_cstring("Transfer(address,address,uint256)")))); // Second topic matches everything (any from_address) topics->Append(base::Value()); diff --git a/components/brave_wallet/browser/eth_transaction.cc b/components/brave_wallet/browser/eth_transaction.cc index 5c23c6de2b8d..e574929dfe3a 100644 --- a/components/brave_wallet/browser/eth_transaction.cc +++ b/components/brave_wallet/browser/eth_transaction.cc @@ -189,7 +189,7 @@ std::vector EthTransaction::GetMessageToSign(uint256_t chain_id, const std::string message = RLPEncode(base::Value(std::move(list))); auto result = std::vector(message.begin(), message.end()); - return hash ? KeccakHash(result) : result; + return hash ? KeccakHashToVector(result) : result; } std::string EthTransaction::GetSignedTransaction() const { @@ -202,7 +202,7 @@ std::string EthTransaction::GetTransactionHash() const { DCHECK(IsSigned()); DCHECK(nonce_); - return KeccakHash(RLPEncode(Serialize())); + return ToHex(KeccakHash(base::as_byte_span(RLPEncode(Serialize())))); } bool EthTransaction::ProcessVRS(const std::vector& v, diff --git a/components/brave_wallet/browser/ethereum_keyring.cc b/components/brave_wallet/browser/ethereum_keyring.cc index def6cd757fb0..3e842587af24 100644 --- a/components/brave_wallet/browser/ethereum_keyring.cc +++ b/components/brave_wallet/browser/ethereum_keyring.cc @@ -8,7 +8,9 @@ #include #include "base/base64.h" +#include "base/containers/extend.h" #include "base/containers/span.h" +#include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "brave/components/brave_wallet/browser/eth_transaction.h" #include "brave/components/brave_wallet/common/eth_address.h" @@ -20,12 +22,11 @@ namespace { // Get the 32 byte message hash std::vector GetMessageHash(base::span message) { - std::string prefix("\x19"); - prefix += std::string("Ethereum Signed Message:\n" + - base::NumberToString(message.size())); + std::string prefix = base::StrCat({"\x19", "Ethereum Signed Message:\n", + base::NumberToString(message.size())}); std::vector hash_input(prefix.begin(), prefix.end()); - hash_input.insert(hash_input.end(), message.begin(), message.end()); - return brave_wallet::KeccakHash(hash_input); + base::Extend(hash_input, message); + return KeccakHashToVector(hash_input); } } // namespace diff --git a/components/brave_wallet/browser/ethereum_provider_impl.cc b/components/brave_wallet/browser/ethereum_provider_impl.cc index 2c3afc66069d..187865047f6b 100644 --- a/components/brave_wallet/browser/ethereum_provider_impl.cc +++ b/components/brave_wallet/browser/ethereum_provider_impl.cc @@ -684,9 +684,10 @@ void EthereumProviderImpl::SignTypedMessage( mojom::SignDataUnionPtr sign_data = mojom::SignDataUnion::NewEthSignTypedData(std::move(eth_sign_typed_data)); - SignMessageInternal(account_id, std::move(sign_data), - std::move(message_to_sign), std::move(callback), - std::move(id)); + SignMessageInternal( + account_id, std::move(sign_data), + std::vector(message_to_sign.begin(), message_to_sign.end()), + std::move(callback), std::move(id)); } void EthereumProviderImpl::SignMessageInternal( diff --git a/components/brave_wallet/browser/internal/hd_key.cc b/components/brave_wallet/browser/internal/hd_key.cc index 4efa32a57bb7..b623f687c8a0 100644 --- a/components/brave_wallet/browser/internal/hd_key.cc +++ b/components/brave_wallet/browser/internal/hd_key.cc @@ -25,6 +25,7 @@ #include "base/strings/string_util.h" #include "brave/components/brave_wallet/common/bitcoin_utils.h" #include "brave/components/brave_wallet/common/hash_utils.h" +#include "brave/components/brave_wallet/common/hex_utils.h" #include "brave/components/brave_wallet/common/zcash_utils.h" #include "brave/third_party/bitcoin-core/src/src/base58.h" #include "brave/vendor/bat-native-tweetnacl/tweetnacl.h" @@ -78,8 +79,7 @@ bool UTCPasswordVerification(const std::string& derived_key, mac_verification_input.insert(mac_verification_input.end(), ciphertext.begin(), ciphertext.end()); // verify password - std::vector mac_verification(KeccakHash(mac_verification_input)); - if (base::ToLowerASCII(base::HexEncode(mac_verification)) != mac) { + if (HexEncodeLower(KeccakHash(mac_verification_input)) != mac) { VLOG(0) << __func__ << ": password does not match"; return false; } @@ -397,7 +397,8 @@ void HDKey::SetPrivateKey(base::span value) { } private_key_.assign(value.begin(), value.end()); GeneratePublicKey(); - identifier_ = Hash160(public_key_); + auto pubkey_hash = Hash160(public_key_); + identifier_.assign(pubkey_hash.begin(), pubkey_hash.end()); const uint8_t* ptr = identifier_.data(); fingerprint_ = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3] << 0; @@ -426,7 +427,8 @@ void HDKey::SetPublicKey( return; } public_key_.assign(value.begin(), value.end()); - identifier_ = Hash160(public_key_); + auto pubkey_hash = Hash160(public_key_); + identifier_.assign(pubkey_hash.begin(), pubkey_hash.end()); const uint8_t* ptr = identifier_.data(); fingerprint_ = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3] << 0; diff --git a/components/brave_wallet/browser/zcash/zcash_keyring.cc b/components/brave_wallet/browser/zcash/zcash_keyring.cc index 1c8ab747eaa8..dfcbb5a8c64a 100644 --- a/components/brave_wallet/browser/zcash/zcash_keyring.cc +++ b/components/brave_wallet/browser/zcash/zcash_keyring.cc @@ -72,7 +72,8 @@ std::optional> ZCashKeyring::GetPubkeyHash( return std::nullopt; } - return Hash160(hd_key_base->GetPublicKeyBytes()); + auto hash = Hash160(hd_key_base->GetPublicKeyBytes()); + return std::vector{hash.begin(), hash.end()}; } #if BUILDFLAG(ENABLE_ORCHARD) diff --git a/components/brave_wallet/common/eth_address.cc b/components/brave_wallet/common/eth_address.cc index 5eaa17a41729..b44662974e14 100644 --- a/components/brave_wallet/common/eth_address.cc +++ b/components/brave_wallet/common/eth_address.cc @@ -3,19 +3,14 @@ * 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/. */ -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(https://github.com/brave/brave-browser/issues/41661): Remove this and -// convert code to safer constructs. -#pragma allow_unsafe_buffers -#endif - #include "brave/components/brave_wallet/common/eth_address.h" #include -#include "base/check_op.h" +#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" #include "base/strings/string_util.h" #include "brave/components/brave_wallet/common/hash_utils.h" @@ -45,12 +40,8 @@ EthAddress EthAddress::FromPublicKey(const std::vector& public_key) { return EthAddress(); } - std::vector hash = KeccakHash(public_key); - std::vector result(hash.end() - kEthAddressLength, hash.end()); - - DCHECK_EQ(result.size(), kEthAddressLength); - - return EthAddress(std::move(result)); + return EthAddress( + base::as_byte_span(KeccakHash(public_key)).last(kEthAddressLength)); } // static @@ -95,8 +86,7 @@ bool EthAddress::IsValidAddress(const std::string& input) { } std::string EthAddress::ToHex() const { - const std::string input(bytes_.begin(), bytes_.end()); - return ::brave_wallet::ToHex(input); + return ::brave_wallet::ToHex(bytes_); } // static @@ -121,21 +111,19 @@ std::optional EthAddress::ToEip1191ChecksumAddress( std::string EthAddress::ToChecksumAddress(uint256_t eip1191_chaincode) const { std::string result = "0x"; - std::string input; + std::string prefix; if (eip1191_chaincode == static_cast(30) || eip1191_chaincode == static_cast(31)) { // TODO(jocelyn): We will need to revise this if there are supported chains // with ID larger than uint64_t. - input += + prefix = base::NumberToString(static_cast(eip1191_chaincode)) + "0x"; } - input += std::string(ToHex().data() + 2); - - const std::string hash_str(KeccakHash(input).data() + 2); - const std::string address_str = - base::ToLowerASCII(base::HexEncode(bytes_.data(), bytes_.size())); + const std::string address_str = HexEncodeLower(bytes_.data(), bytes_.size()); + const std::string hash_str = base::HexEncode( + KeccakHash(base::as_byte_span(base::StrCat({prefix, address_str})))); for (size_t i = 0; i < address_str.length(); ++i) { if (isdigit(address_str[i])) { diff --git a/components/brave_wallet/common/eth_request_helper.cc b/components/brave_wallet/common/eth_request_helper.cc index e721c156bb7a..225370015be6 100644 --- a/components/brave_wallet/common/eth_request_helper.cc +++ b/components/brave_wallet/common/eth_request_helper.cc @@ -528,12 +528,14 @@ mojom::EthSignTypedDataPtr ParseEthSignTypedDataParams( result->meta = nullptr; } - result->domain_hash = domain_hash->first; + result->domain_hash.assign(domain_hash->first.begin(), + domain_hash->first.end()); if (!base::JSONWriter::Write(domain_hash->second, &result->domain_json)) { return nullptr; } - result->primary_hash = primary_hash->first; + result->primary_hash.assign(primary_hash->first.begin(), + primary_hash->first.end()); if (!base::JSONWriter::Write(primary_hash->second, &result->message_json)) { return nullptr; } diff --git a/components/brave_wallet/common/eth_sign_typed_data_helper.cc b/components/brave_wallet/common/eth_sign_typed_data_helper.cc index c2a40825bc56..211e10b4cd16 100644 --- a/components/brave_wallet/common/eth_sign_typed_data_helper.cc +++ b/components/brave_wallet/common/eth_sign_typed_data_helper.cc @@ -3,16 +3,11 @@ * 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/. */ -#ifdef UNSAFE_BUFFERS_BUILD -// TODO(https://github.com/brave/brave-browser/issues/41661): Remove this and -// convert code to safer constructs. -#pragma allow_unsafe_buffers -#endif - #include "brave/components/brave_wallet/common/eth_sign_typed_data_helper.h" #include #include +#include #include #include "base/containers/extend.h" @@ -132,14 +127,13 @@ std::string EthSignTypedDataHelper::EncodeTypes( return result; } -std::vector EthSignTypedDataHelper::GetTypeHash( +EthSignTypedDataHelper::Eip712HashArray EthSignTypedDataHelper::GetTypeHash( const std::string& primary_type_name) const { - const std::string type_hash = - KeccakHash(EncodeTypes(primary_type_name), false); - return std::vector(type_hash.begin(), type_hash.end()); + return KeccakHash(base::as_byte_span(EncodeTypes(primary_type_name))); } -std::optional, base::Value::Dict>> +std::optional< + std::pair> EthSignTypedDataHelper::HashStruct(const std::string& primary_type_name, const base::Value::Dict& data) const { auto encoded_data = EncodeData(primary_type_name, data); @@ -161,8 +155,7 @@ EthSignTypedDataHelper::EncodeData(const std::string& primary_type_name, } std::vector result; - const std::vector type_hash = GetTypeHash(primary_type_name); - result.insert(result.end(), type_hash.begin(), type_hash.end()); + base::Extend(result, GetTypeHash(primary_type_name)); base::Value::Dict sanitized_data; @@ -179,13 +172,11 @@ EthSignTypedDataHelper::EncodeData(const std::string& primary_type_name, if (!encoded_field) { return std::nullopt; } - result.insert(result.end(), encoded_field->begin(), encoded_field->end()); + base::Extend(result, *encoded_field); sanitized_data.Set(*name_str, value->Clone()); } else { if (version_ == Version::kV4) { - for (size_t i = 0; i < 32; ++i) { - result.push_back(0); - } + result.insert(result.end(), 32, 0); } } } @@ -194,12 +185,12 @@ EthSignTypedDataHelper::EncodeData(const std::string& primary_type_name, // Encode each field of a custom type, if a field is also a custom type it // will call EncodeData recursively until it reaches an atomic type -std::optional> EthSignTypedDataHelper::EncodeField( - const std::string& type, - const base::Value& value) const { +std::optional +EthSignTypedDataHelper::EncodeField(const std::string& type_string, + const base::Value& value) const { + auto type = std::string_view(type_string); // ES6 section 20.1.2.6 Number.MAX_SAFE_INTEGER constexpr double kMaxSafeInteger = static_cast(kMaxSafeIntegerUint64); - std::vector result; if (type.ends_with(']')) { if (version_ != Version::kV4) { @@ -221,22 +212,20 @@ std::optional> EthSignTypedDataHelper::EncodeField( if (!encoded_item) { return std::nullopt; } - array_result.insert(array_result.end(), encoded_item->begin(), - encoded_item->end()); + base::Extend(array_result, *encoded_item); } - auto array_hash = KeccakHash(array_result); - result.insert(result.end(), array_hash.begin(), array_hash.end()); - } else if (type == "string") { + return KeccakHash(array_result); + } + + if (type == "string") { const std::string* value_str = value.GetIfString(); if (!value_str) { return std::nullopt; } - const std::string encoded_value = KeccakHash(*value_str, false); - const std::vector encoded_value_bytes(encoded_value.begin(), - encoded_value.end()); - result.insert(result.end(), encoded_value_bytes.begin(), - encoded_value_bytes.end()); - } else if (type == "bytes") { + return KeccakHash(base::as_byte_span(*value_str)); + } + + if (type == "bytes") { const std::string* value_str = value.GetIfString(); if (!value_str || (!value_str->empty() && !IsValidHexString(*value_str))) { return std::nullopt; @@ -245,19 +234,21 @@ std::optional> EthSignTypedDataHelper::EncodeField( if (!value_str->empty()) { CHECK(PrefixedHexStringToBytes(*value_str, &bytes)); } - const std::vector encoded_value = KeccakHash(bytes); - result.insert(result.end(), encoded_value.begin(), encoded_value.end()); - } else if (type == "bool") { + return KeccakHash(bytes); + } + + if (type == "bool") { std::optional value_bool = value.GetIfBool(); if (!value_bool) { return std::nullopt; } - uint256_t encoded_value = (uint256_t)*value_bool; - // Append the encoded value to byte array result in big endian order - for (int i = 256 - 8; i >= 0; i -= 8) { - result.push_back(static_cast((encoded_value >> i) & 0xFF)); - } - } else if (type == "address") { + + Eip712HashArray result = {}; + result.back() = value_bool.value() ? 1 : 0; + return result; + } + + if (type == "address") { const std::string* value_str = value.GetIfString(); if (!value_str || !IsValidHexString(*value_str)) { return std::nullopt; @@ -267,13 +258,15 @@ std::optional> EthSignTypedDataHelper::EncodeField( if (address.size() != 20u) { return std::nullopt; } - for (size_t i = 0; i < 256 - 160; i += 8) { - result.push_back(0); - } - result.insert(result.end(), address.begin(), address.end()); - } else if (type.starts_with("bytes")) { + + Eip712HashArray result = {}; + base::as_writable_byte_span(result).last(20u).copy_from(address); + return result; + } + + if (type.starts_with("bytes")) { unsigned num_bits; - if (!base::StringToUint(type.data() + 5, &num_bits) || num_bits > 32) { + if (!base::StringToUint(type.substr(5), &num_bits) || num_bits > 32) { return std::nullopt; } const std::string* value_str = value.GetIfString(); @@ -285,14 +278,15 @@ std::optional> EthSignTypedDataHelper::EncodeField( if (bytes.size() > 32) { return std::nullopt; } - result.insert(result.end(), bytes.begin(), bytes.end()); - for (size_t i = 0; i < 32u - bytes.size(); ++i) { - result.push_back(0); - } - } else if (type.starts_with("uint")) { + Eip712HashArray result = {}; + base::as_writable_byte_span(result).copy_prefix_from(bytes); + return result; + } + + if (type.starts_with("uint")) { // uint8 to uint256 in steps of 8 unsigned num_bits; - if (!base::StringToUint(type.data() + 4, &num_bits) || + if (!base::StringToUint(type.substr(4), &num_bits) || !ValidSolidityBits(num_bits)) { return std::nullopt; } @@ -324,14 +318,17 @@ std::optional> EthSignTypedDataHelper::EncodeField( return std::nullopt; } - // Append the encoded value to byte array result in big endian order - for (int i = 256 - 8; i >= 0; i -= 8) { - result.push_back(static_cast((encoded_value >> i) & 0xFF)); - } - } else if (type.starts_with("int")) { + Eip712HashArray result = {}; + base::span(result).copy_from(base::byte_span_from_ref(encoded_value)); + base::ranges::reverse(result); + + return result; + } + + if (type.starts_with("int")) { // int8 to int256 in steps of 8 unsigned num_bits; - if (!base::StringToUint(type.data() + 3, &num_bits) || + if (!base::StringToUint(type.substr(3), &num_bits) || !ValidSolidityBits(num_bits)) { return std::nullopt; } @@ -364,32 +361,32 @@ std::optional> EthSignTypedDataHelper::EncodeField( return std::nullopt; } - // Append the encoded value to byte array result in big endian order - for (int i = 256 - 8; i >= 0; i -= 8) { - result.push_back(static_cast((encoded_value >> i) & 0xFF)); - } - } else { - if (!value.is_dict()) { - return std::nullopt; - } - auto encoded_data = EncodeData(type, value.GetDict()); - if (!encoded_data) { - return std::nullopt; - } - std::vector encoded_value = KeccakHash(encoded_data->first); + Eip712HashArray result = {}; + base::span(result).copy_from(base::byte_span_from_ref(encoded_value)); + base::ranges::reverse(result); - result.insert(result.end(), encoded_value.begin(), encoded_value.end()); + return result; } - return result; + + if (!value.is_dict()) { + return std::nullopt; + } + auto encoded_data = EncodeData(type_string, value.GetDict()); + if (!encoded_data) { + return std::nullopt; + } + return KeccakHash(encoded_data->first); } -std::optional, base::Value::Dict>> +std::optional< + std::pair> EthSignTypedDataHelper::GetTypedDataDomainHash( const base::Value::Dict& domain) const { return HashStruct("EIP712Domain", domain); } -std::optional, base::Value::Dict>> +std::optional< + std::pair> EthSignTypedDataHelper::GetTypedDataPrimaryHash( const std::string& primary_type_name, const base::Value::Dict& message) const { @@ -397,7 +394,8 @@ EthSignTypedDataHelper::GetTypedDataPrimaryHash( } // static -std::vector EthSignTypedDataHelper::GetTypedDataMessageToSign( +EthSignTypedDataHelper::Eip712HashArray +EthSignTypedDataHelper::GetTypedDataMessageToSign( base::span domain_hash, base::span primary_hash) { DCHECK(!domain_hash.empty()); diff --git a/components/brave_wallet/common/eth_sign_typed_data_helper.h b/components/brave_wallet/common/eth_sign_typed_data_helper.h index f4655c33328d..7b1200ba0386 100644 --- a/components/brave_wallet/common/eth_sign_typed_data_helper.h +++ b/components/brave_wallet/common/eth_sign_typed_data_helper.h @@ -16,6 +16,7 @@ #include "base/containers/span.h" #include "base/gtest_prod_util.h" #include "base/values.h" +#include "brave/components/brave_wallet/common/hash_utils.h" namespace brave_wallet { @@ -23,6 +24,7 @@ namespace brave_wallet { // https://eips.ethereum.org/EIPS/eip-712 class EthSignTypedDataHelper { public: + using Eip712HashArray = KeccakHashArray; enum class Version { kV3, kV4 }; static std::unique_ptr Create(base::Value::Dict types, Version version); @@ -34,20 +36,20 @@ class EthSignTypedDataHelper { void SetTypes(base::Value::Dict types); void SetVersion(Version version); - std::vector GetTypeHash(const std::string& primary_type_name) const; - std::optional, base::Value::Dict>> HashStruct( + Eip712HashArray GetTypeHash(const std::string& primary_type_name) const; + std::optional> HashStruct( const std::string& primary_type_name, const base::Value::Dict& data) const; std::optional, base::Value::Dict>> EncodeData( const std::string& primary_type_name, const base::Value::Dict& data) const; - static std::vector GetTypedDataMessageToSign( + static Eip712HashArray GetTypedDataMessageToSign( base::span domain_hash, base::span primary_hash); - std::optional, base::Value::Dict>> + std::optional> GetTypedDataPrimaryHash(const std::string& primary_type_name, const base::Value::Dict& message) const; - std::optional, base::Value::Dict>> + std::optional> GetTypedDataDomainHash(const base::Value::Dict& domain) const; private: @@ -66,9 +68,8 @@ class EthSignTypedDataHelper { const std::string& type_name) const; std::string EncodeTypes(const std::string& primary_type_name) const; - std::optional> EncodeField( - const std::string& type, - const base::Value& value) const; + std::optional EncodeField(const std::string& type, + const base::Value& value) const; base::Value::Dict types_; Version version_; diff --git a/components/brave_wallet/common/hash_utils.cc b/components/brave_wallet/common/hash_utils.cc index f66a178c0cc1..2d5ea36c3f78 100644 --- a/components/brave_wallet/common/hash_utils.cc +++ b/components/brave_wallet/common/hash_utils.cc @@ -8,8 +8,6 @@ #include #include -#include "base/check.h" -#include "base/compiler_specific.h" #include "base/containers/adapters.h" #include "base/containers/span.h" #include "base/ranges/algorithm.h" @@ -31,47 +29,38 @@ std::array ConcatArrays(const std::array& arr1, } } // namespace -std::string KeccakHash(const std::string& input, bool to_hex) { - std::vector bytes(input.begin(), input.end()); - std::vector result = KeccakHash(bytes); - std::string result_str(result.begin(), result.end()); - return to_hex ? ToHex(result_str) : result_str; -} - -std::vector KeccakHash(const std::vector& input) { - auto hash = ethash_keccak256(input.data(), input.size()); - return UNSAFE_TODO(std::vector(hash.bytes, hash.bytes + 32)); -} - -eth_abi::Bytes32 KeccakHashBytes32(base::span input) { +KeccakHashArray KeccakHash(base::span input) { auto hash = ethash_keccak256(input.data(), input.size()); - eth_abi::Bytes32 result; + KeccakHashArray result; static_assert(sizeof(result) == sizeof(hash.bytes)); base::ranges::copy(hash.bytes, result.begin()); return result; } +std::vector KeccakHashToVector(base::span input) { + auto hash = KeccakHash(input); + return {hash.begin(), hash.end()}; +} + std::string GetFunctionHash(const std::string& input) { - std::string result = KeccakHash(input); - return result.substr(0, std::min(static_cast(10), result.length())); + return ToHex(GetFunctionHashBytes4(input)); } eth_abi::Bytes4 GetFunctionHashBytes4(const std::string& input) { - auto full_hash = KeccakHashBytes32(base::as_bytes(base::make_span(input))); eth_abi::Bytes4 bytes_result; - base::ranges::copy(base::make_span(full_hash).first<4>(), - bytes_result.begin()); + base::span(bytes_result) + .copy_from(base::span(KeccakHash(base::as_byte_span(input))).first<4>()); return bytes_result; } eth_abi::Bytes32 Namehash(const std::string& name) { eth_abi::Bytes32 hash = {}; - std::vector labels = - SplitString(name, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + auto labels = SplitStringPiece(name, ".", base::KEEP_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); for (const auto& label : base::Reversed(labels)) { - auto label_hash = KeccakHashBytes32(base::as_bytes(base::make_span(label))); - hash = KeccakHashBytes32(ConcatArrays(hash, label_hash)); + auto label_hash = KeccakHash(base::as_byte_span(label)); + hash = KeccakHash(ConcatArrays(hash, label_hash)); } return hash; } @@ -80,15 +69,11 @@ SHA256HashArray DoubleSHA256Hash(base::span input) { return crypto::SHA256Hash(crypto::SHA256Hash(input)); } -std::vector Hash160(base::span input) { - std::vector result(CRIPEMD160::OUTPUT_SIZE); - - std::array sha256hash = - crypto::SHA256Hash(input); - DCHECK(!sha256hash.empty()); +Ripemd160HashArray Hash160(base::span input) { + Ripemd160HashArray result = {}; CRIPEMD160() - .Write(sha256hash.data(), sha256hash.size()) + .Write(crypto::SHA256Hash(input).data(), crypto::kSHA256Length) .Finalize(result.data()); return result; diff --git a/components/brave_wallet/common/hash_utils.h b/components/brave_wallet/common/hash_utils.h index 63d093548b10..4853e24e77de 100644 --- a/components/brave_wallet/common/hash_utils.h +++ b/components/brave_wallet/common/hash_utils.h @@ -8,17 +8,22 @@ #include #include -#include #include "brave/components/brave_wallet/common/eth_abi_utils.h" #include "crypto/sha2.h" namespace brave_wallet { -// Equivalent to web3.utils.keccak256(string) -std::string KeccakHash(const std::string& input, bool to_hex = true); -std::vector KeccakHash(const std::vector& input); -eth_abi::Bytes32 KeccakHashBytes32(base::span input); +inline constexpr size_t kKeccakHashLength = 32; +inline constexpr size_t kRipemd160HashLength = 20; + +using KeccakHashArray = std::array; +using SHA256HashArray = std::array; +using Ripemd160HashArray = std::array; + +KeccakHashArray KeccakHash(base::span input); +// TODO(apaymyshev): remove this when all callers are refactored. +std::vector KeccakHashToVector(base::span input); // Returns the hex encoding of the first 4 bytes of the hash. // For example: keccak('balanceOf(address)') @@ -31,11 +36,10 @@ eth_abi::Bytes4 GetFunctionHashBytes4(const std::string& input); eth_abi::Bytes32 Namehash(const std::string& name); // sha256(sha256(input)) -using SHA256HashArray = std::array; SHA256HashArray DoubleSHA256Hash(base::span input); // ripemd160(sha256(input)) -std::vector Hash160(base::span input); +Ripemd160HashArray Hash160(base::span input); } // namespace brave_wallet diff --git a/components/brave_wallet/common/hash_utils_unittest.cc b/components/brave_wallet/common/hash_utils_unittest.cc index 55da6011d88c..587b4740a162 100644 --- a/components/brave_wallet/common/hash_utils_unittest.cc +++ b/components/brave_wallet/common/hash_utils_unittest.cc @@ -7,6 +7,7 @@ #include +#include "base/containers/span.h" #include "brave/components/brave_wallet/common/hex_utils.h" #include "testing/gtest/include/gtest/gtest.h" @@ -14,10 +15,10 @@ namespace brave_wallet { TEST(HashUtilsUnitTest, KeccakHash) { ASSERT_EQ( - KeccakHash(""), + ToHex(KeccakHash({})), "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); ASSERT_EQ( - KeccakHash("hello world"), + ToHex(KeccakHash(base::byte_span_from_cstring("hello world"))), "0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad"); } diff --git a/components/brave_wallet/common/zcash_utils.cc b/components/brave_wallet/common/zcash_utils.cc index 997ec72b76d9..e0fa83732668 100644 --- a/components/brave_wallet/common/zcash_utils.cc +++ b/components/brave_wallet/common/zcash_utils.cc @@ -10,6 +10,7 @@ #include #include +#include "base/containers/extend.h" #include "base/containers/span.h" #include "base/numerics/byte_conversions.h" #include "base/types/expected.h" @@ -39,7 +40,7 @@ std::array GetPaddedHRP(bool is_testnet) { "Wrong kPaddedHrpSize size"); std::string hrp = is_testnet ? kTestnetHRP : kMainnetHRP; std::array padded_hrp = {}; - base::ranges::copy(base::make_span(hrp), padded_hrp.begin()); + base::ranges::copy(base::as_byte_span(hrp), padded_hrp.begin()); return padded_hrp; } @@ -189,8 +190,8 @@ std::string PubkeyToTransparentAddress(base::span pubkey, bool testnet) { std::vector result = GetNetworkPrefix(testnet); - std::vector data_part = Hash160(pubkey); - result.insert(result.end(), data_part.begin(), data_part.end()); + base::Extend(result, Hash160(pubkey)); + return Base58EncodeWithCheck(result); } @@ -282,18 +283,15 @@ std::optional> ExtractParsedAddresses( return std::nullopt; } - auto padded_hrp = GetPaddedHRP(is_testnet); + auto [body, hrp] = + base::span(*reverted).split_at(reverted->size() - kPaddedHrpSize); // Check that HRP is similar to the padded HRP - if (!std::equal(padded_hrp.begin(), padded_hrp.end(), - reverted->end() - kPaddedHrpSize)) { + if (GetPaddedHRP(is_testnet) != hrp) { return std::nullopt; } - auto parts = ParseUnifiedAddressBody( - base::make_span(*reverted).subspan(0, reverted->size() - kPaddedHrpSize)); - - return parts; + return ParseUnifiedAddressBody(body); } // https://zips.z.cash/zip-0316#encoding-of-unified-addresses