Branch data Line data Source code
1 : : // Copyright (c) 2009-2021 The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #include <chainparams.h>
6 : : #include <key_io.h>
7 : : #include <pubkey.h>
8 : : #include <script/descriptor.h>
9 : : #include <test/fuzz/fuzz.h>
10 : : #include <test/fuzz/util/descriptor.h>
11 : : #include <util/chaintype.h>
12 : : #include <util/strencodings.h>
13 : :
14 : : //! The converter of mocked descriptors, needs to be initialized when the target is.
15 : : MockedDescriptorConverter MOCKED_DESC_CONVERTER;
16 : :
17 : : /** Test a successfully parsed descriptor. */
18 : 0 : static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_provider, std::string& dummy)
19 : : {
20 : : // Trivial helpers.
21 : 0 : (void)desc.IsRange();
22 : 0 : const bool is_solvable{desc.IsSolvable()};
23 : 0 : (void)desc.IsSingleType();
24 : 0 : (void)desc.GetOutputType();
25 : :
26 : : // Serialization to string representation.
27 : 0 : (void)desc.ToString();
28 : 0 : (void)desc.ToPrivateString(sig_provider, dummy);
29 : 0 : (void)desc.ToNormalizedString(sig_provider, dummy);
30 : :
31 : : // Serialization to Script.
32 : 0 : DescriptorCache cache;
33 : 0 : std::vector<CScript> out_scripts;
34 [ # # ]: 0 : (void)desc.Expand(0, sig_provider, out_scripts, sig_provider, &cache);
35 [ # # ]: 0 : (void)desc.ExpandPrivate(0, sig_provider, sig_provider);
36 [ # # ]: 0 : (void)desc.ExpandFromCache(0, cache, out_scripts, sig_provider);
37 : :
38 : : // If we could serialize to script we must be able to infer using the same provider.
39 [ # # ]: 0 : if (!out_scripts.empty()) {
40 [ # # # # ]: 0 : assert(InferDescriptor(out_scripts.back(), sig_provider));
41 : :
42 : : // The ScriptSize() must match the size of the serialized Script. (ScriptSize() is set for all descs but 'combo()'.)
43 [ # # ]: 0 : const bool is_combo{!desc.IsSingleType()};
44 [ # # # # : 0 : assert(is_combo || desc.ScriptSize() == out_scripts.back().size());
# # ]
45 : : }
46 : :
47 [ # # ]: 0 : const auto max_sat_maxsig{desc.MaxSatisfactionWeight(true)};
48 [ # # ]: 0 : const auto max_sat_nonmaxsig{desc.MaxSatisfactionWeight(true)};
49 [ # # ]: 0 : const auto max_elems{desc.MaxSatisfactionElems()};
50 : : // We must be able to estimate the max satisfaction size for any solvable descriptor (but combo).
51 [ # # # # : 0 : const bool is_nontop_or_nonsolvable{!is_solvable || !desc.GetOutputType()};
# # ]
52 [ # # # # : 0 : const bool is_input_size_info_set{max_sat_maxsig && max_sat_nonmaxsig && max_elems};
# # ]
53 [ # # ]: 0 : assert(is_input_size_info_set || is_nontop_or_nonsolvable);
54 : 0 : }
55 : :
56 : 0 : void initialize_descriptor_parse()
57 : : {
58 [ # # # # : 0 : static ECC_Context ecc_context{};
# # ]
59 : 0 : SelectParams(ChainType::MAIN);
60 : 0 : }
61 : :
62 : 0 : void initialize_mocked_descriptor_parse()
63 : : {
64 : 0 : initialize_descriptor_parse();
65 : 0 : MOCKED_DESC_CONVERTER.Init();
66 : 0 : }
67 : :
68 [ # # ]: 0 : FUZZ_TARGET(mocked_descriptor_parse, .init = initialize_mocked_descriptor_parse)
69 : : {
70 : : // Key derivation is expensive. Deriving deep derivation paths take a lot of compute and we'd
71 : : // rather spend time elsewhere in this target, like on the actual descriptor syntax. So rule
72 : : // out strings which could correspond to a descriptor containing a too large derivation path.
73 [ # # ]: 0 : if (HasDeepDerivPath(buffer)) return;
74 : :
75 : : // Some fragments can take a virtually unlimited number of sub-fragments (thresh, multi_a) but
76 : : // may perform quadratic operations on them. Limit the number of sub-fragments per fragment.
77 [ # # ]: 0 : if (HasTooManySubFrag(buffer)) return;
78 : :
79 : : // The script building logic performs quadratic copies in the number of nested wrappers. Limit
80 : : // the number of nested wrappers per fragment.
81 [ # # ]: 0 : if (HasTooManyWrappers(buffer)) return;
82 : :
83 [ # # ]: 0 : const std::string mocked_descriptor{buffer.begin(), buffer.end()};
84 [ # # # # ]: 0 : if (const auto descriptor = MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)) {
85 : 0 : FlatSigningProvider signing_provider;
86 [ # # ]: 0 : std::string error;
87 [ # # ]: 0 : const auto desc = Parse(*descriptor, signing_provider, error);
88 [ # # # # ]: 0 : if (desc) TestDescriptor(*desc, signing_provider, error);
89 : 0 : }
90 : 0 : }
91 : :
92 [ # # ]: 0 : FUZZ_TARGET(descriptor_parse, .init = initialize_descriptor_parse)
93 : : {
94 : : // See comments above for rationales.
95 [ # # ]: 0 : if (HasDeepDerivPath(buffer)) return;
96 [ # # ]: 0 : if (HasTooManySubFrag(buffer)) return;
97 [ # # ]: 0 : if (HasTooManyWrappers(buffer)) return;
98 : :
99 : 0 : const std::string descriptor(buffer.begin(), buffer.end());
100 : 0 : FlatSigningProvider signing_provider;
101 : 0 : std::string error;
102 [ # # ]: 0 : for (const bool require_checksum : {true, false}) {
103 [ # # ]: 0 : const auto desc = Parse(descriptor, signing_provider, error, require_checksum);
104 [ # # # # ]: 0 : if (desc) TestDescriptor(*desc, signing_provider, error);
105 : 0 : }
106 : 0 : }
|