Skip to content

Commit e826b22

Browse files
committed
Merge bitcoin#22275: A few follow-ups for taproot signing
08f57a0 Assert that IsComplete() in GetSpendData() (Pieter Wuille) d8f4b97 Remove default nHashTypeIn arguments to MutableTransactionSignatureCreator (Pieter Wuille) c7048aa Simplify SignTransaction precomputation loop (Pieter Wuille) addb9b5 Improve comments in taproot signing logic (Pieter Wuille) Pull request description: This addresses a few review comments from bitcoin#21365 that were left at the time of merge (as well as some from bitcoin#22166 applying to the commit it shared with bitcoin#21365). I do not think any are blockers for a 22.0 release. ACKs for top commit: theStack: re-ACK 08f57a0 🌴 Zero-1729: crACK 08f57a0 jonatack: Code review ACK 08f57a0 per `git range-diff e9d6eb1 9336670 08f57a0` followed by re-code review per commit to swap context back into memory and debug build/run unit tests + feature_taproot.py as a sanity check Tree-SHA512: 968750109ba8d6faf3016035a38f81c6aefb724c632a3cab0bbf43cf31b9d187b6b0fddd8772768f57338df11eb07ab9c4c6dacdf3cf35b71f29699c67a301ea
2 parents a93e7a4 + 08f57a0 commit e826b22

File tree

8 files changed

+34
-21
lines changed

8 files changed

+34
-21
lines changed

src/key.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,15 @@ class CKey
133133
* optionally tweaked by *merkle_root. Additional nonce entropy can be provided through
134134
* aux.
135135
*
136-
* When merkle_root is not nullptr, this results in a signature with a modified key as
137-
* specified in BIP341:
138-
* - If merkle_root->IsNull(): key + H_TapTweak(pubkey)*G
139-
* - Otherwise: key + H_TapTweak(pubkey || *merkle_root)
136+
* merkle_root is used to optionally perform tweaking of the private key, as specified
137+
* in BIP341:
138+
* - If merkle_root == nullptr: no tweaking is done, sign with key directly (this is
139+
* used for signatures in BIP342 script).
140+
* - If merkle_root->IsNull(): sign with key + H_TapTweak(pubkey) (this is used for
141+
* key path spending when no scripts are present).
142+
* - Otherwise: sign with key + H_TapTweak(pubkey || *merkle_root)
143+
* (this is used for key path spending, with specific
144+
* Merkle root of the script tree).
140145
*/
141146
bool SignSchnorr(const uint256& hash, Span<unsigned char> sig, const uint256* merkle_root = nullptr, const uint256* aux = nullptr) const;
142147

src/script/interpreter.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,13 @@ struct PrecomputedTransactionData
170170

171171
PrecomputedTransactionData() = default;
172172

173+
/** Initialize this PrecomputedTransactionData with transaction data.
174+
*
175+
* @param[in] tx The transaction for which data is being precomputed.
176+
* @param[in] spent_outputs The CTxOuts being spent, one for each tx.vin, in order.
177+
* @param[in] force Whether to precompute data for all optional features,
178+
* regardless of what is in the inputs (used at signing
179+
* time, when the inputs aren't filled in yet). */
173180
template <class T>
174181
void Init(const T& tx, std::vector<CTxOut>&& spent_outputs, bool force = false);
175182

src/script/sign.cpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ bool MutableTransactionSignatureCreator::CreateSchnorrSig(const SigningProvider&
6161

6262
CKey key;
6363
{
64-
// For now, use the old full pubkey-based key derivation logic. As it indexed by
64+
// For now, use the old full pubkey-based key derivation logic. As it is indexed by
6565
// Hash160(full pubkey), we need to try both a version prefixed with 0x02, and one
6666
// with 0x03.
6767
unsigned char b[33] = {0x02};
@@ -640,25 +640,22 @@ bool SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore,
640640

641641
PrecomputedTransactionData txdata;
642642
std::vector<CTxOut> spent_outputs;
643-
spent_outputs.resize(mtx.vin.size());
644-
bool have_all_spent_outputs = true;
645-
for (unsigned int i = 0; i < mtx.vin.size(); i++) {
643+
for (unsigned int i = 0; i < mtx.vin.size(); ++i) {
646644
CTxIn& txin = mtx.vin[i];
647645
auto coin = coins.find(txin.prevout);
648646
if (coin == coins.end() || coin->second.IsSpent()) {
649-
have_all_spent_outputs = false;
647+
txdata.Init(txConst, /* spent_outputs */ {}, /* force */ true);
648+
break;
650649
} else {
651-
spent_outputs[i] = CTxOut(coin->second.out.nValue, coin->second.out.scriptPubKey);
650+
spent_outputs.emplace_back(coin->second.out.nValue, coin->second.out.scriptPubKey);
652651
}
653652
}
654-
if (have_all_spent_outputs) {
653+
if (spent_outputs.size() == mtx.vin.size()) {
655654
txdata.Init(txConst, std::move(spent_outputs), true);
656-
} else {
657-
txdata.Init(txConst, {}, true);
658655
}
659656

660657
// Sign what we can:
661-
for (unsigned int i = 0; i < mtx.vin.size(); i++) {
658+
for (unsigned int i = 0; i < mtx.vin.size(); ++i) {
662659
CTxIn& txin = mtx.vin[i];
663660
auto coin = coins.find(txin.prevout);
664661
if (coin == coins.end() || coin->second.IsSpent()) {

src/script/sign.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ class MutableTransactionSignatureCreator : public BaseSignatureCreator {
4545
const PrecomputedTransactionData* m_txdata;
4646

4747
public:
48-
MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn = SIGHASH_ALL);
49-
MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData* txdata, int nHashTypeIn = SIGHASH_ALL);
48+
MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn);
49+
MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData* txdata, int nHashTypeIn);
5050
const BaseSignatureChecker& Checker() const override { return checker; }
5151
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
5252
bool CreateSchnorrSig(const SigningProvider& provider, std::vector<unsigned char>& sig, const XOnlyPubKey& pubkey, const uint256* leaf_hash, const uint256* merkle_root, SigVersion sigversion) const override;

src/script/standard.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ WitnessV1Taproot TaprootBuilder::GetOutput() { return WitnessV1Taproot{m_output_
504504

505505
TaprootSpendData TaprootBuilder::GetSpendData() const
506506
{
507+
assert(IsComplete());
507508
TaprootSpendData spd;
508509
spd.merkle_root = m_branch.size() == 0 ? uint256() : m_branch[0]->hash;
509510
spd.internal_key = m_internal_key;

src/script/standard.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,11 @@ struct TaprootSpendData
227227
/** The Merkle root of the script tree (0 if no scripts). */
228228
uint256 merkle_root;
229229
/** Map from (script, leaf_version) to (sets of) control blocks.
230-
* The control blocks are sorted by size, so that the signing logic can
231-
* easily prefer the cheapest one. */
230+
* More than one control block for a given script is only possible if it
231+
* appears in multiple branches of the tree. We keep them all so that
232+
* inference can reconstruct the full tree. Within each set, the control
233+
* blocks are sorted by size, so that the signing logic can easily
234+
* prefer the cheapest one. */
232235
std::map<std::pair<CScript, int>, std::set<std::vector<unsigned char>, ShortestVectorFirstComparator>> scripts;
233236
/** Merge other TaprootSpendData (for the same scriptPubKey) into this. */
234237
void Merge(TaprootSpendData other);
@@ -252,7 +255,7 @@ class TaprootBuilder
252255
/** Merkle hash of this node. */
253256
uint256 hash;
254257
/** Tracked leaves underneath this node (either from the node itself, or its children).
255-
* The merkle_branch field for each is the partners to get to *this* node. */
258+
* The merkle_branch field of each is the partners to get to *this* node. */
256259
std::vector<LeafInfo> leaves;
257260
};
258261
/** Whether the builder is in a valid state so far. */

src/test/script_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1160,7 +1160,7 @@ SignatureData CombineSignatures(const CTxOut& txout, const CMutableTransaction&
11601160
SignatureData data;
11611161
data.MergeSignatureData(scriptSig1);
11621162
data.MergeSignatureData(scriptSig2);
1163-
ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(&tx, 0, txout.nValue), txout.scriptPubKey, data);
1163+
ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(&tx, 0, txout.nValue, SIGHASH_DEFAULT), txout.scriptPubKey, data);
11641164
return data;
11651165
}
11661166

src/test/transaction_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ SignatureData CombineSignatures(const CMutableTransaction& input1, const CMutabl
561561
SignatureData sigdata;
562562
sigdata = DataFromTransaction(input1, 0, tx->vout[0]);
563563
sigdata.MergeSignatureData(DataFromTransaction(input2, 0, tx->vout[0]));
564-
ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(&input1, 0, tx->vout[0].nValue), tx->vout[0].scriptPubKey, sigdata);
564+
ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(&input1, 0, tx->vout[0].nValue, SIGHASH_ALL), tx->vout[0].scriptPubKey, sigdata);
565565
return sigdata;
566566
}
567567

0 commit comments

Comments
 (0)