diff --git a/src/script/sigencoding.cpp b/src/script/sigencoding.cpp --- a/src/script/sigencoding.cpp +++ b/src/script/sigencoding.cpp @@ -56,7 +56,7 @@ // Verify that the length of the signature matches the sum of the length // of the elements. - if ((size_t)(lenR + lenS + 7) != sig.size()) return false; + if (size_t(lenR + lenS + 7) != sig.size()) return false; // Check whether the R element is an integer. if (sig[2] != 0x02) return false; diff --git a/src/test/sigencoding_tests.cpp b/src/test/sigencoding_tests.cpp --- a/src/test/sigencoding_tests.cpp +++ b/src/test/sigencoding_tests.cpp @@ -11,6 +11,80 @@ BOOST_FIXTURE_TEST_SUITE(sigencoding_tests, BasicTestingSetup) +static valtype SignatureWithHashType(valtype vchSig, SigHashType sigHash) { + vchSig.push_back(static_cast(sigHash.getRawSigHashType())); + return vchSig; +} + +static void CheckSignatureEncodingWithSigHashType(const valtype &vchSig, + uint32_t flags) { + const bool hasForkId = (flags & SCRIPT_ENABLE_SIGHASH_FORKID) != 0; + const bool hasStrictEnc = (flags & SCRIPT_VERIFY_STRICTENC) != 0; + + std::vector allBaseTypes{ + BaseSigHashType::ALL, BaseSigHashType::NONE, BaseSigHashType::SINGLE}; + + std::vector baseSigHashes; + for (const BaseSigHashType baseType : allBaseTypes) { + const SigHashType baseSigHash = SigHashType().withBaseType(baseType); + baseSigHashes.push_back(baseSigHash); + baseSigHashes.push_back(baseSigHash.withAnyoneCanPay(true)); + } + + for (const SigHashType baseSigHash : baseSigHashes) { + ScriptError err = SCRIPT_ERR_OK; + + // Check the signature with the proper forkid flag. + SigHashType sigHash = baseSigHash.withForkId(hasForkId); + valtype validSig = SignatureWithHashType(vchSig, sigHash); + BOOST_CHECK(CheckSignatureEncoding(validSig, flags, &err)); + + // If we have strict encoding, we prevent the use of undefined flags. + std::array undefSigHashes{ + SigHashType(sigHash.getRawSigHashType() | 0x20), + sigHash.withBaseType(BaseSigHashType::UNSUPPORTED), + }; + + for (SigHashType undefSigHash : undefSigHashes) { + valtype undefSighash = SignatureWithHashType(vchSig, undefSigHash); + BOOST_CHECK_EQUAL(CheckSignatureEncoding(undefSighash, flags, &err), + !hasStrictEnc); + if (hasStrictEnc) { + BOOST_CHECK_EQUAL(err, SCRIPT_ERR_SIG_HASHTYPE); + } + } + + // If we check strict encoding, then invalid forkid is an error. + SigHashType invalidSigHash = baseSigHash.withForkId(!hasForkId); + valtype invalidSig = SignatureWithHashType(vchSig, invalidSigHash); + + BOOST_CHECK_EQUAL(CheckSignatureEncoding(invalidSig, flags, &err), + !hasStrictEnc); + if (hasStrictEnc) { + BOOST_CHECK_EQUAL(err, + hasForkId ? SCRIPT_ERR_MUST_USE_FORKID + : SCRIPT_ERR_ILLEGAL_FORKID); + } + } +} + +BOOST_AUTO_TEST_CASE(checksignatureencoding_test) { + valtype nullfailsig{}; + valtype minimalsig{0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; + + // If we add many more flags, this loop can get too expensive, but we can + // rewrite in the future to randomly pick a set of flags to evaluate. + for (uint32_t flags = 0; flags < (1U << 17); flags++) { + ScriptError err = SCRIPT_ERR_OK; + + // Empty sig is always valid. + BOOST_CHECK(CheckSignatureEncoding({}, flags, &err)); + + // Signature are valid as long as the forkid flag is correct. + CheckSignatureEncodingWithSigHashType(minimalsig, flags); + } +} + BOOST_AUTO_TEST_CASE(checkpubkeyencoding_test) { valtype compressedKey0{0x02, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12,