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.
This commit is contained in:
Jack Grigg 2022-01-22 22:59:28 +00:00
parent 3acf7941d6
commit 80f478e67e
27 changed files with 224 additions and 182 deletions

View File

@ -48,9 +48,11 @@ static void ECDSA(benchmark::State& state)
mtx.vout[i].scriptPubKey = CScript() << OP_1; mtx.vout[i].scriptPubKey = CScript() << OP_1;
} }
const PrecomputedTransactionData txdata(mtx);
// sign all inputs // sign all inputs
for(uint32_t i = 0; i < mtx.vin.size(); i++) { 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); assert(hashSigned);
} }
@ -66,7 +68,7 @@ static void ECDSA(benchmark::State& state)
tx.vin[0].scriptSig, tx.vin[0].scriptSig,
scriptPubKey, scriptPubKey,
SCRIPT_VERIFY_P2SH, SCRIPT_VERIFY_P2SH,
TransactionSignatureChecker(&tx, 0, 1000), TransactionSignatureChecker(&tx, txdata, 0, 1000),
consensusBranchId, consensusBranchId,
&error); &error);
} }

View File

@ -468,6 +468,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& strInput)
} }
const CKeyStore& keystore = tempKeystore; const CKeyStore& keystore = tempKeystore;
const PrecomputedTransactionData txdata(mergedTx);
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
@ -488,14 +489,14 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& strInput)
SignatureData sigdata; SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output: // Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size())) 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: // ... and merge in other signatures:
for (const CTransaction& txv : txVariants) 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); 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; fComplete = false;
} }

View File

@ -113,7 +113,8 @@ void CreateJoinSplitSignature(CMutableTransaction& mtx, uint32_t consensusBranch
// Empty output script. // Empty output script.
CScript scriptCode; CScript scriptCode;
CTransaction signTx(mtx); 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) { if (dataToBeSigned == one) {
throw std::runtime_error("SignatureHash failed"); throw std::runtime_error("SignatureHash failed");
} }
@ -534,20 +535,21 @@ TEST(ContextualCheckShieldedInputsTest, BadTxnsInvalidJoinsplitSignature) {
CMutableTransaction mtx = GetValidTransaction(); CMutableTransaction mtx = GetValidTransaction();
mtx.joinSplitSig.bytes[0] += 1; mtx.joinSplitSig.bytes[0] += 1;
CTransaction tx(mtx); CTransaction tx(mtx);
const PrecomputedTransactionData txdata(tx);
MockCValidationState state; MockCValidationState state;
// during initial block download, for transactions being accepted into the // during initial block download, for transactions being accepted into the
// mempool (and thus not mined), DoS ban score should be zero, else 10 // 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); 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); 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 // for transactions that have been mined in a block, DoS ban score should
// always be 100. // always be 100.
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1); 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); 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) { TEST(ContextualCheckShieldedInputsTest, JoinsplitSignatureDetectsOldBranchId) {
@ -562,11 +564,12 @@ TEST(ContextualCheckShieldedInputsTest, JoinsplitSignatureDetectsOldBranchId) {
// Create a valid transaction for the Sapling epoch. // Create a valid transaction for the Sapling epoch.
CMutableTransaction mtx = GetValidTransaction(saplingBranchId); CMutableTransaction mtx = GetValidTransaction(saplingBranchId);
CTransaction tx(mtx); CTransaction tx(mtx);
const PrecomputedTransactionData txdata(tx);
MockCValidationState state; MockCValidationState state;
// Ensure that the transaction validates against Sapling. // Ensure that the transaction validates against Sapling.
EXPECT_TRUE(ContextualCheckShieldedInputs( EXPECT_TRUE(ContextualCheckShieldedInputs(
tx, state, orchardAuth, consensus, saplingBranchId, false, false, tx, txdata, state, orchardAuth, consensus, saplingBranchId, false, false,
[](const Consensus::Params&) { return false; })); [](const Consensus::Params&) { return false; }));
// Attempt to validate the inputs against Blossom. We should be notified // Attempt to validate the inputs against Blossom. We should be notified
@ -578,7 +581,7 @@ TEST(ContextualCheckShieldedInputsTest, JoinsplitSignatureDetectsOldBranchId) {
HexInt(saplingBranchId)), HexInt(saplingBranchId)),
false, "")).Times(1); false, "")).Times(1);
EXPECT_FALSE(ContextualCheckShieldedInputs( EXPECT_FALSE(ContextualCheckShieldedInputs(
tx, state, orchardAuth, consensus, blossomBranchId, false, false, tx, txdata, state, orchardAuth, consensus, blossomBranchId, false, false,
[](const Consensus::Params&) { return false; })); [](const Consensus::Params&) { return false; }));
// Attempt to validate the inputs against Heartwood. All we should learn is // Attempt to validate the inputs against Heartwood. All we should learn is
@ -588,7 +591,7 @@ TEST(ContextualCheckShieldedInputsTest, JoinsplitSignatureDetectsOldBranchId) {
10, false, REJECT_INVALID, 10, false, REJECT_INVALID,
"bad-txns-invalid-joinsplit-signature", false, "")).Times(1); "bad-txns-invalid-joinsplit-signature", false, "")).Times(1);
EXPECT_FALSE(ContextualCheckShieldedInputs( EXPECT_FALSE(ContextualCheckShieldedInputs(
tx, state, orchardAuth, consensus, heartwoodBranchId, false, false, tx, txdata, state, orchardAuth, consensus, heartwoodBranchId, false, false,
[](const Consensus::Params&) { return false; })); [](const Consensus::Params&) { return false; }));
} }
@ -603,8 +606,9 @@ TEST(ContextualCheckShieldedInputsTest, NonCanonicalEd25519Signature) {
// Check that the signature is valid before we add L // Check that the signature is valid before we add L
{ {
CTransaction tx(mtx); CTransaction tx(mtx);
const PrecomputedTransactionData txdata(tx);
MockCValidationState state; 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 // Copied from libsodium/crypto_sign/ed25519/ref10/open.c
@ -622,20 +626,21 @@ TEST(ContextualCheckShieldedInputsTest, NonCanonicalEd25519Signature) {
} }
CTransaction tx(mtx); CTransaction tx(mtx);
const PrecomputedTransactionData txdata(tx);
MockCValidationState state; MockCValidationState state;
// during initial block download, for transactions being accepted into the // during initial block download, for transactions being accepted into the
// mempool (and thus not mined), DoS ban score should be zero, else 10 // 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); 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); 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 // for transactions that have been mined in a block, DoS ban score should
// always be 100. // always be 100.
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-invalid-joinsplit-signature", false, "")).Times(1); 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); 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) { TEST(ChecktransactionTests, OverwinterConstructors) {
@ -1294,9 +1299,10 @@ TEST(ChecktransactionTests, HeartwoodEnforcesSaplingRulesOnShieldedCoinbase) {
// Coinbase transaction does not pass shielded input checks, as bindingSig // Coinbase transaction does not pass shielded input checks, as bindingSig
// consensus rule is enforced. // consensus rule is enforced.
PrecomputedTransactionData txdata(tx);
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-sapling-binding-signature-invalid", false, "")).Times(1); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-sapling-binding-signature-invalid", false, "")).Times(1);
ContextualCheckShieldedInputs( ContextualCheckShieldedInputs(
tx, state, orchardAuth, chainparams.GetConsensus(), heartwoodBranchId, false, true); tx, txdata, state, orchardAuth, chainparams.GetConsensus(), heartwoodBranchId, false, true);
RegtestDeactivateHeartwood(); RegtestDeactivateHeartwood();
} }

View File

@ -1229,6 +1229,7 @@ bool ContextualCheckTransaction(
bool ContextualCheckShieldedInputs( bool ContextualCheckShieldedInputs(
const CTransaction& tx, const CTransaction& tx,
const PrecomputedTransactionData& txdata,
CValidationState &state, CValidationState &state,
orchard::AuthValidator& orchardAuth, orchard::AuthValidator& orchardAuth,
const Consensus::Params& consensus, const Consensus::Params& consensus,
@ -1259,8 +1260,8 @@ bool ContextualCheckShieldedInputs(
// Empty output script. // Empty output script.
CScript scriptCode; CScript scriptCode;
try { try {
dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); dataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata);
prevDataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, prevConsensusBranchId); prevDataToBeSigned = SignatureHash(scriptCode, tx, NOT_AN_INPUT, SIGHASH_ALL, 0, prevConsensusBranchId, txdata);
} catch (std::logic_error ex) { } catch (std::logic_error ex) {
// A logic error should never occur because we pass NOT_AN_INPUT and // A logic error should never occur because we pass NOT_AN_INPUT and
// SIGHASH_ALL to SignatureHash(). // SIGHASH_ALL to SignatureHash().
@ -2001,6 +2002,7 @@ bool AcceptToMemoryPool(
// Check shielded input signatures. // Check shielded input signatures.
if (!ContextualCheckShieldedInputs( if (!ContextualCheckShieldedInputs(
tx, tx,
txdata,
state, state,
orchardAuth, orchardAuth,
chainparams.GetConsensus(), chainparams.GetConsensus(),
@ -2535,7 +2537,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight)
bool CScriptCheck::operator()() { bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; 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 false;
} }
return true; return true;
@ -3256,7 +3258,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
std::vector<CScriptCheck> vChecks; std::vector<CScriptCheck> vChecks;
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ 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", return error("ConnectBlock(): CheckInputs on %s failed with %s",
tx.GetHash().ToString(), FormatStateMessage(state)); tx.GetHash().ToString(), FormatStateMessage(state));
control.Add(vChecks); control.Add(vChecks);
@ -3265,6 +3267,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// Check shielded inputs. // Check shielded inputs.
if (!ContextualCheckShieldedInputs( if (!ContextualCheckShieldedInputs(
tx, tx,
txdata.back(),
state, state,
orchardAuth, orchardAuth,
chainparams.GetConsensus(), chainparams.GetConsensus(),

View File

@ -373,6 +373,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons
*/ */
bool ContextualCheckShieldedInputs( bool ContextualCheckShieldedInputs(
const CTransaction& tx, const CTransaction& tx,
const PrecomputedTransactionData& txdata,
CValidationState &state, CValidationState &state,
orchard::AuthValidator& orchardAuth, orchard::AuthValidator& orchardAuth,
const Consensus::Params& consensus, const Consensus::Params& consensus,
@ -449,6 +450,8 @@ private:
bool cacheStore; bool cacheStore;
uint32_t consensusBranchId; uint32_t consensusBranchId;
ScriptError error; 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; PrecomputedTransactionData *txdata;
public: public:

View File

@ -219,9 +219,11 @@ public:
uint256 dataToBeSigned; uint256 dataToBeSigned;
CScript scriptCode; CScript scriptCode;
try { try {
PrecomputedTransactionData txdata(mtx);
dataToBeSigned = SignatureHash( dataToBeSigned = SignatureHash(
scriptCode, mtx, NOT_AN_INPUT, SIGHASH_ALL, 0, scriptCode, mtx, NOT_AN_INPUT, SIGHASH_ALL, 0,
CurrentEpochBranchId(nHeight, chainparams.GetConsensus())); CurrentEpochBranchId(nHeight, chainparams.GetConsensus()),
txdata);
} catch (std::logic_error ex) { } catch (std::logic_error ex) {
librustzcash_sapling_proving_ctx_free(ctx); librustzcash_sapling_proving_ctx_free(ctx);
throw ex; throw ex;

View File

@ -1043,6 +1043,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
// Use CTransaction for the constant parts of the // Use CTransaction for the constant parts of the
// transaction to avoid rehashing. // transaction to avoid rehashing.
const CTransaction txConst(mergedTx); const CTransaction txConst(mergedTx);
const PrecomputedTransactionData txdata(txConst);
// Sign what we can: // Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i]; CTxIn& txin = mergedTx.vin[i];
@ -1057,17 +1058,17 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
SignatureData sigdata; SignatureData sigdata;
// Only sign SIGHASH_SINGLE if there's a corresponding output: // Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size())) 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: // ... and merge in other signatures:
for (const CMutableTransaction& txv : txVariants) { 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); UpdateTransaction(mergedTx, i, sigdata);
ScriptError serror = SCRIPT_ERR_OK; 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)); TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror));
} }
} }

View File

@ -1179,7 +1179,7 @@ uint256 SignatureHash(
int nHashType, int nHashType,
const CAmount& amount, const CAmount& amount,
uint32_t consensusBranchId, uint32_t consensusBranchId,
const PrecomputedTransactionData* cache) const PrecomputedTransactionData& txdata)
{ {
if (nIn >= txTo.vin.size() && nIn != NOT_AN_INPUT) { if (nIn >= txTo.vin.size() && nIn != NOT_AN_INPUT) {
// nIn out of range // nIn out of range
@ -1198,10 +1198,9 @@ uint256 SignatureHash(
CDataStream sScriptCode(SER_NETWORK, PROTOCOL_VERSION); CDataStream sScriptCode(SER_NETWORK, PROTOCOL_VERSION);
sScriptCode << *(CScriptBase*)(&scriptCode); sScriptCode << *(CScriptBase*)(&scriptCode);
if (cache) {
uint256 hash; uint256 hash;
zcash_transaction_transparent_signature_digest( zcash_transaction_transparent_signature_digest(
cache->preTx.get(), txdata.preTx.get(),
nHashType, nHashType,
nIn, nIn,
reinterpret_cast<const unsigned char*>(sScriptCode.data()), reinterpret_cast<const unsigned char*>(sScriptCode.data()),
@ -1209,19 +1208,6 @@ uint256 SignatureHash(
amount, amount,
hash.begin()); hash.begin());
return hash; return hash;
} else {
PrecomputedTransactionData local(txTo);
uint256 hash;
zcash_transaction_transparent_signature_digest(
local.preTx.get(),
nHashType,
nIn,
reinterpret_cast<const unsigned char*>(sScriptCode.data()),
sScriptCode.size(),
amount,
hash.begin());
return hash;
}
} }
} else if (sigversion == SIGVERSION_OVERWINTER || sigversion == SIGVERSION_SAPLING) { } else if (sigversion == SIGVERSION_OVERWINTER || sigversion == SIGVERSION_SAPLING) {
uint256 hashPrevouts; uint256 hashPrevouts;
@ -1232,15 +1218,15 @@ uint256 SignatureHash(
uint256 hashShieldedOutputs; uint256 hashShieldedOutputs;
if (!(nHashType & SIGHASH_ANYONECANPAY)) { 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) { 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) { 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()) { } else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION); CBLAKE2bWriter ss(SER_GETHASH, 0, ZCASH_OUTPUTS_HASH_PERSONALIZATION);
ss << txTo.vout[nIn]; ss << txTo.vout[nIn];
@ -1248,15 +1234,15 @@ uint256 SignatureHash(
} }
if (!txTo.vJoinSplit.empty()) { if (!txTo.vJoinSplit.empty()) {
hashJoinSplits = cache ? cache->hashJoinSplits : GetJoinSplitsHash(txTo); hashJoinSplits = txdata.hashJoinSplits;
} }
if (!txTo.vShieldedSpend.empty()) { if (!txTo.vShieldedSpend.empty()) {
hashShieldedSpends = cache ? cache->hashShieldedSpends : GetShieldedSpendsHash(txTo); hashShieldedSpends = txdata.hashShieldedSpends;
} }
if (!txTo.vShieldedOutput.empty()) { if (!txTo.vShieldedOutput.empty()) {
hashShieldedOutputs = cache ? cache->hashShieldedOutputs : GetShieldedOutputsHash(txTo); hashShieldedOutputs = txdata.hashShieldedOutputs;
} }
uint32_t leConsensusBranchId = htole32(consensusBranchId); uint32_t leConsensusBranchId = htole32(consensusBranchId);

View File

@ -116,7 +116,7 @@ uint256 SignatureHash(
int nHashType, int nHashType,
const CAmount& amount, const CAmount& amount,
uint32_t consensusBranchId, uint32_t consensusBranchId,
const PrecomputedTransactionData* cache = NULL); const PrecomputedTransactionData& txdata);
class BaseSignatureChecker class BaseSignatureChecker
{ {
@ -144,14 +144,13 @@ private:
const CTransaction* txTo; const CTransaction* txTo;
unsigned int nIn; unsigned int nIn;
const CAmount amount; const CAmount amount;
const PrecomputedTransactionData* txdata; const PrecomputedTransactionData& txdata;
protected: protected:
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
public: public:
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(NULL) {} TransactionSignatureChecker(const CTransaction* txToIn, const PrecomputedTransactionData& txdataIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(txdataIn) {}
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const; bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const;
bool CheckLockTime(const CScriptNum& nLockTime) const; bool CheckLockTime(const CScriptNum& nLockTime) const;
}; };
@ -162,7 +161,7 @@ private:
const CTransaction txTo; const CTransaction txTo;
public: 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( bool EvalScript(

View File

@ -22,7 +22,7 @@ private:
bool store; bool store;
public: 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<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
}; };

View File

@ -17,7 +17,7 @@ using namespace std;
typedef std::vector<unsigned char> valtype; typedef std::vector<unsigned char> 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<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, uint32_t consensusBranchId) const bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, uint32_t consensusBranchId) const
{ {
@ -27,7 +27,7 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
uint256 hash; uint256 hash;
try { try {
hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId); hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId, txToData);
} catch (logic_error ex) { } catch (logic_error ex) {
return false; return false;
} }
@ -172,6 +172,7 @@ bool SignSignature(
const CKeyStore &keystore, const CKeyStore &keystore,
const CScript& fromPubKey, const CScript& fromPubKey,
CMutableTransaction& txTo, CMutableTransaction& txTo,
const PrecomputedTransactionData& txToData,
unsigned int nIn, unsigned int nIn,
const CAmount& amount, const CAmount& amount,
int nHashType, int nHashType,
@ -180,7 +181,7 @@ bool SignSignature(
assert(nIn < txTo.vin.size()); assert(nIn < txTo.vin.size());
CTransaction txToConst(txTo); CTransaction txToConst(txTo);
TransactionSignatureCreator creator(&keystore, &txToConst, nIn, amount, nHashType); TransactionSignatureCreator creator(&keystore, &txToConst, txToData, nIn, amount, nHashType);
SignatureData sigdata; SignatureData sigdata;
bool ret = ProduceSignature(creator, fromPubKey, sigdata, consensusBranchId); bool ret = ProduceSignature(creator, fromPubKey, sigdata, consensusBranchId);
@ -192,6 +193,7 @@ bool SignSignature(
const CKeyStore &keystore, const CKeyStore &keystore,
const CTransaction& txFrom, const CTransaction& txFrom,
CMutableTransaction& txTo, CMutableTransaction& txTo,
const PrecomputedTransactionData& txToData,
unsigned int nIn, unsigned int nIn,
int nHashType, int nHashType,
uint32_t consensusBranchId) uint32_t consensusBranchId)
@ -201,7 +203,7 @@ bool SignSignature(
assert(txin.prevout.n < txFrom.vout.size()); assert(txin.prevout.n < txFrom.vout.size());
const CTxOut& txout = txFrom.vout[txin.prevout.n]; 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<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, static vector<valtype> CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker,

View File

@ -33,13 +33,14 @@ public:
/** A signature creator for transactions. */ /** A signature creator for transactions. */
class TransactionSignatureCreator : public BaseSignatureCreator { class TransactionSignatureCreator : public BaseSignatureCreator {
const CTransaction* txTo; const CTransaction* txTo;
const PrecomputedTransactionData& txToData;
unsigned int nIn; unsigned int nIn;
int nHashType; int nHashType;
CAmount amount; CAmount amount;
const TransactionSignatureChecker checker; const TransactionSignatureChecker checker;
public: 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; } const BaseSignatureChecker& Checker() const { return checker; }
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const; bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, uint32_t consensusBranchId) const;
}; };
@ -48,7 +49,7 @@ class MutableTransactionSignatureCreator : public TransactionSignatureCreator {
CTransaction tx; CTransaction tx;
public: 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. */ /** A signature creator that just produces 72-byte empty signatures. */
@ -74,6 +75,7 @@ bool SignSignature(
const CKeyStore &keystore, const CKeyStore &keystore,
const CScript& fromPubKey, const CScript& fromPubKey,
CMutableTransaction& txTo, CMutableTransaction& txTo,
const PrecomputedTransactionData& txToData,
unsigned int nIn, unsigned int nIn,
const CAmount& amount, const CAmount& amount,
int nHashType, int nHashType,
@ -82,6 +84,7 @@ bool SignSignature(
const CKeyStore& keystore, const CKeyStore& keystore,
const CTransaction& txFrom, const CTransaction& txFrom,
CMutableTransaction& txTo, CMutableTransaction& txTo,
const PrecomputedTransactionData& txToData,
unsigned int nIn, unsigned int nIn,
int nHashType, int nHashType,
uint32_t consensusBranchId); uint32_t consensusBranchId);

View File

@ -145,7 +145,7 @@ int zcash_script_verify_precomputed(
preTx->tx.vin[nIn].scriptSig, preTx->tx.vin[nIn].scriptSig,
CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen),
flags, flags,
TransactionSignatureChecker(&preTx->tx, nIn, amount, preTx->txdata), TransactionSignatureChecker(&preTx->tx, preTx->txdata, nIn, amount),
consensusBranchId, consensusBranchId,
NULL); NULL);
} }
@ -174,7 +174,7 @@ int zcash_script_verify(
tx.vin[nIn].scriptSig, tx.vin[nIn].scriptSig,
CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen),
flags, flags,
TransactionSignatureChecker(&tx, nIn, amount, txdata), TransactionSignatureChecker(&tx, txdata, nIn, amount),
consensusBranchId, consensusBranchId,
NULL); NULL);
} catch (const std::exception&) { } catch (const std::exception&) {

View File

@ -157,7 +157,8 @@ BOOST_DATA_TEST_CASE(DoS_mapOrphans, boost::unit_test::data::xrange(static_cast<
tx.vout.resize(1); tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT; tx.vout[0].nValue = 1*CENT;
tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); 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); 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.n = j;
tx.vin[j].prevout.hash = txPrev.GetHash(); 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 // Re-use same signature for other inputs
// (they don't have to be valid for this test) // (they don't have to be valid for this test)
for (unsigned int j = 1; j < tx.vin.size(); j++) for (unsigned int j = 1; j < tx.vin.size(); j++)

View File

@ -23,9 +23,9 @@ using namespace std;
BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup) BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
CScript CScript
sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction, int whichIn, uint32_t consensusBranchId) sign_multisig(CScript scriptPubKey, vector<CKey> 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; CScript result;
result << OP_0; // CHECKMULTISIG bug workaround 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; txFrom.vout[2].nValue = 10;
CMutableTransaction txTo[3]; // Spending transaction CMutableTransaction txTo[3]; // Spending transaction
std::vector<PrecomputedTransactionData> txdata;
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
txTo[i].vin.resize(1); 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.n = i;
txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vin[0].prevout.hash = txFrom.GetHash();
txTo[i].vout[0].nValue = 1; txTo[i].vout[0].nValue = 1;
txdata.push_back(PrecomputedTransactionData(txTo[i]));
} }
vector<CKey> keys; vector<CKey> keys;
@ -86,21 +88,21 @@ BOOST_DATA_TEST_CASE(multisig_verify, boost::unit_test::data::xrange(static_cast
// Test a AND b: // Test a AND b:
keys.assign(1,key[0]); keys.assign(1,key[0]);
keys.push_back(key[1]); keys.push_back(key[1]);
s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId); s = sign_multisig(a_and_b, keys, txTo[0], txdata[0], 0, consensusBranchId);
BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err)); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
keys.assign(1,key[i]); keys.assign(1,key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId); 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], 0, amount), consensusBranchId, &err), strprintf("a&b 1: %d", i)); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
keys.assign(1,key[1]); keys.assign(1,key[1]);
keys.push_back(key[i]); keys.push_back(key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId); 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], 0, amount), consensusBranchId, &err), strprintf("a&b 2: %d", i)); 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)); 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++) for (int i = 0; i < 4; i++)
{ {
keys.assign(1,key[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) 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
} }
else 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
} }
} }
s.clear(); s.clear();
s << OP_0 << OP_1; 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)); 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.assign(1,key[i]);
keys.push_back(key[j]); 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) 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
} }
else 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)); 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<i
txFrom.vout[2].nValue = 10; txFrom.vout[2].nValue = 10;
CMutableTransaction txTo[3]; // Spending transaction CMutableTransaction txTo[3]; // Spending transaction
std::vector<PrecomputedTransactionData> txdata;
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
txTo[i].vin.resize(1); txTo[i].vin.resize(1);
@ -222,11 +225,12 @@ BOOST_DATA_TEST_CASE(multisig_Sign, boost::unit_test::data::xrange(static_cast<i
txTo[i].vin[0].prevout.n = i; txTo[i].vin[0].prevout.n = i;
txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vin[0].prevout.hash = txFrom.GetHash();
txTo[i].vout[0].nValue = 1; txTo[i].vout[0].nValue = 1;
txdata.push_back(PrecomputedTransactionData(txTo[i]));
} }
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; 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], txdata[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i));
} }
} }

View File

@ -47,7 +47,8 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri
txTo.vin[0].scriptSig = scriptSig; txTo.vin[0].scriptSig = scriptSig;
txTo.vout[0].nValue = 1; txTo.vout[0].nValue = 1;
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0, txFrom.vout[0].nValue), consensusBranchId, &err); const PrecomputedTransactionData txdata(txTo);
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, txdata, 0, txFrom.vout[0].nValue), consensusBranchId, &err);
} }
@ -98,6 +99,7 @@ BOOST_DATA_TEST_CASE(sign, boost::unit_test::data::xrange(static_cast<int>(Conse
BOOST_CHECK(IsStandardTx(txFrom, reason, Params())); BOOST_CHECK(IsStandardTx(txFrom, reason, Params()));
CMutableTransaction txTo[8]; // Spending transactions CMutableTransaction txTo[8]; // Spending transactions
std::vector<PrecomputedTransactionData> txToData;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
txTo[i].vin.resize(1); txTo[i].vin.resize(1);
@ -106,10 +108,11 @@ BOOST_DATA_TEST_CASE(sign, boost::unit_test::data::xrange(static_cast<int>(Conse
txTo[i].vin[0].prevout.hash = txFrom.GetHash(); txTo[i].vin[0].prevout.hash = txFrom.GetHash();
txTo[i].vout[0].nValue = 1; txTo[i].vout[0].nValue = 1;
BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", 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 < 8; 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 // 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: // 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<int>(Consen
BOOST_CHECK(IsStandardTx(txFrom, reason, Params())); BOOST_CHECK(IsStandardTx(txFrom, reason, Params()));
CMutableTransaction txTo[4]; // Spending transactions CMutableTransaction txTo[4]; // Spending transactions
std::vector<PrecomputedTransactionData> txToData;
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
txTo[i].vin.resize(1); txTo[i].vin.resize(1);
@ -208,10 +212,11 @@ BOOST_DATA_TEST_CASE(set, boost::unit_test::data::xrange(static_cast<int>(Consen
txTo[i].vout[0].nValue = 1*CENT; txTo[i].vout[0].nValue = 1*CENT;
txTo[i].vout[0].scriptPubKey = inner[i]; txTo[i].vout[0].scriptPubKey = inner[i];
BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", 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++) 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)); 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.n = i;
txTo.vin[i].prevout.hash = txFrom.GetHash(); txTo.vin[i].prevout.hash = txFrom.GetHash();
} }
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId)); const PrecomputedTransactionData txToData(txTo);
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1, SIGHASH_ALL, consensusBranchId)); BOOST_CHECK(SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2, 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 // SignSignature doesn't know how to sign these. We're
// not testing validating signatures, so just create // not testing validating signatures, so just create
// dummy signatures that DO include the correct P2SH scripts: // dummy signatures that DO include the correct P2SH scripts:

View File

@ -78,8 +78,9 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, ui
ScriptError err; ScriptError err;
CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey); CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey);
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit); CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit);
const PrecomputedTransactionData txdata(tx);
CMutableTransaction tx2 = 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); BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message);
#if defined(HAVE_SCRIPT_LIB) #if defined(HAVE_SCRIPT_LIB)
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); 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) 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<unsigned char> vchSig, r, s; std::vector<unsigned char> vchSig, r, s;
uint32_t iter = 0; uint32_t iter = 0;
do { do {
@ -664,9 +666,9 @@ BOOST_DATA_TEST_CASE(script_PushData, boost::unit_test::data::xrange(static_cast
} }
CScript CScript
sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transaction, uint32_t consensusBranchId) sign_multisig(CScript scriptPubKey, std::vector<CKey> 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; CScript result;
// //
@ -688,11 +690,11 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
return result; return result;
} }
CScript 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<CKey> keys; std::vector<CKey> keys;
keys.push_back(key); 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 // 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 txFrom12 = BuildCreditingTransaction(scriptPubKey12);
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12); CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12);
const PrecomputedTransactionData txdata12(txTo12);
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12, consensusBranchId); CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12, txdata12, consensusBranchId);
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_OK, ScriptErrorString(err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
txTo12.vout[0].nValue = 2; 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12, consensusBranchId); CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12, txdata12, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err)); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12, consensusBranchId); CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12, txdata12, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err)); 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)); 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 txFrom23 = BuildCreditingTransaction(scriptPubKey23);
CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), txFrom23); CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), txFrom23);
const PrecomputedTransactionData txdata23(txTo23);
std::vector<CKey> keys; std::vector<CKey> keys;
keys.push_back(key1); keys.push_back(key2); keys.push_back(key1); keys.push_back(key2);
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key1); keys.push_back(key3); keys.push_back(key1); keys.push_back(key3);
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key2); keys.push_back(key3); keys.push_back(key2); keys.push_back(key3);
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); 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)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); // Must have signatures keys.clear(); // Must have signatures
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); 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)); 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 txFrom = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID()));
CMutableTransaction txTo = BuildSpendingTransaction(CScript(), txFrom); CMutableTransaction txTo = BuildSpendingTransaction(CScript(), txFrom);
const PrecomputedTransactionData txToData(txTo);
CScript& scriptPubKey = txFrom.vout[0].scriptPubKey; CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
CScript& scriptSig = txTo.vin[0].scriptSig; CScript& scriptSig = txTo.vin[0].scriptSig;
SignatureData empty; 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()); BOOST_CHECK(combined.scriptSig.empty());
// Single signature case: // Single signature case:
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); // changes scriptSig SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId); // changes scriptSig
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig); 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); BOOST_CHECK(combined.scriptSig == scriptSig);
CScript scriptSigCopy = scriptSig; CScript scriptSigCopy = scriptSig;
// Signing again will give a different, valid signature: // Signing again will give a different, valid signature:
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId);
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 == scriptSigCopy || combined.scriptSig == scriptSig); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
// P2SH, single-signature case: // P2SH, single-signature case:
CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG; CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG;
keystore.AddCScript(pkSingle); keystore.AddCScript(pkSingle);
scriptPubKey = GetScriptForDestination(CScriptID(pkSingle)); scriptPubKey = GetScriptForDestination(CScriptID(pkSingle));
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig); 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); BOOST_CHECK(combined.scriptSig == scriptSig);
scriptSigCopy = scriptSig; scriptSigCopy = scriptSig;
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId);
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 == scriptSigCopy || combined.scriptSig == scriptSig); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
// dummy scriptSigCopy with placeholder, should always choose non-placeholder: // dummy scriptSigCopy with placeholder, should always choose non-placeholder:
scriptSigCopy = CScript() << OP_0 << vector<unsigned char>(pkSingle.begin(), pkSingle.end()); scriptSigCopy = CScript() << OP_0 << vector<unsigned char>(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); 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); BOOST_CHECK(combined.scriptSig == scriptSig);
// Hardest case: Multisig 2-of-3 // Hardest case: Multisig 2-of-3
scriptPubKey = GetScriptForMultisig(2, pubkeys); scriptPubKey = GetScriptForMultisig(2, pubkeys);
keystore.AddCScript(scriptPubKey); keystore.AddCScript(scriptPubKey);
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig); 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); BOOST_CHECK(combined.scriptSig == scriptSig);
// A couple of partially-signed versions: // A couple of partially-signed versions:
vector<unsigned char> sig1; vector<unsigned char> 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)); BOOST_CHECK(keys[0].Sign(hash1, sig1));
sig1.push_back(SIGHASH_ALL); sig1.push_back(SIGHASH_ALL);
vector<unsigned char> sig2; vector<unsigned char> 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)); BOOST_CHECK(keys[1].Sign(hash2, sig2));
sig2.push_back(SIGHASH_NONE); sig2.push_back(SIGHASH_NONE);
vector<unsigned char> sig3; vector<unsigned char> 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)); BOOST_CHECK(keys[2].Sign(hash3, sig3));
sig3.push_back(SIGHASH_SINGLE); 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 complete13 = CScript() << OP_0 << sig1 << sig3;
CScript complete23 = CScript() << OP_0 << sig2 << 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); 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); 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); 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); 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); 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); 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); 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); BOOST_CHECK(combined.scriptSig == partial3c);
} }

View File

@ -202,7 +202,8 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle, uint32_t co
// Empty output script. // Empty output script.
CScript scriptCode; CScript scriptCode;
CTransaction signTx(tx); 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( assert(ed25519_sign(
&joinSplitPrivKey, &joinSplitPrivKey,
@ -236,10 +237,11 @@ BOOST_AUTO_TEST_CASE(sighash_test)
CScript scriptCode; CScript scriptCode;
RandomScript(scriptCode); RandomScript(scriptCode);
int nIn = insecure_rand() % txTo.vin.size(); int nIn = insecure_rand() % txTo.vin.size();
const PrecomputedTransactionData txdata(txTo);
uint256 sh, sho; uint256 sh, sho;
sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType); 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) #if defined(PRINT_SIGHASH_JSON)
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << txTo; ss << txTo;
@ -334,7 +336,8 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
continue; 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); BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest);
} }
} }

View File

@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
CAmount amount = 0; CAmount amount = 0;
unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], 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); strTest + comment);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err) + 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()); unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
CAmount amount = 0; CAmount amount = 0;
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], 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(!fValid, strTest + comment);
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err) + 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[0] = GetRandHash();
jsdesc->nullifiers[1] = GetRandHash(); jsdesc->nullifiers[1] = GetRandHash();
const PrecomputedTransactionData txdata(newTx);
BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state)); BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state));
BOOST_CHECK(ContextualCheckTransaction(newTx, state, Params(), 0, true)); 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"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-joinsplit-signature");
// Empty output script. // Empty output script.
CScript scriptCode; CScript scriptCode;
CTransaction signTx(newTx); 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( assert(ed25519_sign(
&joinSplitPrivKey, &joinSplitPrivKey,
@ -469,7 +471,7 @@ void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransa
state = CValidationState(); state = CValidationState();
BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state)); BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state));
BOOST_CHECK(ContextualCheckTransaction(newTx, state, Params(), 0, true)); 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(), ""); BOOST_CHECK_EQUAL(state.GetRejectReason(), "");
} }
{ {
@ -670,9 +672,11 @@ BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) {
mtx.vout[i].scriptPubKey = CScript() << OP_1; mtx.vout[i].scriptPubKey = CScript() << OP_1;
} }
PrecomputedTransactionData txdata(mtx);
// sign all inputs // sign all inputs
for(uint32_t i = 0; i < mtx.vin.size(); i++) { 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); assert(hashSigned);
} }
@ -682,7 +686,6 @@ BOOST_AUTO_TEST_CASE(test_big_overwinter_transaction) {
ssout >> tx; ssout >> tx;
// check all inputs concurrently, with the cache // check all inputs concurrently, with the cache
PrecomputedTransactionData txdata(tx);
boost::thread_group threadGroup; boost::thread_group threadGroup;
CCheckQueue<CScriptCheck> scriptcheckqueue(128); CCheckQueue<CScriptCheck> scriptcheckqueue(128);
CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue); CCheckQueueControl<CScriptCheck> control(&scriptcheckqueue);
@ -915,11 +918,13 @@ BOOST_AUTO_TEST_CASE(TxV5)
amount = test[5].get_int64(); amount = test[5].get_int64();
} }
const PrecomputedTransactionData txdata(tx);
BOOST_CHECK_EQUAL( BOOST_CHECK_EQUAL(
SignatureHash( SignatureHash(
scriptCode, tx, nIn, scriptCode, tx, nIn,
SIGHASH_ALL, SIGHASH_ALL,
amount, *tx.GetConsensusBranchId() amount, *tx.GetConsensusBranchId(), txdata
).GetHex(), ).GetHex(),
test[6].getValStr()); test[6].getValStr());
@ -928,7 +933,7 @@ BOOST_AUTO_TEST_CASE(TxV5)
SignatureHash( SignatureHash(
scriptCode, tx, nIn, scriptCode, tx, nIn,
SIGHASH_NONE, SIGHASH_NONE,
amount, *tx.GetConsensusBranchId() amount, *tx.GetConsensusBranchId(), txdata
).GetHex(), ).GetHex(),
test[7].getValStr()); test[7].getValStr());
} }
@ -938,7 +943,7 @@ BOOST_AUTO_TEST_CASE(TxV5)
SignatureHash( SignatureHash(
scriptCode, tx, nIn, scriptCode, tx, nIn,
SIGHASH_SINGLE, SIGHASH_SINGLE,
amount, *tx.GetConsensusBranchId() amount, *tx.GetConsensusBranchId(), txdata
).GetHex(), ).GetHex(),
test[8].getValStr()); test[8].getValStr());
} }
@ -948,7 +953,7 @@ BOOST_AUTO_TEST_CASE(TxV5)
SignatureHash( SignatureHash(
scriptCode, tx, nIn, scriptCode, tx, nIn,
SIGHASH_ALL | SIGHASH_ANYONECANPAY, SIGHASH_ALL | SIGHASH_ANYONECANPAY,
amount, *tx.GetConsensusBranchId() amount, *tx.GetConsensusBranchId(), txdata
).GetHex(), ).GetHex(),
test[9].getValStr()); test[9].getValStr());
} }
@ -958,7 +963,7 @@ BOOST_AUTO_TEST_CASE(TxV5)
SignatureHash( SignatureHash(
scriptCode, tx, nIn, scriptCode, tx, nIn,
SIGHASH_NONE | SIGHASH_ANYONECANPAY, SIGHASH_NONE | SIGHASH_ANYONECANPAY,
amount, *tx.GetConsensusBranchId() amount, *tx.GetConsensusBranchId(), txdata
).GetHex(), ).GetHex(),
test[10].getValStr()); test[10].getValStr());
} }
@ -968,7 +973,7 @@ BOOST_AUTO_TEST_CASE(TxV5)
SignatureHash( SignatureHash(
scriptCode, tx, nIn, scriptCode, tx, nIn,
SIGHASH_SINGLE | SIGHASH_ANYONECANPAY, SIGHASH_SINGLE | SIGHASH_ANYONECANPAY,
amount, *tx.GetConsensusBranchId() amount, *tx.GetConsensusBranchId(), txdata
).GetHex(), ).GetHex(),
test[11].getValStr()); test[11].getValStr());
} }

View File

@ -48,8 +48,9 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
spends[i].vout[0].scriptPubKey = scriptPubKey; spends[i].vout[0].scriptPubKey = scriptPubKey;
// Sign: // Sign:
const PrecomputedTransactionData txdata(spends[i]);
std::vector<unsigned char> vchSig; std::vector<unsigned char> 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)); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
vchSig.push_back((unsigned char)SIGHASH_ALL); vchSig.push_back((unsigned char)SIGHASH_ALL);
spends[i].vin[0].scriptSig << vchSig; spends[i].vin[0].scriptSig << vchSig;

View File

@ -446,12 +446,13 @@ TransactionBuilderResult TransactionBuilder::Build()
// //
auto consensusBranchId = CurrentEpochBranchId(nHeight, consensusParams); auto consensusBranchId = CurrentEpochBranchId(nHeight, consensusParams);
const PrecomputedTransactionData txdata(mtx);
// Empty output script. // Empty output script.
uint256 dataToBeSigned; uint256 dataToBeSigned;
CScript scriptCode; CScript scriptCode;
try { 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) { } catch (std::logic_error ex) {
librustzcash_sapling_proving_ctx_free(ctx); librustzcash_sapling_proving_ctx_free(ctx);
return TransactionBuilderResult("Could not construct signature hash: " + std::string(ex.what())); return TransactionBuilderResult("Could not construct signature hash: " + std::string(ex.what()));
@ -498,7 +499,7 @@ TransactionBuilderResult TransactionBuilder::Build()
SignatureData sigdata; SignatureData sigdata;
bool signSuccess = ProduceSignature( bool signSuccess = ProduceSignature(
TransactionSignatureCreator( TransactionSignatureCreator(
keystore, &txNewConst, nIn, tIn.value, SIGHASH_ALL), keystore, &txNewConst, txdata, nIn, tIn.value, SIGHASH_ALL),
tIn.scriptPubKey, sigdata, consensusBranchId); tIn.scriptPubKey, sigdata, consensusBranchId);
if (!signSuccess) { if (!signSuccess) {

View File

@ -69,7 +69,8 @@ CMutableTransaction GetValidSproutReceiveTransaction(
uint32_t consensusBranchId = SPROUT_BRANCH_ID; uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CScript scriptCode; CScript scriptCode;
CTransaction signTx(mtx); 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 // Add the signature
assert(ed25519_sign( assert(ed25519_sign(
@ -184,7 +185,8 @@ CWalletTx GetValidSproutSpend(const libzcash::SproutSpendingKey& sk,
uint32_t consensusBranchId = SPROUT_BRANCH_ID; uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CScript scriptCode; CScript scriptCode;
CTransaction signTx(mtx); 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 // Add the signature
assert(ed25519_sign( assert(ed25519_sign(

View File

@ -834,7 +834,8 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(
// Empty output script. // Empty output script.
CScript scriptCode; CScript scriptCode;
CTransaction signTx(mtx); 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 // Add the signature
if (!ed25519_sign( if (!ed25519_sign(

View File

@ -361,7 +361,8 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf
// Empty output script. // Empty output script.
CScript scriptCode; CScript scriptCode;
CTransaction signTx(mtx); 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 // Add the signature
if (!ed25519_sign( if (!ed25519_sign(

View File

@ -2889,8 +2889,9 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
// Empty output script. // Empty output script.
CScript scriptCode; CScript scriptCode;
CTransaction signTx(mtx); CTransaction signTx(mtx);
PrecomputedTransactionData txdata(signTx);
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); 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 // Add the signature
assert(ed25519_sign( assert(ed25519_sign(

View File

@ -4767,13 +4767,14 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// Sign // Sign
int nIn = 0; int nIn = 0;
CTransaction txNewConst(txNew); CTransaction txNewConst(txNew);
const PrecomputedTransactionData txdata(txNewConst);
for (const std::pair<const CWalletTx*, unsigned int>& coin : setCoins) for (const std::pair<const CWalletTx*, unsigned int>& coin : setCoins)
{ {
bool signSuccess; bool signSuccess;
const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey; const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
SignatureData sigdata; SignatureData sigdata;
if (sign) 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 else
signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata, consensusBranchId); signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, sigdata, consensusBranchId);

View File

@ -238,10 +238,12 @@ double benchmark_large_tx(size_t nInputs)
spending_tx.vin.emplace_back(input_hash, 0); spending_tx.vin.emplace_back(input_hash, 0);
} }
PrecomputedTransactionData txdata(spending_tx);
// Sign for all the inputs // Sign for all the inputs
auto consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_SAPLING].nBranchId; auto consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_SAPLING].nBranchId;
for (size_t i = 0; i < nInputs; i++) { 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 // 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: // Benchmark signature verification costs:
struct timeval tv_start; struct timeval tv_start;
timer_start(tv_start); timer_start(tv_start);
PrecomputedTransactionData txdata(final_spending_tx);
for (size_t i = 0; i < nInputs; i++) { for (size_t i = 0; i < nInputs; i++) {
ScriptError serror = SCRIPT_ERR_OK; ScriptError serror = SCRIPT_ERR_OK;
assert(VerifyScript(final_spending_tx.vin[i].scriptSig, assert(VerifyScript(final_spending_tx.vin[i].scriptSig,
prevPubKey, prevPubKey,
STANDARD_SCRIPT_VERIFY_FLAGS, STANDARD_SCRIPT_VERIFY_FLAGS,
TransactionSignatureChecker(&final_spending_tx, i, 1000000, txdata), TransactionSignatureChecker(&final_spending_tx, txdata, i, 1000000),
consensusBranchId, consensusBranchId,
&serror)); &serror));
} }