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