Branch data Line data Source code
1 : : // Copyright (c) 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 <primitives/transaction.h>
6 : : #include <script/interpreter.h>
7 : : #include <test/fuzz/FuzzedDataProvider.h>
8 : : #include <test/fuzz/fuzz.h>
9 : : #include <test/fuzz/util.h>
10 : : #include <util/check.h>
11 : :
12 : : #include <cstdint>
13 : : #include <optional>
14 : : #include <string>
15 : : #include <vector>
16 : :
17 : : bool CastToBool(const std::vector<unsigned char>& vch);
18 : :
19 [ + - ]: 1151 : FUZZ_TARGET(script_interpreter)
20 : : {
21 : 695 : FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
22 : 695 : {
23 : 695 : const CScript script_code = ConsumeScript(fuzzed_data_provider);
24 : 695 : const std::optional<CMutableTransaction> mtx = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS);
25 [ + + ]: 695 : if (mtx) {
26 [ + - ]: 455 : const CTransaction tx_to{*mtx};
27 : 455 : const unsigned int in = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
28 [ - + + + ]: 455 : if (in < tx_to.vin.size()) {
29 : 429 : auto n_hash_type = fuzzed_data_provider.ConsumeIntegral<int>();
30 : 429 : auto amount = ConsumeMoney(fuzzed_data_provider);
31 : 429 : auto sigversion = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0});
32 [ + - ]: 429 : (void)SignatureHash(script_code, tx_to, in, n_hash_type, amount, sigversion, nullptr);
33 : 429 : const std::optional<CMutableTransaction> mtx_precomputed = ConsumeDeserializable<CMutableTransaction>(fuzzed_data_provider, TX_WITH_WITNESS);
34 [ + + ]: 429 : if (mtx_precomputed) {
35 [ + - ]: 209 : const CTransaction tx_precomputed{*mtx_precomputed};
36 [ + - ]: 209 : const PrecomputedTransactionData precomputed_transaction_data{tx_precomputed};
37 : 209 : n_hash_type = fuzzed_data_provider.ConsumeIntegral<int>();
38 : 209 : amount = ConsumeMoney(fuzzed_data_provider);
39 : 209 : sigversion = fuzzed_data_provider.PickValueInArray({SigVersion::BASE, SigVersion::WITNESS_V0});
40 [ + - ]: 209 : (void)SignatureHash(script_code, tx_to, in, n_hash_type, amount, sigversion, &precomputed_transaction_data);
41 : 418 : }
42 : 429 : }
43 : 455 : }
44 : 695 : }
45 : 695 : {
46 [ + - ]: 695 : (void)CastToBool(ConsumeRandomLengthByteVector(fuzzed_data_provider));
47 : : }
48 : 695 : }
49 : :
50 : : /** Differential fuzzing for SignatureHash with and without cache. */
51 [ + - ]: 456 : FUZZ_TARGET(sighash_cache)
52 : : {
53 : 0 : FuzzedDataProvider provider(buffer.data(), buffer.size());
54 : :
55 : : // Get inputs to the sighash function that won't change across types.
56 : 0 : const auto scriptcode{ConsumeScript(provider)};
57 : 0 : const auto tx{ConsumeTransaction(provider, std::nullopt)};
58 [ # # ]: 0 : if (tx.vin.empty()) return;
59 [ # # ]: 0 : const auto in_index{provider.ConsumeIntegralInRange<uint32_t>(0, tx.vin.size() - 1)};
60 : 0 : const auto amount{ConsumeMoney(provider)};
61 : 0 : const auto sigversion{(SigVersion)provider.ConsumeIntegralInRange(0, 1)};
62 : :
63 : : // Check the sighash function will give the same result for 100 fuzzer-generated hash types whether or not a cache is
64 : : // provided. The cache is conserved across types to exercise cache hits.
65 : 0 : SigHashCache sighash_cache{};
66 [ # # ]: 0 : for (int i{0}; i < 100; ++i) {
67 [ # # ]: 0 : const auto hash_type{((i & 2) == 0) ? provider.ConsumeIntegral<int8_t>() : provider.ConsumeIntegral<int32_t>()};
68 [ # # ]: 0 : const auto nocache_res{SignatureHash(scriptcode, tx, in_index, hash_type, amount, sigversion)};
69 [ # # ]: 0 : const auto cache_res{SignatureHash(scriptcode, tx, in_index, hash_type, amount, sigversion, nullptr, &sighash_cache)};
70 [ # # ]: 0 : Assert(nocache_res == cache_res);
71 : : }
72 : 0 : }
|