Add SIGHASH_RANGEPROOF support

This commit is contained in:
Steven Roose 2021-01-26 17:08:03 +01:00
parent 236f0b1762
commit 691040a63d
No known key found for this signature in database
GPG key ID: 2F2A88D7F8D68E87
11 changed files with 144 additions and 54 deletions

View file

@ -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<unsigned char>(SIGHASH_ALL));
witness.stack.push_back(ToByteVector(pubkey));

View file

@ -18,7 +18,7 @@ public:
bool sighash_byte;
SimpleSignatureChecker(const uint256& hashIn, bool sighash_byte_in) : hash(hashIn), sighash_byte(sighash_byte_in) {};
bool CheckSig(const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
bool CheckSig(const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override
{
std::vector<unsigned char> 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<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override
{
CKey key;
if (!provider.GetKey(keyid, key))

View file

@ -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<unsigned char> &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<std::vector<unsigned char> >& 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<std::vector<unsigned char> >& 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 @@ private:
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 @@ public:
/** Serialize an output of txTo */
template<typename S>
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 <class T>
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 <class T>
@ -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 <class T>
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<T> txTmp(txTo, scriptCode, nIn, nHashType);
CTransactionSignatureSerializer<T> txTmp(txTo, scriptCode, nIn, nHashType, flags);
// Serialize and hash
CHashWriter ss(SER_GETHASH, 0);
@ -1710,7 +1770,7 @@ bool GenericTransactionSignatureChecker<T>::VerifySignature(const std::vector<un
}
template <class T>
bool GenericTransactionSignatureChecker<T>::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
bool GenericTransactionSignatureChecker<T>::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const
{
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
@ -1723,7 +1783,7 @@ bool GenericTransactionSignatureChecker<T>::CheckSig(const std::vector<unsigned
int nHashType = vchSig.back();
vchSig.pop_back();
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata);
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, flags, this->txdata);
if (!VerifySignature(vchSig, pubkey, sighash))
return false;

View file

@ -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<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
struct PrecomputedTransactionData
{
uint256 hashPrevouts, hashSequence, hashOutputs, hashIssuance;
uint256 hashPrevouts, hashSequence, hashOutputs, hashIssuance, hashRangeproofs;
bool ready = false;
template <class T>
@ -143,12 +153,12 @@ static constexpr size_t WITNESS_V0_SCRIPTHASH_SIZE = 32;
static constexpr size_t WITNESS_V0_KEYHASH_SIZE = 20;
template <class T>
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<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const
{
return false;
}
@ -181,7 +191,7 @@ protected:
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<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& 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;
};

View file

@ -17,7 +17,7 @@ typedef std::vector<unsigned char> 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<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode, SigVersion sigversion) const
bool MutableTransactionSignatureCreator::CreateSig(const SigningProvider& provider, std::vector<unsigned char>& 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<unsigned char>& sig_out, const CPubKey& pubkey, const CScript& scriptcode, SigVersion sigversion)
static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdata, const SigningProvider& provider, std::vector<unsigned char>& 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<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion, SignatureData& sigdata)
{
std::vector<valtype>& 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<valtype> 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<unsigned char>(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 @@ private:
public:
SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : sigdata(sigdata), checker(checker) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override;
};
bool SignatureExtractorChecker::CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
bool SignatureExtractorChecker::CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& 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<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { return true; }
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override { return true; }
};
const DummySignatureChecker DUMMY_CHECKER;
@ -415,7 +423,7 @@ private:
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<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& 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');

View file

@ -95,7 +95,7 @@ public:
virtual const BaseSignatureChecker& Checker() const =0;
/** Create a singular (non-script) signature. */
virtual bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const =0;
virtual bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& 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<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override;
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override;
};
/** A signature creator that just produces 71-byte empty signatures. */

View file

@ -21,7 +21,7 @@ BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
static CScript
sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& 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

View file

@ -371,7 +371,7 @@ public:
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<unsigned char> 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<CKey>& 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<unsigned char> 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<unsigned char> 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<unsigned char> 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);

View file

@ -129,7 +129,8 @@ BOOST_AUTO_TEST_CASE(sighash_test)
int nRandomTests = 50000;
#endif
for (int i=0; i<nRandomTests; i++) {
int nHashType = InsecureRand32();
// In randomized test, we disable SIGHASH_RANGEPROOF.
int nHashType = InsecureRand32() & ~SIGHASH_RANGEPROOF;
CMutableTransaction txTo;
RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE);
CScript scriptCode;
@ -138,7 +139,7 @@ BOOST_AUTO_TEST_CASE(sighash_test)
uint256 sh, sho;
sho = SignatureHashOld(scriptCode, CTransaction(txTo), nIn, nHashType);
sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, SigVersion::BASE);
sh = SignatureHash(scriptCode, txTo, nIn, nHashType, 0, SigVersion::BASE, SCRIPT_SIGHASH_RANGEPROOF);
#if defined(PRINT_SIGHASH_JSON)
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << txTo;
@ -204,7 +205,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
continue;
}
sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0, SigVersion::BASE);
sh = SignatureHash(scriptCode, *tx, nIn, nHashType, 0, SigVersion::BASE, 0);
BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest);
}
}

View file

@ -57,7 +57,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
// Sign:
std::vector<unsigned char> 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<unsigned char> 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<unsigned char> 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<unsigned char> 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;

View file

@ -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;
}