diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp index cf8ef6b0d5..12288ab899 100644 --- a/src/bench/verify_script.cpp +++ b/src/bench/verify_script.cpp @@ -77,7 +77,7 @@ static void VerifyScriptBench(benchmark::State& state) txSpend.witness.vtxinwit.resize(1); CScriptWitness& witness = txSpend.witness.vtxinwit[0].scriptWitness; witness.stack.emplace_back(); - key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SigVersion::WITNESS_V0), witness.stack.back()); + key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SigVersion::WITNESS_V0, 0), witness.stack.back()); witness.stack.back().push_back(static_cast(SIGHASH_ALL)); witness.stack.push_back(ToByteVector(pubkey)); diff --git a/src/script/generic.hpp b/src/script/generic.hpp index ca1317c584..fb5dd308f3 100644 --- a/src/script/generic.hpp +++ b/src/script/generic.hpp @@ -18,7 +18,7 @@ class SimpleSignatureChecker : public BaseSignatureChecker bool sighash_byte; SimpleSignatureChecker(const uint256& hashIn, bool sighash_byte_in) : hash(hashIn), sighash_byte(sighash_byte_in) {}; - bool CheckSig(const std::vector& vchSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const + bool CheckSig(const std::vector& vchSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override { std::vector vchSigCopy(vchSig); CPubKey pubkey(vchPubKey); @@ -47,7 +47,7 @@ class SimpleSignatureCreator : public BaseSignatureCreator public: SimpleSignatureCreator(const uint256& hashIn, bool sighash_byte_in) : checker(hashIn, sighash_byte_in), sighash_byte(sighash_byte_in) {}; const BaseSignatureChecker& Checker() const { return checker; } - bool CreateSig(const SigningProvider& provider, std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const + bool CreateSig(const SigningProvider& provider, std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override { CKey key; if (!provider.GetKey(keyid, key)) diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 01be38e85a..df34fbb0dd 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -186,11 +186,17 @@ bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) { return true; } -bool static IsDefinedHashtypeSignature(const valtype &vchSig) { +bool static IsDefinedHashtypeSignature(const valtype &vchSig, unsigned int flags) { if (vchSig.size() == 0) { return false; } unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY)); + + // ELEMENTS: Only allow SIGHASH_RANGEPROOF if the flag is set (after dynafed activation). + if ((flags & SCRIPT_SIGHASH_RANGEPROOF) == SCRIPT_SIGHASH_RANGEPROOF) { + nHashType = nHashType & (~(SIGHASH_RANGEPROOF)); + } + if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) return false; @@ -216,7 +222,7 @@ bool CheckSignatureEncoding(const std::vector &vchSig, unsigned i } else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSigCopy, serror)) { // serror is set return false; - } else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSigCopy)) { + } else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSigCopy, flags)) { return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE); } return true; @@ -1213,7 +1219,8 @@ bool EvalScript(std::vector >& stack, const CScript& //serror is set return false; } - bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion); + + bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion, flags); if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size()) return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); @@ -1291,7 +1298,7 @@ bool EvalScript(std::vector >& stack, const CScript& } // Check signature - bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion); + bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion, flags); if (fOk) { isig++; @@ -1466,13 +1473,15 @@ class CTransactionSignatureSerializer const CScript& scriptCode; //!< output script being consumed const unsigned int nIn; //!< input index of txTo being signed const bool fAnyoneCanPay; //!< whether the hashtype has the SIGHASH_ANYONECANPAY flag set + const bool fRangeproof; //!< whether the hashtype has the SIGHASH_RANGEPROOF flag set const bool fHashSingle; //!< whether the hashtype is SIGHASH_SINGLE const bool fHashNone; //!< whether the hashtype is SIGHASH_NONE public: - CTransactionSignatureSerializer(const T& txToIn, const CScript& scriptCodeIn, unsigned int nInIn, int nHashTypeIn) : + CTransactionSignatureSerializer(const T& txToIn, const CScript& scriptCodeIn, unsigned int nInIn, int nHashTypeIn, unsigned int flags) : txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn), fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)), + fRangeproof(!!(flags & SCRIPT_SIGHASH_RANGEPROOF) && !!(nHashTypeIn & SIGHASH_RANGEPROOF)), fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE), fHashNone((nHashTypeIn & 0x1f) == SIGHASH_NONE) {} @@ -1529,11 +1538,23 @@ class CTransactionSignatureSerializer /** Serialize an output of txTo */ template void SerializeOutput(S &s, unsigned int nOutput) const { - if (fHashSingle && nOutput != nIn) + if (fHashSingle && nOutput != nIn) { // Do not lock-in the txout payee at other indices as txin ::Serialize(s, CTxOut()); - else + } else { ::Serialize(s, txTo.vout[nOutput]); + + // Serialize rangeproof + if (fRangeproof) { + if (nOutput < txTo.witness.vtxoutwit.size()) { + ::Serialize(s, txTo.witness.vtxoutwit[nOutput].vchRangeproof); + ::Serialize(s, txTo.witness.vtxoutwit[nOutput].vchSurjectionproof); + } else { + ::Serialize(s, (unsigned char) 0); + ::Serialize(s, (unsigned char) 0); + } + } + } } /** Serialize txTo */ @@ -1599,6 +1620,21 @@ uint256 GetOutputsHash(const T& txTo) return ss.GetHash(); } +template +uint256 GetRangeproofsHash(const T& txTo) { + CHashWriter ss(SER_GETHASH, 0); + for (size_t i = 0; i < txTo.vout.size(); i++) { + if (i < txTo.witness.vtxoutwit.size()) { + ss << txTo.witness.vtxoutwit[i].vchRangeproof; + ss << txTo.witness.vtxoutwit[i].vchSurjectionproof; + } else { + ss << (unsigned char) 0; + ss << (unsigned char) 0; + } + } + return ss.GetHash(); +} + } // namespace template @@ -1610,6 +1646,7 @@ PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo) hashSequence = GetSequenceHash(txTo); hashIssuance = GetIssuanceHash(txTo); hashOutputs = GetOutputsHash(txTo); + hashRangeproofs = GetRangeproofsHash(txTo); ready = true; } } @@ -1619,7 +1656,7 @@ template PrecomputedTransactionData::PrecomputedTransactionData(const CTransacti template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo); template -uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CConfidentialValue& amount, SigVersion sigversion, const PrecomputedTransactionData* cache) +uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CConfidentialValue& amount, SigVersion sigversion, unsigned int flags, const PrecomputedTransactionData* cache) { assert(nIn < txTo.vin.size()); @@ -1628,7 +1665,9 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn uint256 hashSequence; uint256 hashIssuance; uint256 hashOutputs; + uint256 hashRangeproofs; const bool cacheready = cache && cache->ready; + bool fRangeproof = !!(flags & SCRIPT_SIGHASH_RANGEPROOF) && !!(nHashType & SIGHASH_RANGEPROOF); if (!(nHashType & SIGHASH_ANYONECANPAY)) { hashPrevouts = cacheready ? cache->hashPrevouts : GetPrevoutHash(txTo); @@ -1644,10 +1683,26 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) { hashOutputs = cacheready ? cache->hashOutputs : GetOutputsHash(txTo); + + if (fRangeproof) { + hashRangeproofs = cacheready ? cache->hashRangeproofs : GetRangeproofsHash(txTo); + } } else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) { CHashWriter ss(SER_GETHASH, 0); ss << txTo.vout[nIn]; hashOutputs = ss.GetHash(); + + if (fRangeproof) { + CHashWriter ss(SER_GETHASH, 0); + if (nIn < txTo.witness.vtxoutwit.size()) { + ss << txTo.witness.vtxoutwit[nIn].vchRangeproof; + ss << txTo.witness.vtxoutwit[nIn].vchSurjectionproof; + } else { + ss << (unsigned char) 0; + ss << (unsigned char) 0; + } + hashRangeproofs = ss.GetHash(); + } } CHashWriter ss(SER_GETHASH, 0); @@ -1676,6 +1731,11 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn } // Outputs (none/one/all, depending on flags) ss << hashOutputs; + if (fRangeproof) { + // This addition must be conditional because it was added after + // the segwit sighash was specified. + ss << hashRangeproofs; + } // Locktime ss << txTo.nLockTime; // Sighash type @@ -1695,7 +1755,7 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn } // Wrapper to serialize only the necessary parts of the transaction being signed - CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType); + CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType, flags); // Serialize and hash CHashWriter ss(SER_GETHASH, 0); @@ -1710,7 +1770,7 @@ bool GenericTransactionSignatureChecker::VerifySignature(const std::vector -bool GenericTransactionSignatureChecker::CheckSig(const std::vector& vchSigIn, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const +bool GenericTransactionSignatureChecker::CheckSig(const std::vector& vchSigIn, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const { CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) @@ -1723,7 +1783,7 @@ bool GenericTransactionSignatureChecker::CheckSig(const std::vectortxdata); + uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, flags, this->txdata); if (!VerifySignature(vchSig, pubkey, sighash)) return false; diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 8801bd52af..a7a800e6a4 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -25,6 +25,10 @@ enum SIGHASH_NONE = 2, SIGHASH_SINGLE = 3, SIGHASH_ANYONECANPAY = 0x80, + + // ELEMENTS: + // A flag that means the rangeproofs should be included in the sighash. + SIGHASH_RANGEPROOF = 0x40, }; /** Script verification flags. @@ -116,16 +120,22 @@ enum // SCRIPT_VERIFY_CONST_SCRIPTCODE = (1U << 16), + // ELEMENTS: + // Signature checking assumes no sighash byte after the DER signature // SCRIPT_NO_SIGHASH_BYTE = (1U << 17), + + // Support/allow SIGHASH_RANGEPROOF. + // + SCRIPT_SIGHASH_RANGEPROOF = (1U << 18), }; bool CheckSignatureEncoding(const std::vector &vchSig, unsigned int flags, ScriptError* serror); struct PrecomputedTransactionData { - uint256 hashPrevouts, hashSequence, hashOutputs, hashIssuance; + uint256 hashPrevouts, hashSequence, hashOutputs, hashIssuance, hashRangeproofs; bool ready = false; template @@ -143,12 +153,12 @@ static constexpr size_t WITNESS_V0_SCRIPTHASH_SIZE = 32; static constexpr size_t WITNESS_V0_KEYHASH_SIZE = 20; template -uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CConfidentialValue& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr); +uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CConfidentialValue& amount, SigVersion sigversion, unsigned int flags, const PrecomputedTransactionData* cache = nullptr); class BaseSignatureChecker { public: - virtual bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const + virtual bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const { return false; } @@ -181,7 +191,7 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker public: GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {} GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} - bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override; + bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override; bool CheckLockTime(const CScriptNum& nLockTime) const override; bool CheckSequence(const CScriptNum& nSequence) const override; }; diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 6d7af801bc..2b9af7febc 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -17,7 +17,7 @@ typedef std::vector valtype; MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn, int nHashTypeIn) : txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} -bool MutableTransactionSignatureCreator::CreateSig(const SigningProvider& provider, std::vector& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const +bool MutableTransactionSignatureCreator::CreateSig(const SigningProvider& provider, std::vector& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const { CKey key; if (!provider.GetKey(address, key)) @@ -27,7 +27,7 @@ bool MutableTransactionSignatureCreator::CreateSig(const SigningProvider& provid if (sigversion == SigVersion::WITNESS_V0 && !key.IsCompressed()) return false; - uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion); + uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, flags); if (!key.Sign(hash, vchSig)) return false; vchSig.push_back((unsigned char)nHashType); @@ -68,7 +68,7 @@ static bool GetPubKey(const SigningProvider& provider, const SignatureData& sigd return provider.GetPubKey(address, pubkey); } -static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector& sig_out, const CPubKey& pubkey, const CScript& scriptcode, SigVersion sigversion) +static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector& sig_out, const CPubKey& pubkey, const CScript& scriptcode, SigVersion sigversion, unsigned int flags) { CKeyID keyid = pubkey.GetID(); const auto it = sigdata.signatures.find(keyid); @@ -80,7 +80,7 @@ static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdat if (provider.GetKeyOrigin(keyid, info)) { sigdata.misc_pubkeys.emplace(keyid, std::make_pair(pubkey, std::move(info))); } - if (creator.CreateSig(provider, sig_out, keyid, scriptcode, sigversion)) { + if (creator.CreateSig(provider, sig_out, keyid, scriptcode, sigversion, flags)) { auto i = sigdata.signatures.emplace(keyid, SigPair(pubkey, sig_out)); assert(i.second); return true; @@ -97,8 +97,9 @@ static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdat * Returns false if scriptPubKey could not be completely satisfied. */ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey, - std::vector& ret, txnouttype& whichTypeRet, SigVersion sigversion, SignatureData& sigdata) -{ + std::vector& ret, txnouttype& whichTypeRet, SigVersion sigversion, + SignatureData& sigdata, unsigned int flags +) { CScript scriptRet; uint160 h160; ret.clear(); @@ -114,7 +115,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator case TX_WITNESS_UNKNOWN: return false; case TX_PUBKEY: - if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]), scriptPubKey, sigversion)) return false; + if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]), scriptPubKey, sigversion, flags)) return false; ret.push_back(std::move(sig)); return true; case TX_PUBKEYHASH: { @@ -125,7 +126,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator sigdata.missing_pubkeys.push_back(keyID); return false; } - if (!CreateSig(creator, sigdata, provider, sig, pubkey, scriptPubKey, sigversion)) return false; + if (!CreateSig(creator, sigdata, provider, sig, pubkey, scriptPubKey, sigversion, flags)) return false; ret.push_back(std::move(sig)); ret.push_back(ToByteVector(pubkey)); return true; @@ -145,7 +146,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator ret.push_back(valtype()); // workaround CHECKMULTISIG bug for (size_t i = 1; i < vSolutions.size() - 1; ++i) { CPubKey pubkey = CPubKey(vSolutions[i]); - if (ret.size() < required + 1 && CreateSig(creator, sigdata, provider, sig, pubkey, scriptPubKey, sigversion)) { + if (ret.size() < required + 1 && CreateSig(creator, sigdata, provider, sig, pubkey, scriptPubKey, sigversion, flags)) { ret.push_back(std::move(sig)); } } @@ -196,9 +197,14 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato { if (sigdata.complete) return true; + // We will already activate SIGHASH_RANGEPROOF for signing. This means that + // users using the flag before it activates will produce invalid signatures. + unsigned int signFlags = SCRIPT_SIGHASH_RANGEPROOF; + unsigned int verifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS | SCRIPT_SIGHASH_RANGEPROOF | additional_flags; + std::vector result; txnouttype whichType; - bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE, sigdata); + bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE, sigdata, signFlags); bool P2SH = false; CScript subscript; sigdata.scriptWitness.stack.clear(); @@ -210,7 +216,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato // and then the serialized subscript: subscript = CScript(result[0].begin(), result[0].end()); sigdata.redeem_script = subscript; - solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE, sigdata) && whichType != TX_SCRIPTHASH; + solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE, sigdata, signFlags) && whichType != TX_SCRIPTHASH; P2SH = true; } @@ -219,7 +225,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato CScript witnessscript; witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG; txnouttype subType; - solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata); + solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata, signFlags); sigdata.scriptWitness.stack = result; sigdata.witness = true; result.clear(); @@ -229,7 +235,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato CScript witnessscript(result[0].begin(), result[0].end()); sigdata.witness_script = witnessscript; txnouttype subType; - solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH; + solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata, signFlags) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH; result.push_back(std::vector(witnessscript.begin(), witnessscript.end())); sigdata.scriptWitness.stack = result; sigdata.witness = true; @@ -244,7 +250,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato sigdata.scriptSig = PushAll(result); // Test solution - sigdata.complete = solved && VerifyScript(sigdata.scriptSig, fromPubKey, &sigdata.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS|additional_flags, creator.Checker()); + sigdata.complete = solved && VerifyScript(sigdata.scriptSig, fromPubKey, &sigdata.scriptWitness, verifyFlags, creator.Checker()); return sigdata.complete; } @@ -256,12 +262,12 @@ class SignatureExtractorChecker final : public BaseSignatureChecker public: SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : sigdata(sigdata), checker(checker) {} - bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override; + bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override; }; -bool SignatureExtractorChecker::CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const +bool SignatureExtractorChecker::CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const { - if (checker.CheckSig(scriptSig, vchPubKey, scriptCode, sigversion)) { + if (checker.CheckSig(scriptSig, vchPubKey, scriptCode, sigversion, flags)) { CPubKey pubkey(vchPubKey); sigdata.signatures.emplace(pubkey.GetID(), SigPair(pubkey, scriptSig)); return true; @@ -330,6 +336,8 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI stack.witness.clear(); sigversion = SigVersion::WITNESS_V0; } + // We enable SIGHASH_RANGEPROOF for signing. + unsigned int flags = SCRIPT_SIGHASH_RANGEPROOF; if (script_type == TX_MULTISIG && !stack.script.empty()) { // Build a map of pubkey -> signature by matching sigs to pubkeys: assert(solutions.size() > 1); @@ -339,7 +347,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI for (unsigned int i = last_success_key; i < num_pubkeys; ++i) { const valtype& pubkey = solutions[i+1]; // We either have a signature for this pubkey, or we have found a signature and it is valid - if (data.signatures.count(CPubKey(pubkey).GetID()) || extractor_checker.CheckSig(sig, pubkey, next_script, sigversion)) { + if (data.signatures.count(CPubKey(pubkey).GetID()) || extractor_checker.CheckSig(sig, pubkey, next_script, sigversion, flags)) { last_success_key = i + 1; break; } @@ -404,7 +412,7 @@ class DummySignatureChecker final : public BaseSignatureChecker { public: DummySignatureChecker() {} - bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { return true; } + bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override { return true; } }; const DummySignatureChecker DUMMY_CHECKER; @@ -415,7 +423,7 @@ class DummySignatureCreator final : public BaseSignatureCreator { public: DummySignatureCreator(char r_len, char s_len) : m_r_len(r_len), m_s_len(s_len) {} const BaseSignatureChecker& Checker() const override { return DUMMY_CHECKER; } - bool CreateSig(const SigningProvider& provider, std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override + bool CreateSig(const SigningProvider& provider, std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override { // Create a dummy signature that is a valid DER-encoding vchSig.assign(m_r_len + m_s_len + 7, '\000'); diff --git a/src/script/sign.h b/src/script/sign.h index a97e7ec5df..45b44121da 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -95,7 +95,7 @@ class BaseSignatureCreator { virtual const BaseSignatureChecker& Checker() const =0; /** Create a singular (non-script) signature. */ - virtual bool CreateSig(const SigningProvider& provider, std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const =0; + virtual bool CreateSig(const SigningProvider& provider, std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const =0; }; /** A signature creator for transactions. */ @@ -109,7 +109,7 @@ class MutableTransactionSignatureCreator : public BaseSignatureCreator { public: MutableTransactionSignatureCreator(const CMutableTransaction* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn, int nHashTypeIn = SIGHASH_ALL); const BaseSignatureChecker& Checker() const override { return checker; } - bool CreateSig(const SigningProvider& provider, std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override; + bool CreateSig(const SigningProvider& provider, std::vector& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override; }; /** A signature creator that just produces 71-byte empty signatures. */ diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 8afe4b8a59..f19ff2d4d3 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -21,7 +21,7 @@ BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup) static CScript sign_multisig(const CScript& scriptPubKey, const std::vector& keys, const CTransaction& transaction, int whichIn) { - uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SigVersion::BASE); + uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SigVersion::BASE, 0); CScript result; result << OP_0; // CHECKMULTISIG bug workaround diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 8186248b93..967c113ea0 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -371,7 +371,7 @@ class TestBuilder TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32, SigVersion sigversion = SigVersion::BASE, CAmount amount = 0) { - uint256 hash = SignatureHash(script, spendTx, 0, nHashType, amount, sigversion); + uint256 hash = SignatureHash(script, spendTx, 0, nHashType, amount, sigversion, 0); std::vector vchSig, r, s; uint32_t iter = 0; do { @@ -1063,7 +1063,7 @@ BOOST_AUTO_TEST_CASE(script_cltv_truncated) static CScript sign_multisig(const CScript& scriptPubKey, const std::vector& keys, const CTransaction& transaction) { - uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, SigVersion::BASE); + uint256 hash = SignatureHash(scriptPubKey, transaction, 0, SIGHASH_ALL, 0, SigVersion::BASE, 0); CScript result; // @@ -1267,15 +1267,15 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) // A couple of partially-signed versions: std::vector sig1; - uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, SigVersion::BASE); + uint256 hash1 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_ALL, 0, SigVersion::BASE, 0); BOOST_CHECK(keys[0].Sign(hash1, sig1)); sig1.push_back(SIGHASH_ALL); std::vector sig2; - uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, SigVersion::BASE); + uint256 hash2 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_NONE, 0, SigVersion::BASE, 0); BOOST_CHECK(keys[1].Sign(hash2, sig2)); sig2.push_back(SIGHASH_NONE); std::vector sig3; - uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, SigVersion::BASE); + uint256 hash3 = SignatureHash(scriptPubKey, txTo, 0, SIGHASH_SINGLE, 0, SigVersion::BASE, 0); BOOST_CHECK(keys[2].Sign(hash3, sig3)); sig3.push_back(SIGHASH_SINGLE); diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 04d5462acb..978b6eb173 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -129,7 +129,8 @@ BOOST_AUTO_TEST_CASE(sighash_test) int nRandomTests = 50000; #endif for (int i=0; i vchSig; - uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL, 0, SigVersion::BASE); + uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL, 0, SigVersion::BASE, 0); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); spends[i].vin[0].scriptSig << vchSig; @@ -183,7 +183,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Sign, with a non-DER signature { std::vector vchSig; - uint256 hash = SignatureHash(p2pk_scriptPubKey, spend_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE); + uint256 hash = SignatureHash(p2pk_scriptPubKey, spend_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE, 0); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char) 0); // padding byte makes this non-DER vchSig.push_back((unsigned char)SIGHASH_ALL); @@ -256,7 +256,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Sign std::vector vchSig; - uint256 hash = SignatureHash(spend_tx.vout[2].scriptPubKey, invalid_with_cltv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE); + uint256 hash = SignatureHash(spend_tx.vout[2].scriptPubKey, invalid_with_cltv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE, 0); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 101; @@ -284,7 +284,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) // Sign std::vector vchSig; - uint256 hash = SignatureHash(spend_tx.vout[3].scriptPubKey, invalid_with_csv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE); + uint256 hash = SignatureHash(spend_tx.vout[3].scriptPubKey, invalid_with_csv_tx, 0, SIGHASH_ALL, 0, SigVersion::BASE, 0); BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); vchSig.push_back((unsigned char)SIGHASH_ALL); invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 101; diff --git a/src/validation.cpp b/src/validation.cpp index 01671f9a1d..e3ee030a97 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -969,7 +969,14 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool } } - constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS; + unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS; + + // Temporarily add additional script flags based on the activation of + // Dynamic Federations. This can be included in the + // STANDARD_LOCKTIME_VERIFY_FLAGS in a release post-activation. + if (IsDynaFedEnabled(chainActive.Tip(), chainparams.GetConsensus())) { + scriptVerifyFlags |= SCRIPT_SIGHASH_RANGEPROOF; + } // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. @@ -1902,6 +1909,10 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens flags |= SCRIPT_VERIFY_NULLDUMMY; } + if (IsDynaFedEnabled(pindex->pprev, consensusparams)) { + flags |= SCRIPT_SIGHASH_RANGEPROOF; + } + return flags; }