Skip to content

Commit 22cf380

Browse files
committed
Merge a993a7c into merged_master (Elements PR #960)
Several conflicts in the C++ code related to the new `flags` parameter to `CheckSignature` and the corresponding function being renamed upstream to `CheckSignatureECDSA`. Several conflicts in the test harness as Steven sorta pulled the new upstream ECKey module into the Python code, and the actual upstream code was slightly different. Also needed to update the feature_taproot code to always use the non-RANGEPROOF sighash since dynafed is not enabled in the Taproot test. Also had to pull the `set_wif` method out of `ECKey` and inline it because otherwise it triggers a "circular inclusion" error between script.py (which would pull in `base58_to_bytes` from address.py) and address.py (which now pulls in some taproot EC related stuff from script.py). Noticed that #960 does not test the "sighash rangeproof flag set but no witnesses" case.
2 parents 81e75ab + a993a7c commit 22cf380

18 files changed

+410
-65
lines changed

src/bench/verify_script.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ static void VerifyScriptBench(benchmark::Bench& bench)
4545
txSpend.witness.vtxinwit.resize(1);
4646
CScriptWitness& witness = txSpend.witness.vtxinwit[0].scriptWitness;
4747
witness.stack.emplace_back();
48-
key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SigVersion::WITNESS_V0), witness.stack.back());
48+
key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SigVersion::WITNESS_V0, 0), witness.stack.back());
4949
witness.stack.back().push_back(static_cast<unsigned char>(SIGHASH_ALL));
5050
witness.stack.push_back(ToByteVector(pubkey));
5151

src/qt/qrimagewidget.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ bool QRImageWidget::setQR(const QString& data, const QString& text)
6767

6868
// Elements: Hack to get QR address to print right
6969
const size_t MORE_WIDTH = 80;
70-
70+
7171
const int qr_image_size = QR_IMAGE_SIZE + MORE_WIDTH + (text.isEmpty() ? 0 : 2 * QR_IMAGE_MARGIN);
7272
QImage qrAddrImage(qr_image_size, qr_image_size, QImage::Format_RGB32);
7373
qrAddrImage.fill(0xffffff);

src/script/generic.hpp

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

2121
SimpleSignatureChecker(const uint256& hashIn, bool sighash_byte_in) : hash(hashIn), sighash_byte(sighash_byte_in) {};
22-
bool CheckECDSASignature(const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
22+
bool CheckECDSASignature(const std::vector<unsigned char>& vchSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override
2323
{
2424
std::vector<unsigned char> vchSigCopy(vchSig);
2525
CPubKey pubkey(vchPubKey);
@@ -48,7 +48,7 @@ class SimpleSignatureCreator : public BaseSignatureCreator
4848
public:
4949
SimpleSignatureCreator(const uint256& hashIn, bool sighash_byte_in) : checker(hashIn, sighash_byte_in), sighash_byte(sighash_byte_in) {};
5050
const BaseSignatureChecker& Checker() const override { return checker; }
51-
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion) const override
51+
bool CreateSig(const SigningProvider& provider, std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override
5252
{
5353
CKey key;
5454
if (!provider.GetKey(keyid, key))

src/script/interpreter.cpp

Lines changed: 69 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;
@@ -368,7 +374,7 @@ static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPu
368374
//serror is set
369375
return false;
370376
}
371-
fSuccess = checker.CheckECDSASignature(vchSig, vchPubKey, scriptCode, sigversion);
377+
fSuccess = checker.CheckECDSASignature(vchSig, vchPubKey, scriptCode, sigversion, flags);
372378

373379
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size())
374380
return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);
@@ -1466,7 +1472,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
14661472
}
14671473

14681474
// Check signature
1469-
bool fOk = checker.CheckECDSASignature(vchSig, vchPubKey, scriptCode, sigversion);
1475+
bool fOk = checker.CheckECDSASignature(vchSig, vchPubKey, scriptCode, sigversion, flags);
14701476

14711477
if (fOk) {
14721478
isig++;
@@ -1647,13 +1653,15 @@ class CTransactionSignatureSerializer
16471653
const CScript& scriptCode; //!< output script being consumed
16481654
const unsigned int nIn; //!< input index of txTo being signed
16491655
const bool fAnyoneCanPay; //!< whether the hashtype has the SIGHASH_ANYONECANPAY flag set
1656+
const bool fRangeproof; //!< whether the hashtype has the SIGHASH_RANGEPROOF flag set
16501657
const bool fHashSingle; //!< whether the hashtype is SIGHASH_SINGLE
16511658
const bool fHashNone; //!< whether the hashtype is SIGHASH_NONE
16521659

16531660
public:
1654-
CTransactionSignatureSerializer(const T& txToIn, const CScript& scriptCodeIn, unsigned int nInIn, int nHashTypeIn) :
1661+
CTransactionSignatureSerializer(const T& txToIn, const CScript& scriptCodeIn, unsigned int nInIn, int nHashTypeIn, unsigned int flags) :
16551662
txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn),
16561663
fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)),
1664+
fRangeproof(!!(flags & SCRIPT_SIGHASH_RANGEPROOF) && !!(nHashTypeIn & SIGHASH_RANGEPROOF)),
16571665
fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE),
16581666
fHashNone((nHashTypeIn & 0x1f) == SIGHASH_NONE) {}
16591667

@@ -1710,11 +1718,23 @@ class CTransactionSignatureSerializer
17101718
/** Serialize an output of txTo */
17111719
template<typename S>
17121720
void SerializeOutput(S &s, unsigned int nOutput) const {
1713-
if (fHashSingle && nOutput != nIn)
1721+
if (fHashSingle && nOutput != nIn) {
17141722
// Do not lock-in the txout payee at other indices as txin
17151723
::Serialize(s, CTxOut());
1716-
else
1724+
} else {
17171725
::Serialize(s, txTo.vout[nOutput]);
1726+
1727+
// Serialize rangeproof
1728+
if (fRangeproof) {
1729+
if (nOutput < txTo.witness.vtxoutwit.size()) {
1730+
::Serialize(s, txTo.witness.vtxoutwit[nOutput].vchRangeproof);
1731+
::Serialize(s, txTo.witness.vtxoutwit[nOutput].vchSurjectionproof);
1732+
} else {
1733+
::Serialize(s, (unsigned char) 0);
1734+
::Serialize(s, (unsigned char) 0);
1735+
}
1736+
}
1737+
}
17181738
}
17191739

17201740
/** Serialize txTo */
@@ -1803,6 +1823,20 @@ uint256 GetSpentScriptsSHA256(const std::vector<CTxOut>& outputs_spent)
18031823
return ss.GetSHA256();
18041824
}
18051825

1826+
template <class T>
1827+
uint256 GetRangeproofsHash(const T& txTo) {
1828+
CHashWriter ss(SER_GETHASH, 0);
1829+
for (size_t i = 0; i < txTo.vout.size(); i++) {
1830+
if (i < txTo.witness.vtxoutwit.size()) {
1831+
ss << txTo.witness.vtxoutwit[i].vchRangeproof;
1832+
ss << txTo.witness.vtxoutwit[i].vchSurjectionproof;
1833+
} else {
1834+
ss << (unsigned char) 0;
1835+
ss << (unsigned char) 0;
1836+
}
1837+
}
1838+
return ss.GetHash();
1839+
}
18061840

18071841
} // namespace
18081842

@@ -1850,6 +1884,7 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent
18501884
hashSequence = SHA256Uint256(m_sequences_single_hash);
18511885
hashIssuance = SHA256Uint256(GetIssuanceSHA256(txTo));
18521886
hashOutputs = SHA256Uint256(m_outputs_single_hash);
1887+
hashRangeproofs = GetRangeproofsHash(txTo);
18531888
m_bip143_segwit_ready = true;
18541889
}
18551890
if (uses_bip341_taproot) {
@@ -1962,7 +1997,7 @@ bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata
19621997
}
19631998

19641999
template <class T>
1965-
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CConfidentialValue& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
2000+
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CConfidentialValue& amount, SigVersion sigversion, unsigned int flags, const PrecomputedTransactionData* cache)
19662001
{
19672002
assert(nIn < txTo.vin.size());
19682003

@@ -1971,7 +2006,9 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
19712006
uint256 hashSequence;
19722007
uint256 hashIssuance;
19732008
uint256 hashOutputs;
2009+
uint256 hashRangeproofs;
19742010
const bool cacheready = cache && cache->m_bip143_segwit_ready;
2011+
bool fRangeproof = !!(flags & SCRIPT_SIGHASH_RANGEPROOF) && !!(nHashType & SIGHASH_RANGEPROOF);
19752012

19762013
if (!(nHashType & SIGHASH_ANYONECANPAY)) {
19772014
hashPrevouts = cacheready ? cache->hashPrevouts : SHA256Uint256(GetPrevoutsSHA256(txTo));
@@ -1987,10 +2024,26 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
19872024

19882025
if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
19892026
hashOutputs = cacheready ? cache->hashOutputs : SHA256Uint256(GetOutputsSHA256(txTo));
2027+
2028+
if (fRangeproof) {
2029+
hashRangeproofs = cacheready ? cache->hashRangeproofs : SHA256Uint256(GetRangeproofsHash(txTo));
2030+
}
19902031
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
19912032
CHashWriter ss(SER_GETHASH, 0);
19922033
ss << txTo.vout[nIn];
19932034
hashOutputs = ss.GetHash();
2035+
2036+
if (fRangeproof) {
2037+
CHashWriter ss(SER_GETHASH, 0);
2038+
if (nIn < txTo.witness.vtxoutwit.size()) {
2039+
ss << txTo.witness.vtxoutwit[nIn].vchRangeproof;
2040+
ss << txTo.witness.vtxoutwit[nIn].vchSurjectionproof;
2041+
} else {
2042+
ss << (unsigned char) 0;
2043+
ss << (unsigned char) 0;
2044+
}
2045+
hashRangeproofs = ss.GetHash();
2046+
}
19942047
}
19952048

19962049
CHashWriter ss(SER_GETHASH, 0);
@@ -2019,6 +2072,11 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
20192072
}
20202073
// Outputs (none/one/all, depending on flags)
20212074
ss << hashOutputs;
2075+
if (fRangeproof) {
2076+
// This addition must be conditional because it was added after
2077+
// the segwit sighash was specified.
2078+
ss << hashRangeproofs;
2079+
}
20222080
// Locktime
20232081
ss << txTo.nLockTime;
20242082
// Sighash type
@@ -2036,7 +2094,7 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
20362094
}
20372095

20382096
// Wrapper to serialize only the necessary parts of the transaction being signed
2039-
CTransactionSignatureSerializer<T> txTmp(txTo, scriptCode, nIn, nHashType);
2097+
CTransactionSignatureSerializer<T> txTmp(txTo, scriptCode, nIn, nHashType, flags);
20402098

20412099
// Serialize and hash
20422100
CHashWriter ss(SER_GETHASH, 0);
@@ -2057,7 +2115,7 @@ bool GenericTransactionSignatureChecker<T>::VerifySchnorrSignature(Span<const un
20572115
}
20582116

20592117
template <class T>
2060-
bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
2118+
bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const
20612119
{
20622120
CPubKey pubkey(vchPubKey);
20632121
if (!pubkey.IsValid())
@@ -2070,7 +2128,7 @@ bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vecto
20702128
int nHashType = vchSig.back();
20712129
vchSig.pop_back();
20722130

2073-
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata);
2131+
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, flags, this->txdata);
20742132

20752133
if (!VerifyECDSASignature(vchSig, pubkey, sighash))
20762134
return false;

src/script/interpreter.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ enum
3131
SIGHASH_DEFAULT = 0, //!< Taproot only; implied when sighash byte is missing, and equivalent to SIGHASH_ALL
3232
SIGHASH_OUTPUT_MASK = 3,
3333
SIGHASH_INPUT_MASK = 0x80,
34+
35+
// ELEMENTS:
36+
// A flag that means the rangeproofs should be included in the sighash.
37+
SIGHASH_RANGEPROOF = 0x40,
3438
};
3539

3640
/** Script verification flags.
@@ -140,9 +144,15 @@ enum
140144
// Making unknown public key versions (in BIP 342 scripts) non-standard
141145
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20),
142146

147+
// ELEMENTS:
148+
143149
// Signature checking assumes no sighash byte after the DER signature
144150
//
145151
SCRIPT_NO_SIGHASH_BYTE = (1U << 21),
152+
153+
// Support/allow SIGHASH_RANGEPROOF.
154+
//
155+
SCRIPT_SIGHASH_RANGEPROOF = (1U << 22),
146156
};
147157

148158
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
@@ -160,7 +170,7 @@ struct PrecomputedTransactionData
160170
bool m_bip341_taproot_ready = false;
161171

162172
// BIP143 precomputed data (double-SHA256).
163-
uint256 hashPrevouts, hashSequence, hashOutputs, hashIssuance;
173+
uint256 hashPrevouts, hashSequence, hashOutputs, hashIssuance, hashRangeproofs;
164174
//! Whether the 3 fields above are initialized.
165175
bool m_bip143_segwit_ready = false;
166176

@@ -223,12 +233,12 @@ static constexpr size_t TAPROOT_CONTROL_MAX_NODE_COUNT = 128;
223233
static constexpr size_t TAPROOT_CONTROL_MAX_SIZE = TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT;
224234

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

228238
class BaseSignatureChecker
229239
{
230240
public:
231-
virtual bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
241+
virtual bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const
232242
{
233243
return false;
234244
}
@@ -267,7 +277,7 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker
267277
public:
268278
GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
269279
GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
270-
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
280+
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override;
271281
bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override;
272282
bool CheckLockTime(const CScriptNum& nLockTime) const override;
273283
bool CheckSequence(const CScriptNum& nSequence) const override;

0 commit comments

Comments
 (0)