Merge a993a7c675 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.
This commit is contained in:
Andrew Poelstra 2021-03-25 23:46:21 +00:00
commit 22cf380984
18 changed files with 410 additions and 65 deletions

View file

@ -20,7 +20,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))
@ -30,7 +30,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);
@ -71,7 +71,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);
@ -83,7 +83,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;
@ -100,7 +100,8 @@ 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, TxoutType& whichTypeRet, SigVersion sigversion, SignatureData& sigdata)
std::vector<valtype>& ret, TxoutType& whichTypeRet, SigVersion sigversion, SignatureData& sigdata,
unsigned int flags)
{
CScript scriptRet;
uint160 h160;
@ -118,7 +119,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
case TxoutType::WITNESS_V1_TAPROOT:
return false;
case TxoutType::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 TxoutType::PUBKEYHASH: {
@ -129,7 +130,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;
@ -152,7 +153,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
// We need to always call CreateSig in order to fill sigdata with all
// possible signatures that we can create. This will allow further PSBT
// processing to work as it needs all possible signature and pubkey pairs
if (CreateSig(creator, sigdata, provider, sig, pubkey, scriptPubKey, sigversion)) {
if (CreateSig(creator, sigdata, provider, sig, pubkey, scriptPubKey, sigversion, flags)) {
if (ret.size() < required + 1) {
ret.push_back(std::move(sig));
}
@ -207,9 +208,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;
TxoutType 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();
@ -221,7 +227,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 != TxoutType::SCRIPTHASH;
solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE, sigdata, signFlags) && whichType != TxoutType::SCRIPTHASH;
P2SH = true;
}
@ -230,7 +236,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
CScript witnessscript;
witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG;
TxoutType 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();
@ -240,7 +246,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
CScript witnessscript(result[0].begin(), result[0].end());
sigdata.witness_script = witnessscript;
TxoutType subType;
solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata) && subType != TxoutType::SCRIPTHASH && subType != TxoutType::WITNESS_V0_SCRIPTHASH && subType != TxoutType::WITNESS_V0_KEYHASH;
solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata, signFlags) && subType != TxoutType::SCRIPTHASH && subType != TxoutType::WITNESS_V0_SCRIPTHASH && subType != TxoutType::WITNESS_V0_KEYHASH;
result.push_back(std::vector<unsigned char>(witnessscript.begin(), witnessscript.end()));
sigdata.scriptWitness.stack = result;
sigdata.witness = true;
@ -255,7 +261,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;
}
@ -268,9 +274,9 @@ private:
public:
SignatureExtractorChecker(SignatureData& sigdata, BaseSignatureChecker& checker) : sigdata(sigdata), checker(checker) {}
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override
{
if (checker.CheckECDSASignature(scriptSig, vchPubKey, scriptCode, sigversion)) {
if (checker.CheckECDSASignature(scriptSig, vchPubKey, scriptCode, sigversion, flags)) {
CPubKey pubkey(vchPubKey);
sigdata.signatures.emplace(pubkey.GetID(), SigPair(pubkey, scriptSig));
return true;
@ -338,6 +344,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 == TxoutType::MULTISIG && !stack.script.empty()) {
// Build a map of pubkey -> signature by matching sigs to pubkeys:
assert(solutions.size() > 1);
@ -347,7 +355,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.CheckECDSASignature(sig, pubkey, next_script, sigversion)) {
if (data.signatures.count(CPubKey(pubkey).GetID()) || extractor_checker.CheckECDSASignature(sig, pubkey, next_script, sigversion, flags)) {
last_success_key = i + 1;
break;
}
@ -412,7 +420,7 @@ class DummySignatureChecker final : public BaseSignatureChecker
{
public:
DummySignatureChecker() {}
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { return true; }
bool CheckECDSASignature(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;
@ -423,7 +431,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');