1- // Copyright (c) 2021 The Bitcoin Core developers
1+ // Copyright (c) 2021-2022 The Bitcoin Core developers
22// Distributed under the MIT software license, see the accompanying
33// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44
1414
1515namespace {
1616
17- // ! Some pre-computed data to simulate challenges.
17+ // ! Some pre-computed data for more efficient string roundtrips and to simulate challenges.
1818struct TestData {
1919 typedef CPubKey Key;
2020
@@ -72,10 +72,18 @@ struct TestData {
7272 }
7373} TEST_DATA;
7474
75- // ! Context to parse a Miniscript node to and from Script or text representation.
75+ /* *
76+ * Context to parse a Miniscript node to and from Script or text representation.
77+ * Uses an integer (an index in the dummy keys array from the test data) as keys in order
78+ * to focus on fuzzing the Miniscript nodes' test representation, not the key representation.
79+ */
7680struct ParserContext {
7781 typedef CPubKey Key;
7882
83+ bool KeyCompare (const Key& a, const Key& b) const {
84+ return a < b;
85+ }
86+
7987 std::optional<std::string> ToString (const Key& key) const
8088 {
8189 auto it = TEST_DATA.dummy_key_idx_map .find (key);
@@ -84,12 +92,12 @@ struct ParserContext {
8492 return HexStr (Span{&idx, 1 });
8593 }
8694
87- const std::vector<unsigned char > ToPKBytes (const Key& key) const
95+ std::vector<unsigned char > ToPKBytes (const Key& key) const
8896 {
8997 return {key.begin (), key.end ()};
9098 }
9199
92- const std::vector<unsigned char > ToPKHBytes (const Key& key) const
100+ std::vector<unsigned char > ToPKHBytes (const Key& key) const
93101 {
94102 const auto h = Hash160 (key);
95103 return {h.begin (), h.end ()};
@@ -104,15 +112,15 @@ struct ParserContext {
104112 }
105113
106114 template <typename I>
107- std::optional<CPubKey > FromPKBytes (I first, I last) const {
115+ std::optional<Key > FromPKBytes (I first, I last) const {
108116 CPubKey key;
109117 key.Set (first, last);
110118 if (!key.IsValid ()) return {};
111119 return key;
112120 }
113121
114122 template <typename I>
115- std::optional<CPubKey > FromPKHBytes (I first, I last) const {
123+ std::optional<Key > FromPKHBytes (I first, I last) const {
116124 assert (last - first == 20 );
117125 CKeyID keyid;
118126 std::copy (first, last, keyid.begin ());
@@ -124,20 +132,23 @@ struct ParserContext {
124132
125133// ! Context that implements naive conversion from/to script only, for roundtrip testing.
126134struct ScriptParserContext {
135+ // ! For Script roundtrip we never need the key from a key hash.
127136 struct Key {
128137 bool is_hash;
129138 std::vector<unsigned char > data;
130-
131- bool operator <(Key k) const { return data < k.data ; }
132139 };
133140
141+ bool KeyCompare (const Key& a, const Key& b) const {
142+ return a.data < b.data ;
143+ }
144+
134145 const std::vector<unsigned char >& ToPKBytes (const Key& key) const
135146 {
136147 assert (!key.is_hash );
137148 return key.data ;
138149 }
139150
140- const std::vector<unsigned char > ToPKHBytes (const Key& key) const
151+ std::vector<unsigned char > ToPKHBytes (const Key& key) const
141152 {
142153 if (key.is_hash ) return key.data ;
143154 const auto h = Hash160 (key.data );
@@ -223,17 +234,26 @@ struct CheckerContext: BaseSignatureChecker {
223234 bool CheckSequence (const CScriptNum& nSequence) const override { return nSequence.GetInt64 () & 1 ; }
224235} CHECKER_CTX;
225236
237+ // ! Context to check for duplicates when instancing a Node.
238+ struct KeyComparator {
239+ bool KeyCompare (const CPubKey& a, const CPubKey& b) const {
240+ return a < b;
241+ }
242+ } KEY_COMP;
243+
226244// A dummy scriptsig to pass to VerifyScript (we always use Segwit v0).
227245const CScript DUMMY_SCRIPTSIG;
228246
229247using Fragment = miniscript::Fragment;
230248using NodeRef = miniscript::NodeRef<CPubKey>;
231249using Node = miniscript::Node<CPubKey>;
232250using Type = miniscript::Type;
251+ // https://github.com/llvm/llvm-project/issues/53444
252+ // NOLINTNEXTLINE(misc-unused-using-decls)
233253using miniscript::operator " " _mst;
234254
235255// ! Construct a miniscript node as a shared_ptr.
236- template <typename ... Args> NodeRef MakeNodeRef (Args&&... args) { return miniscript::MakeNodeRef<CPubKey>(std::forward<Args>(args)...); }
256+ template <typename ... Args> NodeRef MakeNodeRef (Args&&... args) { return miniscript::MakeNodeRef<CPubKey>(KEY_COMP, std::forward<Args>(args)...); }
237257
238258/* * Information about a yet to be constructed Miniscript node. */
239259struct NodeInfo {
@@ -577,7 +597,7 @@ struct SmartInfo
577597 // Remove all recipes which involve non-constructible types.
578598 type_it->second .erase (std::remove_if (type_it->second .begin (), type_it->second .end (),
579599 [&](const recipe& rec) {
580- return !std::all_of (rec.second .begin (), rec.second .end (), known_constructible);
600+ return !std::all_of (rec.second .begin (), rec.second .end (), known_constructible);
581601 }), type_it->second .end ());
582602 // Delete types entirely which have no recipes left.
583603 if (type_it->second .empty ()) {
@@ -700,7 +720,7 @@ NodeRef GenNode(F ConsumeNode, Type root_type = ""_mst, bool strict_valid = fals
700720 // Fragment/children have not been decided yet. Decide them.
701721 auto node_info = ConsumeNode (type_needed);
702722 if (!node_info) return {};
703- auto subtypes = std::move ( node_info) ->subtypes ;
723+ auto subtypes = node_info->subtypes ;
704724 todo.back ().second = std::move (node_info);
705725 todo.reserve (todo.size () + subtypes.size ());
706726 // As elements on the todo stack are processed back to front, construct
@@ -713,7 +733,7 @@ NodeRef GenNode(F ConsumeNode, Type root_type = ""_mst, bool strict_valid = fals
713733 // those children have been constructed at the back of stack. Pop
714734 // that entry off todo, and use it to construct a new NodeRef on
715735 // stack.
716- const NodeInfo& info = *todo.back ().second ;
736+ NodeInfo& info = *todo.back ().second ;
717737 // Gather children from the back of stack.
718738 std::vector<NodeRef> sub;
719739 sub.reserve (info.n_subs );
@@ -751,9 +771,9 @@ void TestNode(const NodeRef& node, FuzzedDataProvider& provider)
751771 if (!node) return ;
752772
753773 // Check that it roundtrips to text representation
754- std::string str;
755- assert (node-> ToString (PARSER_CTX, str) );
756- auto parsed = miniscript::FromString (str, PARSER_CTX);
774+ std::optional<std:: string> str{node-> ToString (PARSER_CTX)} ;
775+ assert (str);
776+ auto parsed = miniscript::FromString (* str, PARSER_CTX);
757777 assert (parsed);
758778 assert (*parsed == *node);
759779
@@ -780,7 +800,7 @@ void TestNode(const NodeRef& node, FuzzedDataProvider& provider)
780800 assert (decoded->ToScript (PARSER_CTX) == script);
781801 assert (decoded->GetType () == node->GetType ());
782802
783- if (provider.ConsumeBool ()) {
803+ if (provider.ConsumeBool () && node-> GetOps () < MAX_OPS_PER_SCRIPT && node-> ScriptSize () < MAX_STANDARD_P2WSH_SCRIPT_SIZE ) {
784804 // Optionally pad the script with OP_NOPs to max op the ops limit of the constructed script.
785805 // This makes the script obviously not actually miniscript-compatible anymore, but the
786806 // signatures constructed in this test don't commit to the script anyway, so the same
@@ -835,13 +855,13 @@ void TestNode(const NodeRef& node, FuzzedDataProvider& provider)
835855 assert (res || serror == ScriptError::SCRIPT_ERR_OP_COUNT || serror == ScriptError::SCRIPT_ERR_STACK_SIZE);
836856 }
837857
838- if (node->IsSaneTopLevel ()) {
858+ if (node->IsSane ()) {
839859 // For sane nodes, the two algorithms behave identically.
840860 assert (mal_success == nonmal_success);
841861 }
842862
843863 // Verify that if a node is policy-satisfiable, the malleable satisfaction
844- // algorithm succeeds. Given that under IsSaneTopLevel () both satisfactions
864+ // algorithm succeeds. Given that under IsSane () both satisfactions
845865 // are identical, this implies that for such nodes, the non-malleable
846866 // satisfaction will also match the expected policy.
847867 bool satisfiable = node->IsSatisfiable ([](const Node& node) -> bool {
@@ -880,6 +900,8 @@ void TestNode(const NodeRef& node, FuzzedDataProvider& provider)
880900 assert (mal_success == satisfiable);
881901}
882902
903+ } // namespace
904+
883905void FuzzInit ()
884906{
885907 ECC_Start ();
@@ -892,8 +914,6 @@ void FuzzInitSmart()
892914 SMARTINFO.Init ();
893915}
894916
895- } // namespace
896-
897917/* * Fuzz target that runs TestNode on nodes generated using ConsumeNodeStable. */
898918FUZZ_TARGET_INIT (miniscript_stable, FuzzInit)
899919{
@@ -923,9 +943,9 @@ FUZZ_TARGET_INIT(miniscript_string, FuzzInit)
923943 auto parsed = miniscript::FromString (str, PARSER_CTX);
924944 if (!parsed) return ;
925945
926- std::string str2;
927- assert (parsed-> ToString (PARSER_CTX, str2) );
928- auto parsed2 = miniscript::FromString (str2, PARSER_CTX);
946+ const auto str2 = parsed-> ToString (PARSER_CTX) ;
947+ assert (str2);
948+ auto parsed2 = miniscript::FromString (* str2, PARSER_CTX);
929949 assert (parsed2);
930950 assert (*parsed == *parsed2);
931951}
0 commit comments