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) 2019-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/util/random.h>6#include <test/util/setup_common.h>7#include <boost/test/unit_test.hpp>9#include <addresstype.h>10#include <core_io.h>11#include <hash.h>12#include <pubkey.h>13#include <uint256.h>14#include <crypto/ripemd160.h>15#include <crypto/sha256.h>16#include <script/interpreter.h>17#include <script/miniscript.h>18#include <script/script_error.h>19#include <script/signingprovider.h>21#include <algorithm>22#include <cstdint>23#include <string>24#include <vector>26using namespace util::hex_literals;28namespace {30/** TestData groups various kinds of precomputed data necessary in this test. */31struct TestData {32//! The only public keys used in this test.33std::vector<CPubKey> pubkeys;34//! A map from the public keys to their CKeyIDs (faster than hashing every time).35std::map<CPubKey, CKeyID> pkhashes;36std::map<CKeyID, CPubKey> pkmap;37std::map<XOnlyPubKey, CKeyID> xonly_pkhashes;38std::map<CPubKey, std::vector<unsigned char>> signatures;39std::map<XOnlyPubKey, std::vector<unsigned char>> schnorr_signatures;41// Various precomputed hashes42std::vector<std::vector<unsigned char>> sha256;43std::vector<std::vector<unsigned char>> ripemd160;44std::vector<std::vector<unsigned char>> hash256;45std::vector<std::vector<unsigned char>> hash160;46std::map<std::vector<unsigned char>, std::vector<unsigned char>> sha256_preimages;47std::map<std::vector<unsigned char>, std::vector<unsigned char>> ripemd160_preimages;48std::map<std::vector<unsigned char>, std::vector<unsigned char>> hash256_preimages;49std::map<std::vector<unsigned char>, std::vector<unsigned char>> hash160_preimages;51TestData()52{53// All our signatures sign (and are required to sign) this constant message.54constexpr uint256 MESSAGE_HASH{"0000000000000000f5cd94e18b6fe77dd7aca9e35c2b0c9cbd86356c80a71065"};55// We don't pass additional randomness when creating a schnorr signature.56const auto EMPTY_AUX{uint256::ZERO};58// We generate 255 public keys and 255 hashes of each type.59for (int i = 1; i <= 255; ++i) {60// This 32-byte array functions as both private key data and hash preimage (31 zero bytes plus any nonzero byte).61unsigned char keydata[32] = {0};62keydata[31] = i;64// Compute CPubkey and CKeyID65CKey key;66key.Set(keydata, keydata + 32, true);67CPubKey pubkey = key.GetPubKey();68CKeyID keyid = pubkey.GetID();69pubkeys.push_back(pubkey);70pkhashes.emplace(pubkey, keyid);71pkmap.emplace(keyid, pubkey);72XOnlyPubKey xonly_pubkey{pubkey};73uint160 xonly_hash{Hash160(xonly_pubkey)};74xonly_pkhashes.emplace(xonly_pubkey, xonly_hash);75pkmap.emplace(xonly_hash, pubkey);77// Compute ECDSA signatures on MESSAGE_HASH with the private keys.78std::vector<unsigned char> sig, schnorr_sig(64);79BOOST_CHECK(key.Sign(MESSAGE_HASH, sig));80sig.push_back(1); // sighash byte81signatures.emplace(pubkey, sig);82BOOST_CHECK(key.SignSchnorr(MESSAGE_HASH, schnorr_sig, nullptr, EMPTY_AUX));83schnorr_sig.push_back(1); // Maximally sized Schnorr sigs have a sighash byte.84schnorr_signatures.emplace(XOnlyPubKey{pubkey}, schnorr_sig);86// Compute various hashes87std::vector<unsigned char> hash;88hash.resize(32);89CSHA256().Write(keydata, 32).Finalize(hash.data());90sha256.push_back(hash);91sha256_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);92CHash256().Write(keydata).Finalize(hash);93hash256.push_back(hash);94hash256_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);95hash.resize(20);96CRIPEMD160().Write(keydata, 32).Finalize(hash.data());97ripemd160.push_back(hash);98ripemd160_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);99CHash160().Write(keydata).Finalize(hash);100hash160.push_back(hash);101hash160_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);102}103}104};106//! Global TestData object107std::unique_ptr<const TestData> g_testdata;109//! A classification of leaf conditions in miniscripts (excluding true/false).110enum class ChallengeType {111SHA256,112RIPEMD160,113HASH256,114HASH160,115OLDER,116AFTER,117PK118};120/* With each leaf condition we associate a challenge number.121* For hashes it's just the first 4 bytes of the hash. For pubkeys, it's the last 4 bytes.122*/123uint32_t ChallengeNumber(const CPubKey& pubkey) { return ReadLE32(pubkey.data() + 29); }124uint32_t ChallengeNumber(const std::vector<unsigned char>& hash) { return ReadLE32(hash.data()); }126//! A Challenge is a combination of type of leaf condition and its challenge number.127typedef std::pair<ChallengeType, uint32_t> Challenge;129/** A class encapulating conversion routing for CPubKey. */130struct KeyConverter {131typedef CPubKey Key;133const miniscript::MiniscriptContext m_script_ctx;135constexpr KeyConverter(miniscript::MiniscriptContext ctx) noexcept : m_script_ctx{ctx} {}137bool KeyCompare(const Key& a, const Key& b) const {138return a < b;139}141//! Convert a public key to bytes.142std::vector<unsigned char> ToPKBytes(const CPubKey& key) const {143if (!miniscript::IsTapscript(m_script_ctx)) {144return {key.begin(), key.end()};145}146const XOnlyPubKey xonly_pubkey{key};147return {xonly_pubkey.begin(), xonly_pubkey.end()};148}150//! Convert a public key to its Hash160 bytes (precomputed).151std::vector<unsigned char> ToPKHBytes(const CPubKey& key) const {152if (!miniscript::IsTapscript(m_script_ctx)) {153auto hash = g_testdata->pkhashes.at(key);154return {hash.begin(), hash.end()};155}156const XOnlyPubKey xonly_key{key};157auto hash = g_testdata->xonly_pkhashes.at(xonly_key);158return {hash.begin(), hash.end()};159}161//! Parse a public key from a range of hex characters.162std::optional<Key> FromString(std::span<const char>& in) const {163auto bytes = ParseHex(std::string(in.begin(), in.end()));164Key key{bytes.begin(), bytes.end()};165if (key.IsValid()) return key;166return {};167}169template<typename I>170std::optional<Key> FromPKBytes(I first, I last) const {171if (!miniscript::IsTapscript(m_script_ctx)) {172Key key{first, last};173if (key.IsValid()) return key;174return {};175}176if (last - first != 32) return {};177XOnlyPubKey xonly_pubkey;178std::copy(first, last, xonly_pubkey.begin());179return xonly_pubkey.GetEvenCorrespondingCPubKey();180}182template<typename I>183std::optional<Key> FromPKHBytes(I first, I last) const {184assert(last - first == 20);185CKeyID keyid;186std::copy(first, last, keyid.begin());187return g_testdata->pkmap.at(keyid);188}190std::optional<std::string> ToString(const Key& key, bool&) const {191return HexStr(ToPKBytes(key));192}194miniscript::MiniscriptContext MsContext() const {195return m_script_ctx;196}197};199/** A class that encapsulates all signing/hash revealing operations. */200struct Satisfier : public KeyConverter {202Satisfier(miniscript::MiniscriptContext ctx) noexcept : KeyConverter{ctx} {}204//! Which keys/timelocks/hash preimages are available.205std::set<Challenge> supported;207//! Implement simplified CLTV logic: stack value must exactly match an entry in `supported`.208bool CheckAfter(uint32_t value) const {209return supported.contains(Challenge(ChallengeType::AFTER, value));210}212//! Implement simplified CSV logic: stack value must exactly match an entry in `supported`.213bool CheckOlder(uint32_t value) const {214return supported.contains(Challenge(ChallengeType::OLDER, value));215}217//! Produce a signature for the given key.218miniscript::Availability Sign(const CPubKey& key, std::vector<unsigned char>& sig) const {219if (supported.contains(Challenge(ChallengeType::PK, ChallengeNumber(key)))) {220if (!miniscript::IsTapscript(m_script_ctx)) {221auto it = g_testdata->signatures.find(key);222if (it == g_testdata->signatures.end()) return miniscript::Availability::NO;223sig = it->second;224} else {225auto it = g_testdata->schnorr_signatures.find(XOnlyPubKey{key});226if (it == g_testdata->schnorr_signatures.end()) return miniscript::Availability::NO;227sig = it->second;228}229return miniscript::Availability::YES;230}231return miniscript::Availability::NO;232}234//! Helper function for the various hash based satisfactions.235miniscript::Availability SatHash(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage, ChallengeType chtype) const {236if (!supported.contains(Challenge(chtype, ChallengeNumber(hash)))) return miniscript::Availability::NO;237const auto& m =238chtype == ChallengeType::SHA256 ? g_testdata->sha256_preimages :239chtype == ChallengeType::HASH256 ? g_testdata->hash256_preimages :240chtype == ChallengeType::RIPEMD160 ? g_testdata->ripemd160_preimages :241g_testdata->hash160_preimages;242auto it = m.find(hash);243if (it == m.end()) return miniscript::Availability::NO;244preimage = it->second;245return miniscript::Availability::YES;246}248// Functions that produce the preimage for hashes of various types.249miniscript::Availability SatSHA256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return SatHash(hash, preimage, ChallengeType::SHA256); }250miniscript::Availability SatRIPEMD160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const { return SatHash(hash, preimage, ChallengeType::RIPEMD160); }
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.