1 // Copyright (c) 2019-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 <compressor.h>
7 #include <core_io.h>
8 #include <core_memusage.h>
9 #include <key_io.h>
10 #include <policy/policy.h>
11 #include <pubkey.h>
12 #include <rpc/util.h>
13 #include <script/descriptor.h>
14 #include <script/interpreter.h>
15 #include <script/script.h>
16 #include <script/script_error.h>
17 #include <script/sign.h>
18 #include <script/signingprovider.h>
19 #include <script/standard.h>
20 #include <streams.h>
21 #include <test/fuzz/FuzzedDataProvider.h>
22 #include <test/fuzz/fuzz.h>
23 #include <test/fuzz/util.h>
24 #include <univalue.h>
25 
26 #include <algorithm>
27 #include <cassert>
28 #include <cstdint>
29 #include <optional>
30 #include <string>
31 #include <vector>
32 
initialize_script()33 void initialize_script()
34 {
35     // Fuzzers using pubkey must hold an ECCVerifyHandle.
36     static const ECCVerifyHandle verify_handle;
37 
38     SelectParams(CBaseChainParams::REGTEST);
39 }
40 
FUZZ_TARGET_INIT(script,initialize_script)41 FUZZ_TARGET_INIT(script, initialize_script)
42 {
43     FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
44     const std::optional<CScript> script_opt = ConsumeDeserializable<CScript>(fuzzed_data_provider);
45     if (!script_opt) return;
46     const CScript script{*script_opt};
47 
48     CompressedScript compressed;
49     if (CompressScript(script, compressed)) {
50         const unsigned int size = compressed[0];
51         compressed.erase(compressed.begin());
52         assert(size <= 5);
53         CScript decompressed_script;
54         const bool ok = DecompressScript(decompressed_script, size, compressed);
55         assert(ok);
56         assert(script == decompressed_script);
57     }
58 
59     CTxDestination address;
60     TxoutType type_ret;
61     std::vector<CTxDestination> addresses;
62     int required_ret;
63     bool extract_destinations_ret = ExtractDestinations(script, type_ret, addresses, required_ret);
64     bool extract_destination_ret = ExtractDestination(script, address);
65     if (!extract_destinations_ret) {
66         assert(!extract_destination_ret);
67         if (type_ret == TxoutType::MULTISIG) {
68             assert(addresses.empty() && required_ret == 0);
69         } else {
70             assert(type_ret == TxoutType::PUBKEY ||
71                    type_ret == TxoutType::NONSTANDARD ||
72                    type_ret == TxoutType::NULL_DATA);
73         }
74     } else {
75         assert(required_ret >= 1 && required_ret <= 16);
76         assert((unsigned long)required_ret == addresses.size());
77         assert(type_ret == TxoutType::MULTISIG || required_ret == 1);
78     }
79     if (type_ret == TxoutType::NONSTANDARD || type_ret == TxoutType::NULL_DATA) {
80         assert(!extract_destinations_ret);
81     }
82     if (!extract_destination_ret) {
83         assert(type_ret == TxoutType::PUBKEY ||
84                type_ret == TxoutType::NONSTANDARD ||
85                type_ret == TxoutType::NULL_DATA ||
86                type_ret == TxoutType::MULTISIG);
87     } else {
88         assert(address == addresses[0]);
89     }
90     if (type_ret == TxoutType::NONSTANDARD ||
91         type_ret == TxoutType::NULL_DATA ||
92         type_ret == TxoutType::MULTISIG) {
93         assert(!extract_destination_ret);
94     }
95 
96     TxoutType which_type;
97     bool is_standard_ret = IsStandard(script, which_type);
98     assert(type_ret == which_type);
99     if (!is_standard_ret) {
100         assert(which_type == TxoutType::NONSTANDARD ||
101                which_type == TxoutType::NULL_DATA ||
102                which_type == TxoutType::MULTISIG);
103     }
104     if (which_type == TxoutType::NONSTANDARD) {
105         assert(!is_standard_ret);
106     }
107     if (which_type == TxoutType::NULL_DATA) {
108         assert(script.IsUnspendable());
109     }
110     if (script.IsUnspendable()) {
111         assert(which_type == TxoutType::NULL_DATA ||
112                which_type == TxoutType::NONSTANDARD);
113     }
114 
115     const FlatSigningProvider signing_provider;
116     (void)InferDescriptor(script, signing_provider);
117     (void)IsSegWitOutput(signing_provider, script);
118     (void)IsSolvable(signing_provider, script);
119 
120     (void)RecursiveDynamicUsage(script);
121 
122     std::vector<std::vector<unsigned char>> solutions;
123     (void)Solver(script, solutions);
124 
125     (void)script.HasValidOps();
126     (void)script.IsPayToScriptHash();
127     (void)script.IsPayToWitnessScriptHash();
128     (void)script.IsPushOnly();
129     (void)script.GetSigOpCount(/* fAccurate= */ false);
130 
131     (void)FormatScript(script);
132     (void)ScriptToAsmStr(script, false);
133     (void)ScriptToAsmStr(script, true);
134 
135     UniValue o1(UniValue::VOBJ);
136     ScriptPubKeyToUniv(script, o1, true, true);
137     ScriptPubKeyToUniv(script, o1, true, false);
138     UniValue o2(UniValue::VOBJ);
139     ScriptPubKeyToUniv(script, o2, false, true);
140     ScriptPubKeyToUniv(script, o2, false, false);
141     UniValue o3(UniValue::VOBJ);
142     ScriptToUniv(script, o3, true);
143     UniValue o4(UniValue::VOBJ);
144     ScriptToUniv(script, o4, false);
145 
146     {
147         const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
148         CompressedScript compressed_script;
149         compressed_script.assign(bytes.begin(), bytes.end());
150         // DecompressScript(..., ..., bytes) is not guaranteed to be defined if the bytes vector is too short
151         if (compressed_script.size() >= 32) {
152             CScript decompressed_script;
153             DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), compressed_script);
154         }
155     }
156 
157     const std::optional<CScript> other_script = ConsumeDeserializable<CScript>(fuzzed_data_provider);
158     if (other_script) {
159         {
160             CScript script_mut{script};
161             (void)FindAndDelete(script_mut, *other_script);
162         }
163         const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider);
164         const uint32_t u32{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
165         const uint32_t flags{u32 | SCRIPT_VERIFY_P2SH};
166         {
167             CScriptWitness wit;
168             for (const auto& s : random_string_vector) {
169                 wit.stack.emplace_back(s.begin(), s.end());
170             }
171             (void)CountWitnessSigOps(script, *other_script, &wit, flags);
172             wit.SetNull();
173         }
174     }
175 
176     (void)GetOpName(ConsumeOpcodeType(fuzzed_data_provider));
177     (void)ScriptErrorString(static_cast<ScriptError>(fuzzed_data_provider.ConsumeIntegralInRange<int>(0, SCRIPT_ERR_ERROR_COUNT)));
178 
179     {
180         const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
181         CScript append_script{bytes.begin(), bytes.end()};
182         append_script << fuzzed_data_provider.ConsumeIntegral<int64_t>();
183         append_script << ConsumeOpcodeType(fuzzed_data_provider);
184         append_script << CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()};
185         append_script << ConsumeRandomLengthByteVector(fuzzed_data_provider);
186     }
187 
188     {
189         const CTxDestination tx_destination_1{
190             fuzzed_data_provider.ConsumeBool() ?
191                 DecodeDestination(fuzzed_data_provider.ConsumeRandomLengthString()) :
192                 ConsumeTxDestination(fuzzed_data_provider)};
193         const CTxDestination tx_destination_2{ConsumeTxDestination(fuzzed_data_provider)};
194         const std::string encoded_dest{EncodeDestination(tx_destination_1)};
195         const UniValue json_dest{DescribeAddress(tx_destination_1)};
196         Assert(tx_destination_1 == DecodeDestination(encoded_dest));
197         (void)GetKeyForDestination(/* store */ {}, tx_destination_1);
198         const CScript dest{GetScriptForDestination(tx_destination_1)};
199         const bool valid{IsValidDestination(tx_destination_1)};
200         Assert(dest.empty() != valid);
201 
202         Assert(valid == IsValidDestinationString(encoded_dest));
203 
204         (void)(tx_destination_1 < tx_destination_2);
205         if (tx_destination_1 == tx_destination_2) {
206             Assert(encoded_dest == EncodeDestination(tx_destination_2));
207             Assert(json_dest.write() == DescribeAddress(tx_destination_2).write());
208             Assert(dest == GetScriptForDestination(tx_destination_2));
209         }
210     }
211 }
212