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

View File

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

View File

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

View File

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

View File

@ -373,6 +373,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons
*/
bool ContextualCheckShieldedInputs(
const CTransaction& tx,
const PrecomputedTransactionData& txdata,
CValidationState &state,
orchard::AuthValidator& orchardAuth,
const Consensus::Params& consensus,
@ -449,6 +450,8 @@ private:
bool cacheStore;
uint32_t consensusBranchId;
ScriptError error;
// We store a pointer instead of a reference here, to allow it to be null for
// performance reasons (enabling fast swaps in CCheckQueue::Loop).
PrecomputedTransactionData *txdata;
public:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@ -23,9 +23,9 @@ using namespace std;
BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
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;
result << OP_0; // CHECKMULTISIG bug workaround
@ -71,6 +71,7 @@ BOOST_DATA_TEST_CASE(multisig_verify, boost::unit_test::data::xrange(static_cast
txFrom.vout[2].nValue = 10;
CMutableTransaction txTo[3]; // Spending transaction
std::vector<PrecomputedTransactionData> txdata;
for (int i = 0; i < 3; i++)
{
txTo[i].vin.resize(1);
@ -78,6 +79,7 @@ BOOST_DATA_TEST_CASE(multisig_verify, boost::unit_test::data::xrange(static_cast
txTo[i].vin[0].prevout.n = i;
txTo[i].vin[0].prevout.hash = txFrom.GetHash();
txTo[i].vout[0].nValue = 1;
txdata.push_back(PrecomputedTransactionData(txTo[i]));
}
vector<CKey> keys;
@ -86,21 +88,21 @@ BOOST_DATA_TEST_CASE(multisig_verify, boost::unit_test::data::xrange(static_cast
// Test a AND b:
keys.assign(1,key[0]);
keys.push_back(key[1]);
s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId);
BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err));
s = sign_multisig(a_and_b, keys, txTo[0], txdata[0], 0, consensusBranchId);
BOOST_CHECK(VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], txdata[0], 0, amount), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
for (int i = 0; i < 4; i++)
{
keys.assign(1,key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId);
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err), strprintf("a&b 1: %d", i));
s = sign_multisig(a_and_b, keys, txTo[0], txdata[0], 0, consensusBranchId);
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], txdata[0], 0, amount), consensusBranchId, &err), strprintf("a&b 1: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
keys.assign(1,key[1]);
keys.push_back(key[i]);
s = sign_multisig(a_and_b, keys, txTo[0], 0, consensusBranchId);
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount), consensusBranchId, &err), strprintf("a&b 2: %d", i));
s = sign_multisig(a_and_b, keys, txTo[0], txdata[0], 0, consensusBranchId);
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, MutableTransactionSignatureChecker(&txTo[0], txdata[0], 0, amount), consensusBranchId, &err), strprintf("a&b 2: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
@ -108,21 +110,21 @@ BOOST_DATA_TEST_CASE(multisig_verify, boost::unit_test::data::xrange(static_cast
for (int i = 0; i < 4; i++)
{
keys.assign(1,key[i]);
s = sign_multisig(a_or_b, keys, txTo[1], 0, consensusBranchId);
s = sign_multisig(a_or_b, keys, txTo[1], txdata[1], 0, consensusBranchId);
if (i == 0 || i == 1)
{
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], txdata[1], 0, amount), consensusBranchId, &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
else
{
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], txdata[1], 0, amount), consensusBranchId, &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
}
s.clear();
s << OP_0 << OP_1;
BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount), consensusBranchId, &err));
BOOST_CHECK(!VerifyScript(s, a_or_b, flags, MutableTransactionSignatureChecker(&txTo[1], txdata[1], 0, amount), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
@ -131,15 +133,15 @@ BOOST_DATA_TEST_CASE(multisig_verify, boost::unit_test::data::xrange(static_cast
{
keys.assign(1,key[i]);
keys.push_back(key[j]);
s = sign_multisig(escrow, keys, txTo[2], 0, consensusBranchId);
s = sign_multisig(escrow, keys, txTo[2], txdata[2], 0, consensusBranchId);
if (i < j && i < 3 && j < 3)
{
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), consensusBranchId, &err), strprintf("escrow 1: %d %d", i, j));
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], txdata[2], 0, amount), consensusBranchId, &err), strprintf("escrow 1: %d %d", i, j));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
else
{
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount), consensusBranchId, &err), strprintf("escrow 2: %d %d", i, j));
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, MutableTransactionSignatureChecker(&txTo[2], txdata[2], 0, amount), consensusBranchId, &err), strprintf("escrow 2: %d %d", i, j));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
}
@ -215,6 +217,7 @@ BOOST_DATA_TEST_CASE(multisig_Sign, boost::unit_test::data::xrange(static_cast<i
txFrom.vout[2].nValue = 10;
CMutableTransaction txTo[3]; // Spending transaction
std::vector<PrecomputedTransactionData> txdata;
for (int i = 0; i < 3; i++)
{
txTo[i].vin.resize(1);
@ -222,11 +225,12 @@ BOOST_DATA_TEST_CASE(multisig_Sign, boost::unit_test::data::xrange(static_cast<i
txTo[i].vin[0].prevout.n = i;
txTo[i].vin[0].prevout.hash = txFrom.GetHash();
txTo[i].vout[0].nValue = 1;
txdata.push_back(PrecomputedTransactionData(txTo[i]));
}
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.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()));
CMutableTransaction txTo[8]; // Spending transactions
std::vector<PrecomputedTransactionData> txToData;
for (int i = 0; i < 8; i++)
{
txTo[i].vin.resize(1);
@ -106,10 +108,11 @@ BOOST_DATA_TEST_CASE(sign, boost::unit_test::data::xrange(static_cast<int>(Conse
txTo[i].vin[0].prevout.hash = txFrom.GetHash();
txTo[i].vout[0].nValue = 1;
BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
txToData.push_back(PrecomputedTransactionData(txTo[i]));
}
for (int i = 0; i < 8; i++)
{
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i));
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], txToData[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i));
}
// All of the above should be OK, and the txTos have valid signatures
// Check to make sure signature verification fails if we use the wrong ScriptSig:
@ -199,6 +202,7 @@ BOOST_DATA_TEST_CASE(set, boost::unit_test::data::xrange(static_cast<int>(Consen
BOOST_CHECK(IsStandardTx(txFrom, reason, Params()));
CMutableTransaction txTo[4]; // Spending transactions
std::vector<PrecomputedTransactionData> txToData;
for (int i = 0; i < 4; i++)
{
txTo[i].vin.resize(1);
@ -208,10 +212,11 @@ BOOST_DATA_TEST_CASE(set, boost::unit_test::data::xrange(static_cast<int>(Consen
txTo[i].vout[0].nValue = 1*CENT;
txTo[i].vout[0].scriptPubKey = inner[i];
BOOST_CHECK_MESSAGE(IsMine(keystore, txFrom.vout[i].scriptPubKey), strprintf("IsMine %d", i));
txToData.push_back(PrecomputedTransactionData(txTo[i]));
}
for (int i = 0; i < 4; i++)
{
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i));
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], txToData[i], 0, SIGHASH_ALL, consensusBranchId), strprintf("SignSignature %d", i));
BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason, Params()), strprintf("txTo[%d].IsStandard", i));
}
}
@ -347,9 +352,10 @@ BOOST_DATA_TEST_CASE(AreInputsStandard, boost::unit_test::data::xrange(static_ca
txTo.vin[i].prevout.n = i;
txTo.vin[i].prevout.hash = txFrom.GetHash();
}
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 1, SIGHASH_ALL, consensusBranchId));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, 2, SIGHASH_ALL, consensusBranchId));
const PrecomputedTransactionData txToData(txTo);
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, txToData, 1, SIGHASH_ALL, consensusBranchId));
BOOST_CHECK(SignSignature(keystore, txFrom, txTo, txToData, 2, SIGHASH_ALL, consensusBranchId));
// SignSignature doesn't know how to sign these. We're
// not testing validating signatures, so just create
// dummy signatures that DO include the correct P2SH scripts:

View File

@ -78,8 +78,9 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, ui
ScriptError err;
CMutableTransaction txCredit = BuildCreditingTransaction(scriptPubKey);
CMutableTransaction tx = BuildSpendingTransaction(scriptSig, txCredit);
const PrecomputedTransactionData txdata(tx);
CMutableTransaction tx2 = tx;
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue), consensusBranchId, &err) == expect, message);
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, MutableTransactionSignatureChecker(&tx, txdata, 0, txCredit.vout[0].nValue), consensusBranchId, &err) == expect, message);
BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message);
#if defined(HAVE_SCRIPT_LIB)
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
@ -230,7 +231,8 @@ public:
TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32)
{
uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType, 0, consensusBranchId);
const PrecomputedTransactionData txdata(spendTx);
uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType, 0, consensusBranchId, txdata);
std::vector<unsigned char> vchSig, r, s;
uint32_t iter = 0;
do {
@ -664,9 +666,9 @@ BOOST_DATA_TEST_CASE(script_PushData, boost::unit_test::data::xrange(static_cast
}
CScript
sign_multisig(CScript scriptPubKey, std::vector<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;
//
@ -688,11 +690,11 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
return result;
}
CScript
sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction, uint32_t consensusBranchId)
sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction, const PrecomputedTransactionData& txdata, uint32_t consensusBranchId)
{
std::vector<CKey> keys;
keys.push_back(key);
return sign_multisig(scriptPubKey, keys, transaction, consensusBranchId);
return sign_multisig(scriptPubKey, keys, transaction, txdata, consensusBranchId);
}
// Parameterized testing over consensus branch ids
@ -710,20 +712,21 @@ BOOST_DATA_TEST_CASE(script_CHECKMULTISIG12, boost::unit_test::data::xrange(stat
CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12);
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12);
const PrecomputedTransactionData txdata12(txTo12);
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12, txdata12, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, txdata12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
txTo12.vout[0].nValue = 2;
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, txdata12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12, txdata12, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, txdata12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12, txdata12, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, MutableTransactionSignatureChecker(&txTo12, txdata12, 0, txFrom12.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
@ -743,58 +746,59 @@ BOOST_DATA_TEST_CASE(script_CHECKMULTISIG23, boost::unit_test::data::xrange(stat
CMutableTransaction txFrom23 = BuildCreditingTransaction(scriptPubKey23);
CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), txFrom23);
const PrecomputedTransactionData txdata23(txTo23);
std::vector<CKey> keys;
keys.push_back(key1); keys.push_back(key2);
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear();
keys.push_back(key1); keys.push_back(key3);
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear();
keys.push_back(key2); keys.push_back(key3);
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear();
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear();
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear();
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear();
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear();
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); // Must have signatures
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23, txdata23, consensusBranchId);
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, txdata23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
}
@ -818,65 +822,66 @@ BOOST_DATA_TEST_CASE(script_combineSigs, boost::unit_test::data::xrange(static_c
CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID()));
CMutableTransaction txTo = BuildSpendingTransaction(CScript(), txFrom);
const PrecomputedTransactionData txToData(txTo);
CScript& scriptPubKey = txFrom.vout[0].scriptPubKey;
CScript& scriptSig = txTo.vin[0].scriptSig;
SignatureData empty;
SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, empty, consensusBranchId);
SignatureData combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), empty, empty, consensusBranchId);
BOOST_CHECK(combined.scriptSig.empty());
// Single signature case:
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId); // changes scriptSig
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId); // changes scriptSig
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), empty, SignatureData(scriptSig), consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig);
CScript scriptSigCopy = scriptSig;
// Signing again will give a different, valid signature:
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId);
SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
// P2SH, single-signature case:
CScript pkSingle; pkSingle << ToByteVector(keys[0].GetPubKey()) << OP_CHECKSIG;
keystore.AddCScript(pkSingle);
scriptPubKey = GetScriptForDestination(CScriptID(pkSingle));
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), empty, SignatureData(scriptSig), consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig);
scriptSigCopy = scriptSig;
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId);
SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig);
// dummy scriptSigCopy with placeholder, should always choose non-placeholder:
scriptSigCopy = CScript() << OP_0 << vector<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);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy), consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy), consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig);
// Hardest case: Multisig 2-of-3
scriptPubKey = GetScriptForMultisig(2, pubkeys);
keystore.AddCScript(scriptPubKey);
SignSignature(keystore, txFrom, txTo, 0, SIGHASH_ALL, consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
SignSignature(keystore, txFrom, txTo, txToData, 0, SIGHASH_ALL, consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(scriptSig), empty, consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), empty, SignatureData(scriptSig), consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), empty, SignatureData(scriptSig), consensusBranchId);
BOOST_CHECK(combined.scriptSig == scriptSig);
// A couple of partially-signed versions:
vector<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));
sig1.push_back(SIGHASH_ALL);
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));
sig2.push_back(SIGHASH_NONE);
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));
sig3.push_back(SIGHASH_SINGLE);
@ -892,21 +897,21 @@ BOOST_DATA_TEST_CASE(script_combineSigs, boost::unit_test::data::xrange(static_c
CScript complete13 = CScript() << OP_0 << sig1 << sig3;
CScript complete23 = CScript() << OP_0 << sig2 << sig3;
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial1b), consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial1a), SignatureData(partial1b), consensusBranchId);
BOOST_CHECK(combined.scriptSig == partial1a);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1a), SignatureData(partial2a), consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial1a), SignatureData(partial2a), consensusBranchId);
BOOST_CHECK(combined.scriptSig == complete12);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial1a), consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial2a), SignatureData(partial1a), consensusBranchId);
BOOST_CHECK(combined.scriptSig == complete12);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial1b), SignatureData(partial2b), consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial1b), SignatureData(partial2b), consensusBranchId);
BOOST_CHECK(combined.scriptSig == complete12);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial1b), consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial3b), SignatureData(partial1b), consensusBranchId);
BOOST_CHECK(combined.scriptSig == complete13);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial2a), SignatureData(partial3a), consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial2a), SignatureData(partial3a), consensusBranchId);
BOOST_CHECK(combined.scriptSig == complete23);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial2b), consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial3b), SignatureData(partial2b), consensusBranchId);
BOOST_CHECK(combined.scriptSig == complete23);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(partial3b), SignatureData(partial3a), consensusBranchId);
combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, txToData, 0, amount), SignatureData(partial3b), SignatureData(partial3a), consensusBranchId);
BOOST_CHECK(combined.scriptSig == partial3c);
}

View File

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

View File

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

View File

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

View File

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

View File

@ -69,7 +69,8 @@ CMutableTransaction GetValidSproutReceiveTransaction(
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CScript scriptCode;
CTransaction signTx(mtx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
const PrecomputedTransactionData txdata(signTx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata);
// Add the signature
assert(ed25519_sign(
@ -184,7 +185,8 @@ CWalletTx GetValidSproutSpend(const libzcash::SproutSpendingKey& sk,
uint32_t consensusBranchId = SPROUT_BRANCH_ID;
CScript scriptCode;
CTransaction signTx(mtx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
const PrecomputedTransactionData txdata(signTx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata);
// Add the signature
assert(ed25519_sign(

View File

@ -834,7 +834,8 @@ UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(
// Empty output script.
CScript scriptCode;
CTransaction signTx(mtx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId_);
PrecomputedTransactionData txdata(signTx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId_, txdata);
// Add the signature
if (!ed25519_sign(

View File

@ -361,7 +361,8 @@ UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInf
// Empty output script.
CScript scriptCode;
CTransaction signTx(mtx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
PrecomputedTransactionData txdata(signTx);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata);
// Add the signature
if (!ed25519_sign(

View File

@ -2889,8 +2889,9 @@ UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp)
// Empty output script.
CScript scriptCode;
CTransaction signTx(mtx);
PrecomputedTransactionData txdata(signTx);
auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus());
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId, txdata);
// Add the signature
assert(ed25519_sign(

View File

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

View File

@ -238,10 +238,12 @@ double benchmark_large_tx(size_t nInputs)
spending_tx.vin.emplace_back(input_hash, 0);
}
PrecomputedTransactionData txdata(spending_tx);
// Sign for all the inputs
auto consensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_SAPLING].nBranchId;
for (size_t i = 0; i < nInputs; i++) {
SignSignature(tempKeystore, prevPubKey, spending_tx, i, 1000000, SIGHASH_ALL, consensusBranchId);
SignSignature(tempKeystore, prevPubKey, spending_tx, txdata, i, 1000000, SIGHASH_ALL, consensusBranchId);
}
// Spending tx has all its inputs signed and does not need to be mutated anymore
@ -250,13 +252,12 @@ double benchmark_large_tx(size_t nInputs)
// Benchmark signature verification costs:
struct timeval tv_start;
timer_start(tv_start);
PrecomputedTransactionData txdata(final_spending_tx);
for (size_t i = 0; i < nInputs; i++) {
ScriptError serror = SCRIPT_ERR_OK;
assert(VerifyScript(final_spending_tx.vin[i].scriptSig,
prevPubKey,
STANDARD_SCRIPT_VERIFY_FLAGS,
TransactionSignatureChecker(&final_spending_tx, i, 1000000, txdata),
TransactionSignatureChecker(&final_spending_tx, txdata, i, 1000000),
consensusBranchId,
&serror));
}