Skip to content

Commit

Permalink
Expose TWBitcoinSigHashType as enum (#569)
Browse files Browse the repository at this point in the history
* Expose TWSignatureHashType as enum

- Note: Doesn't break funtionality

* Add seperate file TWBitcoinSigHashType

- Change all references

* Add header

* Fix iOS tests

* expose TWBitcoinSigHashTypeIsSingle
  • Loading branch information
BSathvik authored Aug 4, 2019
1 parent b76b2a9 commit e5bf89b
Show file tree
Hide file tree
Showing 24 changed files with 105 additions and 85 deletions.
10 changes: 1 addition & 9 deletions include/TrustWalletCore/TWBitcoin.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,10 @@
#pragma once

#include "TWBase.h"
#include "TWBitcoinSigHashType.h"

TW_EXTERN_C_BEGIN

static const uint32_t TWSignatureHashTypeAll = 0x01;
static const uint32_t TWSignatureHashTypeNone = 0x02;
static const uint32_t TWSignatureHashTypeSingle = 0x03;
static const uint32_t TWSignatureHashTypeFork = 0x40;
static const uint32_t TWSignatureHashTypeAnyoneCanPay = 0x80;

extern bool TWSignatureHashTypeIsSingle(uint32_t type);
extern bool TWSignatureHashTypeIsNone(uint32_t type);

enum TWBitcoinSignatureVersion {
BASE,
WITNESS_V0
Expand Down
28 changes: 28 additions & 0 deletions include/TrustWalletCore/TWBitcoinSigHashType.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright © 2017-2019 Trust Wallet.
//
// This file is part of Trust. The full Trust copyright notice, including
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

#pragma once

#include "TWBase.h"

TW_EXTERN_C_BEGIN

TW_EXPORT_ENUM(uint32_t)
enum TWBitcoinSigHashType {
TWBitcoinSigHashTypeAll = 0x01,
TWBitcoinSigHashTypeNone = 0x02,
TWBitcoinSigHashTypeSingle = 0x03,
TWBitcoinSigHashTypeFork = 0x40,
TWBitcoinSigHashTypeAnyoneCanPay = 0x80
};

TW_EXPORT_METHOD
bool TWBitcoinSigHashTypeIsSingle(enum TWBitcoinSigHashType type);

TW_EXPORT_METHOD
bool TWBitcoinSigHashTypeIsNone(enum TWBitcoinSigHashType type);

TW_EXTERN_C_END
2 changes: 1 addition & 1 deletion js/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "trust-wallet-core",
"version": "0.4.0",
"version": "0.5.0",
"description": "JavaScript wrapper for wallet-core",
"main": "build/lib/index.js",
"types": "build/lib/index.d.ts",
Expand Down
32 changes: 16 additions & 16 deletions src/Bitcoin/Transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
using namespace TW::Bitcoin;

std::vector<uint8_t> Transaction::getPreImage(const Script& scriptCode, size_t index,
uint32_t hashType, uint64_t amount) const {
enum TWBitcoinSigHashType hashType, uint64_t amount) const {
assert(index < inputs.size());

auto data = std::vector<uint8_t>{};
Expand All @@ -25,16 +25,16 @@ std::vector<uint8_t> Transaction::getPreImage(const Script& scriptCode, size_t i
encode32LE(version, data);

// Input prevouts (none/all, depending on flags)
if ((hashType & TWSignatureHashTypeAnyoneCanPay) == 0) {
if ((hashType & TWBitcoinSigHashTypeAnyoneCanPay) == 0) {
auto hashPrevouts = getPrevoutHash();
std::copy(std::begin(hashPrevouts), std::end(hashPrevouts), std::back_inserter(data));
} else {
std::fill_n(back_inserter(data), 32, 0);
}

// Input nSequence (none/all, depending on flags)
if ((hashType & TWSignatureHashTypeAnyoneCanPay) == 0 &&
!TWSignatureHashTypeIsSingle(hashType) && !TWSignatureHashTypeIsNone(hashType)) {
if ((hashType & TWBitcoinSigHashTypeAnyoneCanPay) == 0 &&
!TWBitcoinSigHashTypeIsSingle(hashType) && !TWBitcoinSigHashTypeIsNone(hashType)) {
auto hashSequence = getSequenceHash();
std::copy(std::begin(hashSequence), std::end(hashSequence), std::back_inserter(data));
} else {
Expand All @@ -51,10 +51,10 @@ std::vector<uint8_t> Transaction::getPreImage(const Script& scriptCode, size_t i
encode32LE(inputs[index].sequence, data);

// Outputs (none/one/all, depending on flags)
if (!TWSignatureHashTypeIsSingle(hashType) && !TWSignatureHashTypeIsNone(hashType)) {
if (!TWBitcoinSigHashTypeIsSingle(hashType) && !TWBitcoinSigHashTypeIsNone(hashType)) {
auto hashOutputs = getOutputsHash();
copy(begin(hashOutputs), end(hashOutputs), back_inserter(data));
} else if (TWSignatureHashTypeIsSingle(hashType) && index < outputs.size()) {
} else if (TWBitcoinSigHashTypeIsSingle(hashType) && index < outputs.size()) {
auto outputData = std::vector<uint8_t>{};
outputs[index].encode(outputData);
auto hashOutputs = TW::Hash::hash(hasher, outputData);
Expand Down Expand Up @@ -129,7 +129,7 @@ void Transaction::encode(bool witness, std::vector<uint8_t>& data) const {
}

std::vector<uint8_t> Transaction::getSignatureHash(const Script& scriptCode, size_t index,
uint32_t hashType, uint64_t amount,
enum TWBitcoinSigHashType hashType, uint64_t amount,
TWBitcoinSignatureVersion version) const {
switch (version) {
case BASE:
Expand All @@ -141,7 +141,7 @@ std::vector<uint8_t> Transaction::getSignatureHash(const Script& scriptCode, siz

/// Generates the signature hash for Witness version 0 scripts.
std::vector<uint8_t> Transaction::getSignatureHashWitnessV0(const Script& scriptCode, size_t index,
uint32_t hashType,
enum TWBitcoinSigHashType hashType,
uint64_t amount) const {
auto preimage = getPreImage(scriptCode, index, hashType, amount);
auto hash = TW::Hash::hash(hasher, preimage);
Expand All @@ -150,22 +150,22 @@ std::vector<uint8_t> Transaction::getSignatureHashWitnessV0(const Script& script

/// Generates the signature hash for for scripts other than witness scripts.
std::vector<uint8_t> Transaction::getSignatureHashBase(const Script& scriptCode, size_t index,
uint32_t hashType) const {
enum TWBitcoinSigHashType hashType) const {
assert(index < inputs.size());

auto data = std::vector<uint8_t>{};

encode32LE(version, data);

auto serializedInputCount =
(hashType & TWSignatureHashTypeAnyoneCanPay) != 0 ? 1 : inputs.size();
(hashType & TWBitcoinSigHashTypeAnyoneCanPay) != 0 ? 1 : inputs.size();
encodeVarInt(serializedInputCount, data);
for (auto subindex = 0; subindex < serializedInputCount; subindex += 1) {
serializeInput(subindex, scriptCode, index, hashType, data);
}

auto hashNone = (hashType & 0x1f) == TWSignatureHashTypeNone;
auto hashSingle = (hashType & 0x1f) == TWSignatureHashTypeSingle;
auto hashNone = (hashType & 0x1f) == TWBitcoinSigHashTypeNone;
auto hashSingle = (hashType & 0x1f) == TWBitcoinSigHashTypeSingle;
auto serializedOutputCount = hashNone ? 0 : (hashSingle ? index + 1 : outputs.size());
encodeVarInt(serializedOutputCount, data);
for (auto subindex = 0; subindex < serializedOutputCount; subindex += 1) {
Expand All @@ -188,10 +188,10 @@ std::vector<uint8_t> Transaction::getSignatureHashBase(const Script& scriptCode,
}

void Transaction::serializeInput(size_t subindex, const Script& scriptCode, size_t index,
uint32_t hashType, std::vector<uint8_t>& data) const {
enum TWBitcoinSigHashType hashType, std::vector<uint8_t>& data) const {
// In case of SIGHASH_ANYONECANPAY, only the input being signed is
// serialized
if ((hashType & TWSignatureHashTypeAnyoneCanPay) != 0) {
if ((hashType & TWBitcoinSigHashTypeAnyoneCanPay) != 0) {
subindex = index;
}

Expand All @@ -205,8 +205,8 @@ void Transaction::serializeInput(size_t subindex, const Script& scriptCode, size
}

// Serialize the nSequence
auto hashNone = (hashType & 0x1f) == TWSignatureHashTypeNone;
auto hashSingle = (hashType & 0x1f) == TWSignatureHashTypeSingle;
auto hashNone = (hashType & 0x1f) == TWBitcoinSigHashTypeNone;
auto hashSingle = (hashType & 0x1f) == TWBitcoinSigHashTypeSingle;
if (subindex != index && (hashSingle || hashNone)) {
encode32LE(0, data);
} else {
Expand Down
10 changes: 5 additions & 5 deletions src/Bitcoin/Transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ struct Transaction {
bool empty() const { return inputs.empty() && outputs.empty(); }

/// Generates the signature pre-image.
std::vector<uint8_t> getPreImage(const Script& scriptCode, size_t index, uint32_t hashType,
std::vector<uint8_t> getPreImage(const Script& scriptCode, size_t index, enum TWBitcoinSigHashType hashType,
uint64_t amount) const;
std::vector<uint8_t> getPrevoutHash() const;
std::vector<uint8_t> getSequenceHash() const;
Expand All @@ -59,10 +59,10 @@ struct Transaction {
void encode(bool witness, std::vector<uint8_t>& data) const;

/// Generates the signature hash for this transaction.
std::vector<uint8_t> getSignatureHash(const Script& scriptCode, size_t index, uint32_t hashType,
std::vector<uint8_t> getSignatureHash(const Script& scriptCode, size_t index, enum TWBitcoinSigHashType hashType,
uint64_t amount, TWBitcoinSignatureVersion version) const;

void serializeInput(size_t subindex, const Script&, size_t index, uint32_t hashType,
void serializeInput(size_t subindex, const Script&, size_t index, enum TWBitcoinSigHashType hashType,
std::vector<uint8_t>& data) const;

/// Converts to Protobuf model
Expand All @@ -71,11 +71,11 @@ struct Transaction {
private:
/// Generates the signature hash for Witness version 0 scripts.
std::vector<uint8_t> getSignatureHashWitnessV0(const Script& scriptCode, size_t index,
uint32_t hashType, uint64_t amount) const;
enum TWBitcoinSigHashType hashType, uint64_t amount) const;

/// Generates the signature hash for for scripts other than witness scripts.
std::vector<uint8_t> getSignatureHashBase(const Script& scriptCode, size_t index,
uint32_t hashType) const;
enum TWBitcoinSigHashType hashType) const;
};

} // namespace TW::Bitcoin
Expand Down
8 changes: 4 additions & 4 deletions src/Bitcoin/TransactionSigner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ Result<Transaction> TransactionSigner<Transaction>::sign() {
std::back_inserter(signedInputs));

const bool hashSingle =
((input.hash_type() & ~TWSignatureHashTypeAnyoneCanPay) == TWSignatureHashTypeSingle);
((input.hash_type() & ~TWBitcoinSigHashTypeAnyoneCanPay) == TWBitcoinSigHashTypeSingle);
for (auto i = 0; i < plan.utxos.size(); i += 1) {
auto& utxo = plan.utxos[i];

// Only sign TWSignatureHashTypeSingle if there's a corresponding output
// Only sign TWBitcoinSigHashTypeSingle if there's a corresponding output
if (hashSingle && i >= transaction.outputs.size()) {
continue;
}
Expand All @@ -55,7 +55,7 @@ Result<void> TransactionSigner<Transaction>::sign(Script script, size_t index,
std::vector<Data> witnessStack;

uint32_t signatureVersion = [this]() {
if ((input.hash_type() & TWSignatureHashTypeFork) != 0) {
if ((input.hash_type() & TWBitcoinSigHashTypeFork) != 0) {
return WITNESS_V0;
} else {
return BASE;
Expand Down Expand Up @@ -209,7 +209,7 @@ Data TransactionSigner<Transaction>::createSignature(const Transaction& transact
const Script& script, const Data& key,
size_t index, Amount amount,
uint32_t version) {
auto sighash = transaction.getSignatureHash(script, index, input.hash_type(), amount,
auto sighash = transaction.getSignatureHash(script, index, static_cast<TWBitcoinSigHashType>(input.hash_type()), amount,
static_cast<TWBitcoinSignatureVersion>(version));
auto pk = PrivateKey(key);
auto sig = pk.signAsDER(Data(begin(sighash), end(sighash)), TWCurveSECP256k1);
Expand Down
6 changes: 3 additions & 3 deletions src/Decred/Signer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ Result<Transaction> Signer::sign() {
std::back_inserter(signedInputs));

const bool hashSingle =
((input.hash_type() & ~TWSignatureHashTypeAnyoneCanPay) == TWSignatureHashTypeSingle);
((input.hash_type() & ~TWBitcoinSigHashTypeAnyoneCanPay) == TWBitcoinSigHashTypeSingle);
for (auto i = 0; i < plan.utxos.size(); i += 1) {
auto& utxo = plan.utxos[i];

// Only sign TWSignatureHashTypeSingle if there's a corresponding output
// Only sign TWBitcoinSigHashTypeSingle if there's a corresponding output
if (hashSingle && i >= transaction.outputs.size()) {
continue;
}
Expand Down Expand Up @@ -145,7 +145,7 @@ Result<std::vector<Data>> Signer::signStep(Bitcoin::Script script, size_t index)

Data Signer::createSignature(const Transaction& transaction, const Bitcoin::Script& script,
const Data& key, size_t index) {
auto sighash = transaction.computeSignatureHash(script, index, input.hash_type());
auto sighash = transaction.computeSignatureHash(script, index, static_cast<TWBitcoinSigHashType>(input.hash_type()));
auto pk = PrivateKey(key);
auto signature = pk.signAsDER(Data(begin(sighash), end(sighash)), TWCurveSECP256k1);
if (script.empty()) {
Expand Down
16 changes: 8 additions & 8 deletions src/Decred/Transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,27 @@ std::size_t sigHashWitnessSize(const std::vector<TransactionInput>& inputs,
} // namespace

Data Transaction::computeSignatureHash(const Bitcoin::Script& prevOutScript, size_t index,
uint32_t hashType) const {
enum TWBitcoinSigHashType hashType) const {
assert(index < inputs.size());

if (TWSignatureHashTypeIsSingle(hashType) && index >= outputs.size()) {
if (TWBitcoinSigHashTypeIsSingle(hashType) && index >= outputs.size()) {
throw std::invalid_argument("attempt to sign single input at index "
"larger than the number of outputs");
}

auto inputsToSign = inputs;
auto signIndex = index;
if ((hashType & TWSignatureHashTypeAnyoneCanPay) != 0) {
if ((hashType & TWBitcoinSigHashTypeAnyoneCanPay) != 0) {
inputsToSign = {inputs[index]};
signIndex = 0;
}

auto outputsToSign = outputs;
switch (hashType & sigHashMask) {
case TWSignatureHashTypeNone:
case TWBitcoinSigHashTypeNone:
outputsToSign = {};
break;
case TWSignatureHashTypeSingle:
case TWBitcoinSigHashTypeSingle:
outputsToSign.clear();
std::copy(outputs.begin(), outputs.begin() + index + 1, outputsToSign.end());
break;
Expand All @@ -78,7 +78,7 @@ Data Transaction::computeSignatureHash(const Bitcoin::Script& prevOutScript, siz
Data Transaction::computePrefixHash(const std::vector<TransactionInput>& inputsToSign,
const std::vector<TransactionOutput>& outputsToSign,
std::size_t signIndex, std::size_t index,
uint32_t hashType) const {
enum TWBitcoinSigHashType hashType) const {
auto preimage = Data{};

// Commit to the version and hash serialization type.
Expand All @@ -93,7 +93,7 @@ Data Transaction::computePrefixHash(const std::vector<TransactionInput>& inputsT
input.previousOutput.encode(preimage);

auto sequence = input.sequence;
if ((TWSignatureHashTypeIsNone(hashType) || TWSignatureHashTypeIsSingle(hashType)) &&
if ((TWBitcoinSigHashTypeIsNone(hashType) || TWBitcoinSigHashTypeIsSingle(hashType)) &&
i != signIndex) {
sequence = 0;
}
Expand All @@ -106,7 +106,7 @@ Data Transaction::computePrefixHash(const std::vector<TransactionInput>& inputsT
auto& output = outputsToSign[i];
auto value = output.value;
auto pkScript = output.script;
if (TWSignatureHashTypeIsSingle(hashType) && i != index) {
if (TWBitcoinSigHashTypeIsSingle(hashType) && i != index) {
value = -1;
pkScript = {};
}
Expand Down
4 changes: 2 additions & 2 deletions src/Decred/Transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ struct Transaction {

/// Generates the signature pre-image.
Data computeSignatureHash(const Bitcoin::Script& scriptCode, size_t index,
uint32_t hashType) const;
enum TWBitcoinSigHashType hashType) const;

/// Generates the transaction hash.
Data hash() const;
Expand All @@ -63,7 +63,7 @@ struct Transaction {
private:
Data computePrefixHash(const std::vector<TransactionInput>& inputsToSign,
const std::vector<TransactionOutput>& outputsToSign,
std::size_t signIndex, std::size_t index, uint32_t hashType) const;
std::size_t signIndex, std::size_t index, enum TWBitcoinSigHashType hashType) const;
Data computeWitnessHash(const std::vector<TransactionInput>& inputsToSign,
const Bitcoin::Script& signScript, std::size_t signIndex) const;

Expand Down
14 changes: 7 additions & 7 deletions src/Zcash/Transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const auto shieldedOutputsHashPersonalization = Data({'Z','c','a','s','h','S','O
/// See also https://github.com/zcash/zcash/blob/36243f41f1d8df98bdc834825ba539263f1da121/src/consensus/upgrades.cpp#L28
constexpr std::array<byte, 4> saplingBranchID = {0xbb, 0x09, 0xb8, 0x76};

Data Transaction::getPreImage(const Bitcoin::Script& scriptCode, size_t index, uint32_t hashType,
Data Transaction::getPreImage(const Bitcoin::Script& scriptCode, size_t index, enum TWBitcoinSigHashType hashType,
uint64_t amount) const {
assert(index < inputs.size());

Expand All @@ -38,27 +38,27 @@ Data Transaction::getPreImage(const Bitcoin::Script& scriptCode, size_t index, u
encode32LE(versionGroupId, data);

// Input prevouts (none/all, depending on flags)
if ((hashType & TWSignatureHashTypeAnyoneCanPay) == 0) {
if ((hashType & TWBitcoinSigHashTypeAnyoneCanPay) == 0) {
auto hashPrevouts = getPrevoutHash();
std::copy(std::begin(hashPrevouts), std::end(hashPrevouts), std::back_inserter(data));
} else {
std::fill_n(back_inserter(data), 32, 0);
}

// Input nSequence (none/all, depending on flags)
if ((hashType & TWSignatureHashTypeAnyoneCanPay) == 0 &&
!TWSignatureHashTypeIsSingle(hashType) && !TWSignatureHashTypeIsNone(hashType)) {
if ((hashType & TWBitcoinSigHashTypeAnyoneCanPay) == 0 &&
!TWBitcoinSigHashTypeIsSingle(hashType) && !TWBitcoinSigHashTypeIsNone(hashType)) {
auto hashSequence = getSequenceHash();
std::copy(std::begin(hashSequence), std::end(hashSequence), std::back_inserter(data));
} else {
std::fill_n(back_inserter(data), 32, 0);
}

// Outputs (none/one/all, depending on flags)
if (!TWSignatureHashTypeIsSingle(hashType) && !TWSignatureHashTypeIsNone(hashType)) {
if (!TWBitcoinSigHashTypeIsSingle(hashType) && !TWBitcoinSigHashTypeIsNone(hashType)) {
auto hashOutputs = getOutputsHash();
copy(begin(hashOutputs), end(hashOutputs), back_inserter(data));
} else if (TWSignatureHashTypeIsSingle(hashType) && index < outputs.size()) {
} else if (TWBitcoinSigHashTypeIsSingle(hashType) && index < outputs.size()) {
auto outputData = Data{};
outputs[index].encode(outputData);
auto hashOutputs =
Expand Down Expand Up @@ -176,7 +176,7 @@ void Transaction::encode(Data& data) const {
}

Data Transaction::getSignatureHash(const Bitcoin::Script& scriptCode, size_t index,
uint32_t hashType, uint64_t amount,
enum TWBitcoinSigHashType hashType, uint64_t amount,
TWBitcoinSignatureVersion version) const {
Data personalization;
personalization.reserve(16);
Expand Down
Loading

0 comments on commit e5bf89b

Please sign in to comment.