Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2011-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <test/data/key_io_invalid.json.h>6#include <test/data/key_io_valid.json.h>8#include <key.h>9#include <key_io.h>10#include <script/script.h>11#include <test/util/json.h>12#include <test/util/setup_common.h>13#include <univalue.h>14#include <util/chaintype.h>15#include <util/strencodings.h>17#include <boost/test/unit_test.hpp>19#include <algorithm>21BOOST_FIXTURE_TEST_SUITE(key_io_tests, BasicTestingSetup)23// Goal: check that parsed keys match test payload24BOOST_AUTO_TEST_CASE(key_io_valid_parse)25{26UniValue tests = read_json(json_tests::key_io_valid);27CKey privkey;28CTxDestination destination;29SelectParams(ChainType::MAIN);31for (unsigned int idx = 0; idx < tests.size(); idx++) {32const UniValue& test = tests[idx];33std::string strTest = test.write();34if (test.size() < 3) { // Allow for extra stuff (useful for comments)35BOOST_ERROR("Bad test: " << strTest);36continue;37}38std::string exp_base58string = test[0].get_str();39const std::vector<std::byte> exp_payload{ParseHex<std::byte>(test[1].get_str())};40const UniValue &metadata = test[2].get_obj();41bool isPrivkey = metadata.find_value("isPrivkey").get_bool();42SelectParams(ChainTypeFromString(metadata.find_value("chain").get_str()).value());43bool try_case_flip = metadata.find_value("tryCaseFlip").isNull() ? false : metadata.find_value("tryCaseFlip").get_bool();44if (isPrivkey) {45bool isCompressed = metadata.find_value("isCompressed").get_bool();46// Must be valid private key47privkey = DecodeSecret(exp_base58string);48BOOST_CHECK_MESSAGE(privkey.IsValid(), "!IsValid:" + strTest);49BOOST_CHECK_MESSAGE(privkey.IsCompressed() == isCompressed, "compressed mismatch:" + strTest);50BOOST_CHECK_MESSAGE(std::ranges::equal(privkey, exp_payload), "key mismatch:" + strTest);52// Private key must be invalid public key53destination = DecodeDestination(exp_base58string);54BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid privkey as pubkey:" + strTest);55} else {56// Must be valid public key57destination = DecodeDestination(exp_base58string);58CScript script = GetScriptForDestination(destination);59BOOST_CHECK_MESSAGE(IsValidDestination(destination), "!IsValid:" + strTest);60BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload));62// Try flipped case version63for (char& c : exp_base58string) {64if (c >= 'a' && c <= 'z') {65c = (c - 'a') + 'A';66} else if (c >= 'A' && c <= 'Z') {67c = (c - 'A') + 'a';68}69}70destination = DecodeDestination(exp_base58string);71BOOST_CHECK_MESSAGE(IsValidDestination(destination) == try_case_flip, "!IsValid case flipped:" + strTest);72if (IsValidDestination(destination)) {73script = GetScriptForDestination(destination);74BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload));75}77// Public key must be invalid private key78privkey = DecodeSecret(exp_base58string);79BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid pubkey as privkey:" + strTest);80}81}82}84// Goal: check that generated keys match test vectors85BOOST_AUTO_TEST_CASE(key_io_valid_gen)86{87UniValue tests = read_json(json_tests::key_io_valid);89for (unsigned int idx = 0; idx < tests.size(); idx++) {90const UniValue& test = tests[idx];91std::string strTest = test.write();92if (test.size() < 3) // Allow for extra stuff (useful for comments)93{94BOOST_ERROR("Bad test: " << strTest);95continue;96}97std::string exp_base58string = test[0].get_str();98std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());99const UniValue &metadata = test[2].get_obj();100bool isPrivkey = metadata.find_value("isPrivkey").get_bool();101SelectParams(ChainTypeFromString(metadata.find_value("chain").get_str()).value());102if (isPrivkey) {103bool isCompressed = metadata.find_value("isCompressed").get_bool();104CKey key;105key.Set(exp_payload.begin(), exp_payload.end(), isCompressed);106assert(key.IsValid());107BOOST_CHECK_MESSAGE(EncodeSecret(key) == exp_base58string, "result mismatch: " + strTest);108} else {109CTxDestination dest;110CScript exp_script(exp_payload.begin(), exp_payload.end());111BOOST_CHECK(ExtractDestination(exp_script, dest));112std::string address = EncodeDestination(dest);114BOOST_CHECK_EQUAL(address, exp_base58string);115}116}118SelectParams(ChainType::MAIN);119}122// Goal: check that base58 parsing code is robust against a variety of corrupted data123BOOST_AUTO_TEST_CASE(key_io_invalid)124{125UniValue tests = read_json(json_tests::key_io_invalid); // Negative testcases126CKey privkey;127CTxDestination destination;129for (unsigned int idx = 0; idx < tests.size(); idx++) {130const UniValue& test = tests[idx];131std::string strTest = test.write();132if (test.size() < 1) // Allow for extra stuff (useful for comments)133{134BOOST_ERROR("Bad test: " << strTest);135continue;136}137std::string exp_base58string = test[0].get_str();139// must be invalid as public and as private key140for (const auto& chain : {ChainType::MAIN, ChainType::TESTNET, ChainType::SIGNET, ChainType::REGTEST}) {141SelectParams(chain);142destination = DecodeDestination(exp_base58string);143BOOST_CHECK_MESSAGE(!IsValidDestination(destination), "IsValid pubkey in mainnet:" + strTest);144privkey = DecodeSecret(exp_base58string);145BOOST_CHECK_MESSAGE(!privkey.IsValid(), "IsValid privkey in mainnet:" + strTest);146}147}148}150BOOST_AUTO_TEST_SUITE_END()
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.