From 80f478e67e3b40ff9860c461be640a43d2aa4189 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 22 Jan 2022 22:59:28 +0000 Subject: [PATCH] Make `PrecomputedTransactionData` a required argument of `SignatureHash` The ZIP 244 changes mean that we're going to need to alter every callsite to pass through all of the transparent `CTxOut`s being spent. Given that we need to pass it over to Rust, it makes more sense to just have `PrecomputedTransactionData` be the vehicle for conveying this data across. --- src/bench/verification.cpp | 6 +- src/bitcoin-tx.cpp | 7 +- src/gtest/test_checktransaction.cpp | 34 +++-- src/main.cpp | 11 +- src/main.h | 3 + src/miner.cpp | 4 +- src/rpc/rawtransaction.cpp | 7 +- src/script/interpreter.cpp | 48 +++---- src/script/interpreter.h | 9 +- src/script/sigcache.h | 2 +- src/script/sign.cpp | 10 +- src/script/sign.h | 7 +- src/script/zcash_script.cpp | 4 +- src/test/DoS_tests.cpp | 6 +- src/test/multisig_tests.cpp | 36 +++--- src/test/script_P2SH_tests.cpp | 18 ++- src/test/script_tests.cpp | 121 +++++++++--------- src/test/sighash_tests.cpp | 9 +- src/test/transaction_tests.cpp | 31 +++-- src/test/txvalidationcache_tests.cpp | 3 +- src/transaction_builder.cpp | 5 +- src/utiltest.cpp | 6 +- .../asyncrpcoperation_mergetoaddress.cpp | 3 +- .../asyncrpcoperation_shieldcoinbase.cpp | 3 +- src/wallet/rpcwallet.cpp | 3 +- src/wallet/wallet.cpp | 3 +- src/zcbenchmarks.cpp | 7 +- 27 files changed, 224 insertions(+), 182 deletions(-) diff --git a/src/bench/verification.cpp b/src/bench/verification.cpp index 19c0b27d9..e29f503d2 100644 --- a/src/bench/verification.cpp +++ b/src/bench/verification.cpp @@ -48,9 +48,11 @@ static void ECDSA(benchmark::State& state) mtx.vout[i].scriptPubKey = CScript() << OP_1; } + const PrecomputedTransactionData txdata(mtx); + // sign all inputs for(uint32_t i = 0; i < mtx.vin.size(); i++) { - bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, SIGHASH_ALL, consensusBranchId); + bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, txdata, i, 1000, SIGHASH_ALL, consensusBranchId); assert(hashSigned); } @@ -66,7 +68,7 @@ static void ECDSA(benchmark::State& state) tx.vin[0].scriptSig, scriptPubKey, SCRIPT_VERIFY_P2SH, - TransactionSignatureChecker(&tx, 0, 1000), + TransactionSignatureChecker(&tx, txdata, 0, 1000), consensusBranchId, &error); } diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index ed4cd8cbe..191b936a4 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -468,6 +468,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& strInput) } const CKeyStore& keystore = tempKeystore; + const PrecomputedTransactionData txdata(mergedTx); bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); @@ -488,14 +489,14 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& strInput) SignatureData sigdata; // Only sign SIGHASH_SINGLE if there's a corresponding output: if (!fHashSingle || (i < mergedTx.vout.size())) - ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId); + ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, txdata, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId); // ... and merge in other signatures: for (const CTransaction& txv : txVariants) - sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId); + sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, txdata, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId); UpdateTransaction(mergedTx, i, sigdata); - if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount), consensusBranchId)) + if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, txdata, i, amount), consensusBranchId)) fComplete = false; } diff --git a/src/gtest/test_checktransaction.cpp b/src/gtest/test_checktransaction.cpp index 8a091598b..d87ceaf9a 100644 --- a/src/gtest/test_checktransaction.cpp +++ b/src/gtest/test_checktransaction.cpp @@ -113,7 +113,8 @@ void CreateJoinSplitSignature(CMutableTransaction& mtx, uint32_t consensusBranch // Empty output script. CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); + const PrecomputedTransactionData txdata(signTx); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata); if (dataToBeSigned == one) { throw std::runtime_error("SignatureHash failed"); } @@ -534,20 +535,21 @@ TEST(ContextualCheckShieldedInputsTest, BadTxnsInvalidJoinsplitSignature) { CMutableTransaction mtx = GetValidTransaction(); mtx.joinSplitSig.bytes[0] += 1; CTransaction tx(mtx); + const PrecomputedTransactionData txdata(tx); MockCValidationState state; // during initial block download, for transactions being accepted into the // mempool (and thus not mined), DoS ban score should be zero, else 10 EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1); - ContextualCheckShieldedInputs(tx, state, orchardAuth, consensus, 0, false, false, [](const Consensus::Params&) { return true; }); + ContextualCheckShieldedInputs(tx, txdata, state, orchardAuth, consensus, 0, false, false, [](const Consensus::Params&) { return true; }); EXPECT_CALL(state, DoS(10, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1); - ContextualCheckShieldedInputs(tx, state, orchardAuth, consensus, 0, false, false, [](const Consensus::Params&) { return false; }); + ContextualCheckShieldedInputs(tx, txdata, state, orchardAuth, consensus, 0, false, false, [](const Consensus::Params&) { return false; }); // for transactions that have been mined in a block, DoS ban score should // always be 100. EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1); - ContextualCheckShieldedInputs(tx, state, orchardAuth, consensus, 0, false, true, [](const Consensus::Params&) { return true; }); + ContextualCheckShieldedInputs(tx, txdata, state, orchardAuth, consensus, 0, false, true, [](const Consensus::Params&) { return true; }); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1); - ContextualCheckShieldedInputs(tx, state, orchardAuth, consensus, 0, false, true, [](const Consensus::Params&) { return false; }); + ContextualCheckShieldedInputs(tx, txdata, state, orchardAuth, consensus, 0, false, true, [](const Consensus::Params&) { return false; }); } TEST(ContextualCheckShieldedInputsTest, JoinsplitSignatureDetectsOldBranchId) { @@ -562,11 +564,12 @@ TEST(ContextualCheckShieldedInputsTest, JoinsplitSignatureDetectsOldBranchId) { // Create a valid transaction for the Sapling epoch. CMutableTransaction mtx = GetValidTransaction(saplingBranchId); CTransaction tx(mtx); + const PrecomputedTransactionData txdata(tx); MockCValidationState state; // Ensure that the transaction validates against Sapling. EXPECT_TRUE(ContextualCheckShieldedInputs( - tx, state, orchardAuth, consensus, saplingBranchId, false, false, + tx, txdata, state, orchardAuth, consensus, saplingBranchId, false, false, [](const Consensus::Params&) { return false; })); // Attempt to validate the inputs against Blossom. We should be notified @@ -578,7 +581,7 @@ TEST(ContextualCheckShieldedInputsTest, JoinsplitSignatureDetectsOldBranchId) { HexInt(saplingBranchId)), false, "")).Times(1); EXPECT_FALSE(ContextualCheckShieldedInputs( - tx, state, orchardAuth, consensus, blossomBranchId, false, false, + tx, txdata, state, orchardAuth, consensus, blossomBranchId, false, false, [](const Consensus::Params&) { return false; })); // Attempt to validate the inputs against Heartwood. All we should learn is @@ -588,7 +591,7 @@ TEST(ContextualCheckShieldedInputsTest, JoinsplitSignatureDetectsOldBranchId) { 10, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1); EXPECT_FALSE(ContextualCheckShieldedInputs( - tx, state, orchardAuth, consensus, heartwoodBranchId, false, false, + tx, txdata, state, orchardAuth, consensus, heartwoodBranchId, false, false, [](const Consensus::Params&) { return false; })); } @@ -603,8 +606,9 @@ TEST(ContextualCheckShieldedInputsTest, NonCanonicalEd25519Signature) { // Check that the signature is valid before we add L { CTransaction tx(mtx); + const PrecomputedTransactionData txdata(tx); MockCValidationState state; - EXPECT_TRUE(ContextualCheckShieldedInputs(tx, state, orchardAuth, consensus, saplingBranchId, false, true)); + EXPECT_TRUE(ContextualCheckShieldedInputs(tx, txdata, state, orchardAuth, consensus, saplingBranchId, false, true)); } // Copied from libsodium/crypto_sign/ed25519/ref10/open.c @@ -622,20 +626,21 @@ TEST(ContextualCheckShieldedInputsTest, NonCanonicalEd25519Signature) { } CTransaction tx(mtx); + const PrecomputedTransactionData txdata(tx); MockCValidationState state; // during initial block download, for transactions being accepted into the // mempool (and thus not mined), DoS ban score should be zero, else 10 EXPECT_CALL(state, DoS(0, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1); - ContextualCheckShieldedInputs(tx, state, orchardAuth, consensus, saplingBranchId, false, false, [](const Consensus::Params&) { return true; }); + ContextualCheckShieldedInputs(tx, txdata, state, orchardAuth, consensus, saplingBranchId, false, false, [](const Consensus::Params&) { return true; }); EXPECT_CALL(state, DoS(10, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1); - ContextualCheckShieldedInputs(tx, state, orchardAuth, consensus, saplingBranchId, false, false, [](const Consensus::Params&) { return false; }); + ContextualCheckShieldedInputs(tx, txdata, state, orchardAuth, consensus, saplingBranchId, false, false, [](const Consensus::Params&) { return false; }); // for transactions that have been mined in a block, DoS ban score should // always be 100. EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1); - ContextualCheckShieldedInputs(tx, state, orchardAuth, consensus, saplingBranchId, false, true, [](const Consensus::Params&) { return true; }); + ContextualCheckShieldedInputs(tx, txdata, state, orchardAuth, consensus, saplingBranchId, false, true, [](const Consensus::Params&) { return true; }); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1); - ContextualCheckShieldedInputs(tx, state, orchardAuth, consensus, saplingBranchId, false, true, [](const Consensus::Params&) { return false; }); + ContextualCheckShieldedInputs(tx, txdata, state, orchardAuth, consensus, saplingBranchId, false, true, [](const Consensus::Params&) { return false; }); } TEST(ChecktransactionTests, OverwinterConstructors) { @@ -1294,9 +1299,10 @@ TEST(ChecktransactionTests, HeartwoodEnforcesSaplingRulesOnShieldedCoinbase) { // Coinbase transaction does not pass shielded input checks, as bindingSig // consensus rule is enforced. + PrecomputedTransactionData txdata(tx); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-sapling-binding-signature-invalid", false, "")).Times(1); ContextualCheckShieldedInputs( - tx, state, orchardAuth, chainparams.GetConsensus(), heartwoodBranchId, false, true); + tx, txdata, state, orchardAuth, chainparams.GetConsensus(), heartwoodBranchId, false, true); RegtestDeactivateHeartwood(); } diff --git a/src/main.cpp b/src/main.cpp index b1c79c2f8..44bbb23b1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1229,6 +1229,7 @@ bool ContextualCheckTransaction( bool ContextualCheckShieldedInputs( const CTransaction& tx, + const PrecomputedTransactionData& txdata, CValidationState &state, orchard::AuthValidator& orchardAuth, const Consensus::Params& consensus, @@ -1259,8 +1260,8 @@ bool ContextualCheckShieldedInputs( // Empty output script. CScript scriptCode; try { - dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); - prevDataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, prevConsensusBranchId); + dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata); + prevDataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, prevConsensusBranchId, txdata); } catch (std::logic_error ex) { // A logic error should never occur because we pass NOT_AN_INPUT and // SIGHASH_ALL to SignatureHash(). @@ -2001,6 +2002,7 @@ bool AcceptToMemoryPool( // Check shielded input signatures. if (!ContextualCheckShieldedInputs( tx, + txdata, state, orchardAuth, chainparams.GetConsensus(), @@ -2535,7 +2537,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight) bool CScriptCheck::operator()() { const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; - if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), consensusBranchId, &error)) { + if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, *txdata, nIn, amount, cacheStore), consensusBranchId, &error)) { return false; } return true; @@ -3256,7 +3258,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin std::vector vChecks; bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ - if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, fCacheResults, txdata[i], chainparams.GetConsensus(), consensusBranchId, nScriptCheckThreads ? &vChecks : NULL)) + if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, fCacheResults, txdata.back(), chainparams.GetConsensus(), consensusBranchId, nScriptCheckThreads ? &vChecks : NULL)) return error("ConnectBlock(): CheckInputs on %s failed with %s", tx.GetHash().ToString(), FormatStateMessage(state)); control.Add(vChecks); @@ -3265,6 +3267,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // Check shielded inputs. if (!ContextualCheckShieldedInputs( tx, + txdata.back(), state, orchardAuth, chainparams.GetConsensus(), diff --git a/src/main.h b/src/main.h index c44c68c9e..355021c19 100644 --- a/src/main.h +++ b/src/main.h @@ -373,6 +373,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons */ bool ContextualCheckShieldedInputs( const CTransaction& tx, + const PrecomputedTransactionData& txdata, CValidationState &state, orchard::AuthValidator& orchardAuth, const Consensus::Params& consensus, @@ -449,6 +450,8 @@ private: bool cacheStore; uint32_t consensusBranchId; ScriptError error; + // We store a pointer instead of a reference here, to allow it to be null for + // performance reasons (enabling fast swaps in CCheckQueue::Loop). PrecomputedTransactionData *txdata; public: diff --git a/src/miner.cpp b/src/miner.cpp index 7ab770c2f..3c7d30df9 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -219,9 +219,11 @@ public: uint256 dataToBeSigned; CScript scriptCode; try { + PrecomputedTransactionData txdata(mtx); dataToBeSigned = SignatureHash( scriptCode, mtx, NOT_AN_INPUT, SIGHASH_ALL, 0, - CurrentEpochBranchId(nHeight, chainparams.GetConsensus())); + CurrentEpochBranchId(nHeight, chainparams.GetConsensus()), + txdata); } catch (std::logic_error ex) { librustzcash_sapling_proving_ctx_free(ctx); throw ex; diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 4de0e5bb6..484c1cf30 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1043,6 +1043,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) // Use CTransaction for the constant parts of the // transaction to avoid rehashing. const CTransaction txConst(mergedTx); + const PrecomputedTransactionData txdata(txConst); // Sign what we can: for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { CTxIn& txin = mergedTx.vin[i]; @@ -1057,17 +1058,17 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) SignatureData sigdata; // Only sign SIGHASH_SINGLE if there's a corresponding output: if (!fHashSingle || (i < mergedTx.vout.size())) - ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId); + ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, txdata, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId); // ... and merge in other signatures: for (const CMutableTransaction& txv : txVariants) { - sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId); + sigdata = CombineSignatures(prevPubKey, TransactionSignatureChecker(&txConst, txdata, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId); } UpdateTransaction(mergedTx, i, sigdata); ScriptError serror = SCRIPT_ERR_OK; - if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, i, amount), consensusBranchId, &serror)) { + if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, TransactionSignatureChecker(&txConst, txdata, i, amount), consensusBranchId, &serror)) { TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); } } diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index dc5f6dbda..ac7e5e80b 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1179,7 +1179,7 @@ uint256 SignatureHash( int nHashType, const CAmount& amount, uint32_t consensusBranchId, - const PrecomputedTransactionData* cache) + const PrecomputedTransactionData& txdata) { if (nIn >= txTo.vin.size() && nIn != NOT_AN_INPUT) { // nIn out of range @@ -1198,30 +1198,16 @@ uint256 SignatureHash( CDataStream sScriptCode(SER_NETWORK, PROTOCOL_VERSION); sScriptCode << *(CScriptBase*)(&scriptCode); - if (cache) { - uint256 hash; - zcash_transaction_transparent_signature_digest( - cache->preTx.get(), - nHashType, - nIn, - reinterpret_cast(sScriptCode.data()), - sScriptCode.size(), - amount, - hash.begin()); - return hash; - } else { - PrecomputedTransactionData local(txTo); - uint256 hash; - zcash_transaction_transparent_signature_digest( - local.preTx.get(), - nHashType, - nIn, - reinterpret_cast(sScriptCode.data()), - sScriptCode.size(), - amount, - hash.begin()); - return hash; - } + uint256 hash; + zcash_transaction_transparent_signature_digest( + txdata.preTx.get(), + nHashType, + nIn, + reinterpret_cast(sScriptCode.data()), + sScriptCode.size(), + amount, + hash.begin()); + return hash; } } else if (sigversion == SIGVERSION_OVERWINTER || sigversion == SIGVERSION_SAPLING) { uint256 hashPrevouts; @@ -1232,15 +1218,15 @@ uint256 SignatureHash( uint256 hashShieldedOutputs; if (!(nHashType & SIGHASH_ANYONECANPAY)) { - hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo); + hashPrevouts = txdata.hashPrevouts; } if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { - hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo); + hashSequence = txdata.hashSequence; } if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { - hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo); + hashOutputs = txdata.hashOutputs; } else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) { CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION); ss << txTo.vout[nIn]; @@ -1248,15 +1234,15 @@ uint256 SignatureHash( } if (!txTo.vJoinSplit.empty()) { - hashJoinSplits = cache ? cache->hashJoinSplits : GetJoinSplitsHash(txTo); + hashJoinSplits = txdata.hashJoinSplits; } if (!txTo.vShieldedSpend.empty()) { - hashShieldedSpends = cache ? cache->hashShieldedSpends : GetShieldedSpendsHash(txTo); + hashShieldedSpends = txdata.hashShieldedSpends; } if (!txTo.vShieldedOutput.empty()) { - hashShieldedOutputs = cache ? cache->hashShieldedOutputs : GetShieldedOutputsHash(txTo); + hashShieldedOutputs = txdata.hashShieldedOutputs; } uint32_t leConsensusBranchId = htole32(consensusBranchId); diff --git a/src/script/interpreter.h b/src/script/interpreter.h index c9c21d8c8..ce664a75d 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -116,7 +116,7 @@ uint256 SignatureHash( int nHashType, const CAmount& amount, uint32_t consensusBranchId, - const PrecomputedTransactionData* cache = NULL); + const PrecomputedTransactionData& txdata); class BaseSignatureChecker { @@ -144,14 +144,13 @@ private: const CTransaction* txTo; unsigned int nIn; const CAmount amount; - const PrecomputedTransactionData* txdata; + const PrecomputedTransactionData& txdata; protected: virtual bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; public: - TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {} - TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} + TransactionSignatureChecker(const CTransaction* txToIn, const PrecomputedTransactionData& txdataIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(txdataIn) {} bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const; bool CheckLockTime(const CScriptNum& nLockTime) const; }; @@ -162,7 +161,7 @@ private: const CTransaction txTo; public: - MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {} + MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, const PrecomputedTransactionData& txdataIn, unsigned int nInIn, const CAmount& amount) : TransactionSignatureChecker(&txTo, txdataIn, nInIn, amount), txTo(*txToIn) {} }; bool EvalScript( diff --git a/src/script/sigcache.h b/src/script/sigcache.h index 28de26751..6191b19e5 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -22,7 +22,7 @@ private: bool store; public: - CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {} + CachingTransactionSignatureChecker(const CTransaction* txToIn, PrecomputedTransactionData& txdataIn, unsigned int nInIn, const CAmount& amount, bool storeIn) : TransactionSignatureChecker(txToIn, txdataIn, nInIn, amount), store(storeIn) {} bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; }; diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 19a224b0d..ce77c73a1 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -17,7 +17,7 @@ using namespace std; typedef std::vector valtype; -TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} +TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, const PrecomputedTransactionData& txToDataIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), txToData(txToDataIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, txToDataIn, nIn, amountIn) {} bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& address, const CScript& scriptCode, uint32_t consensusBranchId) const { @@ -27,7 +27,7 @@ bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, uint256 hash; try { - hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId); + hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId, txToData); } catch (logic_error ex) { return false; } @@ -172,6 +172,7 @@ bool SignSignature( const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, + const PrecomputedTransactionData& txToData, unsigned int nIn, const CAmount& amount, int nHashType, @@ -180,7 +181,7 @@ bool SignSignature( assert(nIn < txTo.vin.size()); CTransaction txToConst(txTo); - TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, nHashType); + TransactionSignatureCreator creator(&keystore, &txToConst, txToData, nIn, amount, nHashType); SignatureData sigdata; bool ret = ProduceSignature(creator, fromPubKey, sigdata, consensusBranchId); @@ -192,6 +193,7 @@ bool SignSignature( const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, + const PrecomputedTransactionData& txToData, unsigned int nIn, int nHashType, uint32_t consensusBranchId) @@ -201,7 +203,7 @@ bool SignSignature( assert(txin.prevout.n < txFrom.vout.size()); const CTxOut& txout = txFrom.vout[txin.prevout.n]; - return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType, consensusBranchId); + return SignSignature(keystore, txout.scriptPubKey, txTo, txToData, nIn, txout.nValue, nHashType, consensusBranchId); } static vector CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, diff --git a/src/script/sign.h b/src/script/sign.h index ee457423a..fcf0fbd3d 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -33,13 +33,14 @@ public: /** A signature creator for transactions. */ class TransactionSignatureCreator : public BaseSignatureCreator { const CTransaction* txTo; + const PrecomputedTransactionData& txToData; unsigned int nIn; int nHashType; CAmount amount; const TransactionSignatureChecker checker; public: - TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL); + TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, const PrecomputedTransactionData& txToDataIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn=SIGHASH_ALL); const BaseSignatureChecker& Checker() const { return checker; } bool CreateSig(std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const; }; @@ -48,7 +49,7 @@ class MutableTransactionSignatureCreator : public TransactionSignatureCreator { CTransaction tx; public: - MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, nInIn, amount, nHashTypeIn), tx(*txToIn) {} + MutableTransactionSignatureCreator(const CKeyStore* keystoreIn, const CMutableTransaction* txToIn, const PrecomputedTransactionData& txdataIn, unsigned int nInIn, const CAmount& amount, int nHashTypeIn) : TransactionSignatureCreator(keystoreIn, &tx, txdataIn, nInIn, amount, nHashTypeIn), tx(*txToIn) {} }; /** A signature creator that just produces 72-byte empty signatures. */ @@ -74,6 +75,7 @@ bool SignSignature( const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, + const PrecomputedTransactionData& txToData, unsigned int nIn, const CAmount& amount, int nHashType, @@ -82,6 +84,7 @@ bool SignSignature( const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, + const PrecomputedTransactionData& txToData, unsigned int nIn, int nHashType, uint32_t consensusBranchId); diff --git a/src/script/zcash_script.cpp b/src/script/zcash_script.cpp index aed1e99a9..ba7c969f2 100644 --- a/src/script/zcash_script.cpp +++ b/src/script/zcash_script.cpp @@ -145,7 +145,7 @@ int zcash_script_verify_precomputed( preTx->tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, - TransactionSignatureChecker(&preTx->tx, nIn, amount, preTx->txdata), + TransactionSignatureChecker(&preTx->tx, preTx->txdata, nIn, amount), consensusBranchId, NULL); } @@ -174,7 +174,7 @@ int zcash_script_verify( tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, - TransactionSignatureChecker(&tx, nIn, amount, txdata), + TransactionSignatureChecker(&tx, txdata, nIn, amount), consensusBranchId, NULL); } catch (const std::exception&) { diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index ff13b80a9..36b2df687 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -157,7 +157,8 @@ BOOST_DATA_TEST_CASE(DoS_mapOrphans, boost::unit_test::data::xrange(static_cast< tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); - SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL, consensusBranchId); + const PrecomputedTransactionData txdata(tx); + SignSignature(keystore, txPrev, tx, txdata, 0, SIGHASH_ALL, consensusBranchId); AddOrphanTx(tx, i); } @@ -177,7 +178,8 @@ BOOST_DATA_TEST_CASE(DoS_mapOrphans, boost::unit_test::data::xrange(static_cast< tx.vin[j].prevout.n = j; tx.vin[j].prevout.hash = txPrev.GetHash(); } - SignSignature(keystore, txPrev, tx, 0, SIGHASH_ALL, consensusBranchId); + const PrecomputedTransactionData txdata(tx); + SignSignature(keystore, txPrev, tx, txdata, 0, SIGHASH_ALL, consensusBranchId); // Re-use same signature for other inputs // (they don't have to be valid for this test) for (unsigned int j = 1; j < tx.vin.size(); j++) diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 2986a8359..e1184ff86 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -23,9 +23,9 @@ using namespace std; BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup) CScript -sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, int whichIn, uint32_t consensusBranchId) +sign_multisig(CScript scriptPubKey, vector keys, CTransaction transaction, const PrecomputedTransactionData& txdata, int whichIn, uint32_t consensusBranchId) { - uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, consensusBranchId); + uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, consensusBranchId, txdata); CScript result; result << OP_0; // CHECKMULTISIG bug workaround @@ -71,6 +71,7 @@ BOOST_DATA_TEST_CASE(multisig_verify, boost::unit_test::data::xrange(static_cast txFrom.vout[2].nValue = 10; CMutableTransaction txTo[3]; // Spending transaction + std::vector txdata; for (int i = 0; i < 3; i++) { txTo[i].vin.resize(1); @@ -78,6 +79,7 @@ BOOST_DATA_TEST_CASE(multisig_verify, boost::unit_test::data::xrange(static_cast txTo[i].vin[0].prevout.n = i; txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vout[0].nValue = 1; + txdata.push_back(PrecomputedTransactionData(txTo[i])); } vector keys; @@ -86,21 +88,21 @@ BOOST_DATA_TEST_CASE(multisig_verify, boost::unit_test::data::xrange(static_cast // Test a AND b: keys.assign(1,key[0]); keys.push_back(key[1]); - s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId); - BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err)); + s = sign_multisig(a_and_b, keys, txTo[0], txdata[0], 0, consensusBranchId); + BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], txdata[0], 0, amount), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); for (int i = 0; i < 4; i++) { keys.assign(1,key[i]); - s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId); - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err), strprintf("a&b 1: %d", i)); + s = sign_multisig(a_and_b, keys, txTo[0], txdata[0], 0, consensusBranchId); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], txdata[0], 0, amount), consensusBranchId, &err), strprintf("a&b 1: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); keys.assign(1,key[1]); keys.push_back(key[i]); - s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId); - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err), strprintf("a&b 2: %d", i)); + s = sign_multisig(a_and_b, keys, txTo[0], txdata[0], 0, consensusBranchId); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], txdata[0], 0, amount), consensusBranchId, &err), strprintf("a&b 2: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } @@ -108,21 +110,21 @@ BOOST_DATA_TEST_CASE(multisig_verify, boost::unit_test::data::xrange(static_cast for (int i = 0; i < 4; i++) { keys.assign(1,key[i]); - s = sign_multisig(a_or_b, keys, txTo[1], 0, consensusBranchId); + s = sign_multisig(a_or_b, keys, txTo[1], txdata[1], 0, consensusBranchId); if (i == 0 || i == 1) { - BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err), strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], txdata[1], 0, amount), consensusBranchId, &err), strprintf("a|b: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } else { - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err), strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], txdata[1], 0, amount), consensusBranchId, &err), strprintf("a|b: %d", i)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } } s.clear(); s << OP_0 << OP_1; - BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err)); + BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], txdata[1], 0, amount), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err)); @@ -131,15 +133,15 @@ BOOST_DATA_TEST_CASE(multisig_verify, boost::unit_test::data::xrange(static_cast { keys.assign(1,key[i]); keys.push_back(key[j]); - s = sign_multisig(escrow, keys, txTo[2], 0, consensusBranchId); + s = sign_multisig(escrow, keys, txTo[2], txdata[2], 0, consensusBranchId); if (i < j && i < 3 && j < 3) { - BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), consensusBranchId, &err), strprintf("escrow 1: %d %d", i, j)); + BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], txdata[2], 0, amount), consensusBranchId, &err), strprintf("escrow 1: %d %d", i, j)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); } else { - BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), consensusBranchId, &err), strprintf("escrow 2: %d %d", i, j)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], txdata[2], 0, amount), consensusBranchId, &err), strprintf("escrow 2: %d %d", i, j)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } } @@ -215,6 +217,7 @@ BOOST_DATA_TEST_CASE(multisig_Sign, boost::unit_test::data::xrange(static_cast txdata; for (int i = 0; i < 3; i++) { txTo[i].vin.resize(1); @@ -222,11 +225,12 @@ BOOST_DATA_TEST_CASE(multisig_Sign, boost::unit_test::data::xrange(static_cast(Conse BOOST_CHECK(IsStandardTx(txFrom, reason, Params())); CMutableTransaction txTo[8]; // Spending transactions + std::vector txToData; for (int i = 0; i < 8; i++) { txTo[i].vin.resize(1); @@ -106,10 +108,11 @@ BOOST_DATA_TEST_CASE(sign, boost::unit_test::data::xrange(static_cast(Conse txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vout[0].nValue = 1; BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); + txToData.push_back(PrecomputedTransactionData(txTo[i])); } for (int i = 0; i < 8; i++) { - BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i)); + BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], txToData[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i)); } // All of the above should be OK, and the txTos have valid signatures // Check to make sure signature verification fails if we use the wrong ScriptSig: @@ -199,6 +202,7 @@ BOOST_DATA_TEST_CASE(set, boost::unit_test::data::xrange(static_cast(Consen BOOST_CHECK(IsStandardTx(txFrom, reason, Params())); CMutableTransaction txTo[4]; // Spending transactions + std::vector txToData; for (int i = 0; i < 4; i++) { txTo[i].vin.resize(1); @@ -208,10 +212,11 @@ BOOST_DATA_TEST_CASE(set, boost::unit_test::data::xrange(static_cast(Consen txTo[i].vout[0].nValue = 1*CENT; txTo[i].vout[0].scriptPubKey = inner[i]; BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i)); + txToData.push_back(PrecomputedTransactionData(txTo[i])); } for (int i = 0; i < 4; i++) { - BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i)); + BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], txToData[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i)); BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason, Params()), strprintf("txTo[%d].IsStandard", i)); } } @@ -347,9 +352,10 @@ BOOST_DATA_TEST_CASE(AreInputsStandard, boost::unit_test::data::xrange(static_ca txTo.vin[i].prevout.n = i; txTo.vin[i].prevout.hash = txFrom.GetHash(); } - BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId)); - BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1, SIGHASH_ALL, consensusBranchId)); - BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2, SIGHASH_ALL, consensusBranchId)); + const PrecomputedTransactionData txToData(txTo); + BOOST_CHECK(SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId)); + BOOST_CHECK(SignSignature(keystore, txFrom, txTo, txToData, 1, SIGHASH_ALL, consensusBranchId)); + BOOST_CHECK(SignSignature(keystore, txFrom, txTo, txToData, 2, SIGHASH_ALL, consensusBranchId)); // SignSignature doesn't know how to sign these. We're // not testing validating signatures, so just create // dummy signatures that DO include the correct P2SH scripts: diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 5ce70486a..ea3ed8af3 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -78,8 +78,9 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, ui ScriptError err; CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey); CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit); + const PrecomputedTransactionData txdata(tx); CMutableTransaction tx2 = tx; - BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), consensusBranchId, &err) == expect, message); + BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, txdata, 0, txCredit.vout[0].nValue), consensusBranchId, &err) == expect, message); BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message); #if defined(HAVE_SCRIPT_LIB) CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); @@ -230,7 +231,8 @@ public: TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32) { - uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType, 0, consensusBranchId); + const PrecomputedTransactionData txdata(spendTx); + uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType, 0, consensusBranchId, txdata); std::vector vchSig, r, s; uint32_t iter = 0; do { @@ -664,9 +666,9 @@ BOOST_DATA_TEST_CASE(script_PushData, boost::unit_test::data::xrange(static_cast } CScript -sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction, uint32_t consensusBranchId) +sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transaction, const PrecomputedTransactionData& txdata, uint32_t consensusBranchId) { - uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, consensusBranchId); + uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, consensusBranchId, txdata); CScript result; // @@ -688,11 +690,11 @@ sign_multisig(CScript scriptPubKey, std::vector keys, CTransaction transac return result; } CScript -sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction, uint32_t consensusBranchId) +sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction, const PrecomputedTransactionData& txdata, uint32_t consensusBranchId) { std::vector keys; keys.push_back(key); - return sign_multisig(scriptPubKey, keys, transaction, consensusBranchId); + return sign_multisig(scriptPubKey, keys, transaction, txdata, consensusBranchId); } // Parameterized testing over consensus branch ids @@ -710,20 +712,21 @@ BOOST_DATA_TEST_CASE(script_CHECKMULTISIG12, boost::unit_test::data::xrange(stat CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12); CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12); + const PrecomputedTransactionData txdata12(txTo12); - CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12, consensusBranchId); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err)); + CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12, txdata12, consensusBranchId); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, txdata12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); txTo12.vout[0].nValue = 2; - BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err)); + BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, txdata12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); - CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12, consensusBranchId); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err)); + CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12, txdata12, consensusBranchId); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, txdata12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); - CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12, consensusBranchId); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err)); + CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12, txdata12, consensusBranchId); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, txdata12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); } @@ -743,58 +746,59 @@ BOOST_DATA_TEST_CASE(script_CHECKMULTISIG23, boost::unit_test::data::xrange(stat CMutableTransaction txFrom23 = BuildCreditingTransaction(scriptPubKey23); CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), txFrom23); + const PrecomputedTransactionData txdata23(txTo23); std::vector keys; keys.push_back(key1); keys.push_back(key2); - CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); + CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key3); - CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); + CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key3); - CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); - BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); + CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId); + BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key2); // Can't re-use sig - CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); + CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order - CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); - BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); + CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId); + BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order - CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); - BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); + CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId); + BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys - CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); - BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); + CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId); + BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys - CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); - BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); + CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId); + BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err)); keys.clear(); // Must have signatures - CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); - BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); + CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId); + BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); } @@ -818,65 +822,66 @@ BOOST_DATA_TEST_CASE(script_combineSigs, boost::unit_test::data::xrange(static_c CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID())); CMutableTransaction txTo = BuildSpendingTransaction(CScript(), txFrom); + const PrecomputedTransactionData txToData(txTo); CScript& scriptPubKey = txFrom.vout[0].scriptPubKey; CScript& scriptSig = txTo.vin[0].scriptSig; SignatureData empty; - SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty, consensusBranchId); + SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), empty, empty, consensusBranchId); BOOST_CHECK(combined.scriptSig.empty()); // Single signature case: - SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); // changes scriptSig - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId); + SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId); // changes scriptSig + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSig), empty, consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), empty, SignatureData(scriptSig), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); CScript scriptSigCopy = scriptSig; // Signing again will give a different, valid signature: - SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId); + SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // P2SH, single-signature case: CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG; keystore.AddCScript(pkSingle); scriptPubKey = GetScriptForDestination(CScriptID(pkSingle)); - SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId); + SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSig), empty, consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), empty, SignatureData(scriptSig), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); scriptSigCopy = scriptSig; - SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId); + SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // dummy scriptSigCopy with placeholder, should always choose non-placeholder: scriptSigCopy = CScript() << OP_0 << vector(pkSingle.begin(), pkSingle.end()); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy), consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); // Hardest case: Multisig 2-of-3 scriptPubKey = GetScriptForMultisig(2, pubkeys); keystore.AddCScript(scriptPubKey); - SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId); + SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSig), empty, consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), empty, SignatureData(scriptSig), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); // A couple of partially-signed versions: vector sig1; - uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, consensusBranchId); + uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, consensusBranchId, txToData); BOOST_CHECK(keys[0].Sign(hash1, sig1)); sig1.push_back(SIGHASH_ALL); vector sig2; - uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, consensusBranchId); + uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, consensusBranchId, txToData); BOOST_CHECK(keys[1].Sign(hash2, sig2)); sig2.push_back(SIGHASH_NONE); vector sig3; - uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, consensusBranchId); + uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, consensusBranchId, txToData); BOOST_CHECK(keys[2].Sign(hash3, sig3)); sig3.push_back(SIGHASH_SINGLE); @@ -892,21 +897,21 @@ BOOST_DATA_TEST_CASE(script_combineSigs, boost::unit_test::data::xrange(static_c CScript complete13 = CScript() << OP_0 << sig1 << sig3; CScript complete23 = CScript() << OP_0 << sig2 << sig3; - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b), consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial1a), SignatureData(partial1b), consensusBranchId); BOOST_CHECK(combined.scriptSig == partial1a); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a), consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial1a), SignatureData(partial2a), consensusBranchId); BOOST_CHECK(combined.scriptSig == complete12); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a), consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial2a), SignatureData(partial1a), consensusBranchId); BOOST_CHECK(combined.scriptSig == complete12); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b), consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial1b), SignatureData(partial2b), consensusBranchId); BOOST_CHECK(combined.scriptSig == complete12); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b), consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial3b), SignatureData(partial1b), consensusBranchId); BOOST_CHECK(combined.scriptSig == complete13); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a), consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial2a), SignatureData(partial3a), consensusBranchId); BOOST_CHECK(combined.scriptSig == complete23); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b), consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial3b), SignatureData(partial2b), consensusBranchId); BOOST_CHECK(combined.scriptSig == complete23); - combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a), consensusBranchId); + combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial3b), SignatureData(partial3a), consensusBranchId); BOOST_CHECK(combined.scriptSig == partial3c); } diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 2edd37af2..d75cb245c 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -202,7 +202,8 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle, uint32_t co // Empty output script. CScript scriptCode; CTransaction signTx(tx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); + PrecomputedTransactionData txdata(signTx); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata); assert(ed25519_sign( &joinSplitPrivKey, @@ -236,10 +237,11 @@ BOOST_AUTO_TEST_CASE(sighash_test) CScript scriptCode; RandomScript(scriptCode); int nIn = insecure_rand() % txTo.vin.size(); + const PrecomputedTransactionData txdata(txTo); uint256 sh, sho; sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType); - sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, consensusBranchId); + sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, consensusBranchId, txdata); #if defined(PRINT_SIGHASH_JSON) CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << txTo; @@ -334,7 +336,8 @@ BOOST_AUTO_TEST_CASE(sighash_from_data) continue; } - sh = SignatureHash(scriptCode, tx, nIn, nHashType, 0, consensusBranchId); + const PrecomputedTransactionData txdata(tx); + sh = SignatureHash(scriptCode, tx, nIn, nHashType, 0, consensusBranchId, txdata); BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest); } } diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index da2b4c800..7e72fc769 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) CAmount amount = 0; unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], - verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), consensusBranchId, &err), + verify_flags, TransactionSignatureChecker(&tx, txdata, i, amount), consensusBranchId, &err), strTest + comment); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err) + comment); } @@ -219,7 +219,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); CAmount amount = 0; fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], - verify_flags, TransactionSignatureChecker(&tx, i, amount, txdata), consensusBranchId, &err); + verify_flags, TransactionSignatureChecker(&tx, txdata, i, amount), consensusBranchId, &err); } BOOST_CHECK_MESSAGE(!fValid, strTest + comment); BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err) + comment); @@ -451,15 +451,17 @@ void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransa jsdesc->nullifiers[0] = GetRandHash(); jsdesc->nullifiers[1] = GetRandHash(); + const PrecomputedTransactionData txdata(newTx); + BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state)); BOOST_CHECK(ContextualCheckTransaction(newTx, state, Params(), 0, true)); - BOOST_CHECK(!ContextualCheckShieldedInputs(newTx, state, orchardAuth, Params().GetConsensus(), consensusBranchId, false, true)); + BOOST_CHECK(!ContextualCheckShieldedInputs(newTx, txdata, state, orchardAuth, Params().GetConsensus(), consensusBranchId, false, true)); BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-joinsplit-signature"); // Empty output script. CScript scriptCode; CTransaction signTx(newTx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata); assert(ed25519_sign( &joinSplitPrivKey, @@ -469,7 +471,7 @@ void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransa state = CValidationState(); BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state)); BOOST_CHECK(ContextualCheckTransaction(newTx, state, Params(), 0, true)); - BOOST_CHECK(ContextualCheckShieldedInputs(newTx, state, orchardAuth, Params().GetConsensus(), consensusBranchId, false, true)); + BOOST_CHECK(ContextualCheckShieldedInputs(newTx, txdata, state, orchardAuth, Params().GetConsensus(), consensusBranchId, false, true)); BOOST_CHECK_EQUAL(state.GetRejectReason(), ""); } { @@ -670,9 +672,11 @@ BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) { mtx.vout[i].scriptPubKey = CScript() << OP_1; } + PrecomputedTransactionData txdata(mtx); + // sign all inputs for(uint32_t i = 0; i < mtx.vin.size(); i++) { - bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, i, 1000, sigHashes.at(i % sigHashes.size()), consensusBranchId); + bool hashSigned = SignSignature(keystore, scriptPubKey, mtx, txdata, i, 1000, sigHashes.at(i % sigHashes.size()), consensusBranchId); assert(hashSigned); } @@ -682,7 +686,6 @@ BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) { ssout >> tx; // check all inputs concurrently, with the cache - PrecomputedTransactionData txdata(tx); boost::thread_group threadGroup; CCheckQueue scriptcheckqueue(128); CCheckQueueControl control(&scriptcheckqueue); @@ -915,11 +918,13 @@ BOOST_AUTO_TEST_CASE(TxV5) amount = test[5].get_int64(); } + const PrecomputedTransactionData txdata(tx); + BOOST_CHECK_EQUAL( SignatureHash( scriptCode, tx, nIn, SIGHASH_ALL, - amount, *tx.GetConsensusBranchId() + amount, *tx.GetConsensusBranchId(), txdata ).GetHex(), test[6].getValStr()); @@ -928,7 +933,7 @@ BOOST_AUTO_TEST_CASE(TxV5) SignatureHash( scriptCode, tx, nIn, SIGHASH_NONE, - amount, *tx.GetConsensusBranchId() + amount, *tx.GetConsensusBranchId(), txdata ).GetHex(), test[7].getValStr()); } @@ -938,7 +943,7 @@ BOOST_AUTO_TEST_CASE(TxV5) SignatureHash( scriptCode, tx, nIn, SIGHASH_SINGLE, - amount, *tx.GetConsensusBranchId() + amount, *tx.GetConsensusBranchId(), txdata ).GetHex(), test[8].getValStr()); } @@ -948,7 +953,7 @@ BOOST_AUTO_TEST_CASE(TxV5) SignatureHash( scriptCode, tx, nIn, SIGHASH_ALL | SIGHASH_ANYONECANPAY, - amount, *tx.GetConsensusBranchId() + amount, *tx.GetConsensusBranchId(), txdata ).GetHex(), test[9].getValStr()); } @@ -958,7 +963,7 @@ BOOST_AUTO_TEST_CASE(TxV5) SignatureHash( scriptCode, tx, nIn, SIGHASH_NONE | SIGHASH_ANYONECANPAY, - amount, *tx.GetConsensusBranchId() + amount, *tx.GetConsensusBranchId(), txdata ).GetHex(), test[10].getValStr()); } @@ -968,7 +973,7 @@ BOOST_AUTO_TEST_CASE(TxV5) SignatureHash( scriptCode, tx, nIn, SIGHASH_SINGLE | SIGHASH_ANYONECANPAY, - amount, *tx.GetConsensusBranchId() + amount, *tx.GetConsensusBranchId(), txdata ).GetHex(), test[11].getValStr()); } diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 83114f7d3..9312de738 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -48,8 +48,9 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) spends[i].vout[0].scriptPubKey = scriptPubKey; // Sign: + const PrecomputedTransactionData txdata(spends[i]); std::vector vchSig; - uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL, coinbaseTxns[0].vout[0].nValue, SPROUT_BRANCH_ID); + uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL, coinbaseTxns[0].vout[0].nValue, SPROUT_BRANCH_ID, txdata); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); spends[i].vin[0].scriptSig << vchSig; diff --git a/src/transaction_builder.cpp b/src/transaction_builder.cpp index 94705ebed..d4865bc96 100644 --- a/src/transaction_builder.cpp +++ b/src/transaction_builder.cpp @@ -446,12 +446,13 @@ TransactionBuilderResult TransactionBuilder::Build() // auto consensusBranchId = CurrentEpochBranchId(nHeight, consensusParams); + const PrecomputedTransactionData txdata(mtx); // Empty output script. uint256 dataToBeSigned; CScript scriptCode; try { - dataToBeSigned = SignatureHash(scriptCode, mtx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); + dataToBeSigned = SignatureHash(scriptCode, mtx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata); } catch (std::logic_error ex) { librustzcash_sapling_proving_ctx_free(ctx); return TransactionBuilderResult("Could not construct signature hash: " + std::string(ex.what())); @@ -498,7 +499,7 @@ TransactionBuilderResult TransactionBuilder::Build() SignatureData sigdata; bool signSuccess = ProduceSignature( TransactionSignatureCreator( - keystore, &txNewConst, nIn, tIn.value, SIGHASH_ALL), + keystore, &txNewConst, txdata, nIn, tIn.value, SIGHASH_ALL), tIn.scriptPubKey, sigdata, consensusBranchId); if (!signSuccess) { diff --git a/src/utiltest.cpp b/src/utiltest.cpp index 189c7daeb..41ba2a3f8 100644 --- a/src/utiltest.cpp +++ b/src/utiltest.cpp @@ -69,7 +69,8 @@ CMutableTransaction GetValidSproutReceiveTransaction( uint32_t consensusBranchId = SPROUT_BRANCH_ID; CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); + const PrecomputedTransactionData txdata(signTx); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata); // Add the signature assert(ed25519_sign( @@ -184,7 +185,8 @@ CWalletTx GetValidSproutSpend(const libzcash::SproutSpendingKey& sk, uint32_t consensusBranchId = SPROUT_BRANCH_ID; CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); + const PrecomputedTransactionData txdata(signTx); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata); // Add the signature assert(ed25519_sign( diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index 405528760..415d47220 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -834,7 +834,8 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit( // Empty output script. CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId_); + PrecomputedTransactionData txdata(signTx); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId_, txdata); // Add the signature if (!ed25519_sign( diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp index 2fb0fac85..4f6aa858e 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp @@ -361,7 +361,8 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf // Empty output script. CScript scriptCode; CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); + PrecomputedTransactionData txdata(signTx); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata); // Add the signature if (!ed25519_sign( diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index da4553e9e..7143e687c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2889,8 +2889,9 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp) // Empty output script. CScript scriptCode; CTransaction signTx(mtx); + PrecomputedTransactionData txdata(signTx); auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); + uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata); // Add the signature assert(ed25519_sign( diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 39e6d0ffd..db4ffb71a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4767,13 +4767,14 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt // Sign int nIn = 0; CTransaction txNewConst(txNew); + const PrecomputedTransactionData txdata(txNewConst); for (const std::pair& coin : setCoins) { bool signSuccess; const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey; SignatureData sigdata; if (sign) - signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, coin.first->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata, consensusBranchId); + signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, txdata, nIn, coin.first->vout[coin.second].nValue, SIGHASH_ALL), scriptPubKey, sigdata, consensusBranchId); else signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata, consensusBranchId); diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index 9ff6f0a23..dc5f42166 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -238,10 +238,12 @@ double benchmark_large_tx(size_t nInputs) spending_tx.vin.emplace_back(input_hash, 0); } + PrecomputedTransactionData txdata(spending_tx); + // Sign for all the inputs auto consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_SAPLING].nBranchId; for (size_t i = 0; i < nInputs; i++) { - SignSignature(tempKeystore, prevPubKey, spending_tx, i, 1000000, SIGHASH_ALL, consensusBranchId); + SignSignature(tempKeystore, prevPubKey, spending_tx, txdata, i, 1000000, SIGHASH_ALL, consensusBranchId); } // Spending tx has all its inputs signed and does not need to be mutated anymore @@ -250,13 +252,12 @@ double benchmark_large_tx(size_t nInputs) // Benchmark signature verification costs: struct timeval tv_start; timer_start(tv_start); - PrecomputedTransactionData txdata(final_spending_tx); for (size_t i = 0; i < nInputs; i++) { ScriptError serror = SCRIPT_ERR_OK; assert(VerifyScript(final_spending_tx.vin[i].scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, - TransactionSignatureChecker(&final_spending_tx, i, 1000000, txdata), + TransactionSignatureChecker(&final_spending_tx, txdata, i, 1000000), consensusBranchId, &serror)); }