diff --git a/src/script/sigencoding.cpp b/src/script/sigencoding.cpp --- a/src/script/sigencoding.cpp +++ b/src/script/sigencoding.cpp @@ -24,7 +24,7 @@ * * This function is consensus-critical since BIP66. */ -static bool IsValidSignatureEncoding(const slicedvaltype &sig) { +static bool IsValidDERSignatureEncoding(const slicedvaltype &sig) { // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] // * total-length: 1-byte length descriptor of everything that follows, // excluding the sighash byte. @@ -153,11 +153,12 @@ return true; } -static bool CheckRawSignatureEncoding(const slicedvaltype &sig, uint32_t flags, - ScriptError *serror) { +static bool CheckRawECDSASignatureEncoding(const slicedvaltype &sig, + uint32_t flags, + ScriptError *serror) { if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) && - !IsValidSignatureEncoding(sig)) { + !IsValidDERSignatureEncoding(sig)) { return set_error(serror, SCRIPT_ERR_SIG_DER); } @@ -168,6 +169,11 @@ return true; } +static bool CheckRawSignatureEncoding(const slicedvaltype &sig, uint32_t flags, + ScriptError *serror) { + return CheckRawECDSASignatureEncoding(sig, flags, serror); +} + bool CheckDataSignatureEncoding(const valtype &vchSig, uint32_t flags, ScriptError *serror) { // Empty signature. Not strictly DER encoded, but allowed to provide a @@ -180,21 +186,8 @@ vchSig | boost::adaptors::sliced(0, vchSig.size()), flags, serror); } -bool CheckTransactionSignatureEncoding(const valtype &vchSig, uint32_t flags, - ScriptError *serror) { - // Empty signature. Not strictly DER encoded, but allowed to provide a - // compact way to provide an invalid signature for use with CHECK(MULTI)SIG - if (vchSig.size() == 0) { - return true; - } - - if (!CheckRawSignatureEncoding( - vchSig | boost::adaptors::sliced(0, vchSig.size() - 1), flags, - serror)) { - // serror is set - return false; - } - +static bool CheckSighashEncoding(const valtype &vchSig, uint32_t flags, + ScriptError *serror) { if (flags & SCRIPT_VERIFY_STRICTENC) { if (!GetHashType(vchSig).isDefined()) { return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE); @@ -214,10 +207,46 @@ return true; } +template +static bool CheckTransactionSignatureEncodingImpl(const valtype &vchSig, + uint32_t flags, + ScriptError *serror, F fun) { + // Empty signature. Not strictly DER encoded, but allowed to provide a + // compact way to provide an invalid signature for use with CHECK(MULTI)SIG + if (vchSig.size() == 0) { + return true; + } + + if (!fun(vchSig | boost::adaptors::sliced(0, vchSig.size() - 1), flags, + serror)) { + // serror is set + return false; + } + + return CheckSighashEncoding(vchSig, flags, serror); +} + +bool CheckTransactionSignatureEncoding(const valtype &vchSig, uint32_t flags, + ScriptError *serror) { + return CheckTransactionSignatureEncodingImpl( + vchSig, flags, serror, + [](const slicedvaltype &templateSig, uint32_t templateFlags, + ScriptError *templateSerror) { + return CheckRawSignatureEncoding(templateSig, templateFlags, + templateSerror); + }); +} + bool CheckTransactionECDSASignatureEncoding(const valtype &vchSig, uint32_t flags, ScriptError *serror) { - return CheckTransactionSignatureEncoding(vchSig, flags, serror); + return CheckTransactionSignatureEncodingImpl( + vchSig, flags, serror, + [](const slicedvaltype &templateSig, uint32_t templateFlags, + ScriptError *templateSerror) { + return CheckRawECDSASignatureEncoding(templateSig, templateFlags, + templateSerror); + }); } static bool IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {