Skip to content

Commit

Permalink
Report more detailed signature validation errors
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa committed Oct 9, 2020
1 parent fb6bc8a commit 67750a3
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 67 deletions.
21 changes: 12 additions & 9 deletions src/script/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,8 @@ static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, Scr
if (pubkey.size() == 0) {
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
} else if (pubkey.size() == 32) {
if (success && !checker.CheckSchnorrSignature(sig, pubkey, sigversion, execdata)) {
return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);
if (success && !checker.CheckSchnorrSignature(sig, pubkey, sigversion, execdata, serror)) {
return false;
}
} else {
/*
Expand Down Expand Up @@ -1676,7 +1676,7 @@ bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vecto
}

template <class T>
bool GenericTransactionSignatureChecker<T>::CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey_in, SigVersion sigversion, const ScriptExecutionData& execdata) const
bool GenericTransactionSignatureChecker<T>::CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey_in, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror) const
{
assert(sigversion == SigVersion::TAPROOT || sigversion == SigVersion::TAPSCRIPT);
// Schnorr signatures have 32-byte public keys. The caller is responsible for enforcing this.
Expand All @@ -1685,19 +1685,22 @@ bool GenericTransactionSignatureChecker<T>::CheckSchnorrSignature(Span<const uns
// abort script execution). This is implemented in EvalChecksigTapscript, which won't invoke
// CheckSchnorrSignature in that case. In other contexts, they are invalid like every other signature with
// size different from 64 or 65.
if (sig.size() != 64 && sig.size() != 65) return false;
if (sig.size() != 64 && sig.size() != 65) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_SIZE);

XOnlyPubKey pubkey{pubkey_in};

uint8_t hashtype = SIGHASH_DEFAULT;
if (sig.size() == 65) {
hashtype = SpanPopBack(sig);
if (hashtype == SIGHASH_DEFAULT) return false;
if (hashtype == SIGHASH_DEFAULT) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_HASHTYPE);
}
uint256 sighash;
assert(this->txdata);
if (!SignatureHashSchnorr(sighash, execdata, *txTo, nIn, hashtype, sigversion, *this->txdata)) return false;
return VerifySchnorrSignature(sig, pubkey, sighash);
if (!SignatureHashSchnorr(sighash, execdata, *txTo, nIn, hashtype, sigversion, *this->txdata)) {
return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_HASHTYPE);
}
if (!VerifySchnorrSignature(sig, pubkey, sighash)) return set_error(serror, SCRIPT_ERR_SCHNORR_SIG);
return true;
}

template <class T>
Expand Down Expand Up @@ -1896,8 +1899,8 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
execdata.m_annex_init = true;
if (stack.size() == 1) {
// Key path spending (stack size is 1 after removing optional annex)
if (!checker.CheckSchnorrSignature(stack.front(), program, SigVersion::TAPROOT, execdata)) {
return set_error(serror, SCRIPT_ERR_TAPROOT_INVALID_SIG);
if (!checker.CheckSchnorrSignature(stack.front(), program, SigVersion::TAPROOT, execdata, serror)) {
return false;
}
return set_success(serror);
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/script/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ class BaseSignatureChecker
return false;
}

virtual bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata) const
virtual bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const
{
return false;
}
Expand Down Expand Up @@ -264,7 +264,7 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker
GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata) const override;
bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override;
bool CheckLockTime(const CScriptNum& nLockTime) const override;
bool CheckSequence(const CScriptNum& nSequence) const override;
};
Expand Down
8 changes: 6 additions & 2 deletions src/script/script_error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,12 @@ std::string ScriptErrorString(const ScriptError serror)
return "Witness provided for non-witness script";
case SCRIPT_ERR_WITNESS_PUBKEYTYPE:
return "Using non-compressed keys in segwit";
case SCRIPT_ERR_TAPROOT_INVALID_SIG:
return "Invalid signature for Taproot key path spending";
case SCRIPT_ERR_SCHNORR_SIG_SIZE:
return "Invalid Schnorr signature size";
case SCRIPT_ERR_SCHNORR_SIG_HASHTYPE:
return "Invalid Schnorr signature hash type";
case SCRIPT_ERR_SCHNORR_SIG:
return "Invalid Schnorr signature";
case SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE:
return "Invalid Taproot control block size";
case SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT:
Expand Down
4 changes: 3 additions & 1 deletion src/script/script_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ typedef enum ScriptError_t
SCRIPT_ERR_WITNESS_PUBKEYTYPE,

/* Taproot */
SCRIPT_ERR_TAPROOT_INVALID_SIG,
SCRIPT_ERR_SCHNORR_SIG_SIZE,
SCRIPT_ERR_SCHNORR_SIG_HASHTYPE,
SCRIPT_ERR_SCHNORR_SIG,
SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE,
SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT,
SCRIPT_ERR_TAPSCRIPT_CHECKMULTISIG,
Expand Down
2 changes: 1 addition & 1 deletion src/test/fuzz/signature_checker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class FuzzedSignatureChecker : public BaseSignatureChecker
return m_fuzzed_data_provider.ConsumeBool();
}

bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata) const override
bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override
{
return m_fuzzed_data_provider.ConsumeBool();
}
Expand Down
Loading

0 comments on commit 67750a3

Please sign in to comment.