mirror of
https://github.com/Retropex/bitcoin.git
synced 2025-05-30 05:52:33 +02:00
Implement Taproot signature hashing (BIP 341)
This implements the new sighashing scheme from BIP341, with all relevant whole-transaction values precomputed once and cached. Includes changes to PrecomputedTransactionData by Pieter Wuille.
This commit is contained in:
parent
9eb590894f
commit
5de246ca81
@ -1291,23 +1291,79 @@ uint256 GetOutputsSHA256(const T& txTo)
|
|||||||
return ss.GetSHA256();
|
return ss.GetSHA256();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Compute the (single) SHA256 of the concatenation of all amounts spent by a tx. */
|
||||||
|
uint256 GetSpentAmountsSHA256(const std::vector<CTxOut>& outputs_spent)
|
||||||
|
{
|
||||||
|
CHashWriter ss(SER_GETHASH, 0);
|
||||||
|
for (const auto& txout : outputs_spent) {
|
||||||
|
ss << txout.nValue;
|
||||||
|
}
|
||||||
|
return ss.GetSHA256();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compute the (single) SHA256 of the concatenation of all scriptPubKeys spent by a tx. */
|
||||||
|
uint256 GetSpentScriptsSHA256(const std::vector<CTxOut>& outputs_spent)
|
||||||
|
{
|
||||||
|
CHashWriter ss(SER_GETHASH, 0);
|
||||||
|
for (const auto& txout : outputs_spent) {
|
||||||
|
ss << txout.scriptPubKey;
|
||||||
|
}
|
||||||
|
return ss.GetSHA256();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent_outputs)
|
void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent_outputs)
|
||||||
{
|
{
|
||||||
assert(!m_ready);
|
assert(!m_spent_outputs_ready);
|
||||||
|
|
||||||
m_spent_outputs = std::move(spent_outputs);
|
m_spent_outputs = std::move(spent_outputs);
|
||||||
|
if (!m_spent_outputs.empty()) {
|
||||||
// Cache is calculated only for transactions with witness
|
assert(m_spent_outputs.size() == txTo.vin.size());
|
||||||
if (txTo.HasWitness()) {
|
m_spent_outputs_ready = true;
|
||||||
hashPrevouts = SHA256Uint256(GetPrevoutsSHA256(txTo));
|
|
||||||
hashSequence = SHA256Uint256(GetSequencesSHA256(txTo));
|
|
||||||
hashOutputs = SHA256Uint256(GetOutputsSHA256(txTo));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ready = true;
|
// Determine which precomputation-impacting features this transaction uses.
|
||||||
|
bool uses_bip143_segwit = false;
|
||||||
|
bool uses_bip341_taproot = false;
|
||||||
|
for (size_t inpos = 0; inpos < txTo.vin.size(); ++inpos) {
|
||||||
|
if (!txTo.vin[inpos].scriptWitness.IsNull()) {
|
||||||
|
if (m_spent_outputs_ready && m_spent_outputs[inpos].scriptPubKey.size() == 2 + WITNESS_V1_TAPROOT_SIZE &&
|
||||||
|
m_spent_outputs[inpos].scriptPubKey[0] == OP_1) {
|
||||||
|
// Treat every witness-bearing spend with 34-byte scriptPubKey that starts with OP_1 as a Taproot
|
||||||
|
// spend. This only works if spent_outputs was provided as well, but if it wasn't, actual validation
|
||||||
|
// will fail anyway. Note that this branch may trigger for scriptPubKeys that aren't actually segwit
|
||||||
|
// but in that case validation will fail as SCRIPT_ERR_WITNESS_UNEXPECTED anyway.
|
||||||
|
uses_bip341_taproot = true;
|
||||||
|
} else {
|
||||||
|
// Treat every spend that's not known to native witness v1 as a Witness v0 spend. This branch may
|
||||||
|
// also be taken for unknown witness versions, but it is harmless, and being precise would require
|
||||||
|
// P2SH evaluation to find the redeemScript.
|
||||||
|
uses_bip143_segwit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (uses_bip341_taproot && uses_bip143_segwit) break; // No need to scan further if we already need all.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uses_bip143_segwit || uses_bip341_taproot) {
|
||||||
|
// Computations shared between both sighash schemes.
|
||||||
|
m_prevouts_single_hash = GetPrevoutsSHA256(txTo);
|
||||||
|
m_sequences_single_hash = GetSequencesSHA256(txTo);
|
||||||
|
m_outputs_single_hash = GetOutputsSHA256(txTo);
|
||||||
|
}
|
||||||
|
if (uses_bip143_segwit) {
|
||||||
|
hashPrevouts = SHA256Uint256(m_prevouts_single_hash);
|
||||||
|
hashSequence = SHA256Uint256(m_sequences_single_hash);
|
||||||
|
hashOutputs = SHA256Uint256(m_outputs_single_hash);
|
||||||
|
m_bip143_segwit_ready = true;
|
||||||
|
}
|
||||||
|
if (uses_bip341_taproot) {
|
||||||
|
m_spent_amounts_single_hash = GetSpentAmountsSHA256(m_spent_outputs);
|
||||||
|
m_spent_scripts_single_hash = GetSpentScriptsSHA256(m_spent_outputs);
|
||||||
|
m_bip341_taproot_ready = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
@ -1322,6 +1378,75 @@ template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo,
|
|||||||
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
|
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
|
||||||
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
|
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
|
||||||
|
|
||||||
|
static const CHashWriter HASHER_TAPSIGHASH = TaggedHash("TapSighash");
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool SignatureHashSchnorr(uint256& hash_out, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache)
|
||||||
|
{
|
||||||
|
uint8_t ext_flag;
|
||||||
|
switch (sigversion) {
|
||||||
|
case SigVersion::TAPROOT:
|
||||||
|
ext_flag = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
assert(in_pos < tx_to.vin.size());
|
||||||
|
assert(cache.m_bip341_taproot_ready && cache.m_spent_outputs_ready);
|
||||||
|
|
||||||
|
CHashWriter ss = HASHER_TAPSIGHASH;
|
||||||
|
|
||||||
|
// Epoch
|
||||||
|
static constexpr uint8_t EPOCH = 0;
|
||||||
|
ss << EPOCH;
|
||||||
|
|
||||||
|
// Hash type
|
||||||
|
const uint8_t output_type = (hash_type == SIGHASH_DEFAULT) ? SIGHASH_ALL : (hash_type & SIGHASH_OUTPUT_MASK); // Default (no sighash byte) is equivalent to SIGHASH_ALL
|
||||||
|
const uint8_t input_type = hash_type & SIGHASH_INPUT_MASK;
|
||||||
|
if (!(hash_type <= 0x03 || (hash_type >= 0x81 && hash_type <= 0x83))) return false;
|
||||||
|
ss << hash_type;
|
||||||
|
|
||||||
|
// Transaction level data
|
||||||
|
ss << tx_to.nVersion;
|
||||||
|
ss << tx_to.nLockTime;
|
||||||
|
if (input_type != SIGHASH_ANYONECANPAY) {
|
||||||
|
ss << cache.m_prevouts_single_hash;
|
||||||
|
ss << cache.m_spent_amounts_single_hash;
|
||||||
|
ss << cache.m_spent_scripts_single_hash;
|
||||||
|
ss << cache.m_sequences_single_hash;
|
||||||
|
}
|
||||||
|
if (output_type == SIGHASH_ALL) {
|
||||||
|
ss << cache.m_outputs_single_hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data about the input/prevout being spent
|
||||||
|
const auto& witstack = tx_to.vin[in_pos].scriptWitness.stack;
|
||||||
|
bool have_annex = witstack.size() > 1 && witstack.back().size() > 0 && witstack.back()[0] == ANNEX_TAG;
|
||||||
|
const uint8_t spend_type = (ext_flag << 1) + (have_annex ? 1 : 0); // The low bit indicates whether an annex is present.
|
||||||
|
ss << spend_type;
|
||||||
|
if (input_type == SIGHASH_ANYONECANPAY) {
|
||||||
|
ss << tx_to.vin[in_pos].prevout;
|
||||||
|
ss << cache.m_spent_outputs[in_pos];
|
||||||
|
ss << tx_to.vin[in_pos].nSequence;
|
||||||
|
} else {
|
||||||
|
ss << in_pos;
|
||||||
|
}
|
||||||
|
if (have_annex) {
|
||||||
|
ss << (CHashWriter(SER_GETHASH, 0) << witstack.back()).GetSHA256();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data about the output (if only one).
|
||||||
|
if (output_type == SIGHASH_SINGLE) {
|
||||||
|
if (in_pos >= tx_to.vout.size()) return false;
|
||||||
|
CHashWriter sha_single_output(SER_GETHASH, 0);
|
||||||
|
sha_single_output << tx_to.vout[in_pos];
|
||||||
|
ss << sha_single_output.GetSHA256();
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_out = ss.GetSHA256();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
|
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
|
||||||
{
|
{
|
||||||
@ -1331,7 +1456,7 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
|
|||||||
uint256 hashPrevouts;
|
uint256 hashPrevouts;
|
||||||
uint256 hashSequence;
|
uint256 hashSequence;
|
||||||
uint256 hashOutputs;
|
uint256 hashOutputs;
|
||||||
const bool cacheready = cache && cache->m_ready;
|
const bool cacheready = cache && cache->m_bip143_segwit_ready;
|
||||||
|
|
||||||
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
|
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
|
||||||
hashPrevouts = cacheready ? cache->hashPrevouts : SHA256Uint256(GetPrevoutsSHA256(txTo));
|
hashPrevouts = cacheready ? cache->hashPrevouts : SHA256Uint256(GetPrevoutsSHA256(txTo));
|
||||||
|
@ -25,6 +25,10 @@ enum
|
|||||||
SIGHASH_NONE = 2,
|
SIGHASH_NONE = 2,
|
||||||
SIGHASH_SINGLE = 3,
|
SIGHASH_SINGLE = 3,
|
||||||
SIGHASH_ANYONECANPAY = 0x80,
|
SIGHASH_ANYONECANPAY = 0x80,
|
||||||
|
|
||||||
|
SIGHASH_DEFAULT = 0, //!< Taproot only; implied when sighash byte is missing, and equivalent to SIGHASH_ALL
|
||||||
|
SIGHASH_OUTPUT_MASK = 3,
|
||||||
|
SIGHASH_INPUT_MASK = 0x80,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Script verification flags.
|
/** Script verification flags.
|
||||||
@ -121,9 +125,24 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i
|
|||||||
|
|
||||||
struct PrecomputedTransactionData
|
struct PrecomputedTransactionData
|
||||||
{
|
{
|
||||||
|
// BIP341 precomputed data.
|
||||||
|
// These are single-SHA256, see https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-15.
|
||||||
|
uint256 m_prevouts_single_hash;
|
||||||
|
uint256 m_sequences_single_hash;
|
||||||
|
uint256 m_outputs_single_hash;
|
||||||
|
uint256 m_spent_amounts_single_hash;
|
||||||
|
uint256 m_spent_scripts_single_hash;
|
||||||
|
//! Whether the 5 fields above are initialized.
|
||||||
|
bool m_bip341_taproot_ready = false;
|
||||||
|
|
||||||
|
// BIP143 precomputed data (double-SHA256).
|
||||||
uint256 hashPrevouts, hashSequence, hashOutputs;
|
uint256 hashPrevouts, hashSequence, hashOutputs;
|
||||||
bool m_ready = false;
|
//! Whether the 3 fields above are initialized.
|
||||||
|
bool m_bip143_segwit_ready = false;
|
||||||
|
|
||||||
std::vector<CTxOut> m_spent_outputs;
|
std::vector<CTxOut> m_spent_outputs;
|
||||||
|
//! Whether m_spent_outputs is initialized.
|
||||||
|
bool m_spent_outputs_ready = false;
|
||||||
|
|
||||||
PrecomputedTransactionData() = default;
|
PrecomputedTransactionData() = default;
|
||||||
|
|
||||||
@ -136,13 +155,15 @@ struct PrecomputedTransactionData
|
|||||||
|
|
||||||
enum class SigVersion
|
enum class SigVersion
|
||||||
{
|
{
|
||||||
BASE = 0,
|
BASE = 0, //!< Bare scripts and BIP16 P2SH-wrapped redeemscripts
|
||||||
WITNESS_V0 = 1,
|
WITNESS_V0 = 1, //!< Witness v0 (P2WPKH and P2WSH); see BIP 141
|
||||||
|
TAPROOT = 2, //!< Witness v1 with 32-byte program, not BIP16 P2SH-wrapped, key path spending; see BIP 341
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Signature hash sizes */
|
/** Signature hash sizes */
|
||||||
static constexpr size_t WITNESS_V0_SCRIPTHASH_SIZE = 32;
|
static constexpr size_t WITNESS_V0_SCRIPTHASH_SIZE = 32;
|
||||||
static constexpr size_t WITNESS_V0_KEYHASH_SIZE = 20;
|
static constexpr size_t WITNESS_V0_KEYHASH_SIZE = 20;
|
||||||
|
static constexpr size_t WITNESS_V1_TAPROOT_SIZE = 32;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
|
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
|
||||||
|
@ -44,6 +44,11 @@ static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20
|
|||||||
// SEQUENCE_FINAL).
|
// SEQUENCE_FINAL).
|
||||||
static const uint32_t LOCKTIME_MAX = 0xFFFFFFFFU;
|
static const uint32_t LOCKTIME_MAX = 0xFFFFFFFFU;
|
||||||
|
|
||||||
|
// Tag for input annex. If there are at least two witness elements for a transaction input,
|
||||||
|
// and the first byte of the last element is 0x50, this last element is called annex, and
|
||||||
|
// has meanings independent of the script
|
||||||
|
static constexpr unsigned int ANNEX_TAG = 0x50;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::vector<unsigned char> ToByteVector(const T& in)
|
std::vector<unsigned char> ToByteVector(const T& in)
|
||||||
{
|
{
|
||||||
|
@ -1538,7 +1538,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!txdata.m_ready) {
|
if (!txdata.m_spent_outputs_ready) {
|
||||||
std::vector<CTxOut> spent_outputs;
|
std::vector<CTxOut> spent_outputs;
|
||||||
spent_outputs.reserve(tx.vin.size());
|
spent_outputs.reserve(tx.vin.size());
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user