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 : 340 : static void TestDescriptor(const Descriptor& desc, FlatSigningProvider& sig_provider, std::string& dummy) 19 : : { 20 : : // Trivial helpers. 21 : 340 : (void)desc.IsRange(); 22 : 340 : const bool is_solvable{desc.IsSolvable()}; 23 : 340 : (void)desc.IsSingleType(); 24 : 340 : (void)desc.GetOutputType(); 25 : : 26 : : // Serialization to string representation. 27 : 340 : (void)desc.ToString(); 28 : 340 : (void)desc.ToPrivateString(sig_provider, dummy); 29 : 340 : (void)desc.ToNormalizedString(sig_provider, dummy); 30 : : 31 : : // Serialization to Script. 32 : 340 : DescriptorCache cache; 33 : 340 : std::vector<CScript> out_scripts; 34 [ + - ]: 340 : (void)desc.Expand(0, sig_provider, out_scripts, sig_provider, &cache); 35 [ + - ]: 340 : (void)desc.ExpandPrivate(0, sig_provider, sig_provider); 36 [ + - ]: 340 : (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 [ + + ]: 340 : if (!out_scripts.empty()) { 40 [ + - ][ + - ]: 313 : 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 [ + - ]: 313 : const bool is_combo{!desc.IsSingleType()}; 44 [ + + ][ + - ]: 313 : assert(is_combo || desc.ScriptSize() == out_scripts.back().size()); [ + - ][ + - ] [ - + ] 45 : 313 : } 46 : : 47 [ + - ]: 340 : const auto max_sat_maxsig{desc.MaxSatisfactionWeight(true)}; 48 [ + - ]: 340 : const auto max_sat_nonmaxsig{desc.MaxSatisfactionWeight(true)}; 49 [ + - ]: 340 : const auto max_elems{desc.MaxSatisfactionElems()}; 50 : : // We must be able to estimate the max satisfaction size for any solvable descriptor (but combo). 51 [ + + ][ + - ]: 340 : const bool is_nontop_or_nonsolvable{!is_solvable || !desc.GetOutputType()}; 52 [ + + ][ - + ]: 340 : const bool is_input_size_info_set{max_sat_maxsig && max_sat_nonmaxsig && max_elems}; 53 [ + + ][ + - ]: 340 : assert(is_input_size_info_set || is_nontop_or_nonsolvable); 54 : 340 : } 55 : : 56 : 1 : void initialize_descriptor_parse() 57 : : { 58 : 1 : ECC_Start(); 59 : 1 : SelectParams(ChainType::MAIN); 60 : 1 : } 61 : : 62 : 1 : void initialize_mocked_descriptor_parse() 63 : : { 64 : 1 : initialize_descriptor_parse(); 65 : 1 : MOCKED_DESC_CONVERTER.Init(); 66 : 1 : } 67 : : 68 [ + - ]: 833 : 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 [ + + ]: 829 : if (HasDeepDerivPath(buffer)) return; 74 : : 75 [ + - ]: 828 : const std::string mocked_descriptor{buffer.begin(), buffer.end()}; 76 [ + - ][ + + ]: 1640 : if (const auto descriptor = MOCKED_DESC_CONVERTER.GetDescriptor(mocked_descriptor)) { 77 : 812 : FlatSigningProvider signing_provider; 78 : 812 : std::string error; 79 [ + - ]: 812 : const auto desc = Parse(*descriptor, signing_provider, error); 80 [ + + ][ + - ]: 812 : if (desc) TestDescriptor(*desc, signing_provider, error); 81 : 812 : } 82 : 829 : } 83 : : 84 [ + - ]: 4 : FUZZ_TARGET(descriptor_parse, .init = initialize_descriptor_parse) 85 : : { 86 : : // See comment above for rationale. 87 [ # # ]: 0 : if (HasDeepDerivPath(buffer)) return; 88 : : 89 [ # # ]: 0 : const std::string descriptor(buffer.begin(), buffer.end()); 90 : 0 : FlatSigningProvider signing_provider; 91 : 0 : std::string error; 92 [ # # ]: 0 : for (const bool require_checksum : {true, false}) { 93 [ # # ]: 0 : const auto desc = Parse(descriptor, signing_provider, error, require_checksum); 94 [ # # ][ # # ]: 0 : if (desc) TestDescriptor(*desc, signing_provider, error); 95 : 0 : } 96 : 0 : }