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.
251bool CheckAfter(uint32_t value) const { return value % 2; }252bool CheckOlder(uint32_t value) const { return value % 2; }254// Signature challenges fulfilled with a dummy signature, if it was one of our dummy keys.255miniscript::Availability Sign(const CPubKey& key, std::vector<unsigned char>& sig) const {256bool sig_available{false};257if (auto res = TEST_DATA.GetSig(script_ctx, key)) {258std::tie(sig, sig_available) = *res;259}260return sig_available ? miniscript::Availability::YES : miniscript::Availability::NO;261}263//! Lookup generalization for all the hash satisfactions below264miniscript::Availability LookupHash(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage,265const std::map<std::vector<unsigned char>, std::vector<unsigned char>>& map) const266{267const auto it = map.find(hash);268if (it == map.end()) return miniscript::Availability::NO;269preimage = it->second;270return miniscript::Availability::YES;271}272miniscript::Availability SatSHA256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {273return LookupHash(hash, preimage, TEST_DATA.sha256_preimages);274}275miniscript::Availability SatRIPEMD160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {276return LookupHash(hash, preimage, TEST_DATA.ripemd160_preimages);277}278miniscript::Availability SatHASH256(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {279return LookupHash(hash, preimage, TEST_DATA.hash256_preimages);280}281miniscript::Availability SatHASH160(const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage) const {282return LookupHash(hash, preimage, TEST_DATA.hash160_preimages);283}284};286//! Context to check a satisfaction against the pre-computed data.287const struct CheckerContext: BaseSignatureChecker {288// Signature checker methods. Checks the right dummy signature is used.289bool CheckECDSASignature(const std::vector<unsigned char>& sig, const std::vector<unsigned char>& vchPubKey,290const CScript& scriptCode, SigVersion sigversion) const override291{292const CPubKey key{vchPubKey};293const auto it = TEST_DATA.dummy_sigs.find(key);294if (it == TEST_DATA.dummy_sigs.end()) return false;295return it->second.first == sig;296}297bool CheckSchnorrSignature(std::span<const unsigned char> sig, std::span<const unsigned char> pubkey, SigVersion,298ScriptExecutionData&, ScriptError*) const override {299XOnlyPubKey pk{pubkey};300auto it = TEST_DATA.schnorr_sigs.find(pk);301if (it == TEST_DATA.schnorr_sigs.end()) return false;302return std::ranges::equal(it->second.first, sig);303}304bool CheckLockTime(const CScriptNum& nLockTime) const override { return nLockTime.GetInt64() & 1; }305bool CheckSequence(const CScriptNum& nSequence) const override { return nSequence.GetInt64() & 1; }306} CHECKER_CTX;308//! Context to check for duplicates when instancing a Node.309const struct KeyComparator {310bool KeyCompare(const CPubKey& a, const CPubKey& b) const {311return a < b;312}313} KEY_COMP;315// A dummy scriptsig to pass to VerifyScript (we always use Segwit v0).316const CScript DUMMY_SCRIPTSIG;318/** Information about a yet to be constructed Miniscript node. */319struct NodeInfo {320//! The type of this node321Fragment fragment;322//! The timelock value for older() and after(), the threshold value for multi() and thresh()323uint32_t k;324//! Keys for this node, if it has some325std::vector<CPubKey> keys;326//! The hash value for this node, if it has one327std::vector<unsigned char> hash;328//! The type requirements for the children of this node.329std::vector<Type> subtypes;331NodeInfo(Fragment frag): fragment(frag), k(0) {}332NodeInfo(Fragment frag, CPubKey key): fragment(frag), k(0), keys({key}) {}333NodeInfo(Fragment frag, uint32_t _k): fragment(frag), k(_k) {}334NodeInfo(Fragment frag, std::vector<unsigned char> h): fragment(frag), k(0), hash(std::move(h)) {}335NodeInfo(std::vector<Type> subt, Fragment frag): fragment(frag), k(0), subtypes(std::move(subt)) {}336NodeInfo(std::vector<Type> subt, Fragment frag, uint32_t _k): fragment(frag), k(_k), subtypes(std::move(subt)) {}337NodeInfo(Fragment frag, uint32_t _k, std::vector<CPubKey> _keys): fragment(frag), k(_k), keys(std::move(_keys)) {}338};340/** Pick an index in a collection from a single byte in the fuzzer's output. */341template<typename T, typename A>342T ConsumeIndex(FuzzedDataProvider& provider, A& col) {343const uint8_t i = provider.ConsumeIntegral<uint8_t>();344return col[i];345}347CPubKey ConsumePubKey(FuzzedDataProvider& provider) {348return ConsumeIndex<CPubKey>(provider, TEST_DATA.dummy_keys);349}351std::vector<unsigned char> ConsumeSha256(FuzzedDataProvider& provider) {352return ConsumeIndex<std::vector<unsigned char>>(provider, TEST_DATA.sha256);353}355std::vector<unsigned char> ConsumeHash256(FuzzedDataProvider& provider) {356return ConsumeIndex<std::vector<unsigned char>>(provider, TEST_DATA.hash256);357}359std::vector<unsigned char> ConsumeRipemd160(FuzzedDataProvider& provider) {360return ConsumeIndex<std::vector<unsigned char>>(provider, TEST_DATA.ripemd160);361}363std::vector<unsigned char> ConsumeHash160(FuzzedDataProvider& provider) {364return ConsumeIndex<std::vector<unsigned char>>(provider, TEST_DATA.hash160);365}367std::optional<uint32_t> ConsumeTimeLock(FuzzedDataProvider& provider) {368const uint32_t k = provider.ConsumeIntegral<uint32_t>();369if (k == 0 || k >= 0x80000000) return {};370return k;371}373/**374* Consume a Miniscript node from the fuzzer's output.375*376* This version is intended to have a fixed, stable, encoding for Miniscript nodes:377* - The first byte sets the type of the fragment. 0, 1 and all non-leaf fragments but thresh() are a378* single byte.379* - For the other leaf fragments, the following bytes depend on their type.380* - For older() and after(), the next 4 bytes define the timelock value.381* - For pk_k(), pk_h(), and all hashes, the next byte defines the index of the value in the test data.382* - For multi(), the next 2 bytes define respectively the threshold and the number of keys. Then as many383* bytes as the number of keys define the index of each key in the test data.384* - For multi_a(), same as for multi() but the threshold and the keys count are encoded on two bytes.385* - For thresh(), the next byte defines the threshold value and the following one the number of subs.386*/387std::optional<NodeInfo> ConsumeNodeStable(MsCtx script_ctx, FuzzedDataProvider& provider, Type type_needed) {388bool allow_B = (type_needed == ""_mst) || (type_needed << "B"_mst);389bool allow_K = (type_needed == ""_mst) || (type_needed << "K"_mst);390bool allow_V = (type_needed == ""_mst) || (type_needed << "V"_mst);391bool allow_W = (type_needed == ""_mst) || (type_needed << "W"_mst);393switch (provider.ConsumeIntegral<uint8_t>()) {394case 0:395if (!allow_B) return {};396return {{Fragment::JUST_0}};397case 1:398if (!allow_B) return {};399return {{Fragment::JUST_1}};400case 2:401if (!allow_K) return {};402return {{Fragment::PK_K, ConsumePubKey(provider)}};403case 3:404if (!allow_K) return {};405return {{Fragment::PK_H, ConsumePubKey(provider)}};406case 4: {407if (!allow_B) return {};408const auto k = ConsumeTimeLock(provider);409if (!k) return {};410return {{Fragment::OLDER, *k}};411}412case 5: {413if (!allow_B) return {};414const auto k = ConsumeTimeLock(provider);415if (!k) return {};416return {{Fragment::AFTER, *k}};417}418case 6:419if (!allow_B) return {};420return {{Fragment::SHA256, ConsumeSha256(provider)}};421case 7:422if (!allow_B) return {};423return {{Fragment::HASH256, ConsumeHash256(provider)}};424case 8:425if (!allow_B) return {};426return {{Fragment::RIPEMD160, ConsumeRipemd160(provider)}};427case 9:428if (!allow_B) return {};429return {{Fragment::HASH160, ConsumeHash160(provider)}};430case 10: {431if (!allow_B || IsTapscript(script_ctx)) return {};432const auto k = provider.ConsumeIntegral<uint8_t>();433const auto n_keys = provider.ConsumeIntegral<uint8_t>();434if (n_keys > 20 || k == 0 || k > n_keys) return {};435std::vector<CPubKey> keys{n_keys};436for (auto& key: keys) key = ConsumePubKey(provider);437return {{Fragment::MULTI, k, std::move(keys)}};438}439case 11:440if (!(allow_B || allow_K || allow_V)) return {};441return {{{"B"_mst, type_needed, type_needed}, Fragment::ANDOR}};442case 12:443if (!(allow_B || allow_K || allow_V)) return {};444return {{{"V"_mst, type_needed}, Fragment::AND_V}};445case 13:446if (!allow_B) return {};447return {{{"B"_mst, "W"_mst}, Fragment::AND_B}};448case 15:449if (!allow_B) return {};450return {{{"B"_mst, "W"_mst}, Fragment::OR_B}};451case 16:452if (!allow_V) return {};453return {{{"B"_mst, "V"_mst}, Fragment::OR_C}};454case 17:455if (!allow_B) return {};456return {{{"B"_mst, "B"_mst}, Fragment::OR_D}};457case 18:458if (!(allow_B || allow_K || allow_V)) return {};459return {{{type_needed, type_needed}, Fragment::OR_I}};460case 19: {461if (!allow_B) return {};462auto k = provider.ConsumeIntegral<uint8_t>();463auto n_subs = provider.ConsumeIntegral<uint8_t>();464if (k == 0 || k > n_subs) return {};465std::vector<Type> subtypes;466subtypes.reserve(n_subs);467subtypes.emplace_back("B"_mst);468for (size_t i = 1; i < n_subs; ++i) subtypes.emplace_back("W"_mst);469return {{std::move(subtypes), Fragment::THRESH, k}};470}471case 20:472if (!allow_W) return {};473return {{{"B"_mst}, Fragment::WRAP_A}};474case 21:475if (!allow_W) return {};476return {{{"B"_mst}, Fragment::WRAP_S}};477case 22:478if (!allow_B) return {};479return {{{"K"_mst}, Fragment::WRAP_C}};480case 23:481if (!allow_B) return {};482return {{{"V"_mst}, Fragment::WRAP_D}};483case 24:484if (!allow_V) return {};485return {{{"B"_mst}, Fragment::WRAP_V}};486case 25:487if (!allow_B) return {};488return {{{"B"_mst}, Fragment::WRAP_J}};489case 26:490if (!allow_B) return {};491return {{{"B"_mst}, Fragment::WRAP_N}};492case 27: {493if (!allow_B || !IsTapscript(script_ctx)) return {};494const auto k = provider.ConsumeIntegral<uint16_t>();495const auto n_keys = provider.ConsumeIntegral<uint16_t>();496if (n_keys > 999 || k == 0 || k > n_keys) return {};497std::vector<CPubKey> keys{n_keys};498for (auto& key: keys) key = ConsumePubKey(provider);499return {{Fragment::MULTI_A, k, std::move(keys)}};500}
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.