diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -911,6 +911,62 @@ } } break; + case OP_CHECKDATASIG: + case OP_CHECKDATASIGVERIFY: { + // Make sure this remains an error before activation. + if ((flags & SCRIPT_ENABLE_CHECKDATASIG) == 0) { + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); + } + + // (sig message pubkey -- bool) + if (stack.size() < 3) { + return set_error( + serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + } + + valtype &vchSig = stacktop(-3); + valtype &vchMessage = stacktop(-2); + valtype &vchPubKey = stacktop(-1); + + // The size of the message must be 32 bytes. + if (vchMessage.size() != 32) { + return set_error(serror, + SCRIPT_ERR_INVALID_OPERAND_SIZE); + } + + if (!CheckDataSignatureEncoding(vchSig, flags, + serror) || + !CheckPubKeyEncoding(vchPubKey, flags, serror)) { + // serror is set + return false; + } + + bool fSuccess = false; + if (vchSig.size()) { + uint256 message(vchMessage); + CPubKey pubkey(vchPubKey); + fSuccess = pubkey.Verify(message, vchSig); + } + + if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && + vchSig.size()) { + return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); + } + + popstack(stack); + popstack(stack); + popstack(stack); + stack.push_back(fSuccess ? vchTrue : vchFalse); + if (opcode == OP_CHECKDATASIGVERIFY) { + if (fSuccess) { + popstack(stack); + } else { + return set_error(serror, + SCRIPT_ERR_CHECKDATASIGVERIFY); + } + } + } break; + case OP_CHECKMULTISIG: case OP_CHECKMULTISIGVERIFY: { // ([sig ...] num_of_signatures [pubkey ...] @@ -1045,10 +1101,6 @@ } } break; - case OP_CHECKDATASIG: - case OP_CHECKDATASIGVERIFY: - return set_error(serror, SCRIPT_ERR_BAD_OPCODE); - // // Byte string operations // diff --git a/src/script/script_error.h b/src/script/script_error.h --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -31,6 +31,7 @@ SCRIPT_ERR_EQUALVERIFY, SCRIPT_ERR_CHECKMULTISIGVERIFY, SCRIPT_ERR_CHECKSIGVERIFY, + SCRIPT_ERR_CHECKDATASIGVERIFY, SCRIPT_ERR_NUMEQUALVERIFY, /* Logical/Format/Canonical errors */ diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -20,6 +20,8 @@ return "Script failed an OP_CHECKMULTISIGVERIFY operation"; case SCRIPT_ERR_CHECKSIGVERIFY: return "Script failed an OP_CHECKSIGVERIFY operation"; + case SCRIPT_ERR_CHECKDATASIGVERIFY: + return "Script failed an OP_CHECKDATASIGVERIFY operation"; case SCRIPT_ERR_NUMEQUALVERIFY: return "Script failed an OP_NUMEQUALVERIFY operation"; case SCRIPT_ERR_SCRIPT_SIZE: diff --git a/src/test/checkdatasig_tests.cpp b/src/test/checkdatasig_tests.cpp --- a/src/test/checkdatasig_tests.cpp +++ b/src/test/checkdatasig_tests.cpp @@ -19,36 +19,224 @@ std::array flagset{ {0, STANDARD_SCRIPT_VERIFY_FLAGS, MANDATORY_SCRIPT_VERIFY_FLAGS}}; +const uint8_t vchPrivkey[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; + +struct KeyData { + CKey privkey, privkeyC; + CPubKey pubkey, pubkeyC, pubkeyH; + + KeyData() { + privkey.Set(vchPrivkey, vchPrivkey + 32, false); + privkeyC.Set(vchPrivkey, vchPrivkey + 32, true); + pubkey = privkey.GetPubKey(); + pubkeyH = privkey.GetPubKey(); + pubkeyC = privkeyC.GetPubKey(); + *const_cast(&pubkeyH[0]) = 0x06 | (pubkeyH[64] & 1); + } +}; + +static void CheckError(uint32_t flags, const stacktype &original_stack, + const CScript &script, ScriptError expected) { + BaseSignatureChecker sigchecker; + ScriptError err = SCRIPT_ERR_OK; + stacktype stack{original_stack}; + bool r = EvalScript(stack, script, flags, sigchecker, &err); + BOOST_CHECK(!r); + BOOST_CHECK_EQUAL(err, expected); +} + +static void CheckPass(uint32_t flags, const stacktype &original_stack, + const CScript &script, const stacktype &expected) { + BaseSignatureChecker sigchecker; + ScriptError err = SCRIPT_ERR_OK; + stacktype stack{original_stack}; + bool r = EvalScript(stack, script, flags, sigchecker, &err); + BOOST_CHECK(r); + BOOST_CHECK_EQUAL(err, SCRIPT_ERR_OK); + BOOST_CHECK(stack == expected); +} + /** * General utility functions to check for script passing/failing. */ static void CheckTestResultForAllFlags(const stacktype &original_stack, const CScript &script, const stacktype &expected) { - BaseSignatureChecker sigchecker; - for (uint32_t flags : flagset) { - // The opcode are not implemented yet, so we get a bad opcode error when - // passing the activation flag. - ScriptError err = SCRIPT_ERR_OK; - stacktype stack{original_stack}; - bool r = EvalScript(stack, script, flags | SCRIPT_ENABLE_CHECKDATASIG, - sigchecker, &err); - BOOST_CHECK(!r); - BOOST_CHECK_EQUAL(err, SCRIPT_ERR_BAD_OPCODE); + // Make sure that we get a bad opcode when the activation flag is not + // passed. + CheckError(flags, original_stack, script, SCRIPT_ERR_BAD_OPCODE); + + // The script execute as expected if the opcodes are activated. + CheckPass(flags | SCRIPT_ENABLE_CHECKDATASIG, original_stack, script, + expected); + } +} +static void CheckErrorForAllFlags(const stacktype &original_stack, + const CScript &script, ScriptError expected) { + for (uint32_t flags : flagset) { // Make sure that we get a bad opcode when the activation flag is not // passed. - stack = original_stack; - r = EvalScript(stack, script, flags, sigchecker, &err); - BOOST_CHECK(!r); - BOOST_CHECK_EQUAL(err, SCRIPT_ERR_BAD_OPCODE); + CheckError(flags, original_stack, script, SCRIPT_ERR_BAD_OPCODE); + + // The script generates the proper error if the opcodes are activated. + CheckError(flags | SCRIPT_ENABLE_CHECKDATASIG, original_stack, script, + expected); } } BOOST_AUTO_TEST_CASE(checkdatasig_test) { - CheckTestResultForAllFlags({}, CScript() << OP_CHECKDATASIG, {}); - CheckTestResultForAllFlags({}, CScript() << OP_CHECKDATASIGVERIFY, {}); + // Empty stack. + CheckErrorForAllFlags({}, CScript() << OP_CHECKDATASIG, + SCRIPT_ERR_INVALID_STACK_OPERATION); + CheckErrorForAllFlags({{0x00}}, CScript() << OP_CHECKDATASIG, + SCRIPT_ERR_INVALID_STACK_OPERATION); + CheckErrorForAllFlags({{0x00}, {0x00}}, CScript() << OP_CHECKDATASIG, + SCRIPT_ERR_INVALID_STACK_OPERATION); + CheckErrorForAllFlags({}, CScript() << OP_CHECKDATASIGVERIFY, + SCRIPT_ERR_INVALID_STACK_OPERATION); + CheckErrorForAllFlags({{0x00}}, CScript() << OP_CHECKDATASIGVERIFY, + SCRIPT_ERR_INVALID_STACK_OPERATION); + CheckErrorForAllFlags({{0x00}, {0x00}}, CScript() << OP_CHECKDATASIGVERIFY, + SCRIPT_ERR_INVALID_STACK_OPERATION); + + // Check invalid message sizes. + for (valtype message; message.size() < 42; message.push_back(0x00)) { + if (message.size() == 32) { + // 32 is the epxected size, skip. + continue; + } + + CheckErrorForAllFlags({{0x00}, message, {0x00}}, + CScript() << OP_CHECKDATASIG, + SCRIPT_ERR_INVALID_OPERAND_SIZE); + + CheckErrorForAllFlags({{0x00}, message, {0x00}}, + CScript() << OP_CHECKDATASIGVERIFY, + SCRIPT_ERR_INVALID_OPERAND_SIZE); + } + + // Check various pubkey encoding. + const valtype message(32, 0x00); + + KeyData kd; + valtype pubkey = ToByteVector(kd.pubkey); + valtype pubkeyC = ToByteVector(kd.pubkeyC); + valtype pubkeyH = ToByteVector(kd.pubkeyH); + + CheckTestResultForAllFlags({{}, message, pubkey}, + CScript() << OP_CHECKDATASIG, {{}}); + CheckTestResultForAllFlags({{}, message, pubkeyC}, + CScript() << OP_CHECKDATASIG, {{}}); + CheckErrorForAllFlags({{}, message, pubkey}, + CScript() << OP_CHECKDATASIGVERIFY, + SCRIPT_ERR_CHECKDATASIGVERIFY); + CheckErrorForAllFlags({{}, message, pubkeyC}, + CScript() << OP_CHECKDATASIGVERIFY, + SCRIPT_ERR_CHECKDATASIGVERIFY); + + // Flags dependent checks. + const CScript script = CScript() << OP_CHECKDATASIG << OP_NOT << OP_VERIFY; + const CScript scriptverify = CScript() << OP_CHECKDATASIGVERIFY; + + // Check valid signatures. + const uint256 one(uint256S( + "0000000000000000000000000000000000000000000000000000000000000001")); + const uint256 two(uint256S( + "0000000000000000000000000000000000000000000000000000000000000002")); + + valtype validsig; + kd.privkey.Sign(one, validsig); + + CheckTestResultForAllFlags({validsig, ToByteVector(one), pubkey}, + CScript() << OP_CHECKDATASIG, {{0x01}}); + CheckTestResultForAllFlags({validsig, ToByteVector(one), pubkey}, + CScript() << OP_CHECKDATASIGVERIFY, {}); + + const valtype minimalsig{0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; + const valtype nondersig{0x30, 0x80, 0x06, 0x02, 0x01, + 0x01, 0x02, 0x01, 0x01}; + const valtype highSSig{ + 0x30, 0x45, 0x02, 0x20, 0x3e, 0x45, 0x16, 0xda, 0x72, 0x53, 0xcf, 0x06, + 0x8e, 0xff, 0xec, 0x6b, 0x95, 0xc4, 0x12, 0x21, 0xc0, 0xcf, 0x3a, 0x8e, + 0x6c, 0xcb, 0x8c, 0xbf, 0x17, 0x25, 0xb5, 0x62, 0xe9, 0xaf, 0xde, 0x2c, + 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, + 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, + 0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0}; + + // 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++) { + // Make sure we activate the opcodes. + flags |= SCRIPT_ENABLE_CHECKDATASIG; + + if (flags & SCRIPT_VERIFY_STRICTENC) { + // When strict encoding is enforced, hybrid key are invalid. + CheckError(flags, {{}, message, pubkeyH}, script, + SCRIPT_ERR_PUBKEYTYPE); + CheckError(flags, {{}, message, pubkeyH}, scriptverify, + SCRIPT_ERR_PUBKEYTYPE); + } else { + // When strict encoding is not enforced, hybrid key are valid. + CheckPass(flags, {{}, message, pubkeyH}, script, {}); + CheckError(flags, {{}, message, pubkeyH}, scriptverify, + SCRIPT_ERR_CHECKDATASIGVERIFY); + } + + if (flags & SCRIPT_VERIFY_NULLFAIL) { + // When strict encoding is enforced, hybrid key are invalid. + CheckError(flags, {minimalsig, message, pubkey}, script, + SCRIPT_ERR_SIG_NULLFAIL); + CheckError(flags, {minimalsig, message, pubkey}, scriptverify, + SCRIPT_ERR_SIG_NULLFAIL); + + // Invalid message cause checkdatasig to fail. + CheckError(flags, {validsig, ToByteVector(two), pubkey}, script, + SCRIPT_ERR_SIG_NULLFAIL); + CheckError(flags, {validsig, ToByteVector(two), pubkey}, + scriptverify, SCRIPT_ERR_SIG_NULLFAIL); + } else { + // When nullfail is not enforced, invalid signature are just false. + CheckPass(flags, {minimalsig, message, pubkey}, script, {}); + CheckError(flags, {minimalsig, message, pubkey}, scriptverify, + SCRIPT_ERR_CHECKDATASIGVERIFY); + + // Invalid message cause checkdatasig to fail. + CheckPass(flags, {validsig, ToByteVector(two), pubkey}, script, {}); + CheckError(flags, {validsig, ToByteVector(two), pubkey}, + scriptverify, SCRIPT_ERR_CHECKDATASIGVERIFY); + } + + if (flags & SCRIPT_VERIFY_LOW_S) { + // If we do enforce low S, then high S sigs are rejected. + CheckError(flags, {highSSig, message, pubkey}, script, + SCRIPT_ERR_SIG_HIGH_S); + CheckError(flags, {highSSig, message, pubkey}, scriptverify, + SCRIPT_ERR_SIG_HIGH_S); + } else { + // If we do not enforce low S, then high S sigs are accepted. + CheckPass(flags, {highSSig, message, pubkey}, script, {}); + CheckError(flags, {highSSig, message, pubkey}, scriptverify, + SCRIPT_ERR_CHECKDATASIGVERIFY); + } + + if (flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | + SCRIPT_VERIFY_STRICTENC)) { + // If we get any of the dersig flags, the non canonical dersig + // signature fails. + CheckError(flags, {nondersig, message, pubkey}, script, + SCRIPT_ERR_SIG_DER); + CheckError(flags, {nondersig, message, pubkey}, scriptverify, + SCRIPT_ERR_SIG_DER); + } else { + // If we do not check, then it is accepted. + CheckPass(flags, {nondersig, message, pubkey}, script, {}); + CheckError(flags, {nondersig, message, pubkey}, scriptverify, + SCRIPT_ERR_CHECKDATASIGVERIFY); + } + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json --- a/src/test/data/script_tests.json +++ b/src/test/data/script_tests.json @@ -1036,6 +1036,115 @@ ["1 1 ADD", "0 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], ["11 1 ADD 12 SUB", "11 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"], +["CHECKDATASIG"], +["", "CHECKDATASIG", "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", "INVALID_STACK_OPERATION"], +["0", "CHECKDATASIG", "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", "INVALID_STACK_OPERATION"], +["0 0", "CHECKDATASIG", "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", "INVALID_STACK_OPERATION"], +["0 0 0", "CHECKDATASIG", "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", "OPERAND_SIZE"], +[ + "0 0x21 0x000000000000000000000000000000000000000000000000000000000000000001", + "0 CHECKDATASIG", + "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", + "OPERAND_SIZE" +], +[ + "0 0x1f 0x00000000000000000000000000000000000000000000000000000000000001", + "0 CHECKDATASIG", + "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", + "OPERAND_SIZE" +], +[ + "0 0x20 0x0000000000000000000000000000000000000000000000000000000000000001", + "0 CHECKDATASIG", + "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", + "PUBKEYTYPE" +], +[ + "0 0x20 0x0000000000000000000000000000000000000000000000000000000000000001", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIG", + "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", + "EVAL_FALSE" +], +[ + "0x08 0x3006020101020101 0x20 0x0000000000000000000000000000000000000000000000000000000000000001", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIG", + "P2SH,STRICTENC,CHECKDATASIG", + "EVAL_FALSE", "Check that NULLFAIL trigger only when specified" +], +[ + "0x08 0x3006020101020101 0x20 0x0000000000000000000000000000000000000000000000000000000000000001", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIG", + "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", + "NULLFAIL" +], +[ + "0x09 0x300602010102010101 0x20 0x0000000000000000000000000000000000000000000000000000000000000001", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIG", + "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", + "SIG_DER", "Ensure that sighashtype is ignored" +], +[ + "0x09 0x300702010102020001 0x20 0x0000000000000000000000000000000000000000000000000000000000000001", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIG", + "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", + "SIG_DER", "Non cannonical DER encoding" +], + +["CHECKDATASIGVERIFY"], +["", "CHECKDATASIGVERIFY 1", "P2SH,STRICTENC,CHECKDATASIG", "INVALID_STACK_OPERATION"], +["0", "CHECKDATASIGVERIFY 1", "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", "INVALID_STACK_OPERATION"], +["0 0", "CHECKDATASIGVERIFY 1", "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", "INVALID_STACK_OPERATION"], +["0 0 0", "CHECKDATASIGVERIFY 1", "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", "OPERAND_SIZE"], +[ + "0 0x21 0x000000000000000000000000000000000000000000000000000000000000000001", + "0 CHECKDATASIGVERIFY 1", + "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", + "OPERAND_SIZE" +], +[ + "0 0x1f 0x00000000000000000000000000000000000000000000000000000000000001", + "0 CHECKDATASIGVERIFY 1", + "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", + "OPERAND_SIZE" +], +[ + "0 0x20 0x0000000000000000000000000000000000000000000000000000000000000001", + "0 CHECKDATASIGVERIFY 1", + "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", + "PUBKEYTYPE" +], +[ + "0 0x20 0x0000000000000000000000000000000000000000000000000000000000000001", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIGVERIFY 1", + "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", + "CHECKDATASIGVERIFY" +], +[ + "0x08 0x3006020101020101 0x20 0x0000000000000000000000000000000000000000000000000000000000000001", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIGVERIFY 1", + "P2SH,STRICTENC,CHECKDATASIG", + "CHECKDATASIGVERIFY", "Check that NULLFAIL trigger only when specified" +], +[ + "0x08 0x3006020101020101 0x20 0x0000000000000000000000000000000000000000000000000000000000000001", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIGVERIFY 1", + "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", + "NULLFAIL" +], +[ + "0x09 0x300602010102010101 0x20 0x0000000000000000000000000000000000000000000000000000000000000001", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIGVERIFY 1", + "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", + "SIG_DER", "Ensure that sighashtype is ignored" +], +[ + "0x09 0x300702010102020001 0x20 0x0000000000000000000000000000000000000000000000000000000000000001", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIGVERIFY 1", + "P2SH,STRICTENC,NULLFAIL,CHECKDATASIG", + "SIG_DER", "Non cannonical DER encoding" +], + +["ADD"], ["2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "UNKNOWN_ERROR", "arithmetic operands must be in range [-2^31...2^31] "], ["-2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "UNKNOWN_ERROR", "arithmetic operands must be in range [-2^31...2^31] "], ["2147483647 DUP ADD", "4294967294 NUMEQUAL", "P2SH,STRICTENC", "UNKNOWN_ERROR", "NUMEQUAL must be in numeric range"], @@ -1069,9 +1178,7 @@ ["0x50","1", "P2SH,STRICTENC", "BAD_OPCODE", "opcode 0x50 is reserved"], ["1", "IF CHECKDATASIG ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], -["1", "IF CHECKDATASIG ELSE 1 ENDIF", "P2SH,STRICTENC,CHECKDATASIG", "BAD_OPCODE"], ["1", "IF CHECKDATASIGVERIFY ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], -["1", "IF CHECKDATASIGVERIFY ELSE 1 ENDIF", "P2SH,STRICTENC,CHECKDATASIG", "BAD_OPCODE"], ["1", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE", "opcodes >= FIRST_UNDEFINED_OP_VALUE invalid if executed"], ["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], ["1", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC", "BAD_OPCODE"], @@ -2119,6 +2226,174 @@ "EVAL_FALSE", "P2PK REPLAY PROTECTED" ], +[ + "0x46 0x30440220052a549456efe256a8c190650648e7ebdd46161f330830733fc7c674aeb7d3da0220519999b4f25b37de557a9c909cb5b155d1f0b11293b0890236696bfa0bd310e1 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIG", + "CHECKDATASIG,NULLFAIL,STRICTENC", + "OK", + "Standard CHECKDATASIG" +], +[ + "0x46 0x30440220052a549456efe256a8c190650648e7ebdd46161f330830733fc7c674aeb7d3da0220519999b4f25b37de557a9c909cb5b155d1f0b11293b0890236696bfa0bd310e1 0x20 0x0200000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIG NOT", + "CHECKDATASIG,NULLFAIL,STRICTENC", + "NULLFAIL", + "CHECKDATASIG with NULLFAIL flags" +], +[ + "0x46 0x30440220052a549456efe256a8c190650648e7ebdd46161f330830733fc7c674aeb7d3da0220519999b4f25b37de557a9c909cb5b155d1f0b11293b0890236696bfa0bd310e1 0x20 0x0200000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIG NOT", + "CHECKDATASIG,STRICTENC", + "OK", + "CHECKDATASIG without NULLFAIL flags" +], +[ + "0 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIG NOT", + "CHECKDATASIG,NULLFAIL,STRICTENC", + "OK", + "CHECKDATASIG empty signature" +], +[ + "0x47 0x30450220052a549456efe256a8c190650648e7ebdd46161f330830733fc7c674aeb7d3da022100ae66664b0da4c821aa85636f634a4ea8e8be2bd41b9817398968f292c4633060 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIG", + "CHECKDATASIG,NULLFAIL,STRICTENC", + "OK", + "CHECKDATASIG with High S but no Low S" +], +[ + "0x47 0x30450220052a549456efe256a8c190650648e7ebdd46161f330830733fc7c674aeb7d3da022100ae66664b0da4c821aa85636f634a4ea8e8be2bd41b9817398968f292c4633060 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIG", + "CHECKDATASIG,LOW_S,NULLFAIL,STRICTENC", + "SIG_HIGH_S", + "CHECKDATASIG with High S" +], +[ + "0x46 0x30440220e54f8b4dc9b45e1e76207fd0062f3f8b09381e6131d9be3781d2a791fe889c96022038ff0a5f76c1b972149700568ea98b2932e163b5debc78814fc7f1b89f7bcf02 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIG", + "CHECKDATASIG,NULLFAIL", + "OK", + "CHECKDATASIG with too little R padding but no DERSIG" +], +[ + "0x46 0x30440220e54f8b4dc9b45e1e76207fd0062f3f8b09381e6131d9be3781d2a791fe889c96022038ff0a5f76c1b972149700568ea98b2932e163b5debc78814fc7f1b89f7bcf02 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIG", + "CHECKDATASIG,NULLFAIL,STRICTENC", + "SIG_DER", + "CHECKDATASIG with too little R padding" +], +[ + "0x46 0x304402201f9ab6bce51855179000754f239bcdc91682e556275514ec72a6b429b8972da2022076ba6228144dbaaeffb5e58ead6281a56bd4e3ae05f0890d1bbb5dad8f61b1ac 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKDATASIG", + "CHECKDATASIG,NULLFAIL", + "OK", + "CHECKDATASIG with hybrid pubkey but no STRICTENC" +], +[ + "0x46 0x304402201f9ab6bce51855179000754f239bcdc91682e556275514ec72a6b429b8972da2022076ba6228144dbaaeffb5e58ead6281a56bd4e3ae05f0890d1bbb5dad8f61b1ac 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKDATASIG", + "CHECKDATASIG,NULLFAIL,STRICTENC", + "PUBKEYTYPE", + "CHECKDATASIG with hybrid pubkey" +], +[ + "0x46 0x304402201f9ab6bce51854179000754f239bcdc91682e556275514ec72a6b429b8972da2022076ba6228144dbaaeffb5e58ead6281a56bd4e3ae05f0890d1bbb5dad8f61b1ac 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKDATASIG NOT", + "CHECKDATASIG", + "OK", + "CHECKDATASIG with invalid hybrid pubkey but no STRICTENC" +], +[ + "0x46 0x304402201f9ab6bce51854179000754f239bcdc91682e556275514ec72a6b429b8972da2022076ba6228144dbaaeffb5e58ead6281a56bd4e3ae05f0890d1bbb5dad8f61b1ac 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKDATASIG", + "CHECKDATASIG,NULLFAIL,STRICTENC", + "PUBKEYTYPE", + "CHECKDATASIG with invalid hybrid pubkey" +], +[ + "0x46 0x30440220052a549456efe256a8c190650648e7ebdd46161f330830733fc7c674aeb7d3da0220519999b4f25b37de557a9c909cb5b155d1f0b11293b0890236696bfa0bd310e1 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIGVERIFY 1", + "CHECKDATASIG,NULLFAIL,STRICTENC", + "OK", + "Standard CHECKDATASIGVERIFY" +], +[ + "0x46 0x30440220052a549456efe256a8c190650648e7ebdd46161f330830733fc7c674aeb7d3da0220519999b4f25b37de557a9c909cb5b155d1f0b11293b0890236696bfa0bd310e1 0x20 0x0200000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIGVERIFY 1", + "CHECKDATASIG,NULLFAIL,STRICTENC", + "NULLFAIL", + "CHECKDATASIGVERIFY with NULLFAIL flags" +], +[ + "0x46 0x30440220052a549456efe256a8c190650648e7ebdd46161f330830733fc7c674aeb7d3da0220519999b4f25b37de557a9c909cb5b155d1f0b11293b0890236696bfa0bd310e1 0x20 0x0200000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIGVERIFY 1", + "CHECKDATASIG,STRICTENC", + "CHECKDATASIGVERIFY", + "CHECKDATASIGVERIFY without NULLFAIL flags" +], +[ + "0 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIGVERIFY 1", + "CHECKDATASIG,NULLFAIL,STRICTENC", + "CHECKDATASIGVERIFY", + "CHECKDATASIGVERIFY empty signature" +], +[ + "0x47 0x30450220052a549456efe256a8c190650648e7ebdd46161f330830733fc7c674aeb7d3da022100ae66664b0da4c821aa85636f634a4ea8e8be2bd41b9817398968f292c4633060 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIGVERIFY 1", + "CHECKDATASIG,NULLFAIL,STRICTENC", + "OK", + "CHECKDATASIG with High S but no Low S" +], +[ + "0x47 0x30450220052a549456efe256a8c190650648e7ebdd46161f330830733fc7c674aeb7d3da022100ae66664b0da4c821aa85636f634a4ea8e8be2bd41b9817398968f292c4633060 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIGVERIFY 1", + "CHECKDATASIG,LOW_S,NULLFAIL,STRICTENC", + "SIG_HIGH_S", + "CHECKDATASIG with High S" +], +[ + "0x46 0x30440220e54f8b4dc9b45e1e76207fd0062f3f8b09381e6131d9be3781d2a791fe889c96022038ff0a5f76c1b972149700568ea98b2932e163b5debc78814fc7f1b89f7bcf02 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIGVERIFY 1", + "CHECKDATASIG,NULLFAIL", + "OK", + "CHECKDATASIGVERIFY with too little R padding but no DERSIG" +], +[ + "0x46 0x30440220e54f8b4dc9b45e1e76207fd0062f3f8b09381e6131d9be3781d2a791fe889c96022038ff0a5f76c1b972149700568ea98b2932e163b5debc78814fc7f1b89f7bcf02 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKDATASIGVERIFY 1", + "CHECKDATASIG,NULLFAIL,STRICTENC", + "SIG_DER", + "CHECKDATASIGVERIFY with too little R padding" +], +[ + "0x46 0x304402201f9ab6bce51855179000754f239bcdc91682e556275514ec72a6b429b8972da2022076ba6228144dbaaeffb5e58ead6281a56bd4e3ae05f0890d1bbb5dad8f61b1ac 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKDATASIGVERIFY 1", + "CHECKDATASIG,NULLFAIL", + "OK", + "CHECKDATASIGVERIFY with hybrid pubkey but no STRICTENC" +], +[ + "0x46 0x304402201f9ab6bce51855179000754f239bcdc91682e556275514ec72a6b429b8972da2022076ba6228144dbaaeffb5e58ead6281a56bd4e3ae05f0890d1bbb5dad8f61b1ac 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKDATASIGVERIFY 1", + "CHECKDATASIG,NULLFAIL,STRICTENC", + "PUBKEYTYPE", + "CHECKDATASIGVERIFY with hybrid pubkey" +], +[ + "0x46 0x304402201f9ab6bce51854179000754f239bcdc91682e556275514ec72a6b429b8972da2022076ba6228144dbaaeffb5e58ead6281a56bd4e3ae05f0890d1bbb5dad8f61b1ac 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKDATASIGVERIFY 1", + "CHECKDATASIG", + "CHECKDATASIGVERIFY", + "CHECKDATASIGVERIFY with invalid hybrid pubkey but no STRICTENC" +], +[ + "0x46 0x304402201f9ab6bce51854179000754f239bcdc91682e556275514ec72a6b429b8972da2022076ba6228144dbaaeffb5e58ead6281a56bd4e3ae05f0890d1bbb5dad8f61b1ac 0x20 0x0100000000000000000000000000000000000000000000000000000000000000", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKDATASIGVERIFY 1", + "CHECKDATASIG,NULLFAIL,STRICTENC", + "PUBKEYTYPE", + "CHECKDATASIGVERIFY with invalid hybrid pubkey" +], ["CHECKSEQUENCEVERIFY tests"], ["", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on a empty stack"], diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -61,6 +61,7 @@ {SCRIPT_ERR_EQUALVERIFY, "EQUALVERIFY"}, {SCRIPT_ERR_CHECKMULTISIGVERIFY, "CHECKMULTISIGVERIFY"}, {SCRIPT_ERR_CHECKSIGVERIFY, "CHECKSIGVERIFY"}, + {SCRIPT_ERR_CHECKDATASIGVERIFY, "CHECKDATASIGVERIFY"}, {SCRIPT_ERR_NUMEQUALVERIFY, "NUMEQUALVERIFY"}, {SCRIPT_ERR_BAD_OPCODE, "BAD_OPCODE"}, {SCRIPT_ERR_DISABLED_OPCODE, "DISABLED_OPCODE"}, @@ -318,6 +319,11 @@ return *this; } + TestBuilder &Push(const uint256 &hash) { + DoPush(ToByteVector(hash)); + return *this; + } + TestBuilder &Push(const CScript &_script) { DoPush(std::vector(_script.begin(), _script.end())); return *this; @@ -336,6 +342,12 @@ return *this; } + TestBuilder &PushSig(const CKey &key, const uint256 &hash, + unsigned int lenR = 32, unsigned int lenS = 32) { + DoPush(DoSign(key, hash, lenR, lenS)); + return *this; + } + TestBuilder &Push(const CPubKey &pubkey) { DoPush(std::vector(pubkey.begin(), pubkey.end())); return *this; @@ -1114,6 +1126,185 @@ SCRIPT_ENABLE_SIGHASH_FORKID) .ScriptError(SCRIPT_ERR_EVAL_FALSE)); + // Test OP_CHECKDATASIG + static const uint256 one(uint256S( + "0000000000000000000000000000000000000000000000000000000000000001")); + static const uint256 two(uint256S( + "0000000000000000000000000000000000000000000000000000000000000002")); + const uint32_t checkdatasigflags = SCRIPT_VERIFY_STRICTENC | + SCRIPT_VERIFY_NULLFAIL | + SCRIPT_ENABLE_CHECKDATASIG; + + tests.push_back( + TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIG, + "Standard CHECKDATASIG", checkdatasigflags) + .PushSig(keys.key1, one) + .Push(one)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) + << OP_CHECKDATASIG << OP_NOT, + "CHECKDATASIG with NULLFAIL flags", + checkdatasigflags) + .PushSig(keys.key1, one) + .Push(two) + .ScriptError(SCRIPT_ERR_SIG_NULLFAIL)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) + << OP_CHECKDATASIG << OP_NOT, + "CHECKDATASIG without NULLFAIL flags", + checkdatasigflags & ~SCRIPT_VERIFY_NULLFAIL) + .PushSig(keys.key1, one) + .Push(two)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) + << OP_CHECKDATASIG << OP_NOT, + "CHECKDATASIG empty signature", + checkdatasigflags) + .Num(0) + .Push(one)); + tests.push_back( + TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIG, + "CHECKDATASIG with High S but no Low S", checkdatasigflags) + .PushSig(keys.key1, one, 32, 33) + .Push(one)); + tests.push_back( + TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIG, + "CHECKDATASIG with High S", + checkdatasigflags | SCRIPT_VERIFY_LOW_S) + .PushSig(keys.key1, one, 32, 33) + .Push(one) + .ScriptError(SCRIPT_ERR_SIG_HIGH_S)); + tests.push_back( + TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIG, + "CHECKDATASIG with too little R padding but no DERSIG", + checkdatasigflags & ~SCRIPT_VERIFY_STRICTENC) + .PushSig(keys.key1, one, 33, 32) + .EditPush(1, "45022100", "440220") + .Push(one)); + tests.push_back( + TestBuilder(CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIG, + "CHECKDATASIG with too little R padding", checkdatasigflags) + .PushSig(keys.key1, one, 33, 32) + .EditPush(1, "45022100", "440220") + .Push(one) + .ScriptError(SCRIPT_ERR_SIG_DER)); + tests.push_back( + TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKDATASIG, + "CHECKDATASIG with hybrid pubkey but no STRICTENC", + checkdatasigflags & ~SCRIPT_VERIFY_STRICTENC) + .PushSig(keys.key0, one) + .Push(one)); + tests.push_back( + TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKDATASIG, + "CHECKDATASIG with hybrid pubkey", checkdatasigflags) + .PushSig(keys.key0, one) + .Push(one) + .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); + tests.push_back( + TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKDATASIG + << OP_NOT, + "CHECKDATASIG with invalid hybrid pubkey but no STRICTENC", + SCRIPT_ENABLE_CHECKDATASIG) + .PushSig(keys.key0, one) + .DamagePush(10) + .Push(one)); + tests.push_back( + TestBuilder(CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKDATASIG, + "CHECKDATASIG with invalid hybrid pubkey", + checkdatasigflags) + .PushSig(keys.key0, one) + .DamagePush(10) + .Push(one) + .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); + + // Test OP_CHECKDATASIGVERIFY + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) + << OP_CHECKDATASIGVERIFY << OP_TRUE, + "Standard CHECKDATASIGVERIFY", + checkdatasigflags) + .PushSig(keys.key1, one) + .Push(one)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) + << OP_CHECKDATASIGVERIFY << OP_TRUE, + "CHECKDATASIGVERIFY with NULLFAIL flags", + checkdatasigflags) + .PushSig(keys.key1, one) + .Push(two) + .ScriptError(SCRIPT_ERR_SIG_NULLFAIL)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) + << OP_CHECKDATASIGVERIFY << OP_TRUE, + "CHECKDATASIGVERIFY without NULLFAIL flags", + checkdatasigflags & ~SCRIPT_VERIFY_NULLFAIL) + .PushSig(keys.key1, one) + .Push(two) + .ScriptError(SCRIPT_ERR_CHECKDATASIGVERIFY)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) + << OP_CHECKDATASIGVERIFY << OP_TRUE, + "CHECKDATASIGVERIFY empty signature", + checkdatasigflags) + .Num(0) + .Push(one) + .ScriptError(SCRIPT_ERR_CHECKDATASIGVERIFY)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) + << OP_CHECKDATASIGVERIFY << OP_TRUE, + "CHECKDATASIG with High S but no Low S", + checkdatasigflags) + .PushSig(keys.key1, one, 32, 33) + .Push(one)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) + << OP_CHECKDATASIGVERIFY << OP_TRUE, + "CHECKDATASIG with High S", + checkdatasigflags | SCRIPT_VERIFY_LOW_S) + .PushSig(keys.key1, one, 32, 33) + .Push(one) + .ScriptError(SCRIPT_ERR_SIG_HIGH_S)); + tests.push_back( + TestBuilder( + CScript() << ToByteVector(keys.pubkey1C) << OP_CHECKDATASIGVERIFY + << OP_TRUE, + "CHECKDATASIGVERIFY with too little R padding but no DERSIG", + checkdatasigflags & ~SCRIPT_VERIFY_STRICTENC) + .PushSig(keys.key1, one, 33, 32) + .EditPush(1, "45022100", "440220") + .Push(one)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey1C) + << OP_CHECKDATASIGVERIFY << OP_TRUE, + "CHECKDATASIGVERIFY with too little R padding", + checkdatasigflags) + .PushSig(keys.key1, one, 33, 32) + .EditPush(1, "45022100", "440220") + .Push(one) + .ScriptError(SCRIPT_ERR_SIG_DER)); + tests.push_back( + TestBuilder(CScript() << ToByteVector(keys.pubkey0H) + << OP_CHECKDATASIGVERIFY << OP_TRUE, + "CHECKDATASIGVERIFY with hybrid pubkey but no STRICTENC", + checkdatasigflags & ~SCRIPT_VERIFY_STRICTENC) + .PushSig(keys.key0, one) + .Push(one)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) + << OP_CHECKDATASIGVERIFY << OP_TRUE, + "CHECKDATASIGVERIFY with hybrid pubkey", + checkdatasigflags) + .PushSig(keys.key0, one) + .Push(one) + .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); + tests.push_back( + TestBuilder( + CScript() << ToByteVector(keys.pubkey0H) << OP_CHECKDATASIGVERIFY + << OP_TRUE, + "CHECKDATASIGVERIFY with invalid hybrid pubkey but no STRICTENC", + SCRIPT_ENABLE_CHECKDATASIG) + .PushSig(keys.key0, one) + .DamagePush(10) + .Push(one) + .ScriptError(SCRIPT_ERR_CHECKDATASIGVERIFY)); + tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0H) + << OP_CHECKDATASIGVERIFY << OP_TRUE, + "CHECKDATASIGVERIFY with invalid hybrid pubkey", + checkdatasigflags) + .PushSig(keys.key0, one) + .DamagePush(10) + .Push(one) + .ScriptError(SCRIPT_ERR_PUBKEYTYPE)); + std::set tests_set; {