LCOV - code coverage report
Current view: top level - src - key_io.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 158 165 95.8 %
Date: 2026-06-25 07:23:43 Functions: 28 30 93.3 %

          Line data    Source code
       1             : // Copyright (c) 2014-2021 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 <chainparams.h>
      10             : #include <util/strencodings.h>
      11             : 
      12             : #include <algorithm>
      13             : #include <assert.h>
      14             : #include <string.h>
      15             : 
      16             : namespace {
      17             : class DestinationEncoder
      18             : {
      19             : private:
      20             :     const CChainParams& m_params;
      21             : 
      22             : public:
      23      676536 :     explicit DestinationEncoder(const CChainParams& params) : m_params(params) {}
      24             : 
      25      291283 :     std::string operator()(const PKHash& id) const
      26             :     {
      27      291283 :         std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
      28      291283 :         data.insert(data.end(), id.begin(), id.end());
      29      291283 :         return EncodeBase58Check(data);
      30      291283 :     }
      31             : 
      32       25702 :     std::string operator()(const ScriptHash& id) const
      33             :     {
      34       25702 :         std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
      35       25702 :         data.insert(data.end(), id.begin(), id.end());
      36       25702 :         return EncodeBase58Check(data);
      37       25702 :     }
      38             : 
      39       21283 :     std::string operator()(const CNoDestination& no) const { return {}; }
      40             : };
      41             : 
      42       92550 : CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str)
      43             : {
      44       92550 :     std::vector<unsigned char> data;
      45       92550 :     uint160 hash;
      46       92550 :     error_str = "";
      47       92550 :     if (DecodeBase58Check(str, data, 21)) {
      48             :         // base58-encoded Dash addresses.
      49             :         // Public-key-hash-addresses have version 76 (or 140 testnet).
      50             :         // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
      51       92328 :         const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
      52       92328 :         if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
      53       91224 :             std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
      54       91224 :             return PKHash(hash);
      55             :         }
      56             :         // Script-hash-addresses have version 16 (or 19 testnet).
      57             :         // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
      58        1104 :         const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
      59        1104 :         if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
      60        1050 :             std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
      61        1050 :             return ScriptHash(hash);
      62             :         }
      63             : 
      64             :         // Set potential error message.
      65          54 :         error_str = "Invalid prefix for Base58-encoded address";
      66          54 :     }
      67             :     // Set error message if address can't be interpreted as Base58.
      68         276 :     if (error_str.empty()) error_str = "Invalid address format";
      69             : 
      70         276 :     return CNoDestination();
      71       92550 : }
      72             : } // namespace
      73             : 
      74     1004517 : CKey DecodeSecret(const std::string& str)
      75             : {
      76     1004517 :     CKey key;
      77     1004517 :     std::vector<unsigned char> data;
      78     1004517 :     if (DecodeBase58Check(str, data, 34)) {
      79     1004384 :         const std::vector<unsigned char>& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY);
      80     2008711 :         if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
      81     1004327 :             std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
      82     1004301 :             bool compressed = data.size() == 33 + privkey_prefix.size();
      83     1004301 :             key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed);
      84     1004301 :         }
      85     1004384 :     }
      86     1004517 :     if (!data.empty()) {
      87     1004384 :         memory_cleanse(data.data(), data.size());
      88     1004384 :     }
      89     1004517 :     return key;
      90     1004517 : }
      91             : 
      92        3986 : std::string EncodeSecret(const CKey& key)
      93             : {
      94        3986 :     assert(key.IsValid());
      95        3986 :     std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY);
      96        3986 :     data.insert(data.end(), key.begin(), key.end());
      97        3986 :     if (key.IsCompressed()) {
      98        3962 :         data.push_back(1);
      99        3962 :     }
     100        3986 :     std::string ret = EncodeBase58Check(data);
     101        3986 :     memory_cleanse(data.data(), data.size());
     102        3986 :     return ret;
     103        3986 : }
     104             : 
     105        2854 : CExtPubKey DecodeExtPubKey(const std::string& str)
     106             : {
     107        2854 :     CExtPubKey key;
     108        2854 :     std::vector<unsigned char> data;
     109        2854 :     if (DecodeBase58Check(str, data, 78)) {
     110        2853 :         const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
     111        2853 :         if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
     112        2579 :             key.Decode(data.data() + prefix.size());
     113        2579 :         }
     114        2853 :     }
     115             :     return key;
     116        2854 : }
     117             : 
     118       79657 : std::string EncodeExtPubKey(const CExtPubKey& key)
     119             : {
     120       79657 :     std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
     121       79657 :     size_t size = data.size();
     122       79657 :     data.resize(size + BIP32_EXTKEY_SIZE);
     123       79657 :     key.Encode(data.data() + size);
     124       79657 :     std::string ret = EncodeBase58Check(data);
     125       79657 :     return ret;
     126       79657 : }
     127             : 
     128        2854 : CExtKey DecodeExtKey(const std::string& str)
     129             : {
     130        2854 :     CExtKey key;
     131        2854 :     std::vector<unsigned char> data;
     132        2854 :     if (DecodeBase58Check(str, data, 78)) {
     133        2853 :         const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
     134        2853 :         if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
     135         285 :             key.Decode(data.data() + prefix.size());
     136         285 :         }
     137        2853 :     }
     138        2854 :     return key;
     139        2854 : }
     140             : 
     141         247 : std::string EncodeExtKey(const CExtKey& key)
     142             : {
     143         247 :     std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
     144         247 :     size_t size = data.size();
     145         247 :     data.resize(size + BIP32_EXTKEY_SIZE);
     146         247 :     key.Encode(data.data() + size);
     147         247 :     std::string ret = EncodeBase58Check(data);
     148         247 :     if (!data.empty()) {
     149         247 :         memory_cleanse(data.data(), data.size());
     150         247 :     }
     151         247 :     return ret;
     152         247 : }
     153             : 
     154      338268 : std::string EncodeDestination(const CTxDestination& dest)
     155             : {
     156      338268 :     return std::visit(DestinationEncoder(Params()), dest);
     157             : }
     158             : 
     159       92270 : CTxDestination DecodeDestination(const std::string& str, std::string& error_msg)
     160             : {
     161       92270 :     return DecodeDestination(str, Params(), error_msg);
     162             : }
     163             : 
     164       90192 : CTxDestination DecodeDestination(const std::string& str)
     165             : {
     166       90192 :     std::string error_msg;
     167       90192 :     return DecodeDestination(str, error_msg);
     168       90192 : }
     169             : 
     170         280 : bool IsValidDestinationString(const std::string& str, const CChainParams& params)
     171             : {
     172         280 :     std::string error_msg;
     173         280 :     return IsValidDestination(DecodeDestination(str, params, error_msg));
     174         280 : }
     175             : 
     176         280 : bool IsValidDestinationString(const std::string& str)
     177             : {
     178         280 :     return IsValidDestinationString(str, Params());
     179             : }
     180             : 
     181             : namespace {
     182             : constexpr uint8_t DIP18_TYPE_BYTE_P2PKH = 0xb0;
     183             : constexpr uint8_t DIP18_TYPE_BYTE_P2SH  = 0x80;
     184             : constexpr size_t  DIP18_PAYLOAD_SIZE    = 21; // 1 type byte + 20-byte HASH160
     185             : 
     186           8 : std::string EncodePlatformBech32m(const CChainParams& params, uint8_t type_byte, const BaseHash<uint160>& hash)
     187             : {
     188           8 :     std::vector<uint8_t> payload;
     189           8 :     payload.reserve(DIP18_PAYLOAD_SIZE);
     190           8 :     payload.push_back(type_byte);
     191           8 :     payload.insert(payload.end(), hash.begin(), hash.end());
     192           8 :     std::vector<uint8_t> values;
     193           8 :     values.reserve(((DIP18_PAYLOAD_SIZE * 8) + 4) / 5);
     194         280 :     ConvertBits<8, 5, true>([&](uint8_t v) { values.push_back(v); }, payload.begin(), payload.end());
     195           8 :     return bech32::Encode(bech32::Encoding::BECH32M, params.Bech32PlatformHRP(), values);
     196           8 : }
     197             : 
     198             : class PlatformDestinationEncoder
     199             : {
     200             : private:
     201             :     const CChainParams& m_params;
     202             : 
     203             : public:
     204          16 :     explicit PlatformDestinationEncoder(const CChainParams& params) : m_params(params) {}
     205             : 
     206           6 :     std::string operator()(const PlatformP2PKHDestination& id) const
     207             :     {
     208           6 :         return EncodePlatformBech32m(m_params, DIP18_TYPE_BYTE_P2PKH, id);
     209             :     }
     210           2 :     std::string operator()(const PlatformP2SHDestination& id) const
     211             :     {
     212           2 :         return EncodePlatformBech32m(m_params, DIP18_TYPE_BYTE_P2SH, id);
     213             :     }
     214           0 :     std::string operator()(const CNoDestination&) const { return {}; }
     215             : };
     216             : } // namespace
     217             : 
     218          16 : bool IsValidPlatformDestination(const PlatformDestination& dest)
     219             : {
     220          16 :     return !std::holds_alternative<CNoDestination>(dest);
     221             : }
     222             : 
     223           8 : std::string EncodePlatformDestination(const PlatformDestination& dest)
     224             : {
     225           8 :     return std::visit(PlatformDestinationEncoder(Params()), dest);
     226             : }
     227             : 
     228          16 : PlatformDestination DecodePlatformDestination(const std::string& str, const CChainParams& params, std::string& error_str)
     229             : {
     230          16 :     error_str.clear();
     231          16 :     const bech32::DecodeResult dec = bech32::Decode(str);
     232          16 :     if (dec.encoding == bech32::Encoding::INVALID) {
     233           3 :         error_str = "Invalid bech32m encoding";
     234           3 :         return CNoDestination();
     235             :     }
     236          13 :     if (dec.encoding != bech32::Encoding::BECH32M) {
     237           1 :         error_str = "DIP-18 Platform addresses require bech32m checksum";
     238           1 :         return CNoDestination();
     239             :     }
     240          12 :     if (dec.hrp != params.Bech32PlatformHRP()) {
     241           2 :         error_str = "Invalid Platform HRP for the selected network";
     242           2 :         return CNoDestination();
     243             :     }
     244          10 :     std::vector<uint8_t> payload;
     245          10 :     payload.reserve((dec.data.size() * 5) / 8);
     246         219 :     if (!ConvertBits<5, 8, false>([&](uint8_t b) { payload.push_back(b); }, dec.data.begin(), dec.data.end())) {
     247           0 :         error_str = "Invalid Platform address payload encoding";
     248           0 :         return CNoDestination();
     249             :     }
     250          10 :     if (payload.size() != DIP18_PAYLOAD_SIZE) {
     251           1 :         error_str = "Invalid Platform address payload length";
     252           1 :         return CNoDestination();
     253             :     }
     254           9 :     uint160 hash;
     255           9 :     std::copy(payload.begin() + 1, payload.end(), hash.begin());
     256           9 :     switch (payload[0]) {
     257             :     case DIP18_TYPE_BYTE_P2PKH:
     258           6 :         return PlatformP2PKHDestination(hash);
     259             :     case DIP18_TYPE_BYTE_P2SH:
     260           2 :         return PlatformP2SHDestination(hash);
     261             :     }
     262           1 :     error_str = "Unknown DIP-18 type byte";
     263           1 :     return CNoDestination();
     264          16 : }
     265             : 
     266          16 : PlatformDestination DecodePlatformDestination(const std::string& str, std::string& error_str)
     267             : {
     268          16 :     return DecodePlatformDestination(str, Params(), error_str);
     269             : }
     270             : 
     271           0 : PlatformDestination DecodePlatformDestination(const std::string& str)
     272             : {
     273           0 :     std::string error_str;
     274           0 :     return DecodePlatformDestination(str, error_str);
     275           0 : }

Generated by: LCOV version 1.16