Changeset View
Changeset View
Standalone View
Standalone View
src/test/checkdatasig_tests.cpp
// Copyright (c) 2018 The Bitcoin developers | // Copyright (c) 2018 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include "test/lcg.h" | |||||
#include "test/test_bitcoin.h" | #include "test/test_bitcoin.h" | ||||
#include "policy/policy.h" | #include "policy/policy.h" | ||||
#include "script/interpreter.h" | #include "script/interpreter.h" | ||||
#include <boost/test/unit_test.hpp> | #include <boost/test/unit_test.hpp> | ||||
#include <array> | #include <array> | ||||
#include <bitset> | |||||
typedef std::vector<uint8_t> valtype; | typedef std::vector<uint8_t> valtype; | ||||
typedef std::vector<valtype> stacktype; | typedef std::vector<valtype> stacktype; | ||||
BOOST_FIXTURE_TEST_SUITE(checkdatasig_tests, BasicTestingSetup) | BOOST_FIXTURE_TEST_SUITE(checkdatasig_tests, BasicTestingSetup) | ||||
std::array<uint32_t, 3> flagset{ | std::array<uint32_t, 3> flagset{ | ||||
{0, STANDARD_SCRIPT_VERIFY_FLAGS, MANDATORY_SCRIPT_VERIFY_FLAGS}}; | {0, STANDARD_SCRIPT_VERIFY_FLAGS, MANDATORY_SCRIPT_VERIFY_FLAGS}}; | ||||
▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(checkdatasig_test) { | ||||
const valtype highSSig{ | const valtype highSSig{ | ||||
0x30, 0x45, 0x02, 0x20, 0x3e, 0x45, 0x16, 0xda, 0x72, 0x53, 0xcf, 0x06, | 0x30, 0x45, 0x02, 0x20, 0x3e, 0x45, 0x16, 0xda, 0x72, 0x53, 0xcf, 0x06, | ||||
0x8e, 0xff, 0xec, 0x6b, 0x95, 0xc4, 0x12, 0x21, 0xc0, 0xcf, 0x3a, 0x8e, | 0x8e, 0xff, 0xec, 0x6b, 0x95, 0xc4, 0x12, 0x21, 0xc0, 0xcf, 0x3a, 0x8e, | ||||
0x6c, 0xcb, 0x8c, 0xbf, 0x17, 0x25, 0xb5, 0x62, 0xe9, 0xaf, 0xde, 0x2c, | 0x6c, 0xcb, 0x8c, 0xbf, 0x17, 0x25, 0xb5, 0x62, 0xe9, 0xaf, 0xde, 0x2c, | ||||
0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, | 0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, | ||||
0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, | 0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, | ||||
0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0}; | 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 | MMIXLinearCongruentialGenerator lcg; | ||||
// rewrite in the future to randomly pick a set of flags to evaluate. | for (int i = 0; i < 4096; i++) { | ||||
for (uint32_t flags = 0; flags < (1U << 18); flags++) { | uint32_t flags = lcg.next() | SCRIPT_ENABLE_CHECKDATASIG; | ||||
// Make sure we activate the opcodes. | |||||
flags |= SCRIPT_ENABLE_CHECKDATASIG; | |||||
if (flags & SCRIPT_VERIFY_STRICTENC) { | if (flags & SCRIPT_VERIFY_STRICTENC) { | ||||
// When strict encoding is enforced, hybrid key are invalid. | // When strict encoding is enforced, hybrid keys are invalid. | ||||
CheckError(flags, {{}, message, pubkeyH}, script, | CheckError(flags, {{}, message, pubkeyH}, script, | ||||
SCRIPT_ERR_PUBKEYTYPE); | SCRIPT_ERR_PUBKEYTYPE); | ||||
CheckError(flags, {{}, message, pubkeyH}, scriptverify, | CheckError(flags, {{}, message, pubkeyH}, scriptverify, | ||||
SCRIPT_ERR_PUBKEYTYPE); | SCRIPT_ERR_PUBKEYTYPE); | ||||
} else if (flags & SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE) { | |||||
// When compressed-only is enforced, hybrid keys are invalid. | |||||
CheckError(flags, {{}, message, pubkeyH}, script, | |||||
SCRIPT_ERR_NONCOMPRESSED_PUBKEY); | |||||
CheckError(flags, {{}, message, pubkeyH}, scriptverify, | |||||
SCRIPT_ERR_NONCOMPRESSED_PUBKEY); | |||||
} else { | } else { | ||||
// When strict encoding is not enforced, hybrid key 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); | SCRIPT_ERR_CHECKDATASIGVERIFY); | ||||
} | } | ||||
if (flags & SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE) { | |||||
// When compressed-only is enforced, uncompressed keys are invalid. | |||||
CheckError(flags, {{}, message, pubkey}, script, | |||||
SCRIPT_ERR_NONCOMPRESSED_PUBKEY); | |||||
CheckError(flags, {{}, message, pubkey}, scriptverify, | |||||
SCRIPT_ERR_NONCOMPRESSED_PUBKEY); | |||||
} else { | |||||
// Otherwise, uncompressed keys are valid. | |||||
CheckPass(flags, {{}, message, pubkey}, script, {}); | |||||
CheckError(flags, {{}, message, pubkey}, scriptverify, | |||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | |||||
} | |||||
if (flags & SCRIPT_VERIFY_NULLFAIL) { | if (flags & SCRIPT_VERIFY_NULLFAIL) { | ||||
// When strict encoding is enforced, hybrid key are invalid. | // Invalid signature causes checkdatasig to fail. | ||||
CheckError(flags, {minimalsig, message, pubkey}, script, | CheckError(flags, {minimalsig, message, pubkeyC}, script, | ||||
SCRIPT_ERR_SIG_NULLFAIL); | SCRIPT_ERR_SIG_NULLFAIL); | ||||
CheckError(flags, {minimalsig, message, pubkey}, scriptverify, | CheckError(flags, {minimalsig, message, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_SIG_NULLFAIL); | SCRIPT_ERR_SIG_NULLFAIL); | ||||
// Invalid message cause checkdatasig to fail. | // Invalid message causes checkdatasig to fail. | ||||
CheckError(flags, {validsig, {0x01}, pubkey}, script, | CheckError(flags, {validsig, {0x01}, pubkeyC}, script, | ||||
SCRIPT_ERR_SIG_NULLFAIL); | SCRIPT_ERR_SIG_NULLFAIL); | ||||
CheckError(flags, {validsig, {0x01}, pubkey}, scriptverify, | CheckError(flags, {validsig, {0x01}, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_SIG_NULLFAIL); | SCRIPT_ERR_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, pubkey}, script, {}); | CheckPass(flags, {minimalsig, message, pubkeyC}, script, {}); | ||||
CheckError(flags, {minimalsig, message, pubkey}, scriptverify, | CheckError(flags, {minimalsig, message, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | SCRIPT_ERR_CHECKDATASIGVERIFY); | ||||
// Invalid message cause checkdatasig to fail. | // Invalid message cause checkdatasig to fail. | ||||
CheckPass(flags, {validsig, {0x01}, pubkey}, script, {}); | CheckPass(flags, {validsig, {0x01}, pubkeyC}, script, {}); | ||||
CheckError(flags, {validsig, {0x01}, pubkey}, scriptverify, | CheckError(flags, {validsig, {0x01}, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | SCRIPT_ERR_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, pubkey}, script, | CheckError(flags, {highSSig, message, pubkeyC}, script, | ||||
SCRIPT_ERR_SIG_HIGH_S); | SCRIPT_ERR_SIG_HIGH_S); | ||||
CheckError(flags, {highSSig, message, pubkey}, scriptverify, | CheckError(flags, {highSSig, message, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_SIG_HIGH_S); | SCRIPT_ERR_SIG_HIGH_S); | ||||
} else if (flags & SCRIPT_VERIFY_NULLFAIL) { | |||||
// If we do enforce nullfail, these invalid sigs hit this. | |||||
CheckError(flags, {highSSig, message, pubkeyC}, script, | |||||
SCRIPT_ERR_SIG_NULLFAIL); | |||||
CheckError(flags, {highSSig, message, pubkeyC}, scriptverify, | |||||
SCRIPT_ERR_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, pubkey}, script, {}); | CheckPass(flags, {highSSig, message, pubkeyC}, script, {}); | ||||
CheckError(flags, {highSSig, message, pubkey}, scriptverify, | CheckError(flags, {highSSig, message, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | SCRIPT_ERR_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, pubkey}, script, | CheckError(flags, {nondersig, message, pubkeyC}, script, | ||||
SCRIPT_ERR_SIG_DER); | SCRIPT_ERR_SIG_DER); | ||||
CheckError(flags, {nondersig, message, pubkey}, scriptverify, | CheckError(flags, {nondersig, message, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_SIG_DER); | SCRIPT_ERR_SIG_DER); | ||||
} else if (flags & SCRIPT_VERIFY_NULLFAIL) { | |||||
// If we do enforce nullfail, these invalid sigs hit this. | |||||
CheckError(flags, {nondersig, message, pubkeyC}, script, | |||||
SCRIPT_ERR_SIG_NULLFAIL); | |||||
CheckError(flags, {nondersig, message, pubkeyC}, scriptverify, | |||||
SCRIPT_ERR_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, pubkey}, script, {}); | CheckPass(flags, {nondersig, message, pubkeyC}, script, {}); | ||||
CheckError(flags, {nondersig, message, pubkey}, scriptverify, | CheckError(flags, {nondersig, message, pubkeyC}, scriptverify, | ||||
SCRIPT_ERR_CHECKDATASIGVERIFY); | SCRIPT_ERR_CHECKDATASIGVERIFY); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |