Skip to content

Commit

Permalink
Implement ZCash transparent tx signing (#20895)
Browse files Browse the repository at this point in the history
  • Loading branch information
cypt4 authored Nov 29, 2023
1 parent c84cb76 commit 8c95bd6
Show file tree
Hide file tree
Showing 35 changed files with 1,564 additions and 324 deletions.
8 changes: 8 additions & 0 deletions browser/about_flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,14 @@
FEATURE_VALUE_TYPE( \
brave_wallet::features::kNativeBraveWalletFeature), \
}, \
{ \
"brave-wallet-zcash", \
"Enable BraveWallet ZCash support", \
"ZCash support for native Brave Wallet", \
kOsDesktop | kOsAndroid, \
FEATURE_VALUE_TYPE( \
brave_wallet::features::kBraveWalletZCashFeature), \
}, \
{ \
"brave-wallet-bitcoin", \
"Enable Brave Wallet Bitcoin support", \
Expand Down
3 changes: 3 additions & 0 deletions components/brave_wallet/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ static_library("browser") {
"zcash/zcash_block_tracker.h",
"zcash/zcash_rpc.cc",
"zcash/zcash_rpc.h",
"zcash/zcash_serializer.cc",
"zcash/zcash_serializer.h",
"zcash/zcash_transaction.cc",
"zcash/zcash_transaction.h",
"zcash/zcash_tx_manager.cc",
Expand Down Expand Up @@ -259,6 +261,7 @@ static_library("browser") {
"//brave/components/json/rs:rust_lib",
"//brave/components/p3a_utils",
"//brave/components/resources:strings_grit",
"//brave/third_party/argon2",
"//components/component_updater",
"//components/content_settings/core/browser",
"//components/keyed_service/core",
Expand Down
87 changes: 14 additions & 73 deletions components/brave_wallet/browser/bitcoin/bitcoin_serializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "base/sys_byteorder.h"
#include "brave/components/brave_wallet/common/bitcoin_utils.h"
#include "brave/components/brave_wallet/common/btc_like_serializer_stream.h"
#include "brave/components/brave_wallet/common/hash_utils.h"

namespace brave_wallet {
Expand Down Expand Up @@ -64,13 +65,13 @@ const std::vector<uint8_t>& DummyWitness() {
}

void PushOutpoint(const BitcoinTransaction::Outpoint& outpoint,
BitcoinSerializerStream& stream) {
BtcLikeSerializerStream& stream) {
stream.PushBytesReversed(outpoint.txid);
stream.Push32AsLE(outpoint.index);
}

void PushScriptCodeForSigninig(const DecodedBitcoinAddress& decoded_address,
BitcoinSerializerStream& stream) {
BtcLikeSerializerStream& stream) {
// TODO(apaymyshev): support more.
DCHECK_EQ(decoded_address.address_type,
BitcoinAddressType::kWitnessV0PubkeyHash);
Expand All @@ -87,7 +88,7 @@ SHA256HashArray HashPrevouts(const BitcoinTransaction& tx) {
DCHECK_EQ(tx.sighash_type(), kBitcoinSigHashAll);

std::vector<uint8_t> data;
BitcoinSerializerStream stream(&data);
BtcLikeSerializerStream stream(&data);
for (const auto& input : tx.inputs()) {
PushOutpoint(input.utxo_outpoint, stream);
}
Expand All @@ -99,7 +100,7 @@ SHA256HashArray HashSequence(const BitcoinTransaction& tx) {
DCHECK_EQ(tx.sighash_type(), kBitcoinSigHashAll);

std::vector<uint8_t> data;
BitcoinSerializerStream stream(&data);
BtcLikeSerializerStream stream(&data);
for (const auto& input : tx.inputs()) {
stream.Push32AsLE(input.n_sequence());
}
Expand All @@ -108,7 +109,7 @@ SHA256HashArray HashSequence(const BitcoinTransaction& tx) {
}

void PushOutput(const BitcoinTransaction::TxOutput& output,
BitcoinSerializerStream& stream) {
BtcLikeSerializerStream& stream) {
stream.Push64AsLE(output.amount);
CHECK(output.script_pubkey.size());
stream.PushSizeAndBytes(output.script_pubkey);
Expand All @@ -118,7 +119,7 @@ SHA256HashArray HashOutputs(const BitcoinTransaction& tx) {
DCHECK_EQ(tx.sighash_type(), kBitcoinSigHashAll);

std::vector<uint8_t> data;
BitcoinSerializerStream stream(&data);
BtcLikeSerializerStream stream(&data);
for (const auto& output : tx.outputs()) {
PushOutput(output, stream);
}
Expand All @@ -127,7 +128,7 @@ SHA256HashArray HashOutputs(const BitcoinTransaction& tx) {
}

void SerializeInputs(const BitcoinTransaction& tx,
BitcoinSerializerStream& stream) {
BtcLikeSerializerStream& stream) {
stream.PushVarInt(tx.inputs().size());
for (const auto& input : tx.inputs()) {
PushOutpoint(input.utxo_outpoint, stream);
Expand Down Expand Up @@ -197,15 +198,15 @@ uint32_t GetOutputsVBytes(const BitcoinTransaction& tx) {
}

void SerializeOutputs(const BitcoinTransaction& tx,
BitcoinSerializerStream& stream) {
BtcLikeSerializerStream& stream) {
stream.PushVarInt(tx.outputs().size());
for (const auto& output : tx.outputs()) {
PushOutput(output, stream);
}
}

void SerializeWitnesses(const BitcoinTransaction& tx,
BitcoinSerializerStream& stream) {
BtcLikeSerializerStream& stream) {
for (const auto& input : tx.inputs()) {
DCHECK(!input.witness.empty());
stream.PushBytes(input.witness);
Expand Down Expand Up @@ -233,66 +234,6 @@ uint32_t GetWitnessesWeightUnits(const BitcoinTransaction& tx,

} // namespace

void BitcoinSerializerStream::Push8AsLE(uint8_t i) {
base::span<uint8_t> data_to_insert(reinterpret_cast<uint8_t*>(&i), sizeof(i));
PushBytes(data_to_insert);
}

void BitcoinSerializerStream::Push16AsLE(uint16_t i) {
i = base::ByteSwapToLE16(i);
base::span<uint8_t> data_to_insert(reinterpret_cast<uint8_t*>(&i), sizeof(i));
PushBytes(data_to_insert);
}

void BitcoinSerializerStream::Push32AsLE(uint32_t i) {
i = base::ByteSwapToLE32(i);
base::span<uint8_t> data_to_insert(reinterpret_cast<uint8_t*>(&i), sizeof(i));
PushBytes(data_to_insert);
}

void BitcoinSerializerStream::Push64AsLE(uint64_t i) {
i = base::ByteSwapToLE64(i);
base::span<uint8_t> data_to_insert(reinterpret_cast<uint8_t*>(&i), sizeof(i));
PushBytes(data_to_insert);
}

// https://developer.bitcoin.org/reference/transactions.html#compactsize-unsigned-integers
void BitcoinSerializerStream::PushVarInt(uint64_t i) {
if (i < 0xfd) {
Push8AsLE(i);
} else if (i <= 0xffff) {
Push8AsLE(0xfd);
Push16AsLE(i);
} else if (i <= 0xffffffff) {
Push8AsLE(0xfe);
Push32AsLE(i);
} else {
Push8AsLE(0xff);
Push64AsLE(i);
}
}

void BitcoinSerializerStream::PushSizeAndBytes(
base::span<const uint8_t> bytes) {
PushVarInt(bytes.size());
PushBytes(bytes);
}

void BitcoinSerializerStream::PushBytes(base::span<const uint8_t> bytes) {
if (to()) {
to()->insert(to()->end(), bytes.begin(), bytes.end());
}
serialized_bytes_ += bytes.size();
}

void BitcoinSerializerStream::PushBytesReversed(
base::span<const uint8_t> bytes) {
if (to()) {
to()->insert(to()->end(), bytes.rbegin(), bytes.rend());
}
serialized_bytes_ += bytes.size();
}

std::vector<uint8_t> BitcoinSerializer::AddressToScriptPubkey(
const std::string& address,
bool testnet) {
Expand All @@ -306,7 +247,7 @@ std::vector<uint8_t> BitcoinSerializer::AddressToScriptPubkey(
}

std::vector<uint8_t> data;
BitcoinSerializerStream stream(&data);
BtcLikeSerializerStream stream(&data);

// https://github.com/bitcoin/bitcoin/blob/v25.0/src/script/standard.cpp#L302-L325

Expand Down Expand Up @@ -387,7 +328,7 @@ absl::optional<SHA256HashArray> BitcoinSerializer::SerializeInputForSign(
}

std::vector<uint8_t> data;
BitcoinSerializerStream stream(&data);
BtcLikeSerializerStream stream(&data);
// https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification
stream.Push32AsLE(2); // 1.
stream.PushBytes(HashPrevouts(tx)); // 2.
Expand All @@ -410,7 +351,7 @@ std::vector<uint8_t> BitcoinSerializer::SerializeWitness(
const std::vector<uint8_t>& signature,
const std::vector<uint8_t>& pubkey) {
std::vector<uint8_t> result;
BitcoinSerializerStream witness_stream(&result);
BtcLikeSerializerStream witness_stream(&result);
// https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#transaction-id
// https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wpkh
witness_stream.PushVarInt(2);
Expand All @@ -425,7 +366,7 @@ std::vector<uint8_t> BitcoinSerializer::SerializeSignedTransaction(
DCHECK(tx.IsSigned());

std::vector<uint8_t> data;
BitcoinSerializerStream stream(&data);
BtcLikeSerializerStream stream(&data);

// https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki#specification
stream.Push32AsLE(kTransactionsVersion); // version
Expand Down
21 changes: 0 additions & 21 deletions components/brave_wallet/browser/bitcoin/bitcoin_serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,6 @@

namespace brave_wallet {

class BitcoinSerializerStream {
public:
explicit BitcoinSerializerStream(std::vector<uint8_t>* to) : to_(to) {}

void Push8AsLE(uint8_t i);
void Push16AsLE(uint16_t i);
void Push32AsLE(uint32_t i);
void Push64AsLE(uint64_t i);
void PushVarInt(uint64_t i);
void PushSizeAndBytes(base::span<const uint8_t> bytes);
void PushBytes(base::span<const uint8_t> bytes);
void PushBytesReversed(base::span<const uint8_t> bytes);

uint32_t serialized_bytes() const { return serialized_bytes_; }

private:
uint32_t serialized_bytes_ = 0;
std::vector<uint8_t>* to() { return to_.get(); }
raw_ptr<std::vector<uint8_t>> to_;
};

// TODO(apaymyshev): test with reference test vectors.
class BitcoinSerializer {
public:
Expand Down
Loading

0 comments on commit 8c95bd6

Please sign in to comment.