Changeset View
Changeset View
Standalone View
Standalone View
src/test/sigencoding_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/test_bitcoin.h" | #include "test/test_bitcoin.h" | ||||
#include "script/script_flags.h" | #include "script/script_flags.h" | ||||
#include "script/sigencoding.h" | #include "script/sigencoding.h" | ||||
#include <boost/test/unit_test.hpp> | #include <boost/test/unit_test.hpp> | ||||
BOOST_FIXTURE_TEST_SUITE(sigencoding_tests, BasicTestingSetup) | BOOST_FIXTURE_TEST_SUITE(sigencoding_tests, BasicTestingSetup) | ||||
static uint64_t next(uint64_t x) { | |||||
// Simple linear congruential generator by Donald Knuth. | |||||
return x * 6364136223846793005 + 1442695040888963407; | |||||
} | |||||
static valtype SignatureWithHashType(valtype vchSig, SigHashType sigHash) { | static valtype SignatureWithHashType(valtype vchSig, SigHashType sigHash) { | ||||
vchSig.push_back(static_cast<uint8_t>(sigHash.getRawSigHashType())); | vchSig.push_back(static_cast<uint8_t>(sigHash.getRawSigHashType())); | ||||
return vchSig; | return vchSig; | ||||
} | } | ||||
static void CheckSignatureEncodingWithSigHashType(const valtype &vchSig, | static void CheckSignatureEncodingWithSigHashType(const valtype &vchSig, | ||||
uint32_t flags) { | uint32_t flags) { | ||||
ScriptError err = SCRIPT_ERR_OK; | ScriptError err = SCRIPT_ERR_OK; | ||||
▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | std::vector<valtype> nonParsableSigs{ | ||||
0xcf, 0x06, 0x8e, 0xff, 0xec, 0x6b, 0x95, 0xc4, 0x12, 0x21, 0xc0, | 0xcf, 0x06, 0x8e, 0xff, 0xec, 0x6b, 0x95, 0xc4, 0x12, 0x21, 0xc0, | ||||
0xcf, 0x3a, 0x8e, 0x6c, 0xcb, 0x8c, 0xbf, 0x17, 0x25, 0xb5, 0x62, | 0xcf, 0x3a, 0x8e, 0x6c, 0xcb, 0x8c, 0xbf, 0x17, 0x25, 0xb5, 0x62, | ||||
0xe9, 0xaf, 0xde, 0x2c, 0x02, 0x22, 0x00, 0xab, 0x1e, 0x3d, 0x00, | 0xe9, 0xaf, 0xde, 0x2c, 0x02, 0x22, 0x00, 0xab, 0x1e, 0x3d, 0x00, | ||||
0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, | 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45, 0xa2, 0x0e, 0x0b, 0x99, 0x9e, | ||||
0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, | 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5, 0x48, 0x0d, 0x48, 0x5f, | ||||
0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0}, | 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0}, | ||||
}; | }; | ||||
// If we add many more flags, this loop can get too expensive, but we can | // Use LCG to probe pseudorandom flag patterns: | ||||
// rewrite in the future to randomly pick a set of flags to evaluate. | // first 0x14057b7e, | ||||
for (uint32_t flags = 0; flags < (1U << 17); flags++) { | // then 0x1a08ee11, | ||||
// then 0x9af67822, | |||||
// ... | |||||
// With 4096 iterations, for every possible quadruple of flags you can | |||||
// name, there are at least 199 iterations with all four flags on, and at | |||||
// least 194 iterations with all four flags off. | |||||
uint64_t randstate = 0; | |||||
for (int i = 0; i < 4096; i++) { | |||||
randstate = next(randstate); | |||||
uint32_t flags = randstate >> 32; | |||||
deadalnix: Update the state after picking a value, this ensure we test all zeros. | |||||
markblundebergAuthorUnsubmitted Done Inline Actions👍 markblundeberg: 👍 | |||||
if (i == 99) { | |||||
// make sure the LCG is producing expected values | |||||
BOOST_CHECK_EQUAL(flags, 0xf306b780); | |||||
} | |||||
deadalnixUnsubmitted Not Done Inline ActionsIf you feel this is require,d it's probably better to encapsulate the generator in its own class and write tests for it. This is fairly unrelated to what is tested here. It also seems logical to do that because this is already the second place where this generator is used now. deadalnix: If you feel this is require,d it's probably better to encapsulate the generator in its own… | |||||
markblundebergAuthorUnsubmitted Done Inline ActionsHmm true. I think the class is overkill at the moment but I'll make a separate boost test for this purpose. (My worry with this test is that maybe some architectures don't do the 64 bit multiplication wraparound correctly, and thus maybe get stuck into a small cycle) markblundeberg: Hmm true. I think the class is overkill at the moment but I'll make a separate boost test for… | |||||
ScriptError err = SCRIPT_ERR_OK; | ScriptError err = SCRIPT_ERR_OK; | ||||
// Empty sig is always valid. | // Empty sig is always valid. | ||||
BOOST_CHECK(CheckDataSignatureEncoding({}, flags, &err)); | BOOST_CHECK(CheckDataSignatureEncoding({}, flags, &err)); | ||||
BOOST_CHECK(CheckTransactionSignatureEncoding({}, flags, &err)); | BOOST_CHECK(CheckTransactionSignatureEncoding({}, flags, &err)); | ||||
BOOST_CHECK(CheckTransactionECDSASignatureEncoding({}, flags, &err)); | BOOST_CHECK(CheckTransactionECDSASignatureEncoding({}, flags, &err)); | ||||
// Signature are valid as long as the forkid flag is correct. | // Signature are valid as long as the forkid flag is correct. | ||||
▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | std::vector<valtype> invalidKeys{ | ||||
0x9a, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xde, | 0x9a, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xde, | ||||
0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, | 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x0f, 0xff}, | ||||
// Full key, compressed key size. | // Full key, compressed key size. | ||||
{0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, | {0x04, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, | ||||
0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0xab, 0xba, 0x9a, | 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0xab, 0xba, 0x9a, | ||||
0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, | 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0}, | ||||
}; | }; | ||||
// If we add many more flags, this loop can get too expensive, but we can | // Use LCG to probe pseudorandom flag patterns: | ||||
// rewrite in the future to randomly pick a set of flags to evaluate. | // first 0x14057b7e, | ||||
for (uint32_t flags = 0; flags < (1U << 17); flags++) { | // then 0x1a08ee11, | ||||
// then 0x9af67822, | |||||
// ... | |||||
// With 4096 iterations, for every possible quadruple of flags you can | |||||
// name, there are at least 199 iterations with all four flags on, and at | |||||
// least 194 iterations with all four flags off. | |||||
uint64_t randstate = 0; | |||||
for (int i = 0; i < 4096; i++) { | |||||
randstate = next(randstate); | |||||
uint32_t flags = randstate >> 32; | |||||
deadalnixUnsubmitted Not Done Inline Actionsdito deadalnix: dito | |||||
if (i == 99) { | |||||
// make sure the LCG is producing expected values | |||||
BOOST_CHECK_EQUAL(flags, 0xf306b780); | |||||
} | |||||
deadalnixUnsubmitted Not Done Inline Actionsdito deadalnix: dito | |||||
ScriptError err = SCRIPT_ERR_OK; | ScriptError err = SCRIPT_ERR_OK; | ||||
// Compressed pubkeys are always valid. | // Compressed pubkeys are always valid. | ||||
BOOST_CHECK(CheckPubKeyEncoding(compressedKey0, flags, &err)); | BOOST_CHECK(CheckPubKeyEncoding(compressedKey0, flags, &err)); | ||||
BOOST_CHECK(CheckPubKeyEncoding(compressedKey1, flags, &err)); | BOOST_CHECK(CheckPubKeyEncoding(compressedKey1, flags, &err)); | ||||
// If SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE is specified, full key are | // If SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE is specified, full key are | ||||
// disabled. | // disabled. | ||||
Show All 25 Lines |
Update the state after picking a value, this ensure we test all zeros.