LCOV - code coverage report
Current view: top level - src/test/fuzz - key.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 7 245 2.9 %
Date: 2023-09-26 12:08:55 Functions: 10 15 66.7 %

          Line data    Source code
       1             : // Copyright (c) 2020-2022 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 <key.h>
       7             : #include <key_io.h>
       8             : #include <outputtype.h>
       9             : #include <policy/policy.h>
      10             : #include <pubkey.h>
      11             : #include <rpc/util.h>
      12             : #include <script/keyorigin.h>
      13             : #include <script/script.h>
      14             : #include <script/sign.h>
      15             : #include <script/signingprovider.h>
      16             : #include <script/solver.h>
      17           2 : #include <streams.h>
      18           2 : #include <test/fuzz/FuzzedDataProvider.h>
      19             : #include <test/fuzz/fuzz.h>
      20             : #include <test/fuzz/util.h>
      21             : #include <util/chaintype.h>
      22             : #include <util/strencodings.h>
      23             : 
      24             : #include <array>
      25             : #include <cassert>
      26             : #include <cstddef>
      27           2 : #include <cstdint>
      28             : #include <numeric>
      29             : #include <optional>
      30             : #include <string>
      31             : #include <vector>
      32             : 
      33           0 : void initialize_key()
      34             : {
      35           0 :     ECC_Start();
      36           0 :     SelectParams(ChainType::REGTEST);
      37           0 : }
      38             : 
      39           4 : FUZZ_TARGET(key, .init = initialize_key)
      40             : {
      41           0 :     const CKey key = [&] {
      42           0 :         CKey k;
      43           0 :         k.Set(buffer.begin(), buffer.end(), true);
      44           0 :         return k;
      45           0 :     }();
      46           0 :     if (!key.IsValid()) {
      47           0 :         return;
      48             :     }
      49             : 
      50             :     {
      51           0 :         assert(key.begin() + key.size() == key.end());
      52           0 :         assert(key.IsCompressed());
      53           0 :         assert(key.size() == 32);
      54           0 :         assert(DecodeSecret(EncodeSecret(key)) == key);
      55             :     }
      56             : 
      57             :     {
      58           0 :         CKey invalid_key;
      59           0 :         assert(!(invalid_key == key));
      60           0 :         assert(!invalid_key.IsCompressed());
      61           0 :         assert(!invalid_key.IsValid());
      62           0 :         assert(invalid_key.size() == 0);
      63           0 :     }
      64             : 
      65             :     {
      66           0 :         CKey uncompressed_key;
      67           0 :         uncompressed_key.Set(buffer.begin(), buffer.end(), false);
      68           0 :         assert(!(uncompressed_key == key));
      69           0 :         assert(!uncompressed_key.IsCompressed());
      70           0 :         assert(key.size() == 32);
      71           0 :         assert(uncompressed_key.begin() + uncompressed_key.size() == uncompressed_key.end());
      72           0 :         assert(uncompressed_key.IsValid());
      73           0 :     }
      74           2 : 
      75             :     {
      76           0 :         CKey copied_key;
      77           0 :         copied_key.Set(key.begin(), key.end(), key.IsCompressed());
      78           0 :         assert(copied_key == key);
      79           0 :     }
      80             : 
      81             :     {
      82           0 :         CKey negated_key = key;
      83           0 :         negated_key.Negate();
      84           0 :         assert(negated_key.IsValid());
      85           0 :         assert(!(negated_key == key));
      86             : 
      87           0 :         negated_key.Negate();
      88           0 :         assert(negated_key == key);
      89           0 :     }
      90             : 
      91           0 :     const uint256 random_uint256 = Hash(buffer);
      92             : 
      93             :     {
      94           0 :         CKey child_key;
      95           0 :         ChainCode child_chaincode;
      96           0 :         const bool ok = key.Derive(child_key, child_chaincode, 0, random_uint256);
      97           0 :         assert(ok);
      98           0 :         assert(child_key.IsValid());
      99           0 :         assert(!(child_key == key));
     100           0 :         assert(child_chaincode != random_uint256);
     101           0 :     }
     102             : 
     103           0 :     const CPubKey pubkey = key.GetPubKey();
     104             : 
     105             :     {
     106           0 :         assert(pubkey.size() == 33);
     107           0 :         assert(key.VerifyPubKey(pubkey));
     108           0 :         assert(pubkey.GetHash() != random_uint256);
     109           0 :         assert(pubkey.begin() + pubkey.size() == pubkey.end());
     110           0 :         assert(pubkey.data() == pubkey.begin());
     111           0 :         assert(pubkey.IsCompressed());
     112           0 :         assert(pubkey.IsValid());
     113           0 :         assert(pubkey.IsFullyValid());
     114           0 :         assert(HexToPubKey(HexStr(pubkey)) == pubkey);
     115           0 :         assert(GetAllDestinationsForKey(pubkey).size() == 3);
     116             :     }
     117             : 
     118             :     {
     119           0 :         DataStream data_stream{};
     120           0 :         pubkey.Serialize(data_stream);
     121             : 
     122           0 :         CPubKey pubkey_deserialized;
     123           0 :         pubkey_deserialized.Unserialize(data_stream);
     124           0 :         assert(pubkey_deserialized == pubkey);
     125           0 :     }
     126             : 
     127             :     {
     128           0 :         const CScript tx_pubkey_script = GetScriptForRawPubKey(pubkey);
     129           0 :         assert(!tx_pubkey_script.IsPayToScriptHash());
     130           0 :         assert(!tx_pubkey_script.IsPayToWitnessScriptHash());
     131           0 :         assert(!tx_pubkey_script.IsPushOnly());
     132           0 :         assert(!tx_pubkey_script.IsUnspendable());
     133           0 :         assert(tx_pubkey_script.HasValidOps());
     134           0 :         assert(tx_pubkey_script.size() == 35);
     135             : 
     136           0 :         const CScript tx_multisig_script = GetScriptForMultisig(1, {pubkey});
     137           0 :         assert(!tx_multisig_script.IsPayToScriptHash());
     138           0 :         assert(!tx_multisig_script.IsPayToWitnessScriptHash());
     139           0 :         assert(!tx_multisig_script.IsPushOnly());
     140           0 :         assert(!tx_multisig_script.IsUnspendable());
     141           0 :         assert(tx_multisig_script.HasValidOps());
     142           0 :         assert(tx_multisig_script.size() == 37);
     143             : 
     144           0 :         FillableSigningProvider fillable_signing_provider;
     145           0 :         assert(!IsSegWitOutput(fillable_signing_provider, tx_pubkey_script));
     146           0 :         assert(!IsSegWitOutput(fillable_signing_provider, tx_multisig_script));
     147           0 :         assert(fillable_signing_provider.GetKeys().size() == 0);
     148           0 :         assert(!fillable_signing_provider.HaveKey(pubkey.GetID()));
     149             : 
     150           0 :         const bool ok_add_key = fillable_signing_provider.AddKey(key);
     151           0 :         assert(ok_add_key);
     152           0 :         assert(fillable_signing_provider.HaveKey(pubkey.GetID()));
     153             : 
     154           0 :         FillableSigningProvider fillable_signing_provider_pub;
     155           0 :         assert(!fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
     156             : 
     157           0 :         const bool ok_add_key_pubkey = fillable_signing_provider_pub.AddKeyPubKey(key, pubkey);
     158           0 :         assert(ok_add_key_pubkey);
     159           0 :         assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
     160             : 
     161             :         TxoutType which_type_tx_pubkey;
     162           0 :         const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, std::nullopt, which_type_tx_pubkey);
     163           0 :         assert(is_standard_tx_pubkey);
     164           0 :         assert(which_type_tx_pubkey == TxoutType::PUBKEY);
     165             : 
     166             :         TxoutType which_type_tx_multisig;
     167           0 :         const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, std::nullopt, which_type_tx_multisig);
     168           0 :         assert(is_standard_tx_multisig);
     169           0 :         assert(which_type_tx_multisig == TxoutType::MULTISIG);
     170             : 
     171           0 :         std::vector<std::vector<unsigned char>> v_solutions_ret_tx_pubkey;
     172           0 :         const TxoutType outtype_tx_pubkey = Solver(tx_pubkey_script, v_solutions_ret_tx_pubkey);
     173           0 :         assert(outtype_tx_pubkey == TxoutType::PUBKEY);
     174           0 :         assert(v_solutions_ret_tx_pubkey.size() == 1);
     175           0 :         assert(v_solutions_ret_tx_pubkey[0].size() == 33);
     176             : 
     177           0 :         std::vector<std::vector<unsigned char>> v_solutions_ret_tx_multisig;
     178           0 :         const TxoutType outtype_tx_multisig = Solver(tx_multisig_script, v_solutions_ret_tx_multisig);
     179           0 :         assert(outtype_tx_multisig == TxoutType::MULTISIG);
     180           0 :         assert(v_solutions_ret_tx_multisig.size() == 3);
     181           0 :         assert(v_solutions_ret_tx_multisig[0].size() == 1);
     182           0 :         assert(v_solutions_ret_tx_multisig[1].size() == 33);
     183           0 :         assert(v_solutions_ret_tx_multisig[2].size() == 1);
     184             : 
     185           0 :         OutputType output_type{};
     186           0 :         const CTxDestination tx_destination = GetDestinationForKey(pubkey, output_type);
     187           0 :         assert(output_type == OutputType::LEGACY);
     188           0 :         assert(IsValidDestination(tx_destination));
     189           0 :         assert(PKHash{pubkey} == *std::get_if<PKHash>(&tx_destination));
     190             : 
     191           0 :         const CScript script_for_destination = GetScriptForDestination(tx_destination);
     192           0 :         assert(script_for_destination.size() == 25);
     193             : 
     194           0 :         const std::string destination_address = EncodeDestination(tx_destination);
     195           0 :         assert(DecodeDestination(destination_address) == tx_destination);
     196             : 
     197           0 :         const CPubKey pubkey_from_address_string = AddrToPubKey(fillable_signing_provider, destination_address);
     198           0 :         assert(pubkey_from_address_string == pubkey);
     199             : 
     200           0 :         CKeyID key_id = pubkey.GetID();
     201           0 :         assert(!key_id.IsNull());
     202           0 :         assert(key_id == CKeyID{key_id});
     203           0 :         assert(key_id == GetKeyForDestination(fillable_signing_provider, tx_destination));
     204             : 
     205           0 :         CPubKey pubkey_out;
     206           0 :         const bool ok_get_pubkey = fillable_signing_provider.GetPubKey(key_id, pubkey_out);
     207           0 :         assert(ok_get_pubkey);
     208             : 
     209           0 :         CKey key_out;
     210           0 :         const bool ok_get_key = fillable_signing_provider.GetKey(key_id, key_out);
     211           0 :         assert(ok_get_key);
     212           0 :         assert(fillable_signing_provider.GetKeys().size() == 1);
     213           0 :         assert(fillable_signing_provider.HaveKey(key_id));
     214             : 
     215           0 :         KeyOriginInfo key_origin_info;
     216           0 :         const bool ok_get_key_origin = fillable_signing_provider.GetKeyOrigin(key_id, key_origin_info);
     217           0 :         assert(!ok_get_key_origin);
     218           0 :     }
     219             : 
     220             :     {
     221           0 :         const std::vector<unsigned char> vch_pubkey{pubkey.begin(), pubkey.end()};
     222           0 :         assert(CPubKey::ValidSize(vch_pubkey));
     223           0 :         assert(!CPubKey::ValidSize({pubkey.begin(), pubkey.begin() + pubkey.size() - 1}));
     224             : 
     225           0 :         const CPubKey pubkey_ctor_1{vch_pubkey};
     226           0 :         assert(pubkey == pubkey_ctor_1);
     227             : 
     228           0 :         const CPubKey pubkey_ctor_2{vch_pubkey.begin(), vch_pubkey.end()};
     229           0 :         assert(pubkey == pubkey_ctor_2);
     230             : 
     231           0 :         CPubKey pubkey_set;
     232           0 :         pubkey_set.Set(vch_pubkey.begin(), vch_pubkey.end());
     233           0 :         assert(pubkey == pubkey_set);
     234           0 :     }
     235             : 
     236             :     {
     237           0 :         const CPubKey invalid_pubkey{};
     238           0 :         assert(!invalid_pubkey.IsValid());
     239           0 :         assert(!invalid_pubkey.IsFullyValid());
     240           0 :         assert(!(pubkey == invalid_pubkey));
     241           0 :         assert(pubkey != invalid_pubkey);
     242           0 :         assert(pubkey < invalid_pubkey);
     243             :     }
     244             : 
     245             :     {
     246             :         // Cover CPubKey's operator[](unsigned int pos)
     247           0 :         unsigned int sum = 0;
     248           0 :         for (size_t i = 0; i < pubkey.size(); ++i) {
     249           0 :             sum += pubkey[i];
     250           0 :         }
     251           0 :         assert(std::accumulate(pubkey.begin(), pubkey.end(), 0U) == sum);
     252             :     }
     253             : 
     254             :     {
     255           0 :         CPubKey decompressed_pubkey = pubkey;
     256           0 :         assert(decompressed_pubkey.IsCompressed());
     257             : 
     258           0 :         const bool ok = decompressed_pubkey.Decompress();
     259           0 :         assert(ok);
     260           0 :         assert(!decompressed_pubkey.IsCompressed());
     261           0 :         assert(decompressed_pubkey.size() == 65);
     262             :     }
     263             : 
     264             :     {
     265           0 :         std::vector<unsigned char> vch_sig;
     266           0 :         const bool ok = key.Sign(random_uint256, vch_sig, false);
     267           0 :         assert(ok);
     268           0 :         assert(pubkey.Verify(random_uint256, vch_sig));
     269           0 :         assert(CPubKey::CheckLowS(vch_sig));
     270             : 
     271           0 :         const std::vector<unsigned char> vch_invalid_sig{vch_sig.begin(), vch_sig.begin() + vch_sig.size() - 1};
     272           0 :         assert(!pubkey.Verify(random_uint256, vch_invalid_sig));
     273           0 :         assert(!CPubKey::CheckLowS(vch_invalid_sig));
     274           0 :     }
     275             : 
     276             :     {
     277           0 :         std::vector<unsigned char> vch_compact_sig;
     278           0 :         const bool ok_sign_compact = key.SignCompact(random_uint256, vch_compact_sig);
     279           0 :         assert(ok_sign_compact);
     280             : 
     281           0 :         CPubKey recover_pubkey;
     282           0 :         const bool ok_recover_compact = recover_pubkey.RecoverCompact(random_uint256, vch_compact_sig);
     283           0 :         assert(ok_recover_compact);
     284           0 :         assert(recover_pubkey == pubkey);
     285           0 :     }
     286             : 
     287             :     {
     288           0 :         CPubKey child_pubkey;
     289           0 :         ChainCode child_chaincode;
     290           0 :         const bool ok = pubkey.Derive(child_pubkey, child_chaincode, 0, random_uint256);
     291           0 :         assert(ok);
     292           0 :         assert(child_pubkey != pubkey);
     293           0 :         assert(child_pubkey.IsCompressed());
     294           0 :         assert(child_pubkey.IsFullyValid());
     295           0 :         assert(child_pubkey.IsValid());
     296           0 :         assert(child_pubkey.size() == 33);
     297           0 :         assert(child_chaincode != random_uint256);
     298             :     }
     299             : 
     300           0 :     const CPrivKey priv_key = key.GetPrivKey();
     301             : 
     302             :     {
     303           0 :         for (const bool skip_check : {true, false}) {
     304           0 :             CKey loaded_key;
     305           0 :             const bool ok = loaded_key.Load(priv_key, pubkey, skip_check);
     306           0 :             assert(ok);
     307           0 :             assert(key == loaded_key);
     308           0 :         }
     309             :     }
     310           0 : }
     311             : 
     312           4 : FUZZ_TARGET(ellswift_roundtrip, .init = initialize_key)
     313             : {
     314           0 :     FuzzedDataProvider fdp{buffer.data(), buffer.size()};
     315             : 
     316           0 :     CKey key = ConsumePrivateKey(fdp, /*compressed=*/true);
     317           0 :     if (!key.IsValid()) return;
     318             : 
     319           0 :     auto ent32 = fdp.ConsumeBytes<std::byte>(32);
     320           0 :     ent32.resize(32);
     321             : 
     322           0 :     auto encoded_ellswift = key.EllSwiftCreate(ent32);
     323           0 :     auto decoded_pubkey = encoded_ellswift.Decode();
     324             : 
     325           0 :     assert(key.VerifyPubKey(decoded_pubkey));
     326           0 : }
     327             : 
     328           4 : FUZZ_TARGET(bip324_ecdh, .init = initialize_key)
     329             : {
     330           0 :     FuzzedDataProvider fdp{buffer.data(), buffer.size()};
     331             : 
     332             :     // We generate private key, k1.
     333           0 :     CKey k1 = ConsumePrivateKey(fdp, /*compressed=*/true);
     334           0 :     if (!k1.IsValid()) return;
     335             : 
     336             :     // They generate private key, k2.
     337           0 :     CKey k2 = ConsumePrivateKey(fdp, /*compressed=*/true);
     338           0 :     if (!k2.IsValid()) return;
     339             : 
     340             :     // We construct an ellswift encoding for our key, k1_ellswift.
     341           0 :     auto ent32_1 = fdp.ConsumeBytes<std::byte>(32);
     342           0 :     ent32_1.resize(32);
     343           0 :     auto k1_ellswift = k1.EllSwiftCreate(ent32_1);
     344             : 
     345             :     // They construct an ellswift encoding for their key, k2_ellswift.
     346           0 :     auto ent32_2 = fdp.ConsumeBytes<std::byte>(32);
     347           0 :     ent32_2.resize(32);
     348           0 :     auto k2_ellswift = k2.EllSwiftCreate(ent32_2);
     349             : 
     350             :     // They construct another (possibly distinct) ellswift encoding for their key, k2_ellswift_bad.
     351           0 :     auto ent32_2_bad = fdp.ConsumeBytes<std::byte>(32);
     352           0 :     ent32_2_bad.resize(32);
     353           0 :     auto k2_ellswift_bad = k2.EllSwiftCreate(ent32_2_bad);
     354           0 :     assert((ent32_2_bad == ent32_2) == (k2_ellswift_bad == k2_ellswift));
     355             : 
     356             :     // Determine who is who.
     357           0 :     bool initiating = fdp.ConsumeBool();
     358             : 
     359             :     // We compute our shared secret using our key and their public key.
     360           0 :     auto ecdh_secret_1 = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, initiating);
     361             :     // They compute their shared secret using their key and our public key.
     362           0 :     auto ecdh_secret_2 = k2.ComputeBIP324ECDHSecret(k1_ellswift, k2_ellswift, !initiating);
     363             :     // Those must match, as everyone is behaving correctly.
     364           0 :     assert(ecdh_secret_1 == ecdh_secret_2);
     365             : 
     366           0 :     if (k1_ellswift != k2_ellswift) {
     367             :         // Unless the two keys are exactly identical, acting as the wrong party breaks things.
     368           0 :         auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, !initiating);
     369           0 :         assert(ecdh_secret_bad != ecdh_secret_1);
     370           0 :     }
     371             : 
     372           0 :     if (k2_ellswift_bad != k2_ellswift) {
     373             :         // Unless both encodings created by them are identical, using the second one breaks things.
     374           0 :         auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift_bad, k1_ellswift, initiating);
     375           0 :         assert(ecdh_secret_bad != ecdh_secret_1);
     376           0 :     }
     377           0 : }

Generated by: LCOV version 1.14