26using miniscript::operator
""_mst;
33 std::vector<Key> dummy_keys;
34 std::map<Key, int> dummy_key_idx_map;
35 std::map<CKeyID, Key> dummy_keys_map;
36 std::map<Key, std::pair<std::vector<unsigned char>,
bool>> dummy_sigs;
37 std::map<XOnlyPubKey, std::pair<std::vector<unsigned char>,
bool>> schnorr_sigs;
40 std::vector<std::vector<unsigned char>> sha256;
41 std::vector<std::vector<unsigned char>> ripemd160;
42 std::vector<std::vector<unsigned char>> hash256;
43 std::vector<std::vector<unsigned char>> hash160;
44 std::map<std::vector<unsigned char>, std::vector<unsigned char>> sha256_preimages;
45 std::map<std::vector<unsigned char>, std::vector<unsigned char>> ripemd160_preimages;
46 std::map<std::vector<unsigned char>, std::vector<unsigned char>> hash256_preimages;
47 std::map<std::vector<unsigned char>, std::vector<unsigned char>> hash160_preimages;
51 unsigned char keydata[32] = {1};
53 constexpr uint256 MESSAGE_HASH{
"0000000000000000f5cd94e18b6fe77dd7aca9e35c2b0c9cbd86356c80a71065"};
57 for (
size_t i = 0; i < 256; i++) {
60 privkey.
Set(keydata, keydata + 32,
true);
63 dummy_keys.push_back(pubkey);
64 dummy_key_idx_map.emplace(pubkey, i);
65 dummy_keys_map.insert({pubkey.GetID(), pubkey});
66 XOnlyPubKey xonly_pubkey{pubkey};
67 dummy_key_idx_map.emplace(xonly_pubkey, i);
68 uint160 xonly_hash{
Hash160(xonly_pubkey)};
69 dummy_keys_map.emplace(xonly_hash, pubkey);
71 std::vector<unsigned char> sig, schnorr_sig(64);
72 privkey.
Sign(MESSAGE_HASH, sig);
74 dummy_sigs.insert({pubkey, {sig, i & 1}});
76 schnorr_sig.push_back(1);
77 schnorr_sigs.emplace(XOnlyPubKey{pubkey}, std::make_pair(std::move(schnorr_sig), i & 1));
79 std::vector<unsigned char> hash;
81 CSHA256().Write(keydata, 32).Finalize(hash.data());
82 sha256.push_back(hash);
83 if (i & 1) sha256_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
84 CHash256().Write(keydata).Finalize(hash);
85 hash256.push_back(hash);
86 if (i & 1) hash256_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
88 CRIPEMD160().Write(keydata, 32).Finalize(hash.data());
90 ripemd160.push_back(hash);
91 if (i & 1) ripemd160_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
92 CHash160().Write(keydata).Finalize(hash);
93 hash160.push_back(hash);
94 if (i & 1) hash160_preimages[hash] = std::vector<unsigned char>(keydata, keydata + 32);
99 const std::pair<std::vector<unsigned char>,
bool>* GetSig(
const MsCtx script_ctx,
const Key& key)
const {
101 const auto it = dummy_sigs.find(key);
102 if (it == dummy_sigs.end())
return nullptr;
105 const auto it = schnorr_sigs.find(XOnlyPubKey{key});
106 if (it == schnorr_sigs.end())
return nullptr;
117struct ParserContext {
120 const MsCtx script_ctx;
122 constexpr ParserContext(MsCtx ctx) noexcept : script_ctx(ctx) {}
124 bool KeyCompare(
const Key& a,
const Key& b)
const {
128 std::optional<std::string>
ToString(
const Key& key,
bool& has_priv_key)
const
130 has_priv_key =
false;
131 auto it = TEST_DATA.dummy_key_idx_map.find(key);
132 if (it == TEST_DATA.dummy_key_idx_map.end()) {
136 uint8_t idx = it->second;
137 return HexStr(std::span{&idx, 1});
140 std::vector<unsigned char> ToPKBytes(
const Key& key)
const {
142 return {key.begin(), key.end()};
144 const XOnlyPubKey xonly_pubkey{key};
145 return {xonly_pubkey.
begin(), xonly_pubkey.
end()};
148 std::vector<unsigned char> ToPKHBytes(
const Key& key)
const {
151 return {h.begin(), h.end()};
153 const auto h =
Hash160(XOnlyPubKey{key});
154 return {h.begin(), h.end()};
157 std::optional<Key>
FromString(std::span<const char>& in)
const {
158 if (in.size() != 2)
return {};
159 auto idx =
ParseHex(std::string(in.begin(), in.end()));
160 if (idx.size() != 1)
return {};
161 return TEST_DATA.dummy_keys[idx[0]];
165 std::optional<Key> FromPKBytes(I first, I last)
const {
167 Key key{first, last};
168 if (key.IsValid())
return key;
171 if (last - first != 32)
return {};
172 XOnlyPubKey xonly_pubkey;
173 std::copy(first, last, xonly_pubkey.
begin());
178 std::optional<Key> FromPKHBytes(I first, I last)
const {
179 assert(last - first == 20);
181 std::copy(first, last, keyid.
begin());
182 const auto it = TEST_DATA.dummy_keys_map.find(keyid);
183 if (it == TEST_DATA.dummy_keys_map.end())
return {};
187 MsCtx MsContext()
const {
193struct ScriptParserContext {
194 const MsCtx script_ctx;
196 constexpr ScriptParserContext(MsCtx ctx) noexcept : script_ctx(ctx) {}
201 std::vector<unsigned char> data;
204 bool KeyCompare(
const Key& a,
const Key& b)
const {
205 return a.data < b.data;
208 const std::vector<unsigned char>& ToPKBytes(
const Key& key)
const
214 std::vector<unsigned char> ToPKHBytes(
const Key& key)
const
216 if (key.is_hash)
return key.data;
217 const auto h =
Hash160(key.data);
218 return {h.begin(), h.end()};
222 std::optional<Key> FromPKBytes(I first, I last)
const
225 key.data.assign(first, last);
231 std::optional<Key> FromPKHBytes(I first, I last)
const
234 key.data.assign(first, last);
239 MsCtx MsContext()
const {
245struct SatisfierContext : ParserContext {
247 constexpr SatisfierContext(MsCtx ctx) noexcept : ParserContext(ctx) {}
251 bool CheckAfter(uint32_t value)
const {
return value % 2; }
252 bool CheckOlder(uint32_t value)
const {
return value % 2; }
256 bool sig_available{
false};
257 if (
auto res = TEST_DATA.GetSig(script_ctx, key)) {
258 std::tie(sig, sig_available) = *res;
265 const std::map<std::vector<unsigned char>, std::vector<unsigned char>>& map)
const
267 const auto it = map.find(hash);
269 preimage = it->second;
272 miniscript::Availability SatSHA256(
const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage)
const {
273 return LookupHash(hash, preimage, TEST_DATA.sha256_preimages);
275 miniscript::Availability SatRIPEMD160(
const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage)
const {
276 return LookupHash(hash, preimage, TEST_DATA.ripemd160_preimages);
278 miniscript::Availability SatHASH256(
const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage)
const {
279 return LookupHash(hash, preimage, TEST_DATA.hash256_preimages);
281 miniscript::Availability SatHASH160(
const std::vector<unsigned char>& hash, std::vector<unsigned char>& preimage)
const {
282 return LookupHash(hash, preimage, TEST_DATA.hash160_preimages);
289 bool CheckECDSASignature(
const std::vector<unsigned char>& sig,
const std::vector<unsigned char>& vchPubKey,
290 const CScript& scriptCode,
SigVersion sigversion)
const override
292 const CPubKey key{vchPubKey};
293 const auto it = TEST_DATA.dummy_sigs.find(key);
294 if (it == TEST_DATA.dummy_sigs.end())
return false;
295 return it->second.first == sig;
297 bool CheckSchnorrSignature(std::span<const unsigned char> sig, std::span<const unsigned char> pubkey,
SigVersion,
298 ScriptExecutionData&,
ScriptError*)
const override {
299 XOnlyPubKey
pk{pubkey};
300 auto it = TEST_DATA.schnorr_sigs.find(pk);
301 if (it == TEST_DATA.schnorr_sigs.end())
return false;
302 return std::ranges::equal(it->second.first, sig);
304 bool CheckLockTime(
const CScriptNum& nLockTime)
const override {
return nLockTime.
GetInt64() & 1; }
305 bool CheckSequence(
const CScriptNum& nSequence)
const override {
return nSequence.
GetInt64() & 1; }
309const struct KeyComparator {
310 bool KeyCompare(
const CPubKey& a,
const CPubKey& b)
const {
325 std::vector<CPubKey> keys;
327 std::vector<unsigned char> hash;
329 std::vector<Type> subtypes;
331 NodeInfo(Fragment frag): fragment(frag), k(0) {}
332 NodeInfo(Fragment frag, CPubKey key): fragment(frag), k(0), keys({key}) {}
333 NodeInfo(Fragment frag, uint32_t _k): fragment(frag), k(_k) {}
334 NodeInfo(Fragment frag, std::vector<unsigned char> h): fragment(frag), k(0), hash(std::move(h)) {}
335 NodeInfo(std::vector<Type> subt, Fragment frag): fragment(frag), k(0), subtypes(std::move(subt)) {}
336 NodeInfo(std::vector<Type> subt, Fragment frag, uint32_t _k): fragment(frag), k(_k), subtypes(std::move(subt)) {}
337 NodeInfo(Fragment frag, uint32_t _k, std::vector<CPubKey> _keys): fragment(frag), k(_k), keys(std::move(_keys)) {}
341template<
typename T,
typename A>
348 return ConsumeIndex<CPubKey>(provider, TEST_DATA.dummy_keys);
352 return ConsumeIndex<std::vector<unsigned char>>(provider, TEST_DATA.sha256);
356 return ConsumeIndex<std::vector<unsigned char>>(provider, TEST_DATA.hash256);
360 return ConsumeIndex<std::vector<unsigned char>>(provider, TEST_DATA.ripemd160);
364 return ConsumeIndex<std::vector<unsigned char>>(provider, TEST_DATA.hash160);
369 if (
k == 0 ||
k >= 0x80000000)
return {};
387std::optional<NodeInfo> ConsumeNodeStable(MsCtx script_ctx,
FuzzedDataProvider& provider, Type type_needed) {
388 bool allow_B = (type_needed ==
""_mst) || (type_needed <<
"B"_mst);
389 bool allow_K = (type_needed ==
""_mst) || (type_needed <<
"K"_mst);
390 bool allow_V = (type_needed ==
""_mst) || (type_needed <<
"V"_mst);
391 bool allow_W = (type_needed ==
""_mst) || (type_needed <<
"W"_mst);
395 if (!allow_B)
return {};
396 return {{Fragment::JUST_0}};
398 if (!allow_B)
return {};
399 return {{Fragment::JUST_1}};
401 if (!allow_K)
return {};
402 return {{Fragment::PK_K, ConsumePubKey(provider)}};
404 if (!allow_K)
return {};
405 return {{Fragment::PK_H, ConsumePubKey(provider)}};
407 if (!allow_B)
return {};
408 const auto k = ConsumeTimeLock(provider);
410 return {{Fragment::OLDER, *
k}};
413 if (!allow_B)
return {};
414 const auto k = ConsumeTimeLock(provider);
416 return {{Fragment::AFTER, *
k}};
419 if (!allow_B)
return {};
420 return {{Fragment::SHA256, ConsumeSha256(provider)}};
422 if (!allow_B)
return {};
423 return {{Fragment::HASH256, ConsumeHash256(provider)}};
425 if (!allow_B)
return {};
426 return {{Fragment::RIPEMD160, ConsumeRipemd160(provider)}};
428 if (!allow_B)
return {};
429 return {{Fragment::HASH160, ConsumeHash160(provider)}};
431 if (!allow_B ||
IsTapscript(script_ctx))
return {};
434 if (n_keys > 20 ||
k == 0 ||
k > n_keys)
return {};
435 std::vector<CPubKey> keys{n_keys};
436 for (
auto& key: keys) key = ConsumePubKey(provider);
437 return {{Fragment::MULTI,
k, std::move(keys)}};
440 if (!(allow_B || allow_K || allow_V))
return {};
441 return {{{
"B"_mst, type_needed, type_needed}, Fragment::ANDOR}};
443 if (!(allow_B || allow_K || allow_V))
return {};
444 return {{{
"V"_mst, type_needed}, Fragment::AND_V}};
446 if (!allow_B)
return {};
447 return {{{
"B"_mst,
"W"_mst}, Fragment::AND_B}};
449 if (!allow_B)
return {};
450 return {{{
"B"_mst,
"W"_mst}, Fragment::OR_B}};
452 if (!allow_V)
return {};
453 return {{{
"B"_mst,
"V"_mst}, Fragment::OR_C}};
455 if (!allow_B)
return {};
456 return {{{
"B"_mst,
"B"_mst}, Fragment::OR_D}};
458 if (!(allow_B || allow_K || allow_V))
return {};
459 return {{{type_needed, type_needed}, Fragment::OR_I}};
461 if (!allow_B)
return {};
464 if (
k == 0 ||
k > n_subs)
return {};
465 std::vector<Type> subtypes;
466 subtypes.reserve(n_subs);
467 subtypes.emplace_back(
"B"_mst);
468 for (
size_t i = 1; i < n_subs; ++i) subtypes.emplace_back(
"W"_mst);
469 return {{std::move(subtypes), Fragment::THRESH,
k}};
472 if (!allow_W)
return {};
473 return {{{
"B"_mst}, Fragment::WRAP_A}};
475 if (!allow_W)
return {};
476 return {{{
"B"_mst}, Fragment::WRAP_S}};
478 if (!allow_B)
return {};
479 return {{{
"K"_mst}, Fragment::WRAP_C}};
481 if (!allow_B)
return {};
482 return {{{
"V"_mst}, Fragment::WRAP_D}};
484 if (!allow_V)
return {};
485 return {{{
"B"_mst}, Fragment::WRAP_V}};
487 if (!allow_B)
return {};
488 return {{{
"B"_mst}, Fragment::WRAP_J}};
490 if (!allow_B)
return {};
491 return {{{
"B"_mst}, Fragment::WRAP_N}};
493 if (!allow_B || !
IsTapscript(script_ctx))
return {};
496 if (n_keys > 999 ||
k == 0 ||
k > n_keys)
return {};
497 std::vector<CPubKey> keys{n_keys};
498 for (
auto& key: keys) key = ConsumePubKey(provider);
499 return {{Fragment::MULTI_A,
k, std::move(keys)}};
516 using recipe = std::pair<Fragment, std::vector<Type>>;
517 std::map<Type, std::vector<recipe>> wsh_table, tap_table;
521 Init(wsh_table, MsCtx::P2WSH);
522 Init(tap_table, MsCtx::TAPSCRIPT);
525 void Init(std::map<Type, std::vector<recipe>>& table, MsCtx script_ctx)
528 std::vector<Type> types;
529 for (
int base = 0; base < 4; ++base) {
530 Type type_base = base == 0 ?
"B"_mst : base == 1 ?
"K"_mst : base == 2 ?
"V"_mst :
"W"_mst;
531 for (
int zo = 0; zo < 3; ++zo) {
532 Type type_zo = zo == 0 ?
"z"_mst : zo == 1 ?
"o"_mst :
""_mst;
533 for (
int n = 0; n < 2; ++n) {
534 if (zo == 0 && n == 1)
continue;
535 if (base == 3 && n == 1)
continue;
536 Type type_n = n == 0 ?
""_mst :
"n"_mst;
537 for (
int d = 0; d < 2; ++d) {
538 if (base == 2 && d == 1)
continue;
539 Type type_d = d == 0 ?
""_mst :
"d"_mst;
540 for (
int u = 0; u < 2; ++u) {
541 if (base == 2 && u == 1)
continue;
542 Type type_u = u == 0 ?
""_mst :
"u"_mst;
543 Type type = type_base | type_zo | type_n | type_d | type_u;
544 types.push_back(type);
557 auto is_super_of = [](
const recipe& a,
const recipe& b) {
558 if (a.first != b.first)
return false;
559 if (a.second.size() != b.second.size())
return false;
560 for (
size_t i = 0; i < a.second.size(); ++i) {
561 if (!(b.second[i] << a.second[i]))
return false;
571 std::sort(types.begin(), types.end());
574 for (
int fragidx = 0; fragidx <= int(Fragment::MULTI_A); ++fragidx) {
577 size_t data_size = 0;
594 case Fragment::MULTI:
595 case Fragment::MULTI_A:
599 case Fragment::OLDER:
600 case Fragment::AFTER:
603 case Fragment::SHA256:
604 case Fragment::HASH256:
607 case Fragment::RIPEMD160:
608 case Fragment::HASH160:
611 case Fragment::JUST_0:
612 case Fragment::JUST_1:
614 case Fragment::WRAP_A:
615 case Fragment::WRAP_S:
616 case Fragment::WRAP_C:
617 case Fragment::WRAP_D:
618 case Fragment::WRAP_V:
619 case Fragment::WRAP_J:
620 case Fragment::WRAP_N:
623 case Fragment::AND_V:
624 case Fragment::AND_B:
631 case Fragment::ANDOR:
634 case Fragment::THRESH:
643 std::vector<Type> subt;
644 for (
int subs = sub_count; subs < sub_count + sub_range; ++subs) {
646 for (Type x : types) {
647 for (Type y : types) {
648 for (Type z : types) {
651 if (subs > 0) subt.push_back(x);
652 if (subs > 1) subt.push_back(y);
653 if (subs > 2) subt.push_back(z);
656 if ((res <<
"K"_mst) + (res <<
"V"_mst) + (res <<
"B"_mst) + (res <<
"W"_mst) != 1)
continue;
658 recipe entry{frag, subt};
659 auto super_of_entry = [&](
const recipe& rec) {
return is_super_of(rec, entry); };
662 for (Type s : types) {
663 if ((res &
"BKVWzondu"_mst) << s) {
664 auto& recipes = table[
s];
666 if (!std::any_of(recipes.begin(), recipes.end(), super_of_entry)) {
667 recipes.push_back(entry);
672 if (subs <= 2)
break;
674 if (subs <= 1)
break;
676 if (subs <= 0)
break;
684 std::set<Type> useful_types{
"B"_mst,
"V"_mst,
"K"_mst,
"W"_mst};
687 size_t set_size = useful_types.size();
688 for (
const auto& [type, recipes] : table) {
689 if (useful_types.contains(type)) {
690 for (
const auto& [
_, subtypes] : recipes) {
691 for (
auto subtype : subtypes) useful_types.insert(subtype);
695 if (useful_types.size() == set_size)
break;
698 for (
auto type_it = table.begin(); type_it != table.end();) {
699 if (!useful_types.contains(type_it->first)) {
700 type_it = table.erase(type_it);
711 std::set<Type> constructible_types{};
712 auto known_constructible = [&](Type type) {
return constructible_types.contains(type); };
715 size_t set_size = constructible_types.size();
717 for (
const auto& [type, recipes] : table) {
718 if (!known_constructible(type)) {
720 for (
const auto& [
_, subt] : recipes) {
723 if (std::all_of(subt.begin(), subt.end(), known_constructible)) {
724 constructible_types.insert(type);
730 if (constructible_types.size() == set_size)
break;
732 for (
auto type_it = table.begin(); type_it != table.end();) {
734 type_it->second.erase(std::remove_if(type_it->second.begin(), type_it->second.end(),
735 [&](
const recipe& rec) {
736 return !std::all_of(rec.second.begin(), rec.second.end(), known_constructible);
737 }), type_it->second.end());
739 if (type_it->second.empty()) {
740 type_it = table.erase(type_it);
746 for (
auto& [type, recipes] : table) {
750 std::sort(recipes.begin(), recipes.end(),
751 [](
const recipe& a,
const recipe& b) {
752 if (a.second.size() < b.second.size()) return true;
753 if (a.second.size() > b.second.size()) return false;
771std::optional<NodeInfo> ConsumeNodeSmart(MsCtx script_ctx,
FuzzedDataProvider& provider, Type type_needed) {
773 const auto& table{
IsTapscript(script_ctx) ? SMARTINFO.tap_table : SMARTINFO.wsh_table};
774 auto recipes_it = table.find(type_needed);
775 assert(recipes_it != table.end());
777 const auto& [frag, subt] =
PickValue(provider, recipes_it->second);
783 return {{frag, ConsumePubKey(provider)}};
784 case Fragment::MULTI: {
787 std::vector<CPubKey> keys{n_keys};
788 for (
auto& key: keys) key = ConsumePubKey(provider);
789 return {{frag,
k, std::move(keys)}};
791 case Fragment::MULTI_A: {
794 std::vector<CPubKey> keys{n_keys};
795 for (
auto& key: keys) key = ConsumePubKey(provider);
796 return {{frag,
k, std::move(keys)}};
798 case Fragment::OLDER:
799 case Fragment::AFTER:
801 case Fragment::SHA256:
802 return {{frag,
PickValue(provider, TEST_DATA.sha256)}};
803 case Fragment::HASH256:
804 return {{frag,
PickValue(provider, TEST_DATA.hash256)}};
805 case Fragment::RIPEMD160:
806 return {{frag,
PickValue(provider, TEST_DATA.ripemd160)}};
807 case Fragment::HASH160:
808 return {{frag,
PickValue(provider, TEST_DATA.hash160)}};
809 case Fragment::JUST_0:
810 case Fragment::JUST_1:
811 case Fragment::WRAP_A:
812 case Fragment::WRAP_S:
813 case Fragment::WRAP_C:
814 case Fragment::WRAP_D:
815 case Fragment::WRAP_V:
816 case Fragment::WRAP_J:
817 case Fragment::WRAP_N:
818 case Fragment::AND_V:
819 case Fragment::AND_B:
824 case Fragment::ANDOR:
825 return {{subt, frag}};
826 case Fragment::THRESH: {
828 if (subt.size() < 2) {
829 children = subt.size();
836 std::vector<Type> subs = subt;
837 while (subs.size() < children) subs.push_back(subs.back());
838 return {{std::move(subs), frag,
k}};
854std::optional<Node> GenNode(MsCtx script_ctx, F
ConsumeNode, Type root_type,
bool strict_valid =
false)
857 std::vector<Node> stack;
859 std::vector<std::pair<Type, std::optional<NodeInfo>>> todo{{root_type, {}}};
864 uint32_t scriptsize{1};
866 while (!todo.empty()) {
868 auto type_needed = todo.back().first;
869 if (!todo.back().second) {
872 if (!node_info)
return {};
877 node_info->keys.size(), script_ctx) - 1;
879 switch (node_info->fragment) {
880 case Fragment::JUST_0:
881 case Fragment::JUST_1:
888 case Fragment::OLDER:
889 case Fragment::AFTER:
892 case Fragment::RIPEMD160:
893 case Fragment::SHA256:
894 case Fragment::HASH160:
895 case Fragment::HASH256:
898 case Fragment::ANDOR:
901 case Fragment::AND_V:
903 case Fragment::AND_B:
916 case Fragment::THRESH:
917 ops += node_info->subtypes.size();
919 case Fragment::MULTI:
922 case Fragment::MULTI_A:
923 ops += node_info->keys.size() + 1;
925 case Fragment::WRAP_A:
928 case Fragment::WRAP_S:
931 case Fragment::WRAP_C:
934 case Fragment::WRAP_D:
937 case Fragment::WRAP_V:
941 case Fragment::WRAP_J:
944 case Fragment::WRAP_N:
949 auto subtypes = node_info->subtypes;
950 todo.back().second = std::move(node_info);
951 todo.reserve(todo.size() + subtypes.size());
954 for (
size_t i = 0; i < subtypes.size(); ++i) {
955 todo.emplace_back(*(subtypes.rbegin() + i), std::nullopt);
962 NodeInfo& info = *todo.back().second;
964 std::vector<Node> sub;
965 sub.reserve(info.subtypes.size());
966 for (
size_t i = 0; i < info.subtypes.size(); ++i) {
967 sub.push_back(std::move(*(stack.end() - info.subtypes.size() + i)));
969 stack.erase(stack.end() - info.subtypes.size(), stack.end());
972 if (info.keys.empty()) {
976 assert(info.hash.empty());
980 if ((
node.GetType() &
"KVWB"_mst) ==
""_mst) {
984 if (!(type_needed ==
""_mst)) {
987 if (!
node.IsValid())
return {};
989 if (
node.Fragment() == Fragment::WRAP_V &&
node.Subs()[0].GetType() <<
"x"_mst) {
998 stack.push_back(std::move(
node));
1002 assert(stack.size() == 1);
1003 assert(stack[0].GetStaticOps() == ops);
1004 assert(stack[0].ScriptSize() == scriptsize);
1005 stack[0].DuplicateKeyCheck(KEY_COMP);
1006 return std::move(stack[0]);
1035 const ParserContext parser_ctx{script_ctx};
1036 std::optional<std::string> str{
node->ToString(parser_ctx)};
1048 if (!(
node->GetType() <<
"K"_mst)) {
1049 bool ends_in_verify = !(
node->GetType() <<
"x"_mst);
1054 if (!
node->IsValidTopLevel())
return;
1063 assert(decoded->GetType() ==
node->GetType());
1078 const auto node_ops{
node->GetOps()};
1081 int add = std::min<int>(
1084 for (
int i = 0; i < add; ++i)
script.push_back(
OP_NOP);
1089 const auto node_exec_ss{
node->GetExecStackSize()};
1092 witness_mal.
stack.resize(add);
1093 witness_nonmal.
stack.resize(add);
1095 for (
unsigned i = 0; i < add; ++i)
script.push_back(
OP_NIP);
1099 const SatisfierContext satisfier_ctx{script_ctx};
1103 const CScript script_pubkey{ScriptPubKey(script_ctx,
script, builder)};
1106 std::vector<std::vector<unsigned char>> stack_mal;
1110 std::vector<std::vector<unsigned char>> stack_nonmal;
1113 if (nonmal_success) {
1118 assert(stack_nonmal.size() <= max_stack_size);
1121 assert(stack_nonmal == stack_mal);
1124 assert(wit_size <= *node->GetWitnessSize());
1127 witness_nonmal.
stack.insert(witness_nonmal.
stack.end(), std::make_move_iterator(stack_nonmal.begin()), std::make_move_iterator(stack_nonmal.end()));
1128 SatisfactionToWitness(script_ctx, witness_nonmal,
script, builder);
1136 (!
node->CheckOpsLimit() && serror == ScriptError::SCRIPT_ERR_OP_COUNT) ||
1137 (!
node->CheckStackSize() && serror == ScriptError::SCRIPT_ERR_STACK_SIZE));
1140 if (mal_success && (!nonmal_success || witness_mal.
stack != witness_nonmal.
stack)) {
1142 witness_mal.
stack.insert(witness_mal.
stack.end(), std::make_move_iterator(stack_mal.begin()), std::make_move_iterator(stack_mal.end()));
1143 SatisfactionToWitness(script_ctx, witness_mal,
script, builder);
1148 assert(res || serror == ScriptError::SCRIPT_ERR_OP_COUNT || serror == ScriptError::SCRIPT_ERR_STACK_SIZE);
1151 if (
node->IsSane()) {
1153 assert(mal_success == nonmal_success);
1160 const auto is_key_satisfiable = [script_ctx](
const CPubKey& pubkey) ->
bool {
1161 auto sig_ptr{TEST_DATA.GetSig(script_ctx, pubkey)};
1162 return sig_ptr !=
nullptr && sig_ptr->second;
1164 bool satisfiable =
node->IsSatisfiable([&](
const Node&
node) ->
bool {
1165 switch (
node.Fragment()) {
1166 case Fragment::PK_K:
1167 case Fragment::PK_H:
1168 return is_key_satisfiable(
node.Keys()[0]);
1169 case Fragment::MULTI:
1170 case Fragment::MULTI_A: {
1171 size_t sats = std::ranges::count_if(
node.Keys(), [&](
const auto& key) {
1172 return size_t(is_key_satisfiable(key));
1174 return sats >=
node.K();
1176 case Fragment::OLDER:
1177 case Fragment::AFTER:
1178 return node.K() & 1;
1179 case Fragment::SHA256:
1180 return TEST_DATA.sha256_preimages.contains(
node.Data());
1181 case Fragment::HASH256:
1182 return TEST_DATA.hash256_preimages.contains(
node.Data());
1183 case Fragment::RIPEMD160:
1184 return TEST_DATA.ripemd160_preimages.contains(
node.Data());
1185 case Fragment::HASH160:
1186 return TEST_DATA.hash160_preimages.contains(
node.Data());
1192 assert(mal_success == satisfiable);
1213 for (
const auto script_ctx: {MsCtx::P2WSH, MsCtx::TAPSCRIPT}) {
1215 TestNode(script_ctx, GenNode(script_ctx, [&](Type needed_type) {
1216 return ConsumeNodeStable(script_ctx, provider, needed_type);
1217 },
""_mst), provider);
1225 static constexpr std::array<Type, 4> BASE_TYPES{
"B"_mst,
"V"_mst,
"K"_mst,
"W"_mst};
1228 const auto script_ctx{(MsCtx)provider.
ConsumeBool()};
1229 TestNode(script_ctx, GenNode(script_ctx, [&](Type needed_type) {
1230 return ConsumeNodeSmart(script_ctx, provider, needed_type);
1231 },
PickValue(provider, BASE_TYPES),
true), provider);
1239 if (buffer.empty())
return;
1243 const ParserContext parser_ctx{(MsCtx)provider.
ConsumeBool()};
1245 if (!parsed)
return;
1247 const auto str2 = parsed->ToString(parser_ctx);
1251 assert(*parsed == *parsed2);
1261 const ScriptParserContext script_parser_ctx{(MsCtx)fuzzed_data_provider.
ConsumeBool()};
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
std::string ToString(const T &t)
Locale-independent version of std::to_string.
bool SignSchnorr(const uint256 &hash, std::span< unsigned char > sig, const uint256 *merkle_root, const uint256 &aux) const
Create a BIP-340 Schnorr signature, for the xonly-pubkey corresponding to *this, optionally tweaked b...
bool Sign(const uint256 &hash, std::vector< unsigned char > &vchSig, bool grind=true, uint32_t test_case=0) const
Create a DER-serialized signature.
CPubKey GetPubKey() const
Compute the public key from a private key.
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
An encapsulated public key.
Serialized script, used inside transaction inputs and outputs.
RAII class initializing and deinitializing global state for elliptic curve support.
std::string ConsumeBytesAsString(size_t num_bytes)
T ConsumeIntegralInRange(T min, T max)
Top-level interface for a bitcoin node (bitcoind process).
Utility class to construct Taproot outputs from internal key and script tree.
WitnessV1Taproot GetOutput()
Compute scriptPubKey (after Finalize()).
TaprootSpendData GetSpendData() const
Compute spending data (after Finalize()).
TaprootBuilder & Add(int depth, std::span< const unsigned char > script, int leaf_version, bool track=true)
Add a new script at a certain depth in the tree.
TaprootBuilder & Finalize(const XOnlyPubKey &internal_key)
Finalize the construction.
const unsigned char * end() const
const unsigned char * begin() const
static const XOnlyPubKey NUMS_H
Nothing Up My Sleeve point H Used as an internal key for provably disabling the key path spend see BI...
CPubKey GetEvenCorrespondingCPubKey() const
constexpr unsigned char * begin()
A node in a miniscript expression.
This type encapsulates the miniscript type system properties.
static const uint256 ZERO
uint160 Hash160(const T1 &in1)
Compute the 160-bit hash an object.
#define T(expected, seed, data)
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, const CScriptWitness *witness, script_verify_flags flags, const BaseSignatureChecker &checker, ScriptError *serror)
static constexpr uint8_t TAPROOT_LEAF_TAPSCRIPT
size_t ComputeScriptLen(Fragment fragment, Type sub0typ, size_t subsize, uint32_t k, size_t n_subs, size_t n_keys, MiniscriptContext ms_ctx)
Helper function for Node::CalcScriptLen.
constexpr uint32_t MaxScriptSize(MiniscriptContext ms_ctx)
The maximum size of a script depending on the context.
Type ComputeType(Fragment fragment, Type x, Type y, Type z, const std::vector< Type > &sub_types, uint32_t k, size_t data_size, size_t n_subs, size_t n_keys, MiniscriptContext ms_ctx)
Helper function for Node::CalcType.
constexpr bool IsTapscript(MiniscriptContext ms_ctx)
Whether the context Tapscript, ensuring the only other possibility is P2WSH.
std::optional< Node< typename Ctx::Key > > FromScript(const CScript &script, const Ctx &ctx)
std::optional< Node< typename Ctx::Key > > FromString(const std::string &str, const Ctx &ctx)
Fragment
The different node types in miniscript.
static constexpr script_verify_flags STANDARD_SCRIPT_VERIFY_FLAGS
Standard script verification flags that standard transactions will comply with.
static constexpr unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE
The maximum size in bytes of a standard witnessScript.
static const int MAX_STACK_SIZE
static const int MAX_OPS_PER_SCRIPT
enum ScriptError_t ScriptError
constexpr unsigned int GetSizeOfCompactSize(uint64_t nSize)
Compact Size size < 253 – 1 byte size <= USHRT_MAX – 3 bytes (253 + 2 bytes) size <= UINT_MAX – 5 byt...
uint64_t GetSerializeSize(const T &t)
constexpr auto MakeUCharSpan(const V &v) -> decltype(UCharSpanCast(std::span{v}))
Like the std::span constructor, but for (const) unsigned char member types only.
std::vector< Byte > ParseHex(std::string_view hex_str)
Like TryParseHex, but returns an empty vector on invalid input.
std::vector< std::vector< unsigned char > > stack
std::map< std::pair< std::vector< unsigned char >, int >, std::set< std::vector< unsigned char >, ShortestVectorFirstComparator > > scripts
Map from (script, leaf_version) to (sets of) control blocks.
bool HasTooManySubFrag(std::span< const uint8_t > buff, const int max_subs, const size_t max_nested_subs)
Whether the buffer, if it represents a valid descriptor, contains a fragment with more sub-fragments ...
bool HasTooManyWrappers(std::span< const uint8_t > buff, const int max_wrappers)
Whether the buffer, if it represents a valid descriptor, contains a fragment with more wrappers than ...
auto ConsumeNode(FuzzedDataProvider &fuzzed_data_provider, const std::optional< NodeId > &node_id_in=std::nullopt) noexcept
auto & PickValue(FuzzedDataProvider &fuzzed_data_provider, Collection &col)
std::optional< T > ConsumeDeserializable(FuzzedDataProvider &fuzzed_data_provider, const P ¶ms, const std::optional< size_t > &max_length=std::nullopt) noexcept
consteval auto _(util::TranslatedLiteral str)