mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-13 12:33:42 +02:00
Add SIGHASH_RANGEPROOF support
This commit is contained in:
parent
cb2d10341a
commit
559f1d15a3
11 changed files with 144 additions and 54 deletions
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue