Skip to content

Commit 559f1d1

Browse files
committed
Add SIGHASH_RANGEPROOF support
1 parent cb2d103 commit 559f1d1

File tree

11 files changed

+144
-54
lines changed

11 files changed

+144
-54
lines changed

src/bench/verify_script.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static void VerifyScriptBench(benchmark::State& state)
7777
txSpend.witness.vtxinwit.resize(1);
7878
CScriptWitness& witness = txSpend.witness.vtxinwit[0].scriptWitness;
7979
witness.stack.emplace_back();
80-
key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SigVersion::WITNESS_V0), witness.stack.back());
80+
key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SigVersion::WITNESS_V0, 0), witness.stack.back());
8181
witness.stack.back().push_back(static_cast<unsigned char>(SIGHASH_ALL));
8282
witness.stack.push_back(ToByteVector(pubkey));
8383

src/script/generic.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class SimpleSignatureChecker : public BaseSignatureChecker
1818
bool sighash_byte;
1919

2020
SimpleSignatureChecker(const uint256& hashIn, bool sighash_byte_in) : hash(hashIn), sighash_byte(sighash_byte_in) {};
21-
bool CheckSig(const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
21+
bool CheckSig(const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override
2222
{
2323
std::vector<unsigned char> vchSigCopy(vchSig);
2424
CPubKey pubkey(vchPubKey);
@@ -47,7 +47,7 @@ class SimpleSignatureCreator : public BaseSignatureCreator
4747
public:
4848
SimpleSignatureCreator(const uint256& hashIn, bool sighash_byte_in) : checker(hashIn, sighash_byte_in), sighash_byte(sighash_byte_in) {};
4949
const BaseSignatureChecker& Checker() const { return checker; }
50-
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const
50+
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override
5151
{
5252
CKey key;
5353
if (!provider.GetKey(keyid, key))

src/script/interpreter.cpp

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,17 @@ bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) {
186186
return true;
187187
}
188188

189-
bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
189+
bool static IsDefinedHashtypeSignature(const valtype &vchSig, unsigned int flags) {
190190
if (vchSig.size() == 0) {
191191
return false;
192192
}
193193
unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY));
194+
195+
// ELEMENTS: Only allow SIGHASH_RANGEPROOF if the flag is set (after dynafed activation).
196+
if ((flags & SCRIPT_SIGHASH_RANGEPROOF) == SCRIPT_SIGHASH_RANGEPROOF) {
197+
nHashType = nHashType & (~(SIGHASH_RANGEPROOF));
198+
}
199+
194200
if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)
195201
return false;
196202

@@ -216,7 +222,7 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i
216222
} else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSigCopy, serror)) {
217223
// serror is set
218224
return false;
219-
} else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSigCopy)) {
225+
} else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSigCopy, flags)) {
220226
return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE);
221227
}
222228
return true;
@@ -1213,7 +1219,8 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
12131219
//serror is set
12141220
return false;
12151221
}
1216-
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);
1222+
1223+
bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion, flags);
12171224

12181225
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size())
12191226
return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);
@@ -1291,7 +1298,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
12911298
}
12921299

12931300
// Check signature
1294-
bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion);
1301+
bool fOk = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion, flags);
12951302

12961303
if (fOk) {
12971304
isig++;
@@ -1466,13 +1473,15 @@ class CTransactionSignatureSerializer
14661473
const CScript& scriptCode; //!< output script being consumed
14671474
const unsigned int nIn; //!< input index of txTo being signed
14681475
const bool fAnyoneCanPay; //!< whether the hashtype has the SIGHASH_ANYONECANPAY flag set
1476+
const bool fRangeproof; //!< whether the hashtype has the SIGHASH_RANGEPROOF flag set
14691477
const bool fHashSingle; //!< whether the hashtype is SIGHASH_SINGLE
14701478
const bool fHashNone; //!< whether the hashtype is SIGHASH_NONE
14711479

14721480
public:
1473-
CTransactionSignatureSerializer(const T& txToIn, const CScript& scriptCodeIn, unsigned int nInIn, int nHashTypeIn) :
1481+
CTransactionSignatureSerializer(const T& txToIn, const CScript& scriptCodeIn, unsigned int nInIn, int nHashTypeIn, unsigned int flags) :
14741482
txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn),
14751483
fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)),
1484+
fRangeproof(!!(flags & SCRIPT_SIGHASH_RANGEPROOF) && !!(nHashTypeIn & SIGHASH_RANGEPROOF)),
14761485
fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE),
14771486
fHashNone((nHashTypeIn & 0x1f) == SIGHASH_NONE) {}
14781487

@@ -1529,11 +1538,23 @@ class CTransactionSignatureSerializer
15291538
/** Serialize an output of txTo */
15301539
template<typename S>
15311540
void SerializeOutput(S &s, unsigned int nOutput) const {
1532-
if (fHashSingle && nOutput != nIn)
1541+
if (fHashSingle && nOutput != nIn) {
15331542
// Do not lock-in the txout payee at other indices as txin
15341543
::Serialize(s, CTxOut());
1535-
else
1544+
} else {
15361545
::Serialize(s, txTo.vout[nOutput]);
1546+
1547+
// Serialize rangeproof
1548+
if (fRangeproof) {
1549+
if (nOutput < txTo.witness.vtxoutwit.size()) {
1550+
::Serialize(s, txTo.witness.vtxoutwit[nOutput].vchRangeproof);
1551+
::Serialize(s, txTo.witness.vtxoutwit[nOutput].vchSurjectionproof);
1552+
} else {
1553+
::Serialize(s, (unsigned char) 0);
1554+
::Serialize(s, (unsigned char) 0);
1555+
}
1556+
}
1557+
}
15371558
}
15381559

15391560
/** Serialize txTo */
@@ -1599,6 +1620,21 @@ uint256 GetOutputsHash(const T& txTo)
15991620
return ss.GetHash();
16001621
}
16011622

1623+
template <class T>
1624+
uint256 GetRangeproofsHash(const T& txTo) {
1625+
CHashWriter ss(SER_GETHASH, 0);
1626+
for (size_t i = 0; i < txTo.vout.size(); i++) {
1627+
if (i < txTo.witness.vtxoutwit.size()) {
1628+
ss << txTo.witness.vtxoutwit[i].vchRangeproof;
1629+
ss << txTo.witness.vtxoutwit[i].vchSurjectionproof;
1630+
} else {
1631+
ss << (unsigned char) 0;
1632+
ss << (unsigned char) 0;
1633+
}
1634+
}
1635+
return ss.GetHash();
1636+
}
1637+
16021638
} // namespace
16031639

16041640
template <class T>
@@ -1610,6 +1646,7 @@ PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo)
16101646
hashSequence = GetSequenceHash(txTo);
16111647
hashIssuance = GetIssuanceHash(txTo);
16121648
hashOutputs = GetOutputsHash(txTo);
1649+
hashRangeproofs = GetRangeproofsHash(txTo);
16131650
ready = true;
16141651
}
16151652
}
@@ -1619,7 +1656,7 @@ template PrecomputedTransactionData::PrecomputedTransactionData(const CTransacti
16191656
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
16201657

16211658
template <class T>
1622-
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CConfidentialValue& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
1659+
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CConfidentialValue& amount, SigVersion sigversion, unsigned int flags, const PrecomputedTransactionData* cache)
16231660
{
16241661
assert(nIn < txTo.vin.size());
16251662

@@ -1628,7 +1665,9 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
16281665
uint256 hashSequence;
16291666
uint256 hashIssuance;
16301667
uint256 hashOutputs;
1668+
uint256 hashRangeproofs;
16311669
const bool cacheready = cache && cache->ready;
1670+
bool fRangeproof = !!(flags & SCRIPT_SIGHASH_RANGEPROOF) && !!(nHashType & SIGHASH_RANGEPROOF);
16321671

16331672
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
16341673
hashPrevouts = cacheready ? cache->hashPrevouts : GetPrevoutHash(txTo);
@@ -1644,10 +1683,26 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
16441683

16451684
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
16461685
hashOutputs = cacheready ? cache->hashOutputs : GetOutputsHash(txTo);
1686+
1687+
if (fRangeproof) {
1688+
hashRangeproofs = cacheready ? cache->hashRangeproofs : GetRangeproofsHash(txTo);
1689+
}
16471690
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
16481691
CHashWriter ss(SER_GETHASH, 0);
16491692
ss << txTo.vout[nIn];
16501693
hashOutputs = ss.GetHash();
1694+
1695+
if (fRangeproof) {
1696+
CHashWriter ss(SER_GETHASH, 0);
1697+
if (nIn < txTo.witness.vtxoutwit.size()) {
1698+
ss << txTo.witness.vtxoutwit[nIn].vchRangeproof;
1699+
ss << txTo.witness.vtxoutwit[nIn].vchSurjectionproof;
1700+
} else {
1701+
ss << (unsigned char) 0;
1702+
ss << (unsigned char) 0;
1703+
}
1704+
hashRangeproofs = ss.GetHash();
1705+
}
16511706
}
16521707

16531708
CHashWriter ss(SER_GETHASH, 0);
@@ -1676,6 +1731,11 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
16761731
}
16771732
// Outputs (none/one/all, depending on flags)
16781733
ss << hashOutputs;
1734+
if (fRangeproof) {
1735+
// This addition must be conditional because it was added after
1736+
// the segwit sighash was specified.
1737+
ss << hashRangeproofs;
1738+
}
16791739
// Locktime
16801740
ss << txTo.nLockTime;
16811741
// Sighash type
@@ -1695,7 +1755,7 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
16951755
}
16961756

16971757
// Wrapper to serialize only the necessary parts of the transaction being signed
1698-
CTransactionSignatureSerializer<T> txTmp(txTo, scriptCode, nIn, nHashType);
1758+
CTransactionSignatureSerializer<T> txTmp(txTo, scriptCode, nIn, nHashType, flags);
16991759

17001760
// Serialize and hash
17011761
CHashWriter ss(SER_GETHASH, 0);
@@ -1710,7 +1770,7 @@ bool GenericTransactionSignatureChecker<T>::VerifySignature(const std::vector<un
17101770
}
17111771

17121772
template <class T>
1713-
bool GenericTransactionSignatureChecker<T>::CheckSig(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
1773+
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
17141774
{
17151775
CPubKey pubkey(vchPubKey);
17161776
if (!pubkey.IsValid())
@@ -1723,7 +1783,7 @@ bool GenericTransactionSignatureChecker<T>::CheckSig(const std::vector<unsigned
17231783
int nHashType = vchSig.back();
17241784
vchSig.pop_back();
17251785

1726-
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata);
1786+
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, flags, this->txdata);
17271787

17281788
if (!VerifySignature(vchSig, pubkey, sighash))
17291789
return false;

src/script/interpreter.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ enum
2525
SIGHASH_NONE = 2,
2626
SIGHASH_SINGLE = 3,
2727
SIGHASH_ANYONECANPAY = 0x80,
28+
29+
// ELEMENTS:
30+
// A flag that means the rangeproofs should be included in the sighash.
31+
SIGHASH_RANGEPROOF = 0x40,
2832
};
2933

3034
/** Script verification flags.
@@ -116,16 +120,22 @@ enum
116120
//
117121
SCRIPT_VERIFY_CONST_SCRIPTCODE = (1U << 16),
118122

123+
// ELEMENTS:
124+
119125
// Signature checking assumes no sighash byte after the DER signature
120126
//
121127
SCRIPT_NO_SIGHASH_BYTE = (1U << 17),
128+
129+
// Support/allow SIGHASH_RANGEPROOF.
130+
//
131+
SCRIPT_SIGHASH_RANGEPROOF = (1U << 18),
122132
};
123133

124134
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
125135

126136
struct PrecomputedTransactionData
127137
{
128-
uint256 hashPrevouts, hashSequence, hashOutputs, hashIssuance;
138+
uint256 hashPrevouts, hashSequence, hashOutputs, hashIssuance, hashRangeproofs;
129139
bool ready = false;
130140

131141
template <class T>
@@ -143,12 +153,12 @@ static constexpr size_t WITNESS_V0_SCRIPTHASH_SIZE = 32;
143153
static constexpr size_t WITNESS_V0_KEYHASH_SIZE = 20;
144154

145155
template <class T>
146-
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CConfidentialValue& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
156+
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);
147157

148158
class BaseSignatureChecker
149159
{
150160
public:
151-
virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
161+
virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const
152162
{
153163
return false;
154164
}
@@ -181,7 +191,7 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker
181191
public:
182192
GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
183193
GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
184-
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
194+
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override;
185195
bool CheckLockTime(const CScriptNum& nLockTime) const override;
186196
bool CheckSequence(const CScriptNum& nSequence) const override;
187197
};

0 commit comments

Comments
 (0)