1 // Copyright (c) 2009-2020 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 <pubkey.h>
6 #include <script/interpreter.h>
7 #include <streams.h>
8 #include <util/memory.h>
9 #include <version.h>
10
11 #include <test/fuzz/fuzz.h>
12
13 /** Flags that are not forbidden by an assert */
14 static bool IsValidFlagCombination(unsigned flags);
15
initialize()16 void initialize()
17 {
18 static const ECCVerifyHandle verify_handle;
19 }
20
test_one_input(const std::vector<uint8_t> & buffer)21 void test_one_input(const std::vector<uint8_t>& buffer)
22 {
23 CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION);
24 try {
25 int nVersion;
26 ds >> nVersion;
27 ds.SetVersion(nVersion);
28 } catch (const std::ios_base::failure&) {
29 return;
30 }
31
32 try {
33 const CTransaction tx(deserialize, ds);
34
35 unsigned int verify_flags;
36 ds >> verify_flags;
37
38 if (!IsValidFlagCombination(verify_flags)) return;
39
40 unsigned int fuzzed_flags;
41 ds >> fuzzed_flags;
42
43 std::vector<CTxOut> spent_outputs;
44 for (unsigned i = 0; i < tx.vin.size(); ++i) {
45 CTxOut prevout;
46 ds >> prevout;
47 spent_outputs.push_back(prevout);
48 }
49 PrecomputedTransactionData txdata;
50 txdata.Init(tx, std::move(spent_outputs));
51
52 for (unsigned i = 0; i < tx.vin.size(); ++i) {
53 const CTxOut& prevout = txdata.m_spent_outputs.at(i);
54 const TransactionSignatureChecker checker{&tx, i, prevout.nValue, txdata};
55
56 ScriptError serror;
57 const bool ret = VerifyScript(tx.vin.at(i).scriptSig, prevout.scriptPubKey, &tx.vin.at(i).scriptWitness, verify_flags, checker, &serror);
58 assert(ret == (serror == SCRIPT_ERR_OK));
59
60 // Verify that removing flags from a passing test or adding flags to a failing test does not change the result
61 if (ret) {
62 verify_flags &= ~fuzzed_flags;
63 } else {
64 verify_flags |= fuzzed_flags;
65 }
66 if (!IsValidFlagCombination(verify_flags)) return;
67
68 ScriptError serror_fuzzed;
69 const bool ret_fuzzed = VerifyScript(tx.vin.at(i).scriptSig, prevout.scriptPubKey, &tx.vin.at(i).scriptWitness, verify_flags, checker, &serror_fuzzed);
70 assert(ret_fuzzed == (serror_fuzzed == SCRIPT_ERR_OK));
71
72 assert(ret_fuzzed == ret);
73 }
74 } catch (const std::ios_base::failure&) {
75 return;
76 }
77 }
78
IsValidFlagCombination(unsigned flags)79 static bool IsValidFlagCombination(unsigned flags)
80 {
81 if (flags & SCRIPT_VERIFY_CLEANSTACK && ~flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) return false;
82 if (flags & SCRIPT_VERIFY_WITNESS && ~flags & SCRIPT_VERIFY_P2SH) return false;
83 return true;
84 }
85