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
236f0b1762
commit
691040a63d
11 changed files with 144 additions and 54 deletions
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue