Changeset View
Changeset View
Standalone View
Standalone View
src/test/checkdatasig_tests.cpp
Show All 35 Lines | KeyData() { | ||||
pubkeyC = privkeyC.GetPubKey(); | pubkeyC = privkeyC.GetPubKey(); | ||||
*const_cast<uint8_t *>(&pubkeyH[0]) = 0x06 | (pubkeyH[64] & 1); | *const_cast<uint8_t *>(&pubkeyH[0]) = 0x06 | (pubkeyH[64] & 1); | ||||
} | } | ||||
}; | }; | ||||
static void CheckError(uint32_t flags, const stacktype &original_stack, | static void CheckError(uint32_t flags, const stacktype &original_stack, | ||||
const CScript &script, ScriptError expected) { | const CScript &script, ScriptError expected) { | ||||
BaseSignatureChecker sigchecker; | BaseSignatureChecker sigchecker; | ||||
ScriptError err = SCRIPT_ERR_OK; | ScriptError err = ScriptError::OK; | ||||
stacktype stack{original_stack}; | stacktype stack{original_stack}; | ||||
bool r = EvalScript(stack, script, flags, sigchecker, &err); | bool r = EvalScript(stack, script, flags, sigchecker, &err); | ||||
BOOST_CHECK(!r); | BOOST_CHECK(!r); | ||||
BOOST_CHECK_EQUAL(err, expected); | BOOST_CHECK(err == expected); | ||||
} | } | ||||
static void CheckPass(uint32_t flags, const stacktype &original_stack, | static void CheckPass(uint32_t flags, const stacktype &original_stack, | ||||
const CScript &script, const stacktype &expected) { | const CScript &script, const stacktype &expected) { | ||||
BaseSignatureChecker sigchecker; | BaseSignatureChecker sigchecker; | ||||
ScriptError err = SCRIPT_ERR_OK; | ScriptError err = ScriptError::OK; | ||||
stacktype stack{original_stack}; | stacktype stack{original_stack}; | ||||
bool r = EvalScript(stack, script, flags, sigchecker, &err); | bool r = EvalScript(stack, script, flags, sigchecker, &err); | ||||
BOOST_CHECK(r); | BOOST_CHECK(r); | ||||
BOOST_CHECK_EQUAL(err, SCRIPT_ERR_OK); | BOOST_CHECK(err == ScriptError::OK); | ||||
BOOST_CHECK(stack == expected); | BOOST_CHECK(stack == expected); | ||||
} | } | ||||
/** | /** | ||||
* General utility functions to check for script passing/failing. | * General utility functions to check for script passing/failing. | ||||
*/ | */ | ||||
static void CheckTestResultForAllFlags(const stacktype &original_stack, | static void CheckTestResultForAllFlags(const stacktype &original_stack, | ||||
const CScript &script, | const CScript &script, | ||||
Show All 18 Lines | for (uint32_t flags : flagset) { | ||||
CheckError(flags | SCRIPT_VERIFY_CHECKDATASIG_SIGOPS, original_stack, | CheckError(flags | SCRIPT_VERIFY_CHECKDATASIG_SIGOPS, original_stack, | ||||
script, expected); | script, expected); | ||||
} | } | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(checkdatasig_test) { | BOOST_AUTO_TEST_CASE(checkdatasig_test) { | ||||
// Empty stack. | // Empty stack. | ||||
CheckErrorForAllFlags({}, CScript() << OP_CHECKDATASIG, | CheckErrorForAllFlags({}, CScript() << OP_CHECKDATASIG, | ||||
SCRIPT_ERR_INVALID_STACK_OPERATION); | ScriptError::INVALID_STACK_OPERATION); | ||||
CheckErrorForAllFlags({{0x00}}, CScript() << OP_CHECKDATASIG, | CheckErrorForAllFlags({{0x00}}, CScript() << OP_CHECKDATASIG, | ||||
SCRIPT_ERR_INVALID_STACK_OPERATION); | ScriptError::INVALID_STACK_OPERATION); | ||||
CheckErrorForAllFlags({{0x00}, {0x00}}, CScript() << OP_CHECKDATASIG, | CheckErrorForAllFlags({{0x00}, {0x00}}, CScript() << OP_CHECKDATASIG, | ||||
SCRIPT_ERR_INVALID_STACK_OPERATION); | ScriptError::INVALID_STACK_OPERATION); | ||||
CheckErrorForAllFlags({}, CScript() << OP_CHECKDATASIGVERIFY, | CheckErrorForAllFlags({}, CScript() << OP_CHECKDATASIGVERIFY, | ||||
SCRIPT_ERR_INVALID_STACK_OPERATION); | ScriptError::INVALID_STACK_OPERATION); | ||||
CheckErrorForAllFlags({{0x00}}, CScript() << OP_CHECKDATASIGVERIFY, | CheckErrorForAllFlags({{0x00}}, CScript() << OP_CHECKDATASIGVERIFY, | ||||
SCRIPT_ERR_INVALID_STACK_OPERATION); | ScriptError::INVALID_STACK_OPERATION); | ||||
CheckErrorForAllFlags({{0x00}, {0x00}}, CScript() << OP_CHECKDATASIGVERIFY, | CheckErrorForAllFlags({{0x00}, {0x00}}, CScript() << OP_CHECKDATASIGVERIFY, | ||||
SCRIPT_ERR_INVALID_STACK_OPERATION); | ScriptError::INVALID_STACK_OPERATION); | ||||
// Check various pubkey encoding. | // Check various pubkey encoding. | ||||
const valtype message{}; | const valtype message{}; | ||||
valtype vchHash(32); | valtype vchHash(32); | ||||
CSHA256().Write(message.data(), message.size()).Finalize(vchHash.data()); | CSHA256().Write(message.data(), message.size()).Finalize(vchHash.data()); | ||||
uint256 messageHash(vchHash); | uint256 messageHash(vchHash); | ||||
KeyData kd; | KeyData kd; | ||||
valtype pubkey = ToByteVector(kd.pubkey); | valtype pubkey = ToByteVector(kd.pubkey); | ||||
valtype pubkeyC = ToByteVector(kd.pubkeyC); | valtype pubkeyC = ToByteVector(kd.pubkeyC); | ||||
valtype pubkeyH = ToByteVector(kd.pubkeyH); | valtype pubkeyH = ToByteVector(kd.pubkeyH); | ||||
CheckTestResultForAllFlags({{}, message, pubkey}, | CheckTestResultForAllFlags({{}, message, pubkey}, | ||||
CScript() << OP_CHECKDATASIG, {{}}); | CScript() << OP_CHECKDATASIG, {{}}); | ||||
CheckTestResultForAllFlags({{}, message, pubkeyC}, | CheckTestResultForAllFlags({{}, message, pubkeyC}, | ||||
CScript() << OP_CHECKDATASIG, {{}}); | CScript() << OP_CHECKDATASIG, {{}}); | ||||
CheckErrorForAllFlags({{}, message, pubkey}, | CheckErrorForAllFlags({{}, message, pubkey}, | ||||
CScript() << OP_CHECKDATASIGVERIFY, | CScript() << OP_CHECKDATASIGVERIFY, | ||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | ScriptError::CHECKDATASIGVERIFY); | ||||
CheckErrorForAllFlags({{}, message, pubkeyC}, | CheckErrorForAllFlags({{}, message, pubkeyC}, | ||||
CScript() << OP_CHECKDATASIGVERIFY, | CScript() << OP_CHECKDATASIGVERIFY, | ||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | ScriptError::CHECKDATASIGVERIFY); | ||||
// Flags dependent checks. | // Flags dependent checks. | ||||
const CScript script = CScript() << OP_CHECKDATASIG << OP_NOT << OP_VERIFY; | const CScript script = CScript() << OP_CHECKDATASIG << OP_NOT << OP_VERIFY; | ||||
const CScript scriptverify = CScript() << OP_CHECKDATASIGVERIFY; | const CScript scriptverify = CScript() << OP_CHECKDATASIGVERIFY; | ||||
// Check valid signatures (as in the signature format is valid). | // Check valid signatures (as in the signature format is valid). | ||||
valtype validsig; | valtype validsig; | ||||
kd.privkey.SignECDSA(messageHash, validsig); | kd.privkey.SignECDSA(messageHash, validsig); | ||||
Show All 16 Lines | BOOST_AUTO_TEST_CASE(checkdatasig_test) { | ||||
MMIXLinearCongruentialGenerator lcg; | MMIXLinearCongruentialGenerator lcg; | ||||
for (int i = 0; i < 4096; i++) { | for (int i = 0; i < 4096; i++) { | ||||
uint32_t flags = lcg.next() | SCRIPT_VERIFY_CHECKDATASIG_SIGOPS; | uint32_t flags = lcg.next() | SCRIPT_VERIFY_CHECKDATASIG_SIGOPS; | ||||
if (flags & SCRIPT_VERIFY_STRICTENC) { | if (flags & SCRIPT_VERIFY_STRICTENC) { | ||||
// When strict encoding is enforced, hybrid keys are invalid. | // When strict encoding is enforced, hybrid keys are invalid. | ||||
CheckError(flags, {{}, message, pubkeyH}, script, | CheckError(flags, {{}, message, pubkeyH}, script, | ||||
SCRIPT_ERR_PUBKEYTYPE); | ScriptError::PUBKEYTYPE); | ||||
CheckError(flags, {{}, message, pubkeyH}, scriptverify, | CheckError(flags, {{}, message, pubkeyH}, scriptverify, | ||||
SCRIPT_ERR_PUBKEYTYPE); | ScriptError::PUBKEYTYPE); | ||||
} else if (flags & SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE) { | } else if (flags & SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE) { | ||||
// When compressed-only is enforced, hybrid keys are invalid. | // When compressed-only is enforced, hybrid keys are invalid. | ||||
CheckError(flags, {{}, message, pubkeyH}, script, | CheckError(flags, {{}, message, pubkeyH}, script, | ||||
SCRIPT_ERR_NONCOMPRESSED_PUBKEY); | ScriptError::NONCOMPRESSED_PUBKEY); | ||||
CheckError(flags, {{}, message, pubkeyH}, scriptverify, | CheckError(flags, {{}, message, pubkeyH}, scriptverify, | ||||
SCRIPT_ERR_NONCOMPRESSED_PUBKEY); | ScriptError::NONCOMPRESSED_PUBKEY); | ||||
} else { | } else { | ||||
// Otherwise, hybrid keys are valid. | // Otherwise, hybrid keys are valid. | ||||
CheckPass(flags, {{}, message, pubkeyH}, script, {}); | CheckPass(flags, {{}, message, pubkeyH}, script, {}); | ||||
CheckError(flags, {{}, message, pubkeyH}, scriptverify, | CheckError(flags, {{}, message, pubkeyH}, scriptverify, | ||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | ScriptError::CHECKDATASIGVERIFY); | ||||
} | } | ||||
if (flags & SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE) { | if (flags & SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE) { | ||||
// When compressed-only is enforced, uncompressed keys are invalid. | // When compressed-only is enforced, uncompressed keys are invalid. | ||||
CheckError(flags, {{}, message, pubkey}, script, | CheckError(flags, {{}, message, pubkey}, script, | ||||
SCRIPT_ERR_NONCOMPRESSED_PUBKEY); | ScriptError::NONCOMPRESSED_PUBKEY); | ||||
CheckError(flags, {{}, message, pubkey}, scriptverify, | CheckError(flags, {{}, message, pubkey}, scriptverify, | ||||
SCRIPT_ERR_NONCOMPRESSED_PUBKEY); | ScriptError::NONCOMPRESSED_PUBKEY); | ||||
} else { | } else { | ||||
// Otherwise, uncompressed keys are valid. | // Otherwise, uncompressed keys are valid. | ||||
CheckPass(flags, {{}, message, pubkey}, script, {}); | CheckPass(flags, {{}, message, pubkey}, script, {}); | ||||
CheckError(flags, {{}, message, pubkey}, scriptverify, | CheckError(flags, {{}, message, pubkey}, scriptverify, | ||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | ScriptError::CHECKDATASIGVERIFY); | ||||
} | } | ||||
if (flags & SCRIPT_VERIFY_NULLFAIL) { | if (flags & SCRIPT_VERIFY_NULLFAIL) { | ||||
// Invalid signature causes checkdatasig to fail. | // Invalid signature causes checkdatasig to fail. | ||||
CheckError(flags, {minimalsig, message, pubkeyC}, script, | CheckError(flags, {minimalsig, message, pubkeyC}, script, | ||||
SCRIPT_ERR_SIG_NULLFAIL); | ScriptError::SIG_NULLFAIL); | ||||
CheckError(flags, {minimalsig, message, pubkeyC}, scriptverify, | CheckError(flags, {minimalsig, message, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_SIG_NULLFAIL); | ScriptError::SIG_NULLFAIL); | ||||
// Invalid message causes checkdatasig to fail. | // Invalid message causes checkdatasig to fail. | ||||
CheckError(flags, {validsig, {0x01}, pubkeyC}, script, | CheckError(flags, {validsig, {0x01}, pubkeyC}, script, | ||||
SCRIPT_ERR_SIG_NULLFAIL); | ScriptError::SIG_NULLFAIL); | ||||
CheckError(flags, {validsig, {0x01}, pubkeyC}, scriptverify, | CheckError(flags, {validsig, {0x01}, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_SIG_NULLFAIL); | ScriptError::SIG_NULLFAIL); | ||||
} else { | } else { | ||||
// When nullfail is not enforced, invalid signature are just false. | // When nullfail is not enforced, invalid signature are just false. | ||||
CheckPass(flags, {minimalsig, message, pubkeyC}, script, {}); | CheckPass(flags, {minimalsig, message, pubkeyC}, script, {}); | ||||
CheckError(flags, {minimalsig, message, pubkeyC}, scriptverify, | CheckError(flags, {minimalsig, message, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | ScriptError::CHECKDATASIGVERIFY); | ||||
// Invalid message cause checkdatasig to fail. | // Invalid message cause checkdatasig to fail. | ||||
CheckPass(flags, {validsig, {0x01}, pubkeyC}, script, {}); | CheckPass(flags, {validsig, {0x01}, pubkeyC}, script, {}); | ||||
CheckError(flags, {validsig, {0x01}, pubkeyC}, scriptverify, | CheckError(flags, {validsig, {0x01}, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | ScriptError::CHECKDATASIGVERIFY); | ||||
} | } | ||||
if (flags & SCRIPT_VERIFY_LOW_S) { | if (flags & SCRIPT_VERIFY_LOW_S) { | ||||
// If we do enforce low S, then high S sigs are rejected. | // If we do enforce low S, then high S sigs are rejected. | ||||
CheckError(flags, {highSSig, message, pubkeyC}, script, | CheckError(flags, {highSSig, message, pubkeyC}, script, | ||||
SCRIPT_ERR_SIG_HIGH_S); | ScriptError::SIG_HIGH_S); | ||||
CheckError(flags, {highSSig, message, pubkeyC}, scriptverify, | CheckError(flags, {highSSig, message, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_SIG_HIGH_S); | ScriptError::SIG_HIGH_S); | ||||
} else if (flags & SCRIPT_VERIFY_NULLFAIL) { | } else if (flags & SCRIPT_VERIFY_NULLFAIL) { | ||||
// If we do enforce nullfail, these invalid sigs hit this. | // If we do enforce nullfail, these invalid sigs hit this. | ||||
CheckError(flags, {highSSig, message, pubkeyC}, script, | CheckError(flags, {highSSig, message, pubkeyC}, script, | ||||
SCRIPT_ERR_SIG_NULLFAIL); | ScriptError::SIG_NULLFAIL); | ||||
CheckError(flags, {highSSig, message, pubkeyC}, scriptverify, | CheckError(flags, {highSSig, message, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_SIG_NULLFAIL); | ScriptError::SIG_NULLFAIL); | ||||
} else { | } else { | ||||
// If we do not enforce low S, then high S sigs are accepted. | // If we do not enforce low S, then high S sigs are accepted. | ||||
CheckPass(flags, {highSSig, message, pubkeyC}, script, {}); | CheckPass(flags, {highSSig, message, pubkeyC}, script, {}); | ||||
CheckError(flags, {highSSig, message, pubkeyC}, scriptverify, | CheckError(flags, {highSSig, message, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | ScriptError::CHECKDATASIGVERIFY); | ||||
} | } | ||||
if (flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | | if (flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | | ||||
SCRIPT_VERIFY_STRICTENC)) { | SCRIPT_VERIFY_STRICTENC)) { | ||||
// If we get any of the dersig flags, the non canonical dersig | // If we get any of the dersig flags, the non canonical dersig | ||||
// signature fails. | // signature fails. | ||||
CheckError(flags, {nondersig, message, pubkeyC}, script, | CheckError(flags, {nondersig, message, pubkeyC}, script, | ||||
SCRIPT_ERR_SIG_DER); | ScriptError::SIG_DER); | ||||
CheckError(flags, {nondersig, message, pubkeyC}, scriptverify, | CheckError(flags, {nondersig, message, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_SIG_DER); | ScriptError::SIG_DER); | ||||
} else if (flags & SCRIPT_VERIFY_NULLFAIL) { | } else if (flags & SCRIPT_VERIFY_NULLFAIL) { | ||||
// If we do enforce nullfail, these invalid sigs hit this. | // If we do enforce nullfail, these invalid sigs hit this. | ||||
CheckError(flags, {nondersig, message, pubkeyC}, script, | CheckError(flags, {nondersig, message, pubkeyC}, script, | ||||
SCRIPT_ERR_SIG_NULLFAIL); | ScriptError::SIG_NULLFAIL); | ||||
CheckError(flags, {nondersig, message, pubkeyC}, scriptverify, | CheckError(flags, {nondersig, message, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_SIG_NULLFAIL); | ScriptError::SIG_NULLFAIL); | ||||
} else { | } else { | ||||
// If we do not check, then it is accepted. | // If we do not check, then it is accepted. | ||||
CheckPass(flags, {nondersig, message, pubkeyC}, script, {}); | CheckPass(flags, {nondersig, message, pubkeyC}, script, {}); | ||||
CheckError(flags, {nondersig, message, pubkeyC}, scriptverify, | CheckError(flags, {nondersig, message, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | ScriptError::CHECKDATASIGVERIFY); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(checkdatasig_inclusion_in_standard_and_mandatory_flags) { | BOOST_AUTO_TEST_CASE(checkdatasig_inclusion_in_standard_and_mandatory_flags) { | ||||
BOOST_CHECK(STANDARD_SCRIPT_VERIFY_FLAGS & | BOOST_CHECK(STANDARD_SCRIPT_VERIFY_FLAGS & | ||||
SCRIPT_VERIFY_CHECKDATASIG_SIGOPS); | SCRIPT_VERIFY_CHECKDATASIG_SIGOPS); | ||||
BOOST_CHECK( | BOOST_CHECK( | ||||
!(MANDATORY_SCRIPT_VERIFY_FLAGS & SCRIPT_VERIFY_CHECKDATASIG_SIGOPS)); | !(MANDATORY_SCRIPT_VERIFY_FLAGS & SCRIPT_VERIFY_CHECKDATASIG_SIGOPS)); | ||||
} | } | ||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |