LCOV - code coverage report
Current view: top level - src - key_io.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 98.4 % 189 186
Test Date: 2026-10-03 06:20:55 Functions: 100.0 % 18 18
Branches: 64.6 % 314 203

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2014-present 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 <key_io.h>
       6                 :             : 
       7                 :             : #include <base58.h>
       8                 :             : #include <bech32.h>
       9                 :             : #include <script/interpreter.h>
      10                 :             : #include <script/solver.h>
      11                 :             : #include <streams.h>
      12                 :             : #include <tinyformat.h>
      13                 :             : #include <util/overflow.h>
      14                 :             : #include <util/strencodings.h>
      15                 :             : 
      16                 :             : #include <algorithm>
      17                 :             : #include <cassert>
      18                 :             : #include <cstring>
      19                 :             : 
      20                 :             : /// Maximum witness length for Bech32 addresses.
      21                 :             : static constexpr std::size_t BECH32_WITNESS_PROG_MAX_LEN = 40;
      22                 :             : 
      23                 :             : namespace {
      24                 :             : class DestinationEncoder
      25                 :             : {
      26                 :             : private:
      27                 :             :     const CChainParams& m_params;
      28                 :             : 
      29                 :             : public:
      30                 :      707429 :     explicit DestinationEncoder(const CChainParams& params) : m_params(params) {}
      31                 :             : 
      32                 :       77506 :     std::string operator()(const PKHash& id) const
      33                 :             :     {
      34                 :       77506 :         std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
      35         [ +  - ]:       77506 :         data.insert(data.end(), id.begin(), id.end());
      36   [ -  +  +  - ]:       77506 :         return EncodeBase58Check(data);
      37                 :       77506 :     }
      38                 :             : 
      39                 :      225068 :     std::string operator()(const ScriptHash& id) const
      40                 :             :     {
      41                 :      225068 :         std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
      42         [ +  - ]:      225068 :         data.insert(data.end(), id.begin(), id.end());
      43   [ -  +  +  - ]:      225068 :         return EncodeBase58Check(data);
      44                 :      225068 :     }
      45                 :             : 
      46                 :      118535 :     std::string operator()(const WitnessV0KeyHash& id) const
      47                 :             :     {
      48                 :      118535 :         std::vector<unsigned char> data = {0};
      49         [ +  - ]:      118535 :         data.reserve(33);
      50         [ +  - ]:     3911655 :         ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.begin(), id.end());
      51         [ +  - ]:      118535 :         return bech32::Encode(bech32::Encoding::BECH32, m_params.Bech32HRP(), data);
      52                 :      118535 :     }
      53                 :             : 
      54                 :      108048 :     std::string operator()(const WitnessV0ScriptHash& id) const
      55                 :             :     {
      56                 :      108048 :         std::vector<unsigned char> data = {0};
      57         [ +  - ]:      108048 :         data.reserve(53);
      58         [ +  - ]:     5726544 :         ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.begin(), id.end());
      59         [ +  - ]:      108048 :         return bech32::Encode(bech32::Encoding::BECH32, m_params.Bech32HRP(), data);
      60                 :      108048 :     }
      61                 :             : 
      62                 :      125090 :     std::string operator()(const WitnessV1Taproot& tap) const
      63                 :             :     {
      64                 :      125090 :         std::vector<unsigned char> data = {1};
      65         [ +  - ]:      125090 :         data.reserve(53);
      66         [ +  - ]:     6629770 :         ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, tap.begin(), tap.end());
      67         [ +  - ]:      125090 :         return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data);
      68                 :      125090 :     }
      69                 :             : 
      70                 :       47091 :     std::string operator()(const WitnessUnknown& id) const
      71                 :             :     {
      72         [ +  - ]:       47091 :         const std::vector<unsigned char>& program = id.GetWitnessProgram();
      73   [ +  -  +  -  :       94182 :         if (id.GetWitnessVersion() < 1 || id.GetWitnessVersion() > 16 || program.size() < 2 || program.size() > 40) {
             +  -  -  + ]
      74                 :           0 :             return {};
      75                 :             :         }
      76                 :       47091 :         std::vector<unsigned char> data = {(unsigned char)id.GetWitnessVersion()};
      77   [ -  +  +  - ]:       47091 :         data.reserve(1 + CeilDiv(program.size() * 8, 5u));
      78         [ +  - ]:     1093417 :         ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, program.begin(), program.end());
      79         [ +  - ]:       47091 :         return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data);
      80                 :       47091 :     }
      81                 :             : 
      82                 :        5356 :     std::string operator()(const CNoDestination& no) const { return {}; }
      83                 :         735 :     std::string operator()(const PubKeyDestination& pk) const { return {}; }
      84                 :             : };
      85                 :             : 
      86                 :       12412 : CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str, std::vector<int>* error_locations)
      87                 :             : {
      88                 :       12412 :     std::vector<unsigned char> data;
      89                 :       12412 :     uint160 hash;
      90         [ +  - ]:       12412 :     error_str = "";
      91                 :             : 
      92                 :             :     // Note this will be false if it is a valid Bech32 address for a different network
      93   [ -  +  +  -  :       24824 :     bool is_bech32 = (ToLower(str.substr(0, params.Bech32HRP().size())) == params.Bech32HRP());
                   +  - ]
      94                 :             : 
      95   [ +  +  +  -  :       12412 :     if (!is_bech32 && DecodeBase58Check(str, data, 21)) {
                   +  + ]
      96                 :             :         // base58-encoded Bitcoin addresses.
      97                 :             :         // Public-key-hash-addresses have version 0 (or 111 testnet).
      98                 :             :         // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
      99         [ -  + ]:        4426 :         const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
     100   [ -  +  -  +  :        4426 :         if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
             +  +  +  + ]
     101                 :        8428 :             std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
     102                 :        4214 :             return PKHash(hash);
     103                 :             :         }
     104                 :             :         // Script-hash-addresses have version 5 (or 196 testnet).
     105                 :             :         // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
     106         [ -  + ]:         212 :         const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
     107   [ -  +  +  +  :         212 :         if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
                   +  + ]
     108                 :         166 :             std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
     109                 :         166 :             return ScriptHash(hash);
     110                 :             :         }
     111                 :             : 
     112                 :             :         // If the prefix of data matches either the script or pubkey prefix, the length must have been wrong
     113         [ +  + ]:          45 :         if ((data.size() >= script_prefix.size() &&
     114   [ +  +  +  + ]:          46 :                 std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) ||
     115   [ +  +  +  + ]:          45 :             (data.size() >= pubkey_prefix.size() &&
     116         [ +  + ]:          44 :                 std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin()))) {
     117         [ +  - ]:           2 :             error_str = "Invalid length for Base58 address (P2PKH or P2SH)";
     118                 :             :         } else {
     119         [ +  - ]:          44 :             error_str = "Invalid or unsupported Base58-encoded address.";
     120                 :             :         }
     121                 :          46 :         return CNoDestination();
     122         [ +  + ]:        7986 :     } else if (!is_bech32) {
     123                 :             :         // Try Base58 decoding without the checksum, using a much larger max length
     124   [ +  -  +  + ]:        6463 :         if (!DecodeBase58(str, data, 100)) {
     125         [ +  - ]:        1070 :             error_str = "Invalid or unsupported Segwit (Bech32) or Base58 encoding.";
     126                 :             :         } else {
     127         [ +  - ]:        5393 :             error_str = "Invalid checksum or length of Base58 address (P2PKH or P2SH)";
     128                 :             :         }
     129                 :        6463 :         return CNoDestination();
     130                 :             :     }
     131                 :             : 
     132         [ -  + ]:        1523 :     data.clear();
     133         [ +  - ]:        1523 :     const auto dec = bech32::Decode(str);
     134         [ +  + ]:        1523 :     if (dec.encoding == bech32::Encoding::BECH32 || dec.encoding == bech32::Encoding::BECH32M) {
     135         [ +  + ]:         755 :         if (dec.data.empty()) {
     136         [ +  - ]:           5 :             error_str = "Empty Bech32 data section";
     137                 :           5 :             return CNoDestination();
     138                 :             :         }
     139                 :             :         // Bech32 decoding
     140         [ +  + ]:         750 :         if (dec.hrp != params.Bech32HRP()) {
     141         [ +  - ]:          10 :             error_str = strprintf("Invalid or unsupported prefix for Segwit (Bech32) address (expected %s, got %s).", params.Bech32HRP(), dec.hrp);
     142                 :          10 :             return CNoDestination();
     143                 :             :         }
     144         [ +  + ]:         740 :         int version = dec.data[0]; // The first 5 bit symbol is the witness version (0-16)
     145   [ +  +  +  + ]:         740 :         if (version == 0 && dec.encoding != bech32::Encoding::BECH32) {
     146         [ +  - ]:           2 :             error_str = "Version 0 witness address must use Bech32 checksum";
     147                 :           2 :             return CNoDestination();
     148                 :             :         }
     149         [ +  + ]:         175 :         if (version != 0 && dec.encoding != bech32::Encoding::BECH32M) {
     150         [ +  - ]:           6 :             error_str = "Version 1+ witness address must use Bech32m checksum";
     151                 :           6 :             return CNoDestination();
     152                 :             :         }
     153                 :             :         // The rest of the symbols are converted witness program bytes.
     154   [ -  +  +  - ]:         732 :         data.reserve(((dec.data.size() - 1) * 5) / 8);
     155   [ +  -  +  + ]:       15145 :         if (ConvertBits<5, 8, false>([&](unsigned char c) { data.push_back(c); }, dec.data.begin() + 1, dec.data.end())) {
     156                 :             : 
     157   [ -  +  +  - ]:         716 :             std::string_view byte_str{data.size() == 1 ? "byte" : "bytes"};
     158                 :             : 
     159         [ +  + ]:         716 :             if (version == 0) {
     160                 :         558 :                 {
     161         [ +  + ]:         558 :                     WitnessV0KeyHash keyid;
     162         [ +  + ]:         558 :                     if (data.size() == keyid.size()) {
     163                 :         497 :                         std::copy(data.begin(), data.end(), keyid.begin());
     164                 :         497 :                         return keyid;
     165                 :             :                     }
     166                 :             :                 }
     167                 :          61 :                 {
     168         [ +  + ]:          61 :                     WitnessV0ScriptHash scriptid;
     169         [ +  + ]:          61 :                     if (data.size() == scriptid.size()) {
     170                 :          42 :                         std::copy(data.begin(), data.end(), scriptid.begin());
     171                 :          42 :                         return scriptid;
     172                 :             :                     }
     173                 :             :                 }
     174                 :             : 
     175         [ +  - ]:          19 :                 error_str = strprintf("Invalid Bech32 v0 address program size (%d %s), per BIP141", data.size(), byte_str);
     176                 :          19 :                 return CNoDestination();
     177                 :             :             }
     178                 :             : 
     179   [ +  +  +  + ]:         158 :             if (version == 1 && data.size() == WITNESS_V1_TAPROOT_SIZE) {
     180                 :          30 :                 static_assert(WITNESS_V1_TAPROOT_SIZE == WitnessV1Taproot::size());
     181                 :          30 :                 WitnessV1Taproot tap;
     182                 :          30 :                 std::copy(data.begin(), data.end(), tap.begin());
     183                 :          30 :                 return tap;
     184                 :             :             }
     185                 :             : 
     186   [ +  -  +  + ]:         128 :             if (CScript::IsPayToAnchor(version, data)) {
     187         [ +  - ]:          24 :                 return PayToAnchor();
     188                 :             :             }
     189                 :             : 
     190         [ -  + ]:         104 :             if (version > 16) {
     191         [ #  # ]:           0 :                 error_str = "Invalid Bech32 address witness version";
     192                 :           0 :                 return CNoDestination();
     193                 :             :             }
     194                 :             : 
     195   [ -  +  +  -  :         104 :             if (data.size() < 2 || data.size() > BECH32_WITNESS_PROG_MAX_LEN) {
                   +  + ]
     196         [ +  - ]:           4 :                 error_str = strprintf("Invalid Bech32 address program size (%d %s)", data.size(), byte_str);
     197                 :           4 :                 return CNoDestination();
     198                 :             :             }
     199                 :             : 
     200         [ +  - ]:         100 :             return WitnessUnknown{version, data};
     201                 :             :         } else {
     202         [ +  - ]:          16 :             error_str = strprintf("Invalid padding in Bech32 data section");
     203                 :          16 :             return CNoDestination();
     204                 :             :         }
     205                 :             :     }
     206                 :             : 
     207                 :             :     // Perform Bech32 error location
     208         [ +  - ]:         768 :     auto res = bech32::LocateErrors(str);
     209         [ +  - ]:         768 :     error_str = res.first;
     210         [ +  + ]:         768 :     if (error_locations) *error_locations = std::move(res.second);
     211                 :         768 :     return CNoDestination();
     212                 :       14703 : }
     213                 :             : } // namespace
     214                 :             : 
     215                 :       97128 : CKey DecodeSecret(const std::string& str)
     216                 :             : {
     217                 :       97128 :     CKey key;
     218                 :       97128 :     std::vector<unsigned char> data;
     219   [ +  -  +  + ]:       97128 :     if (DecodeBase58Check(str, data, 34)) {
     220   [ +  -  -  + ]:       57400 :         const std::vector<unsigned char>& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY);
     221                 :       57400 :         if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
           [ -  +  -  +  
          +  +  +  +  +  
                +  +  + ]
     222         [ +  + ]:       57393 :             std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
     223                 :       57386 :             bool compressed = data.size() == 33 + privkey_prefix.size();
     224         [ +  - ]:       57386 :             key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed);
     225                 :             :         }
     226                 :             :     }
     227         [ +  + ]:       97128 :     if (!data.empty()) {
     228   [ -  +  +  - ]:       57400 :         memory_cleanse(data.data(), data.size());
     229                 :             :     }
     230                 :       97128 :     return key;
     231                 :       97128 : }
     232                 :             : 
     233                 :      131591 : std::string EncodeSecret(const CKey& key)
     234                 :             : {
     235         [ -  + ]:      131591 :     assert(key.IsValid());
     236                 :      131591 :     std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY);
     237   [ +  -  +  -  :      394773 :     data.insert(data.end(), UCharCast(key.begin()), UCharCast(key.end()));
                   +  - ]
     238         [ +  + ]:      131591 :     if (key.IsCompressed()) {
     239         [ +  - ]:      130924 :         data.push_back(1);
     240                 :             :     }
     241   [ -  +  +  - ]:      131591 :     std::string ret = EncodeBase58Check(data);
     242   [ -  +  +  - ]:      131591 :     memory_cleanse(data.data(), data.size());
     243                 :      131591 :     return ret;
     244                 :      131591 : }
     245                 :             : 
     246                 :      141121 : CExtPubKey DecodeExtPubKey(const std::string& str)
     247                 :             : {
     248         [ +  - ]:      141121 :     CExtPubKey key;
     249                 :      141121 :     std::vector<unsigned char> data;
     250   [ +  -  +  + ]:      141121 :     if (DecodeBase58Check(str, data, 78)) {
     251   [ +  -  -  + ]:      140613 :         const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
     252   [ -  +  -  +  :      140613 :         if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
             +  +  +  + ]
     253         [ +  - ]:       29609 :             SpanReader{std::span{data}.subspan(prefix.size())} >> key;
     254                 :             :         }
     255                 :             :     }
     256                 :      141121 :     return key;
     257                 :      141121 : }
     258                 :             : 
     259                 :     2755097 : std::string EncodeExtPubKey(const CExtPubKey& key)
     260                 :             : {
     261                 :     2755097 :     std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
     262   [ -  +  +  - ]:     2755097 :     VectorWriter{data, data.size(), key};
     263   [ -  +  +  - ]:     2755097 :     std::string ret = EncodeBase58Check(data);
     264                 :     2755097 :     return ret;
     265                 :     2755097 : }
     266                 :             : 
     267                 :      141120 : CExtKey DecodeExtKey(const std::string& str)
     268                 :             : {
     269         [ +  - ]:      141120 :     CExtKey key;
     270                 :      141120 :     std::vector<unsigned char> data;
     271   [ +  -  +  + ]:      141120 :     if (DecodeBase58Check(str, data, 78)) {
     272   [ +  -  -  + ]:      140612 :         const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
     273   [ -  +  -  +  :      140612 :         if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
             +  +  +  + ]
     274         [ +  - ]:      110969 :             SpanReader{std::span{data}.subspan(prefix.size())} >> key;
     275                 :             :         }
     276                 :             :     }
     277         [ +  + ]:      141120 :     if (!data.empty()) {
     278   [ -  +  +  - ]:      140612 :         memory_cleanse(data.data(), data.size());
     279                 :             :     }
     280                 :      141120 :     return key;
     281                 :      141120 : }
     282                 :             : 
     283                 :      637611 : std::string EncodeExtKey(const CExtKey& key)
     284                 :             : {
     285                 :      637611 :     std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
     286   [ -  +  +  - ]:      637611 :     VectorWriter{data, data.size(), key};
     287   [ -  +  +  - ]:      637611 :     std::string ret = EncodeBase58Check(data);
     288   [ -  +  +  - ]:      637611 :     memory_cleanse(data.data(), data.size());
     289                 :      637611 :     return ret;
     290                 :      637611 : }
     291                 :             : 
     292                 :      707429 : std::string EncodeDestination(const CTxDestination& dest)
     293                 :             : {
     294                 :      707429 :     return std::visit(DestinationEncoder(Params()), dest);
     295                 :             : }
     296                 :             : 
     297                 :       10301 : CTxDestination DecodeDestination(const std::string& str, std::string& error_msg, std::vector<int>* error_locations)
     298                 :             : {
     299                 :       10301 :     return DecodeDestination(str, Params(), error_msg, error_locations);
     300                 :             : }
     301                 :             : 
     302                 :       10244 : CTxDestination DecodeDestination(const std::string& str)
     303                 :             : {
     304         [ +  - ]:       10244 :     std::string error_msg;
     305         [ +  - ]:       10244 :     return DecodeDestination(str, error_msg);
     306                 :       10244 : }
     307                 :             : 
     308                 :        2111 : bool IsValidDestinationString(const std::string& str, const CChainParams& params)
     309                 :             : {
     310         [ +  - ]:        2111 :     std::string error_msg;
     311   [ +  -  +  - ]:        2111 :     return IsValidDestination(DecodeDestination(str, params, error_msg, nullptr));
     312                 :        2111 : }
     313                 :             : 
     314                 :        2111 : bool IsValidDestinationString(const std::string& str)
     315                 :             : {
     316                 :        2111 :     return IsValidDestinationString(str, Params());
     317                 :             : }
        

Generated by: LCOV version 2.5.0-full