Branch data Line data Source code
# 1 : : // Copyright (c) 2011-2021 The Bitcoin Core developers
# 2 : : // Distributed under the MIT software license, see the accompanying
# 3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
# 4 : :
# 5 : : #include <test/data/key_io_invalid.json.h>
# 6 : : #include <test/data/key_io_valid.json.h>
# 7 : :
# 8 : : #include <key.h>
# 9 : : #include <key_io.h>
# 10 : : #include <script/script.h>
# 11 : : #include <test/util/setup_common.h>
# 12 : : #include <util/strencodings.h>
# 13 : :
# 14 : : #include <boost/test/unit_test.hpp>
# 15 : :
# 16 : : #include <univalue.h>
# 17 : :
# 18 : : UniValue read_json(const std::string& jsondata);
# 19 : :
# 20 : : BOOST_FIXTURE_TEST_SUITE(key_io_tests, BasicTestingSetup)
# 21 : :
# 22 : : // Goal: check that parsed keys match test payload
# 23 : : BOOST_AUTO_TEST_CASE(key_io_valid_parse)
# 24 : 2 : {
# 25 : 2 : UniValue tests = read_json(std::string(json_tests::key_io_valid, json_tests::key_io_valid + sizeof(json_tests::key_io_valid)));
# 26 : 2 : CKey privkey;
# 27 : 2 : CTxDestination destination;
# 28 : 2 : SelectParams(CBaseChainParams::MAIN);
# 29 : :
# 30 [ + + ]: 142 : for (unsigned int idx = 0; idx < tests.size(); idx++) {
# 31 : 140 : UniValue test = tests[idx];
# 32 : 140 : std::string strTest = test.write();
# 33 [ - + ]: 140 : if (test.size() < 3) { // Allow for extra stuff (useful for comments)
# 34 : 0 : BOOST_ERROR("Bad test: " << strTest);
# 35 : 0 : continue;
# 36 : 0 : }
# 37 : 140 : std::string exp_base58string = test[0].get_str();
# 38 : 140 : std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
# 39 : 140 : const UniValue &metadata = test[2].get_obj();
# 40 : 140 : bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
# 41 : 140 : SelectParams(find_value(metadata, "chain").get_str());
# 42 [ + + ]: 140 : bool try_case_flip = find_value(metadata, "tryCaseFlip").isNull() ? false : find_value(metadata, "tryCaseFlip").get_bool();
# 43 [ + + ]: 140 : if (isPrivkey) {
# 44 : 32 : bool isCompressed = find_value(metadata, "isCompressed").get_bool();
# 45 : : // Must be valid private key
# 46 : 32 : privkey = DecodeSecret(exp_base58string);
# 47 : 32 : BOOST_CHECK_MESSAGE(privkey.IsValid(), "!IsValid:" + strTest);
# 48 : 32 : BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);
# 49 : 32 : BOOST_CHECK_MESSAGE(Span{privkey} == Span{exp_payload}, "key mismatch:" + strTest);
# 50 : :
# 51 : : // Private key must be invalid public key
# 52 : 32 : destination = DecodeDestination(exp_base58string);
# 53 : 32 : BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid privkey as pubkey:" + strTest);
# 54 : 108 : } else {
# 55 : : // Must be valid public key
# 56 : 108 : destination = DecodeDestination(exp_base58string);
# 57 : 108 : CScript script = GetScriptForDestination(destination);
# 58 : 108 : BOOST_CHECK_MESSAGE(IsValidDestination(destination), "!IsValid:" + strTest);
# 59 : 108 : BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload));
# 60 : :
# 61 : : // Try flipped case version
# 62 [ + + ]: 4944 : for (char& c : exp_base58string) {
# 63 [ + + ][ + - ]: 4944 : if (c >= 'a' && c <= 'z') {
# 64 : 3162 : c = (c - 'a') + 'A';
# 65 [ + + ][ + - ]: 3162 : } else if (c >= 'A' && c <= 'Z') {
# 66 : 606 : c = (c - 'A') + 'a';
# 67 : 606 : }
# 68 : 4944 : }
# 69 : 108 : destination = DecodeDestination(exp_base58string);
# 70 : 108 : BOOST_CHECK_MESSAGE(IsValidDestination(destination) == try_case_flip, "!IsValid case flipped:" + strTest);
# 71 [ + + ]: 108 : if (IsValidDestination(destination)) {
# 72 : 64 : script = GetScriptForDestination(destination);
# 73 : 64 : BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload));
# 74 : 64 : }
# 75 : :
# 76 : : // Public key must be invalid private key
# 77 : 108 : privkey = DecodeSecret(exp_base58string);
# 78 : 108 : BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid pubkey as privkey:" + strTest);
# 79 : 108 : }
# 80 : 140 : }
# 81 : 2 : }
# 82 : :
# 83 : : // Goal: check that generated keys match test vectors
# 84 : : BOOST_AUTO_TEST_CASE(key_io_valid_gen)
# 85 : 2 : {
# 86 : 2 : UniValue tests = read_json(std::string(json_tests::key_io_valid, json_tests::key_io_valid + sizeof(json_tests::key_io_valid)));
# 87 : :
# 88 [ + + ]: 142 : for (unsigned int idx = 0; idx < tests.size(); idx++) {
# 89 : 140 : UniValue test = tests[idx];
# 90 : 140 : std::string strTest = test.write();
# 91 [ - + ]: 140 : if (test.size() < 3) // Allow for extra stuff (useful for comments)
# 92 : 0 : {
# 93 : 0 : BOOST_ERROR("Bad test: " << strTest);
# 94 : 0 : continue;
# 95 : 0 : }
# 96 : 140 : std::string exp_base58string = test[0].get_str();
# 97 : 140 : std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
# 98 : 140 : const UniValue &metadata = test[2].get_obj();
# 99 : 140 : bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
# 100 : 140 : SelectParams(find_value(metadata, "chain").get_str());
# 101 [ + + ]: 140 : if (isPrivkey) {
# 102 : 32 : bool isCompressed = find_value(metadata, "isCompressed").get_bool();
# 103 : 32 : CKey key;
# 104 : 32 : key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);
# 105 : 32 : assert(key.IsValid());
# 106 : 0 : BOOST_CHECK_MESSAGE(EncodeSecret(key) == exp_base58string, "result mismatch: " + strTest);
# 107 : 108 : } else {
# 108 : 108 : CTxDestination dest;
# 109 : 108 : CScript exp_script(exp_payload.begin(), exp_payload.end());
# 110 : 108 : BOOST_CHECK(ExtractDestination(exp_script, dest));
# 111 : 108 : std::string address = EncodeDestination(dest);
# 112 : :
# 113 : 108 : BOOST_CHECK_EQUAL(address, exp_base58string);
# 114 : 108 : }
# 115 : 140 : }
# 116 : :
# 117 : 2 : SelectParams(CBaseChainParams::MAIN);
# 118 : 2 : }
# 119 : :
# 120 : :
# 121 : : // Goal: check that base58 parsing code is robust against a variety of corrupted data
# 122 : : BOOST_AUTO_TEST_CASE(key_io_invalid)
# 123 : 2 : {
# 124 : 2 : UniValue tests = read_json(std::string(json_tests::key_io_invalid, json_tests::key_io_invalid + sizeof(json_tests::key_io_invalid))); // Negative testcases
# 125 : 2 : CKey privkey;
# 126 : 2 : CTxDestination destination;
# 127 : :
# 128 [ + + ]: 142 : for (unsigned int idx = 0; idx < tests.size(); idx++) {
# 129 : 140 : UniValue test = tests[idx];
# 130 : 140 : std::string strTest = test.write();
# 131 [ - + ]: 140 : if (test.size() < 1) // Allow for extra stuff (useful for comments)
# 132 : 0 : {
# 133 : 0 : BOOST_ERROR("Bad test: " << strTest);
# 134 : 0 : continue;
# 135 : 0 : }
# 136 : 140 : std::string exp_base58string = test[0].get_str();
# 137 : :
# 138 : : // must be invalid as public and as private key
# 139 [ + + ]: 560 : for (const auto& chain : { CBaseChainParams::MAIN, CBaseChainParams::TESTNET, CBaseChainParams::SIGNET, CBaseChainParams::REGTEST }) {
# 140 : 560 : SelectParams(chain);
# 141 : 560 : destination = DecodeDestination(exp_base58string);
# 142 : 560 : BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey in mainnet:" + strTest);
# 143 : 560 : privkey = DecodeSecret(exp_base58string);
# 144 : 560 : BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid privkey in mainnet:" + strTest);
# 145 : 560 : }
# 146 : 140 : }
# 147 : 2 : }
# 148 : :
# 149 : : BOOST_AUTO_TEST_SUITE_END()
|