diff options
Diffstat (limited to 'src/test/fuzz')
25 files changed, 1266 insertions, 30 deletions
diff --git a/src/test/fuzz/base_encode_decode.cpp b/src/test/fuzz/base_encode_decode.cpp index cb0fbdf76f..adad6b3f96 100644 --- a/src/test/fuzz/base_encode_decode.cpp +++ b/src/test/fuzz/base_encode_decode.cpp @@ -5,6 +5,7 @@ #include <test/fuzz/fuzz.h> #include <base58.h> +#include <psbt.h> #include <util/string.h> #include <util/strencodings.h> @@ -44,4 +45,8 @@ void test_one_input(const std::vector<uint8_t>& buffer) assert(encoded_string == TrimString(encoded_string)); assert(ToLower(encoded_string) == ToLower(TrimString(random_encoded_string))); } + + PartiallySignedTransaction psbt; + std::string error; + (void)DecodeBase64PSBT(psbt, random_encoded_string, error); } diff --git a/src/test/fuzz/block.cpp b/src/test/fuzz/block.cpp index 431248de4a..9d0ad369a2 100644 --- a/src/test/fuzz/block.cpp +++ b/src/test/fuzz/block.cpp @@ -19,7 +19,7 @@ void initialize() { - const static auto verify_handle = MakeUnique<ECCVerifyHandle>(); + static const ECCVerifyHandle verify_handle; SelectParams(CBaseChainParams::REGTEST); } @@ -59,5 +59,7 @@ void test_one_input(const std::vector<uint8_t>& buffer) } (void)GetBlockWeight(block); (void)GetWitnessCommitmentIndex(block); - (void)RecursiveDynamicUsage(block); + const size_t raw_memory_size = RecursiveDynamicUsage(block); + const size_t raw_memory_size_as_shared_ptr = RecursiveDynamicUsage(std::make_shared<CBlock>(block)); + assert(raw_memory_size_as_shared_ptr > raw_memory_size); } diff --git a/src/test/fuzz/bloom_filter.cpp b/src/test/fuzz/bloom_filter.cpp index b78744d9df..d1112f8e62 100644 --- a/src/test/fuzz/bloom_filter.cpp +++ b/src/test/fuzz/bloom_filter.cpp @@ -27,7 +27,7 @@ void test_one_input(const std::vector<uint8_t>& buffer) while (fuzzed_data_provider.remaining_bytes() > 0) { switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 6)) { case 0: { - const std::vector<unsigned char>& b = ConsumeRandomLengthByteVector(fuzzed_data_provider); + const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider); (void)bloom_filter.contains(b); bloom_filter.insert(b); const bool present = bloom_filter.contains(b); diff --git a/src/test/fuzz/descriptor_parse.cpp b/src/test/fuzz/descriptor_parse.cpp index 47d5038c26..a0ef08cca6 100644 --- a/src/test/fuzz/descriptor_parse.cpp +++ b/src/test/fuzz/descriptor_parse.cpp @@ -10,7 +10,7 @@ void initialize() { - static const auto verify_handle = MakeUnique<ECCVerifyHandle>(); + static const ECCVerifyHandle verify_handle; SelectParams(CBaseChainParams::REGTEST); } diff --git a/src/test/fuzz/deserialize.cpp b/src/test/fuzz/deserialize.cpp index f06f339b9d..964fc85302 100644 --- a/src/test/fuzz/deserialize.cpp +++ b/src/test/fuzz/deserialize.cpp @@ -13,6 +13,7 @@ #include <key.h> #include <merkleblock.h> #include <net.h> +#include <node/utxo_snapshot.h> #include <primitives/block.h> #include <protocol.h> #include <psbt.h> @@ -34,7 +35,7 @@ void initialize() { // Fuzzers using pubkey must hold an ECCVerifyHandle. - static const auto verify_handle = MakeUnique<ECCVerifyHandle>(); + static const ECCVerifyHandle verify_handle; } namespace { @@ -214,9 +215,24 @@ void test_one_input(const std::vector<uint8_t>& buffer) #elif BLOCKTRANSACTIONSREQUEST_DESERIALIZE BlockTransactionsRequest btr; DeserializeFromFuzzingInput(buffer, btr); +#elif SNAPSHOTMETADATA_DESERIALIZE + SnapshotMetadata snapshot_metadata; + DeserializeFromFuzzingInput(buffer, snapshot_metadata); +#elif UINT160_DESERIALIZE + uint160 u160; + DeserializeFromFuzzingInput(buffer, u160); + AssertEqualAfterSerializeDeserialize(u160); +#elif UINT256_DESERIALIZE + uint256 u256; + DeserializeFromFuzzingInput(buffer, u256); + AssertEqualAfterSerializeDeserialize(u256); #else #error Need at least one fuzz target to compile #endif + // Classes intentionally not covered in this file since their deserialization code is + // fuzzed elsewhere: + // * Deserialization of CTxOut is fuzzed in test/fuzz/tx_out.cpp + // * Deserialization of CMutableTransaction is fuzzed in src/test/fuzz/transaction.cpp } catch (const invalid_fuzzing_input_exception&) { } } diff --git a/src/test/fuzz/eval_script.cpp b/src/test/fuzz/eval_script.cpp index 7acdd76857..6a1b037630 100644 --- a/src/test/fuzz/eval_script.cpp +++ b/src/test/fuzz/eval_script.cpp @@ -12,7 +12,7 @@ void initialize() { - static const auto verify_handle = MakeUnique<ECCVerifyHandle>(); + static const ECCVerifyHandle verify_handle; } void test_one_input(const std::vector<uint8_t>& buffer) diff --git a/src/test/fuzz/float.cpp b/src/test/fuzz/float.cpp new file mode 100644 index 0000000000..a24bae5b35 --- /dev/null +++ b/src/test/fuzz/float.cpp @@ -0,0 +1,42 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <memusage.h> +#include <serialize.h> +#include <streams.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <version.h> + +#include <cassert> +#include <cstdint> + +void test_one_input(const std::vector<uint8_t>& buffer) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + + { + const double d = fuzzed_data_provider.ConsumeFloatingPoint<double>(); + (void)memusage::DynamicUsage(d); + assert(ser_uint64_to_double(ser_double_to_uint64(d)) == d); + + CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION); + stream << d; + double d_deserialized; + stream >> d_deserialized; + assert(d == d_deserialized); + } + + { + const float f = fuzzed_data_provider.ConsumeFloatingPoint<float>(); + (void)memusage::DynamicUsage(f); + assert(ser_uint32_to_float(ser_float_to_uint32(f)) == f); + + CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION); + stream << f; + float f_deserialized; + stream >> f_deserialized; + assert(f == f_deserialized); + } +} diff --git a/src/test/fuzz/hex.cpp b/src/test/fuzz/hex.cpp index 54693180be..3bbf0084c2 100644 --- a/src/test/fuzz/hex.cpp +++ b/src/test/fuzz/hex.cpp @@ -2,8 +2,13 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <core_io.h> +#include <pubkey.h> +#include <primitives/block.h> +#include <rpc/util.h> #include <test/fuzz/fuzz.h> - +#include <uint256.h> +#include <univalue.h> #include <util/strencodings.h> #include <cassert> @@ -11,6 +16,10 @@ #include <string> #include <vector> +void initialize() { + static const ECCVerifyHandle verify_handle; +} + void test_one_input(const std::vector<uint8_t>& buffer) { const std::string random_hex_string(buffer.begin(), buffer.end()); @@ -19,4 +28,16 @@ void test_one_input(const std::vector<uint8_t>& buffer) if (IsHex(random_hex_string)) { assert(ToLower(random_hex_string) == hex_data); } + (void)IsHexNumber(random_hex_string); + uint256 result; + (void)ParseHashStr(random_hex_string, result); + (void)uint256S(random_hex_string); + try { + (void)HexToPubKey(random_hex_string); + } catch (const UniValue&) { + } + CBlockHeader block_header; + (void)DecodeHexBlockHeader(block_header, random_hex_string); + CBlock block; + (void)DecodeHexBlk(block, random_hex_string); } diff --git a/src/test/fuzz/integer.cpp b/src/test/fuzz/integer.cpp index 723938bcdb..980042e811 100644 --- a/src/test/fuzz/integer.cpp +++ b/src/test/fuzz/integer.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <amount.h> #include <arith_uint256.h> #include <compressor.h> #include <consensus/merkle.h> @@ -13,17 +14,21 @@ #include <netbase.h> #include <policy/settings.h> #include <pow.h> +#include <protocol.h> #include <pubkey.h> #include <rpc/util.h> #include <script/signingprovider.h> #include <script/standard.h> #include <serialize.h> +#include <streams.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <uint256.h> +#include <util/moneystr.h> #include <util/strencodings.h> #include <util/system.h> #include <util/time.h> +#include <version.h> #include <cassert> #include <limits> @@ -53,10 +58,18 @@ void test_one_input(const std::vector<uint8_t>& buffer) // We cannot assume a specific value of std::is_signed<char>::value: // ConsumeIntegral<char>() instead of casting from {u,}int8_t. const char ch = fuzzed_data_provider.ConsumeIntegral<char>(); + const bool b = fuzzed_data_provider.ConsumeBool(); const Consensus::Params& consensus_params = Params().GetConsensus(); (void)CheckProofOfWork(u256, u32, consensus_params); - (void)CompressAmount(u64); + if (u64 <= MAX_MONEY) { + const uint64_t compressed_money_amount = CompressAmount(u64); + assert(u64 == DecompressAmount(compressed_money_amount)); + static const uint64_t compressed_money_amount_max = CompressAmount(MAX_MONEY - 1); + assert(compressed_money_amount <= compressed_money_amount_max); + } else { + (void)CompressAmount(u64); + } static const uint256 u256_min(uint256S("0000000000000000000000000000000000000000000000000000000000000000")); static const uint256 u256_max(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); const std::vector<uint256> v256{u256, u256_min, u256_max}; @@ -65,11 +78,19 @@ void test_one_input(const std::vector<uint8_t>& buffer) (void)DecompressAmount(u64); (void)FormatISO8601Date(i64); (void)FormatISO8601DateTime(i64); + // FormatMoney(i) not defined when i == std::numeric_limits<int64_t>::min() + if (i64 != std::numeric_limits<int64_t>::min()) { + int64_t parsed_money; + if (ParseMoney(FormatMoney(i64), parsed_money)) { + assert(parsed_money == i64); + } + } (void)GetSizeOfCompactSize(u64); (void)GetSpecialScriptSize(u32); // (void)GetVirtualTransactionSize(i64, i64); // function defined only for a subset of int64_t inputs // (void)GetVirtualTransactionSize(i64, i64, u32); // function defined only for a subset of int64_t/uint32_t inputs (void)HexDigit(ch); + (void)MoneyRange(i64); (void)i64tostr(i64); (void)IsDigit(ch); (void)IsSpace(ch); @@ -95,6 +116,14 @@ void test_one_input(const std::vector<uint8_t>& buffer) (void)SipHashUint256(u64, u64, u256); (void)SipHashUint256Extra(u64, u64, u256, u32); (void)ToLower(ch); + (void)ToUpper(ch); + // ValueFromAmount(i) not defined when i == std::numeric_limits<int64_t>::min() + if (i64 != std::numeric_limits<int64_t>::min()) { + int64_t parsed_money; + if (ParseMoney(ValueFromAmount(i64).getValStr(), parsed_money)) { + assert(parsed_money == i64); + } + } const arith_uint256 au256 = UintToArith256(u256); assert(ArithToUint256(au256) == u256); @@ -124,4 +153,74 @@ void test_one_input(const std::vector<uint8_t>& buffer) (void)GetScriptForDestination(destination); (void)IsValidDestination(destination); } + + { + CDataStream stream(SER_NETWORK, INIT_PROTO_VERSION); + + uint256 deserialized_u256; + stream << u256; + stream >> deserialized_u256; + assert(u256 == deserialized_u256 && stream.empty()); + + uint160 deserialized_u160; + stream << u160; + stream >> deserialized_u160; + assert(u160 == deserialized_u160 && stream.empty()); + + uint64_t deserialized_u64; + stream << u64; + stream >> deserialized_u64; + assert(u64 == deserialized_u64 && stream.empty()); + + int64_t deserialized_i64; + stream << i64; + stream >> deserialized_i64; + assert(i64 == deserialized_i64 && stream.empty()); + + uint32_t deserialized_u32; + stream << u32; + stream >> deserialized_u32; + assert(u32 == deserialized_u32 && stream.empty()); + + int32_t deserialized_i32; + stream << i32; + stream >> deserialized_i32; + assert(i32 == deserialized_i32 && stream.empty()); + + uint16_t deserialized_u16; + stream << u16; + stream >> deserialized_u16; + assert(u16 == deserialized_u16 && stream.empty()); + + int16_t deserialized_i16; + stream << i16; + stream >> deserialized_i16; + assert(i16 == deserialized_i16 && stream.empty()); + + uint8_t deserialized_u8; + stream << u8; + stream >> deserialized_u8; + assert(u8 == deserialized_u8 && stream.empty()); + + int8_t deserialized_i8; + stream << i8; + stream >> deserialized_i8; + assert(i8 == deserialized_i8 && stream.empty()); + + char deserialized_ch; + stream << ch; + stream >> deserialized_ch; + assert(ch == deserialized_ch && stream.empty()); + + bool deserialized_b; + stream << b; + stream >> deserialized_b; + assert(b == deserialized_b && stream.empty()); + } + + { + const ServiceFlags service_flags = (ServiceFlags)u64; + (void)HasAllDesirableServiceFlags(service_flags); + (void)MayHaveUsefulAddressDB(service_flags); + } } diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp new file mode 100644 index 0000000000..1919a5f881 --- /dev/null +++ b/src/test/fuzz/key.cpp @@ -0,0 +1,309 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <chainparams.h> +#include <chainparamsbase.h> +#include <key.h> +#include <key_io.h> +#include <outputtype.h> +#include <policy/policy.h> +#include <pubkey.h> +#include <rpc/util.h> +#include <script/keyorigin.h> +#include <script/script.h> +#include <script/sign.h> +#include <script/signingprovider.h> +#include <script/standard.h> +#include <streams.h> +#include <test/fuzz/fuzz.h> +#include <util/memory.h> +#include <util/strencodings.h> + +#include <cassert> +#include <cstdint> +#include <numeric> +#include <string> +#include <vector> + +void initialize() +{ + static const ECCVerifyHandle ecc_verify_handle; + ECC_Start(); + SelectParams(CBaseChainParams::REGTEST); +} + +void test_one_input(const std::vector<uint8_t>& buffer) +{ + const CKey key = [&] { + CKey k; + k.Set(buffer.begin(), buffer.end(), true); + return k; + }(); + if (!key.IsValid()) { + return; + } + + { + assert(key.begin() + key.size() == key.end()); + assert(key.IsCompressed()); + assert(key.size() == 32); + assert(DecodeSecret(EncodeSecret(key)) == key); + } + + { + CKey invalid_key; + assert(!(invalid_key == key)); + assert(!invalid_key.IsCompressed()); + assert(!invalid_key.IsValid()); + assert(invalid_key.size() == 0); + } + + { + CKey uncompressed_key; + uncompressed_key.Set(buffer.begin(), buffer.end(), false); + assert(!(uncompressed_key == key)); + assert(!uncompressed_key.IsCompressed()); + assert(key.size() == 32); + assert(uncompressed_key.begin() + uncompressed_key.size() == uncompressed_key.end()); + assert(uncompressed_key.IsValid()); + } + + { + CKey copied_key; + copied_key.Set(key.begin(), key.end(), key.IsCompressed()); + assert(copied_key == key); + } + + { + CKey negated_key = key; + negated_key.Negate(); + assert(negated_key.IsValid()); + assert(!(negated_key == key)); + + negated_key.Negate(); + assert(negated_key == key); + } + + const uint256 random_uint256 = Hash(buffer.begin(), buffer.end()); + + { + CKey child_key; + ChainCode child_chaincode; + const bool ok = key.Derive(child_key, child_chaincode, 0, random_uint256); + assert(ok); + assert(child_key.IsValid()); + assert(!(child_key == key)); + assert(child_chaincode != random_uint256); + } + + const CPubKey pubkey = key.GetPubKey(); + + { + assert(pubkey.size() == 33); + assert(key.VerifyPubKey(pubkey)); + assert(pubkey.GetHash() != random_uint256); + assert(pubkey.begin() + pubkey.size() == pubkey.end()); + assert(pubkey.data() == pubkey.begin()); + assert(pubkey.IsCompressed()); + assert(pubkey.IsValid()); + assert(pubkey.IsFullyValid()); + assert(HexToPubKey(HexStr(pubkey.begin(), pubkey.end())) == pubkey); + assert(GetAllDestinationsForKey(pubkey).size() == 3); + } + + { + CDataStream data_stream{SER_NETWORK, INIT_PROTO_VERSION}; + pubkey.Serialize(data_stream); + + CPubKey pubkey_deserialized; + pubkey_deserialized.Unserialize(data_stream); + assert(pubkey_deserialized == pubkey); + } + + { + const CScript tx_pubkey_script = GetScriptForRawPubKey(pubkey); + assert(!tx_pubkey_script.IsPayToScriptHash()); + assert(!tx_pubkey_script.IsPayToWitnessScriptHash()); + assert(!tx_pubkey_script.IsPushOnly()); + assert(!tx_pubkey_script.IsUnspendable()); + assert(tx_pubkey_script.HasValidOps()); + assert(tx_pubkey_script.size() == 35); + + const CScript tx_multisig_script = GetScriptForMultisig(1, {pubkey}); + assert(!tx_multisig_script.IsPayToScriptHash()); + assert(!tx_multisig_script.IsPayToWitnessScriptHash()); + assert(!tx_multisig_script.IsPushOnly()); + assert(!tx_multisig_script.IsUnspendable()); + assert(tx_multisig_script.HasValidOps()); + assert(tx_multisig_script.size() == 37); + + FillableSigningProvider fillable_signing_provider; + assert(IsSolvable(fillable_signing_provider, tx_pubkey_script)); + assert(IsSolvable(fillable_signing_provider, tx_multisig_script)); + assert(!IsSegWitOutput(fillable_signing_provider, tx_pubkey_script)); + assert(!IsSegWitOutput(fillable_signing_provider, tx_multisig_script)); + assert(fillable_signing_provider.GetKeys().size() == 0); + assert(!fillable_signing_provider.HaveKey(pubkey.GetID())); + + const bool ok_add_key = fillable_signing_provider.AddKey(key); + assert(ok_add_key); + assert(fillable_signing_provider.HaveKey(pubkey.GetID())); + + FillableSigningProvider fillable_signing_provider_pub; + assert(!fillable_signing_provider_pub.HaveKey(pubkey.GetID())); + + const bool ok_add_key_pubkey = fillable_signing_provider_pub.AddKeyPubKey(key, pubkey); + assert(ok_add_key_pubkey); + assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID())); + + txnouttype which_type_tx_pubkey; + const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, which_type_tx_pubkey); + assert(is_standard_tx_pubkey); + assert(which_type_tx_pubkey == txnouttype::TX_PUBKEY); + + txnouttype which_type_tx_multisig; + const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, which_type_tx_multisig); + assert(is_standard_tx_multisig); + assert(which_type_tx_multisig == txnouttype::TX_MULTISIG); + + std::vector<std::vector<unsigned char>> v_solutions_ret_tx_pubkey; + const txnouttype outtype_tx_pubkey = Solver(tx_pubkey_script, v_solutions_ret_tx_pubkey); + assert(outtype_tx_pubkey == txnouttype::TX_PUBKEY); + assert(v_solutions_ret_tx_pubkey.size() == 1); + assert(v_solutions_ret_tx_pubkey[0].size() == 33); + + std::vector<std::vector<unsigned char>> v_solutions_ret_tx_multisig; + const txnouttype outtype_tx_multisig = Solver(tx_multisig_script, v_solutions_ret_tx_multisig); + assert(outtype_tx_multisig == txnouttype::TX_MULTISIG); + assert(v_solutions_ret_tx_multisig.size() == 3); + assert(v_solutions_ret_tx_multisig[0].size() == 1); + assert(v_solutions_ret_tx_multisig[1].size() == 33); + assert(v_solutions_ret_tx_multisig[2].size() == 1); + + OutputType output_type{}; + const CTxDestination tx_destination = GetDestinationForKey(pubkey, output_type); + assert(output_type == OutputType::LEGACY); + assert(IsValidDestination(tx_destination)); + assert(CTxDestination{PKHash{pubkey}} == tx_destination); + + const CScript script_for_destination = GetScriptForDestination(tx_destination); + assert(script_for_destination.size() == 25); + + const std::string destination_address = EncodeDestination(tx_destination); + assert(DecodeDestination(destination_address) == tx_destination); + + const CPubKey pubkey_from_address_string = AddrToPubKey(fillable_signing_provider, destination_address); + assert(pubkey_from_address_string == pubkey); + + CKeyID key_id = pubkey.GetID(); + assert(!key_id.IsNull()); + assert(key_id == CKeyID{key_id}); + assert(key_id == GetKeyForDestination(fillable_signing_provider, tx_destination)); + + CPubKey pubkey_out; + const bool ok_get_pubkey = fillable_signing_provider.GetPubKey(key_id, pubkey_out); + assert(ok_get_pubkey); + + CKey key_out; + const bool ok_get_key = fillable_signing_provider.GetKey(key_id, key_out); + assert(ok_get_key); + assert(fillable_signing_provider.GetKeys().size() == 1); + assert(fillable_signing_provider.HaveKey(key_id)); + + KeyOriginInfo key_origin_info; + const bool ok_get_key_origin = fillable_signing_provider.GetKeyOrigin(key_id, key_origin_info); + assert(!ok_get_key_origin); + } + + { + const std::vector<unsigned char> vch_pubkey{pubkey.begin(), pubkey.end()}; + assert(CPubKey::ValidSize(vch_pubkey)); + assert(!CPubKey::ValidSize({pubkey.begin(), pubkey.begin() + pubkey.size() - 1})); + + const CPubKey pubkey_ctor_1{vch_pubkey}; + assert(pubkey == pubkey_ctor_1); + + const CPubKey pubkey_ctor_2{vch_pubkey.begin(), vch_pubkey.end()}; + assert(pubkey == pubkey_ctor_2); + + CPubKey pubkey_set; + pubkey_set.Set(vch_pubkey.begin(), vch_pubkey.end()); + assert(pubkey == pubkey_set); + } + + { + const CPubKey invalid_pubkey{}; + assert(!invalid_pubkey.IsValid()); + assert(!invalid_pubkey.IsFullyValid()); + assert(!(pubkey == invalid_pubkey)); + assert(pubkey != invalid_pubkey); + assert(pubkey < invalid_pubkey); + } + + { + // Cover CPubKey's operator[](unsigned int pos) + unsigned int sum = 0; + for (size_t i = 0; i < pubkey.size(); ++i) { + sum += pubkey[i]; + } + assert(std::accumulate(pubkey.begin(), pubkey.end(), 0U) == sum); + } + + { + CPubKey decompressed_pubkey = pubkey; + assert(decompressed_pubkey.IsCompressed()); + + const bool ok = decompressed_pubkey.Decompress(); + assert(ok); + assert(!decompressed_pubkey.IsCompressed()); + assert(decompressed_pubkey.size() == 65); + } + + { + std::vector<unsigned char> vch_sig; + const bool ok = key.Sign(random_uint256, vch_sig, false); + assert(ok); + assert(pubkey.Verify(random_uint256, vch_sig)); + assert(CPubKey::CheckLowS(vch_sig)); + + const std::vector<unsigned char> vch_invalid_sig{vch_sig.begin(), vch_sig.begin() + vch_sig.size() - 1}; + assert(!pubkey.Verify(random_uint256, vch_invalid_sig)); + assert(!CPubKey::CheckLowS(vch_invalid_sig)); + } + + { + std::vector<unsigned char> vch_compact_sig; + const bool ok_sign_compact = key.SignCompact(random_uint256, vch_compact_sig); + assert(ok_sign_compact); + + CPubKey recover_pubkey; + const bool ok_recover_compact = recover_pubkey.RecoverCompact(random_uint256, vch_compact_sig); + assert(ok_recover_compact); + assert(recover_pubkey == pubkey); + } + + { + CPubKey child_pubkey; + ChainCode child_chaincode; + const bool ok = pubkey.Derive(child_pubkey, child_chaincode, 0, random_uint256); + assert(ok); + assert(child_pubkey != pubkey); + assert(child_pubkey.IsCompressed()); + assert(child_pubkey.IsFullyValid()); + assert(child_pubkey.IsValid()); + assert(child_pubkey.size() == 33); + assert(child_chaincode != random_uint256); + } + + const CPrivKey priv_key = key.GetPrivKey(); + + { + for (const bool skip_check : {true, false}) { + CKey loaded_key; + const bool ok = loaded_key.Load(priv_key, pubkey, skip_check); + assert(ok); + assert(key == loaded_key); + } + } +} diff --git a/src/test/fuzz/key_io.cpp b/src/test/fuzz/key_io.cpp new file mode 100644 index 0000000000..62aefb650d --- /dev/null +++ b/src/test/fuzz/key_io.cpp @@ -0,0 +1,50 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <chainparams.h> +#include <key_io.h> +#include <rpc/util.h> +#include <script/signingprovider.h> +#include <script/standard.h> +#include <test/fuzz/fuzz.h> + +#include <cassert> +#include <cstdint> +#include <string> +#include <vector> + +void initialize() +{ + static const ECCVerifyHandle verify_handle; + ECC_Start(); + SelectParams(CBaseChainParams::MAIN); +} + +void test_one_input(const std::vector<uint8_t>& buffer) +{ + const std::string random_string(buffer.begin(), buffer.end()); + + const CKey key = DecodeSecret(random_string); + if (key.IsValid()) { + assert(key == DecodeSecret(EncodeSecret(key))); + } + + const CExtKey ext_key = DecodeExtKey(random_string); + if (ext_key.key.size() == 32) { + assert(ext_key == DecodeExtKey(EncodeExtKey(ext_key))); + } + + const CExtPubKey ext_pub_key = DecodeExtPubKey(random_string); + if (ext_pub_key.pubkey.size() == CPubKey::COMPRESSED_SIZE) { + assert(ext_pub_key == DecodeExtPubKey(EncodeExtPubKey(ext_pub_key))); + } + + const CTxDestination tx_destination = DecodeDestination(random_string); + (void)DescribeAddress(tx_destination); + (void)GetKeyForDestination(/* store */ {}, tx_destination); + (void)GetScriptForDestination(tx_destination); + (void)IsValidDestination(tx_destination); + + (void)IsValidDestinationString(random_string); +} diff --git a/src/test/fuzz/locale.cpp b/src/test/fuzz/locale.cpp new file mode 100644 index 0000000000..c8288123e8 --- /dev/null +++ b/src/test/fuzz/locale.cpp @@ -0,0 +1,96 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <test/fuzz/fuzz.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <tinyformat.h> +#include <util/strencodings.h> + +#include <cassert> +#include <clocale> +#include <cstdint> +#include <locale> +#include <string> +#include <vector> + +namespace { +const std::string locale_identifiers[] = { + "C", "C.UTF-8", "aa_DJ", "aa_DJ.ISO-8859-1", "aa_DJ.UTF-8", "aa_ER", "aa_ER.UTF-8", "aa_ET", "aa_ET.UTF-8", "af_ZA", "af_ZA.ISO-8859-1", "af_ZA.UTF-8", "agr_PE", "agr_PE.UTF-8", "ak_GH", "ak_GH.UTF-8", "am_ET", "am_ET.UTF-8", "an_ES", "an_ES.ISO-8859-15", "an_ES.UTF-8", "anp_IN", "anp_IN.UTF-8", "ar_AE", "ar_AE.ISO-8859-6", "ar_AE.UTF-8", "ar_BH", "ar_BH.ISO-8859-6", "ar_BH.UTF-8", "ar_DZ", "ar_DZ.ISO-8859-6", "ar_DZ.UTF-8", "ar_EG", "ar_EG.ISO-8859-6", "ar_EG.UTF-8", "ar_IN", "ar_IN.UTF-8", "ar_IQ", "ar_IQ.ISO-8859-6", "ar_IQ.UTF-8", "ar_JO", "ar_JO.ISO-8859-6", "ar_JO.UTF-8", "ar_KW", "ar_KW.ISO-8859-6", "ar_KW.UTF-8", "ar_LB", "ar_LB.ISO-8859-6", "ar_LB.UTF-8", "ar_LY", "ar_LY.ISO-8859-6", "ar_LY.UTF-8", "ar_MA", "ar_MA.ISO-8859-6", "ar_MA.UTF-8", "ar_OM", "ar_OM.ISO-8859-6", "ar_OM.UTF-8", "ar_QA", "ar_QA.ISO-8859-6", "ar_QA.UTF-8", "ar_SA", "ar_SA.ISO-8859-6", "ar_SA.UTF-8", "ar_SD", "ar_SD.ISO-8859-6", "ar_SD.UTF-8", "ar_SS", "ar_SS.UTF-8", "ar_SY", "ar_SY.ISO-8859-6", "ar_SY.UTF-8", "ar_TN", "ar_TN.ISO-8859-6", "ar_TN.UTF-8", "ar_YE", "ar_YE.ISO-8859-6", "ar_YE.UTF-8", "as_IN", "as_IN.UTF-8", "ast_ES", "ast_ES.ISO-8859-15", "ast_ES.UTF-8", "ayc_PE", "ayc_PE.UTF-8", "az_AZ", "az_AZ.UTF-8", "az_IR", "az_IR.UTF-8", "be_BY", "be_BY.CP1251", "be_BY.UTF-8", "bem_ZM", "bem_ZM.UTF-8", "ber_DZ", "ber_DZ.UTF-8", "ber_MA", "ber_MA.UTF-8", "bg_BG", "bg_BG.CP1251", "bg_BG.UTF-8", "bho_IN", "bho_IN.UTF-8", "bho_NP", "bho_NP.UTF-8", "bi_VU", "bi_VU.UTF-8", "bn_BD", "bn_BD.UTF-8", "bn_IN", "bn_IN.UTF-8", "bo_CN", "bo_CN.UTF-8", "bo_IN", "bo_IN.UTF-8", "br_FR", "br_FR.ISO-8859-1", "br_FR.UTF-8", "brx_IN", "brx_IN.UTF-8", "bs_BA", "bs_BA.ISO-8859-2", "bs_BA.UTF-8", "byn_ER", "byn_ER.UTF-8", "ca_AD", "ca_AD.ISO-8859-15", "ca_AD.UTF-8", "ca_ES", "ca_ES.ISO-8859-1", "ca_ES.UTF-8", "ca_FR", "ca_FR.ISO-8859-15", "ca_FR.UTF-8", "ca_IT", "ca_IT.ISO-8859-15", "ca_IT.UTF-8", "ce_RU", "ce_RU.UTF-8", "chr_US", "chr_US.UTF-8", "ckb_IQ", "ckb_IQ.UTF-8", "cmn_TW", "cmn_TW.UTF-8", "crh_UA", "crh_UA.UTF-8", "csb_PL", "csb_PL.UTF-8", "cs_CZ", "cs_CZ.ISO-8859-2", "cs_CZ.UTF-8", "cv_RU", "cv_RU.UTF-8", "cy_GB", "cy_GB.ISO-8859-14", "cy_GB.UTF-8", "da_DK", "da_DK.ISO-8859-1", "da_DK.UTF-8", "de_AT", "de_AT.ISO-8859-1", "de_AT.UTF-8", "de_BE", "de_BE.ISO-8859-1", "de_BE.UTF-8", "de_CH", "de_CH.ISO-8859-1", "de_CH.UTF-8", "de_DE", "de_DE.ISO-8859-1", "de_DE.UTF-8", "de_IT", "de_IT.ISO-8859-1", "de_IT.UTF-8", "de_LU", "de_LU.ISO-8859-1", "de_LU.UTF-8", "doi_IN", "doi_IN.UTF-8", "dv_MV", "dv_MV.UTF-8", "dz_BT", "dz_BT.UTF-8", "el_CY", "el_CY.ISO-8859-7", "el_CY.UTF-8", "el_GR", "el_GR.ISO-8859-7", "el_GR.UTF-8", "en_AG", "en_AG.UTF-8", "en_AU", "en_AU.ISO-8859-1", "en_AU.UTF-8", "en_BW", "en_BW.ISO-8859-1", "en_BW.UTF-8", "en_CA", "en_CA.ISO-8859-1", "en_CA.UTF-8", "en_DK", "en_DK.ISO-8859-1", "en_DK.ISO-8859-15", "en_DK.UTF-8", "en_GB", "en_GB.ISO-8859-1", "en_GB.ISO-8859-15", "en_GB.UTF-8", "en_HK", "en_HK.ISO-8859-1", "en_HK.UTF-8", "en_IE", "en_IE.ISO-8859-1", "en_IE.UTF-8", "en_IL", "en_IL.UTF-8", "en_IN", "en_IN.UTF-8", "en_NG", "en_NG.UTF-8", "en_NZ", "en_NZ.ISO-8859-1", "en_NZ.UTF-8", "en_PH", "en_PH.ISO-8859-1", "en_PH.UTF-8", "en_SG", "en_SG.ISO-8859-1", "en_SG.UTF-8", "en_US", "en_US.ISO-8859-1", "en_US.ISO-8859-15", "en_US.UTF-8", "en_ZA", "en_ZA.ISO-8859-1", "en_ZA.UTF-8", "en_ZM", "en_ZM.UTF-8", "en_ZW", "en_ZW.ISO-8859-1", "en_ZW.UTF-8", "es_AR", "es_AR.ISO-8859-1", "es_AR.UTF-8", "es_BO", "es_BO.ISO-8859-1", "es_BO.UTF-8", "es_CL", "es_CL.ISO-8859-1", "es_CL.UTF-8", "es_CO", "es_CO.ISO-8859-1", "es_CO.UTF-8", "es_CR", "es_CR.ISO-8859-1", "es_CR.UTF-8", "es_CU", "es_CU.UTF-8", "es_DO", "es_DO.ISO-8859-1", "es_DO.UTF-8", "es_EC", "es_EC.ISO-8859-1", "es_EC.UTF-8", "es_ES", "es_ES.ISO-8859-1", "es_ES.UTF-8", "es_GT", "es_GT.ISO-8859-1", "es_GT.UTF-8", "es_HN", "es_HN.ISO-8859-1", "es_HN.UTF-8", "es_MX", "es_MX.ISO-8859-1", "es_MX.UTF-8", "es_NI", "es_NI.ISO-8859-1", "es_NI.UTF-8", "es_PA", "es_PA.ISO-8859-1", "es_PA.UTF-8", "es_PE", "es_PE.ISO-8859-1", "es_PE.UTF-8", "es_PR", "es_PR.ISO-8859-1", "es_PR.UTF-8", "es_PY", "es_PY.ISO-8859-1", "es_PY.UTF-8", "es_SV", "es_SV.ISO-8859-1", "es_SV.UTF-8", "es_US", "es_US.ISO-8859-1", "es_US.UTF-8", "es_UY", "es_UY.ISO-8859-1", "es_UY.UTF-8", "es_VE", "es_VE.ISO-8859-1", "es_VE.UTF-8", "et_EE", "et_EE.ISO-8859-1", "et_EE.ISO-8859-15", "et_EE.UTF-8", "eu_ES", "eu_ES.ISO-8859-1", "eu_ES.UTF-8", "eu_FR", "eu_FR.ISO-8859-1", "eu_FR.UTF-8", "fa_IR", "fa_IR.UTF-8", "ff_SN", "ff_SN.UTF-8", "fi_FI", "fi_FI.ISO-8859-1", "fi_FI.UTF-8", "fil_PH", "fil_PH.UTF-8", "fo_FO", "fo_FO.ISO-8859-1", "fo_FO.UTF-8", "fr_BE", "fr_BE.ISO-8859-1", "fr_BE.UTF-8", "fr_CA", "fr_CA.ISO-8859-1", "fr_CA.UTF-8", "fr_CH", "fr_CH.ISO-8859-1", "fr_CH.UTF-8", "fr_FR", "fr_FR.ISO-8859-1", "fr_FR.UTF-8", "fr_LU", "fr_LU.ISO-8859-1", "fr_LU.UTF-8", "fur_IT", "fur_IT.UTF-8", "fy_DE", "fy_DE.UTF-8", "fy_NL", "fy_NL.UTF-8", "ga_IE", "ga_IE.ISO-8859-1", "ga_IE.UTF-8", "gd_GB", "gd_GB.ISO-8859-15", "gd_GB.UTF-8", "gez_ER", "gez_ER.UTF-8", "gez_ET", "gez_ET.UTF-8", "gl_ES", "gl_ES.ISO-8859-1", "gl_ES.UTF-8", "gu_IN", "gu_IN.UTF-8", "gv_GB", "gv_GB.ISO-8859-1", "gv_GB.UTF-8", "hak_TW", "hak_TW.UTF-8", "ha_NG", "ha_NG.UTF-8", "he_IL", "he_IL.ISO-8859-8", "he_IL.UTF-8", "hif_FJ", "hif_FJ.UTF-8", "hi_IN", "hi_IN.UTF-8", "hne_IN", "hne_IN.UTF-8", "hr_HR", "hr_HR.ISO-8859-2", "hr_HR.UTF-8", "hsb_DE", "hsb_DE.ISO-8859-2", "hsb_DE.UTF-8", "ht_HT", "ht_HT.UTF-8", "hu_HU", "hu_HU.ISO-8859-2", "hu_HU.UTF-8", "hy_AM", "hy_AM.ARMSCII-8", "hy_AM.UTF-8", "ia_FR", "ia_FR.UTF-8", "id_ID", "id_ID.ISO-8859-1", "id_ID.UTF-8", "ig_NG", "ig_NG.UTF-8", "ik_CA", "ik_CA.UTF-8", "is_IS", "is_IS.ISO-8859-1", "is_IS.UTF-8", "it_CH", "it_CH.ISO-8859-1", "it_CH.UTF-8", "it_IT", "it_IT.ISO-8859-1", "it_IT.UTF-8", "iu_CA", "iu_CA.UTF-8", "kab_DZ", "kab_DZ.UTF-8", "ka_GE", "ka_GE.GEORGIAN-PS", "ka_GE.UTF-8", "kk_KZ", "kk_KZ.PT154", "kk_KZ.RK1048", "kk_KZ.UTF-8", "kl_GL", "kl_GL.ISO-8859-1", "kl_GL.UTF-8", "km_KH", "km_KH.UTF-8", "kn_IN", "kn_IN.UTF-8", "kok_IN", "kok_IN.UTF-8", "ks_IN", "ks_IN.UTF-8", "ku_TR", "ku_TR.ISO-8859-9", "ku_TR.UTF-8", "kw_GB", "kw_GB.ISO-8859-1", "kw_GB.UTF-8", "ky_KG", "ky_KG.UTF-8", "lb_LU", "lb_LU.UTF-8", "lg_UG", "lg_UG.ISO-8859-10", "lg_UG.UTF-8", "li_BE", "li_BE.UTF-8", "lij_IT", "lij_IT.UTF-8", "li_NL", "li_NL.UTF-8", "ln_CD", "ln_CD.UTF-8", "lo_LA", "lo_LA.UTF-8", "lt_LT", "lt_LT.ISO-8859-13", "lt_LT.UTF-8", "lv_LV", "lv_LV.ISO-8859-13", "lv_LV.UTF-8", "lzh_TW", "lzh_TW.UTF-8", "mag_IN", "mag_IN.UTF-8", "mai_IN", "mai_IN.UTF-8", "mai_NP", "mai_NP.UTF-8", "mfe_MU", "mfe_MU.UTF-8", "mg_MG", "mg_MG.ISO-8859-15", "mg_MG.UTF-8", "mhr_RU", "mhr_RU.UTF-8", "mi_NZ", "mi_NZ.ISO-8859-13", "mi_NZ.UTF-8", "miq_NI", "miq_NI.UTF-8", "mjw_IN", "mjw_IN.UTF-8", "mk_MK", "mk_MK.ISO-8859-5", "mk_MK.UTF-8", "ml_IN", "ml_IN.UTF-8", "mni_IN", "mni_IN.UTF-8", "mn_MN", "mn_MN.UTF-8", "mr_IN", "mr_IN.UTF-8", "ms_MY", "ms_MY.ISO-8859-1", "ms_MY.UTF-8", "mt_MT", "mt_MT.ISO-8859-3", "mt_MT.UTF-8", "my_MM", "my_MM.UTF-8", "nan_TW", "nan_TW.UTF-8", "nb_NO", "nb_NO.ISO-8859-1", "nb_NO.UTF-8", "nds_DE", "nds_DE.UTF-8", "nds_NL", "nds_NL.UTF-8", "ne_NP", "ne_NP.UTF-8", "nhn_MX", "nhn_MX.UTF-8", "niu_NU", "niu_NU.UTF-8", "niu_NZ", "niu_NZ.UTF-8", "nl_AW", "nl_AW.UTF-8", "nl_BE", "nl_BE.ISO-8859-1", "nl_BE.UTF-8", "nl_NL", "nl_NL.ISO-8859-1", "nl_NL.UTF-8", "nn_NO", "nn_NO.ISO-8859-1", "nn_NO.UTF-8", "nr_ZA", "nr_ZA.UTF-8", "nso_ZA", "nso_ZA.UTF-8", "oc_FR", "oc_FR.ISO-8859-1", "oc_FR.UTF-8", "om_ET", "om_ET.UTF-8", "om_KE", "om_KE.ISO-8859-1", "om_KE.UTF-8", "or_IN", "or_IN.UTF-8", "os_RU", "os_RU.UTF-8", "pa_IN", "pa_IN.UTF-8", "pap_AW", "pap_AW.UTF-8", "pap_CW", "pap_CW.UTF-8", "pa_PK", "pa_PK.UTF-8", "pl_PL", "pl_PL.ISO-8859-2", "pl_PL.UTF-8", "ps_AF", "ps_AF.UTF-8", "pt_BR", "pt_BR.ISO-8859-1", "pt_BR.UTF-8", "pt_PT", "pt_PT.ISO-8859-1", "pt_PT.UTF-8", "quz_PE", "quz_PE.UTF-8", "raj_IN", "raj_IN.UTF-8", "ro_RO", "ro_RO.ISO-8859-2", "ro_RO.UTF-8", "ru_RU", "ru_RU.CP1251", "ru_RU.ISO-8859-5", "ru_RU.KOI8-R", "ru_RU.UTF-8", "ru_UA", "ru_UA.KOI8-U", "ru_UA.UTF-8", "rw_RW", "rw_RW.UTF-8", "sa_IN", "sa_IN.UTF-8", "sat_IN", "sat_IN.UTF-8", "sc_IT", "sc_IT.UTF-8", "sd_IN", "sd_IN.UTF-8", "sd_PK", "sd_PK.UTF-8", "se_NO", "se_NO.UTF-8", "sgs_LT", "sgs_LT.UTF-8", "shn_MM", "shn_MM.UTF-8", "shs_CA", "shs_CA.UTF-8", "sid_ET", "sid_ET.UTF-8", "si_LK", "si_LK.UTF-8", "sk_SK", "sk_SK.ISO-8859-2", "sk_SK.UTF-8", "sl_SI", "sl_SI.ISO-8859-2", "sl_SI.UTF-8", "sm_WS", "sm_WS.UTF-8", "so_DJ", "so_DJ.ISO-8859-1", "so_DJ.UTF-8", "so_ET", "so_ET.UTF-8", "so_KE", "so_KE.ISO-8859-1", "so_KE.UTF-8", "so_SO", "so_SO.ISO-8859-1", "so_SO.UTF-8", "sq_AL", "sq_AL.ISO-8859-1", "sq_AL.UTF-8", "sq_MK", "sq_MK.UTF-8", "sr_ME", "sr_ME.UTF-8", "sr_RS", "sr_RS.UTF-8", "ss_ZA", "ss_ZA.UTF-8", "st_ZA", "st_ZA.ISO-8859-1", "st_ZA.UTF-8", "sv_FI", "sv_FI.ISO-8859-1", "sv_FI.UTF-8", "sv_SE", "sv_SE.ISO-8859-1", "sv_SE.ISO-8859-15", "sv_SE.UTF-8", "sw_KE", "sw_KE.UTF-8", "sw_TZ", "sw_TZ.UTF-8", "szl_PL", "szl_PL.UTF-8", "ta_IN", "ta_IN.UTF-8", "ta_LK", "ta_LK.UTF-8", "te_IN", "te_IN.UTF-8", "tg_TJ", "tg_TJ.KOI8-T", "tg_TJ.UTF-8", "the_NP", "the_NP.UTF-8", "th_TH", "th_TH.TIS-620", "th_TH.UTF-8", "ti_ER", "ti_ER.UTF-8", "ti_ET", "ti_ET.UTF-8", "tig_ER", "tig_ER.UTF-8", "tk_TM", "tk_TM.UTF-8", "tl_PH", "tl_PH.ISO-8859-1", "tl_PH.UTF-8", "tn_ZA", "tn_ZA.UTF-8", "to_TO", "to_TO.UTF-8", "tpi_PG", "tpi_PG.UTF-8", "tr_CY", "tr_CY.ISO-8859-9", "tr_CY.UTF-8", "tr_TR", "tr_TR.ISO-8859-9", "tr_TR.UTF-8", "ts_ZA", "ts_ZA.UTF-8", "tt_RU", "tt_RU.UTF-8", "ug_CN", "ug_CN.UTF-8", "uk_UA", "uk_UA.KOI8-U", "uk_UA.UTF-8", "unm_US", "unm_US.UTF-8", "ur_IN", "ur_IN.UTF-8", "ur_PK", "ur_PK.UTF-8", "uz_UZ", "uz_UZ.ISO-8859-1", "uz_UZ.UTF-8", "ve_ZA", "ve_ZA.UTF-8", "vi_VN", "vi_VN.UTF-8", "wa_BE", "wa_BE.ISO-8859-1", "wa_BE.UTF-8", "wae_CH", "wae_CH.UTF-8", "wal_ET", "wal_ET.UTF-8", "wo_SN", "wo_SN.UTF-8", "xh_ZA", "xh_ZA.ISO-8859-1", "xh_ZA.UTF-8", "yi_US", "yi_US.CP1255", "yi_US.UTF-8", "yo_NG", "yo_NG.UTF-8", "yue_HK", "yue_HK.UTF-8", "yuw_PG", "yuw_PG.UTF-8", "zh_CN", "zh_CN.GB18030", "zh_CN.GB2312", "zh_CN.GBK", "zh_CN.UTF-8", "zh_HK", "zh_HK.BIG5-HKSCS", "zh_HK.UTF-8", "zh_SG", "zh_SG.GB2312", "zh_SG.GBK", "zh_SG.UTF-8", "zh_TW", "zh_TW.BIG5", "zh_TW.EUC-TW", "zh_TW.UTF-8", "zu_ZA", "zu_ZA.ISO-8859-1", "zu_ZA.UTF-8" +}; + +std::string ConsumeLocaleIdentifier(FuzzedDataProvider& fuzzed_data_provider) +{ + return fuzzed_data_provider.PickValueInArray<std::string>(locale_identifiers); +} + +bool IsAvailableLocale(const std::string& locale_identifier) +{ + try { + (void)std::locale(locale_identifier); + } catch (const std::runtime_error&) { + return false; + } + return true; +} +} // namespace + +void test_one_input(const std::vector<uint8_t>& buffer) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + const std::string locale_identifier = ConsumeLocaleIdentifier(fuzzed_data_provider); + if (!IsAvailableLocale(locale_identifier)) { + return; + } + const char* c_locale = std::setlocale(LC_ALL, "C"); + assert(c_locale != nullptr); + + const std::string random_string = fuzzed_data_provider.ConsumeRandomLengthString(5); + int32_t parseint32_out_without_locale; + const bool parseint32_without_locale = ParseInt32(random_string, &parseint32_out_without_locale); + int64_t parseint64_out_without_locale; + const bool parseint64_without_locale = ParseInt64(random_string, &parseint64_out_without_locale); + const int64_t atoi64_without_locale = atoi64(random_string); + const int atoi_without_locale = atoi(random_string); + const int64_t atoi64c_without_locale = atoi64(random_string.c_str()); + const int64_t random_int64 = fuzzed_data_provider.ConsumeIntegral<int64_t>(); + const std::string i64tostr_without_locale = i64tostr(random_int64); + const int32_t random_int32 = fuzzed_data_provider.ConsumeIntegral<int32_t>(); + const std::string itostr_without_locale = itostr(random_int32); + const std::string strprintf_int_without_locale = strprintf("%d", random_int64); + const double random_double = fuzzed_data_provider.ConsumeFloatingPoint<double>(); + const std::string strprintf_double_without_locale = strprintf("%f", random_double); + + const char* new_locale = std::setlocale(LC_ALL, locale_identifier.c_str()); + assert(new_locale != nullptr); + + int32_t parseint32_out_with_locale; + const bool parseint32_with_locale = ParseInt32(random_string, &parseint32_out_with_locale); + assert(parseint32_without_locale == parseint32_with_locale); + if (parseint32_without_locale) { + assert(parseint32_out_without_locale == parseint32_out_with_locale); + } + int64_t parseint64_out_with_locale; + const bool parseint64_with_locale = ParseInt64(random_string, &parseint64_out_with_locale); + assert(parseint64_without_locale == parseint64_with_locale); + if (parseint64_without_locale) { + assert(parseint64_out_without_locale == parseint64_out_with_locale); + } + const int64_t atoi64_with_locale = atoi64(random_string); + assert(atoi64_without_locale == atoi64_with_locale); + const int64_t atoi64c_with_locale = atoi64(random_string.c_str()); + assert(atoi64c_without_locale == atoi64c_with_locale); + const int atoi_with_locale = atoi(random_string); + assert(atoi_without_locale == atoi_with_locale); + const std::string i64tostr_with_locale = i64tostr(random_int64); + assert(i64tostr_without_locale == i64tostr_with_locale); + const std::string itostr_with_locale = itostr(random_int32); + assert(itostr_without_locale == itostr_with_locale); + const std::string strprintf_int_with_locale = strprintf("%d", random_int64); + assert(strprintf_int_without_locale == strprintf_int_with_locale); + const std::string strprintf_double_with_locale = strprintf("%f", random_double); + assert(strprintf_double_without_locale == strprintf_double_with_locale); + + const std::locale current_cpp_locale; + assert(current_cpp_locale == std::locale::classic()); +} diff --git a/src/test/fuzz/netaddress.cpp b/src/test/fuzz/netaddress.cpp new file mode 100644 index 0000000000..d8d53566c7 --- /dev/null +++ b/src/test/fuzz/netaddress.cpp @@ -0,0 +1,134 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <netaddress.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> + +#include <cassert> +#include <cstdint> +#include <netinet/in.h> +#include <vector> + +namespace { +CNetAddr ConsumeNetAddr(FuzzedDataProvider& fuzzed_data_provider) noexcept +{ + const Network network = fuzzed_data_provider.PickValueInArray({Network::NET_IPV4, Network::NET_IPV6, Network::NET_INTERNAL, Network::NET_ONION}); + if (network == Network::NET_IPV4) { + const in_addr v4_addr = { + .s_addr = fuzzed_data_provider.ConsumeIntegral<uint32_t>()}; + return CNetAddr{v4_addr}; + } else if (network == Network::NET_IPV6) { + if (fuzzed_data_provider.remaining_bytes() < 16) { + return CNetAddr{}; + } + in6_addr v6_addr = {}; + memcpy(v6_addr.s6_addr, fuzzed_data_provider.ConsumeBytes<uint8_t>(16).data(), 16); + return CNetAddr{v6_addr, fuzzed_data_provider.ConsumeIntegral<uint32_t>()}; + } else if (network == Network::NET_INTERNAL) { + CNetAddr net_addr; + net_addr.SetInternal(fuzzed_data_provider.ConsumeBytesAsString(32)); + return net_addr; + } else if (network == Network::NET_ONION) { + CNetAddr net_addr; + net_addr.SetSpecial(fuzzed_data_provider.ConsumeBytesAsString(32)); + return net_addr; + } else { + assert(false); + } +} +}; // namespace + +void test_one_input(const std::vector<uint8_t>& buffer) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + + const CNetAddr net_addr = ConsumeNetAddr(fuzzed_data_provider); + for (int i = 0; i < 15; ++i) { + (void)net_addr.GetByte(i); + } + (void)net_addr.GetHash(); + (void)net_addr.GetNetClass(); + if (net_addr.GetNetwork() == Network::NET_IPV4) { + assert(net_addr.IsIPv4()); + } + if (net_addr.GetNetwork() == Network::NET_IPV6) { + assert(net_addr.IsIPv6()); + } + if (net_addr.GetNetwork() == Network::NET_ONION) { + assert(net_addr.IsTor()); + } + if (net_addr.GetNetwork() == Network::NET_INTERNAL) { + assert(net_addr.IsInternal()); + } + if (net_addr.GetNetwork() == Network::NET_UNROUTABLE) { + assert(!net_addr.IsRoutable()); + } + (void)net_addr.IsBindAny(); + if (net_addr.IsInternal()) { + assert(net_addr.GetNetwork() == Network::NET_INTERNAL); + } + if (net_addr.IsIPv4()) { + assert(net_addr.GetNetwork() == Network::NET_IPV4 || net_addr.GetNetwork() == Network::NET_UNROUTABLE); + } + if (net_addr.IsIPv6()) { + assert(net_addr.GetNetwork() == Network::NET_IPV6 || net_addr.GetNetwork() == Network::NET_UNROUTABLE); + } + (void)net_addr.IsLocal(); + if (net_addr.IsRFC1918() || net_addr.IsRFC2544() || net_addr.IsRFC6598() || net_addr.IsRFC5737() || net_addr.IsRFC3927()) { + assert(net_addr.IsIPv4()); + } + (void)net_addr.IsRFC2544(); + if (net_addr.IsRFC3849() || net_addr.IsRFC3964() || net_addr.IsRFC4380() || net_addr.IsRFC4843() || net_addr.IsRFC7343() || net_addr.IsRFC4862() || net_addr.IsRFC6052() || net_addr.IsRFC6145()) { + assert(net_addr.IsIPv6()); + } + (void)net_addr.IsRFC3927(); + (void)net_addr.IsRFC3964(); + if (net_addr.IsRFC4193()) { + assert(net_addr.GetNetwork() == Network::NET_ONION || net_addr.GetNetwork() == Network::NET_INTERNAL || net_addr.GetNetwork() == Network::NET_UNROUTABLE); + } + (void)net_addr.IsRFC4380(); + (void)net_addr.IsRFC4843(); + (void)net_addr.IsRFC4862(); + (void)net_addr.IsRFC5737(); + (void)net_addr.IsRFC6052(); + (void)net_addr.IsRFC6145(); + (void)net_addr.IsRFC6598(); + (void)net_addr.IsRFC7343(); + if (!net_addr.IsRoutable()) { + assert(net_addr.GetNetwork() == Network::NET_UNROUTABLE || net_addr.GetNetwork() == Network::NET_INTERNAL); + } + if (net_addr.IsTor()) { + assert(net_addr.GetNetwork() == Network::NET_ONION); + } + (void)net_addr.IsValid(); + (void)net_addr.ToString(); + (void)net_addr.ToStringIP(); + + const CSubNet sub_net{net_addr, fuzzed_data_provider.ConsumeIntegral<int32_t>()}; + (void)sub_net.IsValid(); + (void)sub_net.ToString(); + + const CService service{net_addr, fuzzed_data_provider.ConsumeIntegral<uint16_t>()}; + (void)service.GetKey(); + (void)service.GetPort(); + (void)service.ToString(); + (void)service.ToStringIPPort(); + (void)service.ToStringPort(); + + const CNetAddr other_net_addr = ConsumeNetAddr(fuzzed_data_provider); + (void)net_addr.GetReachabilityFrom(&other_net_addr); + (void)sub_net.Match(other_net_addr); + + const CService other_service{net_addr, fuzzed_data_provider.ConsumeIntegral<uint16_t>()}; + assert((service == other_service) != (service != other_service)); + (void)(service < other_service); + + const CSubNet sub_net_copy_1{net_addr, other_net_addr}; + const CSubNet sub_net_copy_2{net_addr}; + + CNetAddr mutable_net_addr; + mutable_net_addr.SetIP(net_addr); + assert(net_addr == mutable_net_addr); +} diff --git a/src/test/fuzz/p2p_transport_deserializer.cpp b/src/test/fuzz/p2p_transport_deserializer.cpp new file mode 100644 index 0000000000..57393fed45 --- /dev/null +++ b/src/test/fuzz/p2p_transport_deserializer.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <chainparams.h> +#include <net.h> +#include <protocol.h> +#include <test/fuzz/fuzz.h> + +#include <cassert> +#include <cstdint> +#include <limits> +#include <vector> + +void initialize() +{ + SelectParams(CBaseChainParams::REGTEST); +} + +void test_one_input(const std::vector<uint8_t>& buffer) +{ + V1TransportDeserializer deserializer{Params().MessageStart(), SER_NETWORK, INIT_PROTO_VERSION}; + const char* pch = (const char*)buffer.data(); + size_t n_bytes = buffer.size(); + while (n_bytes > 0) { + const int handled = deserializer.Read(pch, n_bytes); + if (handled < 0) { + break; + } + pch += handled; + n_bytes -= handled; + if (deserializer.Complete()) { + const int64_t m_time = std::numeric_limits<int64_t>::max(); + const CNetMessage msg = deserializer.GetMessage(Params().MessageStart(), m_time); + assert(msg.m_command.size() <= CMessageHeader::COMMAND_SIZE); + assert(msg.m_raw_message_size <= buffer.size()); + assert(msg.m_raw_message_size == CMessageHeader::HEADER_SIZE + msg.m_message_size); + assert(msg.m_time == m_time); + if (msg.m_valid_header) { + assert(msg.m_valid_netmagic); + } + if (!msg.m_valid_netmagic) { + assert(!msg.m_valid_header); + } + } + } +} diff --git a/src/test/fuzz/parse_univalue.cpp b/src/test/fuzz/parse_univalue.cpp index 3ad112dbad..571364aaa6 100644 --- a/src/test/fuzz/parse_univalue.cpp +++ b/src/test/fuzz/parse_univalue.cpp @@ -14,7 +14,7 @@ void initialize() { - static const auto verify_handle = MakeUnique<ECCVerifyHandle>(); + static const ECCVerifyHandle verify_handle; SelectParams(CBaseChainParams::REGTEST); } @@ -35,21 +35,31 @@ void test_one_input(const std::vector<uint8_t>& buffer) } try { (void)ParseHashO(univalue, "A"); + } catch (const UniValue&) { + } catch (const std::runtime_error&) { + } + try { (void)ParseHashO(univalue, random_string); } catch (const UniValue&) { } catch (const std::runtime_error&) { } try { (void)ParseHashV(univalue, "A"); + } catch (const UniValue&) { + } catch (const std::runtime_error&) { + } + try { (void)ParseHashV(univalue, random_string); } catch (const UniValue&) { } catch (const std::runtime_error&) { } try { (void)ParseHexO(univalue, "A"); + } catch (const UniValue&) { + } + try { (void)ParseHexO(univalue, random_string); } catch (const UniValue&) { - } catch (const std::runtime_error&) { } try { (void)ParseHexUV(univalue, "A"); @@ -59,6 +69,10 @@ void test_one_input(const std::vector<uint8_t>& buffer) } try { (void)ParseHexV(univalue, "A"); + } catch (const UniValue&) { + } catch (const std::runtime_error&) { + } + try { (void)ParseHexV(univalue, random_string); } catch (const UniValue&) { } catch (const std::runtime_error&) { diff --git a/src/test/fuzz/process_message.cpp b/src/test/fuzz/process_message.cpp new file mode 100644 index 0000000000..934f741068 --- /dev/null +++ b/src/test/fuzz/process_message.cpp @@ -0,0 +1,98 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <banman.h> +#include <chainparams.h> +#include <consensus/consensus.h> +#include <net.h> +#include <net_processing.h> +#include <protocol.h> +#include <scheduler.h> +#include <script/script.h> +#include <streams.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/util/mining.h> +#include <test/util/setup_common.h> +#include <util/memory.h> +#include <validationinterface.h> +#include <version.h> + +#include <algorithm> +#include <atomic> +#include <cassert> +#include <chrono> +#include <cstdint> +#include <iosfwd> +#include <iostream> +#include <map> +#include <memory> +#include <set> +#include <string> +#include <vector> + +bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, BanMan* banman, const std::atomic<bool>& interruptMsgProc); + +namespace { + +#ifdef MESSAGE_TYPE +#define TO_STRING_(s) #s +#define TO_STRING(s) TO_STRING_(s) +const std::string LIMIT_TO_MESSAGE_TYPE{TO_STRING(MESSAGE_TYPE)}; +#else +const std::string LIMIT_TO_MESSAGE_TYPE; +#endif + +const std::map<std::string, std::set<std::string>> EXPECTED_DESERIALIZATION_EXCEPTIONS = { + {"CDataStream::read(): end of data: iostream error", {"addr", "block", "blocktxn", "cmpctblock", "feefilter", "filteradd", "filterload", "getblocks", "getblocktxn", "getdata", "getheaders", "headers", "inv", "notfound", "ping", "sendcmpct", "tx"}}, + {"CompactSize exceeds limit of type: iostream error", {"cmpctblock"}}, + {"differential value overflow: iostream error", {"getblocktxn"}}, + {"index overflowed 16 bits: iostream error", {"getblocktxn"}}, + {"index overflowed 16-bits: iostream error", {"cmpctblock"}}, + {"indexes overflowed 16 bits: iostream error", {"getblocktxn"}}, + {"non-canonical ReadCompactSize(): iostream error", {"addr", "block", "blocktxn", "cmpctblock", "filteradd", "filterload", "getblocks", "getblocktxn", "getdata", "getheaders", "headers", "inv", "notfound", "tx"}}, + {"ReadCompactSize(): size too large: iostream error", {"addr", "block", "blocktxn", "cmpctblock", "filteradd", "filterload", "getblocks", "getblocktxn", "getdata", "getheaders", "headers", "inv", "notfound", "tx"}}, + {"Superfluous witness record: iostream error", {"block", "blocktxn", "cmpctblock", "tx"}}, + {"Unknown transaction optional data: iostream error", {"block", "blocktxn", "cmpctblock", "tx"}}, +}; + +const RegTestingSetup* g_setup; +} // namespace + +void initialize() +{ + static RegTestingSetup setup{}; + g_setup = &setup; + + for (int i = 0; i < 2 * COINBASE_MATURITY; i++) { + MineBlock(g_setup->m_node, CScript() << OP_TRUE); + } + SyncWithValidationInterfaceQueue(); +} + +void test_one_input(const std::vector<uint8_t>& buffer) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + const std::string random_message_type{fuzzed_data_provider.ConsumeBytesAsString(CMessageHeader::COMMAND_SIZE).c_str()}; + if (!LIMIT_TO_MESSAGE_TYPE.empty() && random_message_type != LIMIT_TO_MESSAGE_TYPE) { + return; + } + CDataStream random_bytes_data_stream{fuzzed_data_provider.ConsumeRemainingBytes<unsigned char>(), SER_NETWORK, PROTOCOL_VERSION}; + CNode p2p_node{0, ServiceFlags(NODE_NETWORK | NODE_WITNESS | NODE_BLOOM), 0, INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, false}; + p2p_node.fSuccessfullyConnected = true; + p2p_node.nVersion = PROTOCOL_VERSION; + p2p_node.SetSendVersion(PROTOCOL_VERSION); + g_setup->m_node.peer_logic->InitializeNode(&p2p_node); + try { + (void)ProcessMessage(&p2p_node, random_message_type, random_bytes_data_stream, GetTimeMillis(), Params(), g_setup->m_node.connman.get(), g_setup->m_node.banman.get(), std::atomic<bool>{false}); + } catch (const std::ios_base::failure& e) { + const std::string exception_message{e.what()}; + const auto p = EXPECTED_DESERIALIZATION_EXCEPTIONS.find(exception_message); + if (p == EXPECTED_DESERIALIZATION_EXCEPTIONS.cend() || p->second.count(random_message_type) == 0) { + std::cout << "Unexpected exception when processing message type \"" << random_message_type << "\": " << exception_message << std::endl; + assert(false); + } + } + SyncWithValidationInterfaceQueue(); +} diff --git a/src/test/fuzz/psbt.cpp b/src/test/fuzz/psbt.cpp index 1ce28f9a6d..ca3e0b8586 100644 --- a/src/test/fuzz/psbt.cpp +++ b/src/test/fuzz/psbt.cpp @@ -19,7 +19,7 @@ void initialize() { - static const auto verify_handle = MakeUnique<ECCVerifyHandle>(); + static const ECCVerifyHandle verify_handle; } void test_one_input(const std::vector<uint8_t>& buffer) diff --git a/src/test/fuzz/rolling_bloom_filter.cpp b/src/test/fuzz/rolling_bloom_filter.cpp index ce69c4e8da..3b37321977 100644 --- a/src/test/fuzz/rolling_bloom_filter.cpp +++ b/src/test/fuzz/rolling_bloom_filter.cpp @@ -24,7 +24,7 @@ void test_one_input(const std::vector<uint8_t>& buffer) while (fuzzed_data_provider.remaining_bytes() > 0) { switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 2)) { case 0: { - const std::vector<unsigned char>& b = ConsumeRandomLengthByteVector(fuzzed_data_provider); + const std::vector<unsigned char> b = ConsumeRandomLengthByteVector(fuzzed_data_provider); (void)rolling_bloom_filter.contains(b); rolling_bloom_filter.insert(b); const bool present = rolling_bloom_filter.contains(b); diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index 0469e87de6..2f50f1b838 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -14,13 +14,18 @@ #include <script/signingprovider.h> #include <script/standard.h> #include <streams.h> +#include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> +#include <univalue.h> #include <util/memory.h> void initialize() { // Fuzzers using pubkey must hold an ECCVerifyHandle. - static const auto verify_handle = MakeUnique<ECCVerifyHandle>(); + static const ECCVerifyHandle verify_handle; + + SelectParams(CBaseChainParams::REGTEST); } void test_one_input(const std::vector<uint8_t>& buffer) @@ -28,7 +33,15 @@ void test_one_input(const std::vector<uint8_t>& buffer) const CScript script(buffer.begin(), buffer.end()); std::vector<unsigned char> compressed; - (void)CompressScript(script, compressed); + if (CompressScript(script, compressed)) { + const unsigned int size = compressed[0]; + compressed.erase(compressed.begin()); + assert(size >= 0 && size <= 5); + CScript decompressed_script; + const bool ok = DecompressScript(decompressed_script, size, compressed); + assert(ok); + assert(script == decompressed_script); + } CTxDestination address; (void)ExtractDestination(script, address); @@ -61,4 +74,27 @@ void test_one_input(const std::vector<uint8_t>& buffer) (void)script.IsPushOnly(); (void)script.IsUnspendable(); (void)script.GetSigOpCount(/* fAccurate= */ false); + + (void)FormatScript(script); + (void)ScriptToAsmStr(script, false); + (void)ScriptToAsmStr(script, true); + + UniValue o1(UniValue::VOBJ); + ScriptPubKeyToUniv(script, o1, true); + UniValue o2(UniValue::VOBJ); + ScriptPubKeyToUniv(script, o2, false); + UniValue o3(UniValue::VOBJ); + ScriptToUniv(script, o3, true); + UniValue o4(UniValue::VOBJ); + ScriptToUniv(script, o4, false); + + { + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider); + // DecompressScript(..., ..., bytes) is not guaranteed to be defined if bytes.size() <= 23. + if (bytes.size() >= 24) { + CScript decompressed_script; + DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), bytes); + } + } } diff --git a/src/test/fuzz/script_flags.cpp b/src/test/fuzz/script_flags.cpp index 08622d0979..3d8ece7c61 100644 --- a/src/test/fuzz/script_flags.cpp +++ b/src/test/fuzz/script_flags.cpp @@ -15,7 +15,7 @@ static bool IsValidFlagCombination(unsigned flags); void initialize() { - static const auto verify_handle = MakeUnique<ECCVerifyHandle>(); + static const ECCVerifyHandle verify_handle; } void test_one_input(const std::vector<uint8_t>& buffer) diff --git a/src/test/fuzz/script_ops.cpp b/src/test/fuzz/script_ops.cpp new file mode 100644 index 0000000000..0cd129ba7a --- /dev/null +++ b/src/test/fuzz/script_ops.cpp @@ -0,0 +1,67 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <script/script.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> + +#include <cstdint> +#include <string> +#include <vector> + +void test_one_input(const std::vector<uint8_t>& buffer) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + CScript script = ConsumeScript(fuzzed_data_provider); + while (fuzzed_data_provider.remaining_bytes() > 0) { + switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 7)) { + case 0: + script += ConsumeScript(fuzzed_data_provider); + break; + case 1: + script = script + ConsumeScript(fuzzed_data_provider); + break; + case 2: + script << fuzzed_data_provider.ConsumeIntegral<int64_t>(); + break; + case 3: + script << ConsumeOpcodeType(fuzzed_data_provider); + break; + case 4: + script << ConsumeScriptNum(fuzzed_data_provider); + break; + case 5: + script << ConsumeRandomLengthByteVector(fuzzed_data_provider); + break; + case 6: + script.clear(); + break; + case 7: { + (void)script.GetSigOpCount(false); + (void)script.GetSigOpCount(true); + (void)script.GetSigOpCount(script); + (void)script.HasValidOps(); + (void)script.IsPayToScriptHash(); + (void)script.IsPayToWitnessScriptHash(); + (void)script.IsPushOnly(); + (void)script.IsUnspendable(); + { + CScript::const_iterator pc = script.begin(); + opcodetype opcode; + (void)script.GetOp(pc, opcode); + std::vector<uint8_t> data; + (void)script.GetOp(pc, opcode, data); + (void)script.IsPushOnly(pc); + } + { + int version; + std::vector<uint8_t> program; + (void)script.IsWitnessProgram(version, program); + } + break; + } + } + } +} diff --git a/src/test/fuzz/scriptnum_ops.cpp b/src/test/fuzz/scriptnum_ops.cpp new file mode 100644 index 0000000000..db44bb9e19 --- /dev/null +++ b/src/test/fuzz/scriptnum_ops.cpp @@ -0,0 +1,137 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <script/script.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> + +#include <cassert> +#include <cstdint> +#include <limits> +#include <vector> + +namespace { +bool IsValidAddition(const CScriptNum& lhs, const CScriptNum& rhs) +{ + return rhs == 0 || (rhs > 0 && lhs <= CScriptNum{std::numeric_limits<int64_t>::max()} - rhs) || (rhs < 0 && lhs >= CScriptNum{std::numeric_limits<int64_t>::min()} - rhs); +} + +bool IsValidSubtraction(const CScriptNum& lhs, const CScriptNum& rhs) +{ + return rhs == 0 || (rhs > 0 && lhs >= CScriptNum{std::numeric_limits<int64_t>::min()} + rhs) || (rhs < 0 && lhs <= CScriptNum{std::numeric_limits<int64_t>::max()} + rhs); +} +} // namespace + +void test_one_input(const std::vector<uint8_t>& buffer) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + CScriptNum script_num = ConsumeScriptNum(fuzzed_data_provider); + while (fuzzed_data_provider.remaining_bytes() > 0) { + switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 11)) { + case 0: { + const int64_t i = fuzzed_data_provider.ConsumeIntegral<int64_t>(); + assert((script_num == i) != (script_num != i)); + assert((script_num <= i) != script_num > i); + assert((script_num >= i) != (script_num < i)); + // Avoid signed integer overflow: + // script/script.h:264:93: runtime error: signed integer overflow: -2261405121394637306 + -9223372036854775802 cannot be represented in type 'long' + if (IsValidAddition(script_num, CScriptNum{i})) { + assert((script_num + i) - i == script_num); + } + // Avoid signed integer overflow: + // script/script.h:265:93: runtime error: signed integer overflow: 9223371895120855039 - -9223372036854710486 cannot be represented in type 'long' + if (IsValidSubtraction(script_num, CScriptNum{i})) { + assert((script_num - i) + i == script_num); + } + break; + } + case 1: { + const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); + assert((script_num == random_script_num) != (script_num != random_script_num)); + assert((script_num <= random_script_num) != (script_num > random_script_num)); + assert((script_num >= random_script_num) != (script_num < random_script_num)); + // Avoid signed integer overflow: + // script/script.h:264:93: runtime error: signed integer overflow: -9223126527765971126 + -9223372036854756825 cannot be represented in type 'long' + if (IsValidAddition(script_num, random_script_num)) { + assert((script_num + random_script_num) - random_script_num == script_num); + } + // Avoid signed integer overflow: + // script/script.h:265:93: runtime error: signed integer overflow: 6052837899185946624 - -9223372036854775808 cannot be represented in type 'long' + if (IsValidSubtraction(script_num, random_script_num)) { + assert((script_num - random_script_num) + random_script_num == script_num); + } + break; + } + case 2: { + const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); + if (!IsValidAddition(script_num, random_script_num)) { + // Avoid assertion failure: + // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)' failed. + break; + } + script_num += random_script_num; + break; + } + case 3: { + const CScriptNum random_script_num = ConsumeScriptNum(fuzzed_data_provider); + if (!IsValidSubtraction(script_num, random_script_num)) { + // Avoid assertion failure: + // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)' failed. + break; + } + script_num -= random_script_num; + break; + } + case 4: + script_num = script_num & fuzzed_data_provider.ConsumeIntegral<int64_t>(); + break; + case 5: + script_num = script_num & ConsumeScriptNum(fuzzed_data_provider); + break; + case 6: + script_num &= ConsumeScriptNum(fuzzed_data_provider); + break; + case 7: + if (script_num == CScriptNum{std::numeric_limits<int64_t>::min()}) { + // Avoid assertion failure: + // ./script/script.h:279: CScriptNum CScriptNum::operator-() const: Assertion `m_value != std::numeric_limits<int64_t>::min()' failed. + break; + } + script_num = -script_num; + break; + case 8: + script_num = fuzzed_data_provider.ConsumeIntegral<int64_t>(); + break; + case 9: { + const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral<int64_t>(); + if (!IsValidAddition(script_num, CScriptNum{random_integer})) { + // Avoid assertion failure: + // ./script/script.h:292: CScriptNum &CScriptNum::operator+=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) || (rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs)' failed. + break; + } + script_num += random_integer; + break; + } + case 10: { + const int64_t random_integer = fuzzed_data_provider.ConsumeIntegral<int64_t>(); + if (!IsValidSubtraction(script_num, CScriptNum{random_integer})) { + // Avoid assertion failure: + // ./script/script.h:300: CScriptNum &CScriptNum::operator-=(const int64_t &): Assertion `rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) || (rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs)' failed. + break; + } + script_num -= random_integer; + break; + } + case 11: + script_num &= fuzzed_data_provider.ConsumeIntegral<int64_t>(); + break; + } + // Avoid negation failure: + // script/script.h:332:35: runtime error: negation of -9223372036854775808 cannot be represented in type 'int64_t' (aka 'long'); cast to an unsigned type to negate this value to itself + if (script_num != CScriptNum{std::numeric_limits<int64_t>::min()}) { + (void)script_num.getvch(); + } + } +} diff --git a/src/test/fuzz/strprintf.cpp b/src/test/fuzz/strprintf.cpp index 0de21f0e7c..d5be1070bd 100644 --- a/src/test/fuzz/strprintf.cpp +++ b/src/test/fuzz/strprintf.cpp @@ -8,7 +8,6 @@ #include <util/strencodings.h> #include <algorithm> -#include <cassert> #include <cstdint> #include <string> #include <vector> @@ -27,7 +26,7 @@ void test_one_input(const std::vector<uint8_t>& buffer) // * strprintf("%.222222200000000$", 1.1); // // Upstream bug report: https://github.com/c42f/tinyformat/issues/70 - if (format_string.find("%") != std::string::npos && digits_in_format_specifier >= 7) { + if (format_string.find('%') != std::string::npos && digits_in_format_specifier >= 7) { return; } @@ -35,7 +34,7 @@ void test_one_input(const std::vector<uint8_t>& buffer) // * strprintf("%1$*1$*", -11111111); // // Upstream bug report: https://github.com/c42f/tinyformat/issues/70 - if (format_string.find("%") != std::string::npos && format_string.find("$") != std::string::npos && format_string.find("*") != std::string::npos && digits_in_format_specifier > 0) { + if (format_string.find('%') != std::string::npos && format_string.find('$') != std::string::npos && format_string.find('*') != std::string::npos && digits_in_format_specifier > 0) { return; } @@ -96,7 +95,7 @@ void test_one_input(const std::vector<uint8_t>& buffer) } try { - switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 13)) { + switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 5)) { case 0: (void)strprintf(format_string, fuzzed_data_provider.ConsumeRandomLengthString(32)); break; @@ -115,32 +114,52 @@ void test_one_input(const std::vector<uint8_t>& buffer) case 5: (void)strprintf(format_string, fuzzed_data_provider.ConsumeBool()); break; - case 6: + } + } catch (const tinyformat::format_error&) { + } + + if (format_string.find('%') != std::string::npos && format_string.find('c') != std::string::npos) { + // Avoid triggering the following: + // * strprintf("%c", 1.31783e+38); + // tinyformat.h:244:36: runtime error: 1.31783e+38 is outside the range of representable values of type 'char' + return; + } + + if (format_string.find('%') != std::string::npos && format_string.find('*') != std::string::npos) { + // Avoid triggering the following: + // * strprintf("%*", -2.33527e+38); + // tinyformat.h:283:65: runtime error: -2.33527e+38 is outside the range of representable values of type 'int' + // * strprintf("%*", -2147483648); + // tinyformat.h:763:25: runtime error: negation of -2147483648 cannot be represented in type 'int'; cast to an unsigned type to negate this value to itself + return; + } + + try { + switch (fuzzed_data_provider.ConsumeIntegralInRange(0, 7)) { + case 0: (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<float>()); break; - case 7: + case 1: (void)strprintf(format_string, fuzzed_data_provider.ConsumeFloatingPoint<double>()); break; - case 8: + case 2: (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int16_t>()); break; - case 9: + case 3: (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint16_t>()); break; - case 10: + case 4: (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int32_t>()); break; - case 11: + case 5: (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint32_t>()); break; - case 12: + case 6: (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<int64_t>()); break; - case 13: + case 7: (void)strprintf(format_string, fuzzed_data_provider.ConsumeIntegral<uint64_t>()); break; - default: - assert(false); } } catch (const tinyformat::format_error&) { } diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp index fefafda36b..d8e84f1a0f 100644 --- a/src/test/fuzz/transaction.cpp +++ b/src/test/fuzz/transaction.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <chainparams.h> #include <coins.h> #include <consensus/tx_check.h> #include <consensus/tx_verify.h> @@ -13,12 +14,18 @@ #include <primitives/transaction.h> #include <streams.h> #include <test/fuzz/fuzz.h> +#include <univalue.h> #include <util/rbf.h> #include <validation.h> #include <version.h> #include <cassert> +void initialize() +{ + SelectParams(CBaseChainParams::REGTEST); +} + void test_one_input(const std::vector<uint8_t>& buffer) { CDataStream ds(buffer, SER_NETWORK, INIT_PROTO_VERSION); @@ -85,4 +92,23 @@ void test_one_input(const std::vector<uint8_t>& buffer) (void)IsStandardTx(tx, reason); (void)RecursiveDynamicUsage(tx); (void)SignalsOptInRBF(tx); + + CCoinsView coins_view; + const CCoinsViewCache coins_view_cache(&coins_view); + (void)AreInputsStandard(tx, coins_view_cache); + (void)IsWitnessStandard(tx, coins_view_cache); + + UniValue u(UniValue::VOBJ); + // ValueFromAmount(i) not defined when i == std::numeric_limits<int64_t>::min() + bool skip_tx_to_univ = false; + for (const CTxOut& txout : tx.vout) { + if (txout.nValue == std::numeric_limits<int64_t>::min()) { + skip_tx_to_univ = true; + } + } + if (!skip_tx_to_univ) { + TxToUniv(tx, /* hashBlock */ {}, u); + static const uint256 u256_max(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); + TxToUniv(tx, u256_max, u); + } } diff --git a/src/test/fuzz/util.h b/src/test/fuzz/util.h index 62907c7e0b..2f4aa9ad2b 100644 --- a/src/test/fuzz/util.h +++ b/src/test/fuzz/util.h @@ -7,9 +7,11 @@ #include <attributes.h> #include <optional.h> +#include <script/script.h> #include <serialize.h> #include <streams.h> #include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> #include <version.h> #include <cstdint> @@ -25,7 +27,7 @@ NODISCARD inline std::vector<uint8_t> ConsumeRandomLengthByteVector(FuzzedDataPr template <typename T> NODISCARD inline Optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_data_provider, size_t max_length = 4096) noexcept { - const std::vector<uint8_t>& buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length); + const std::vector<uint8_t> buffer = ConsumeRandomLengthByteVector(fuzzed_data_provider, max_length); CDataStream ds{buffer, SER_NETWORK, INIT_PROTO_VERSION}; T obj; try { @@ -36,4 +38,20 @@ NODISCARD inline Optional<T> ConsumeDeserializable(FuzzedDataProvider& fuzzed_da return obj; } +NODISCARD inline opcodetype ConsumeOpcodeType(FuzzedDataProvider& fuzzed_data_provider) noexcept +{ + return static_cast<opcodetype>(fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, MAX_OPCODE)); +} + +NODISCARD inline CScript ConsumeScript(FuzzedDataProvider& fuzzed_data_provider) noexcept +{ + const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider); + return {b.begin(), b.end()}; +} + +NODISCARD inline CScriptNum ConsumeScriptNum(FuzzedDataProvider& fuzzed_data_provider) noexcept +{ + return CScriptNum{fuzzed_data_provider.ConsumeIntegral<int64_t>()}; +} + #endif // BITCOIN_TEST_FUZZ_UTIL_H |