LCOV - code coverage report
Current view: top level - src - key_io.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 152 165 92.1 %
Date: 2026-06-25 07:23:51 Functions: 26 30 86.7 %

          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       77396 :     explicit DestinationEncoder(const CChainParams& params) : m_params(params) {}
      24             : 
      25       32065 :     std::string operator()(const PKHash& id) const
      26             :     {
      27       32065 :         std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
      28       32065 :         data.insert(data.end(), id.begin(), id.end());
      29       32065 :         return EncodeBase58Check(data);
      30       32065 :     }
      31             : 
      32          53 :     std::string operator()(const ScriptHash& id) const
      33             :     {
      34          53 :         std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
      35          53 :         data.insert(data.end(), id.begin(), id.end());
      36          53 :         return EncodeBase58Check(data);
      37          53 :     }
      38             : 
      39        6580 :     std::string operator()(const CNoDestination& no) const { return {}; }
      40             : };
      41             : 
      42        6476 : CTxDestination DecodeDestination(const std::string& str, const CChainParams& params, std::string& error_str)
      43             : {
      44        6476 :     std::vector<unsigned char> data;
      45        6476 :     uint160 hash;
      46        6476 :     error_str = "";
      47        6476 :     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        6312 :         const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
      52        6312 :         if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
      53        6246 :             std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
      54        6246 :             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          66 :         const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
      59          66 :         if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
      60          26 :             std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
      61          26 :             return ScriptHash(hash);
      62             :         }
      63             : 
      64             :         // Set potential error message.
      65          40 :         error_str = "Invalid prefix for Base58-encoded address";
      66          40 :     }
      67             :     // Set error message if address can't be interpreted as Base58.
      68         204 :     if (error_str.empty()) error_str = "Invalid address format";
      69             : 
      70         204 :     return CNoDestination();
      71        6476 : }
      72             : } // namespace
      73             : 
      74         267 : CKey DecodeSecret(const std::string& str)
      75             : {
      76         267 :     CKey key;
      77         267 :     std::vector<unsigned char> data;
      78         267 :     if (DecodeBase58Check(str, data, 34)) {
      79         154 :         const std::vector<unsigned char>& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY);
      80         251 :         if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
      81          97 :             std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
      82          71 :             bool compressed = data.size() == 33 + privkey_prefix.size();
      83          71 :             key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed);
      84          71 :         }
      85         154 :     }
      86         267 :     if (!data.empty()) {
      87         154 :         memory_cleanse(data.data(), data.size());
      88         154 :     }
      89         267 :     return key;
      90         267 : }
      91             : 
      92          66 : std::string EncodeSecret(const CKey& key)
      93             : {
      94          66 :     assert(key.IsValid());
      95          66 :     std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY);
      96          66 :     data.insert(data.end(), key.begin(), key.end());
      97          66 :     if (key.IsCompressed()) {
      98          42 :         data.push_back(1);
      99          42 :     }
     100          66 :     std::string ret = EncodeBase58Check(data);
     101          66 :     memory_cleanse(data.data(), data.size());
     102          66 :     return ret;
     103          66 : }
     104             : 
     105         162 : CExtPubKey DecodeExtPubKey(const std::string& str)
     106             : {
     107         162 :     CExtPubKey key;
     108         162 :     std::vector<unsigned char> data;
     109         162 :     if (DecodeBase58Check(str, data, 78)) {
     110         161 :         const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
     111         161 :         if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
     112         119 :             key.Decode(data.data() + prefix.size());
     113         119 :         }
     114         161 :     }
     115             :     return key;
     116         162 : }
     117             : 
     118       11499 : std::string EncodeExtPubKey(const CExtPubKey& key)
     119             : {
     120       11499 :     std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_PUBLIC_KEY);
     121       11499 :     size_t size = data.size();
     122       11499 :     data.resize(size + BIP32_EXTKEY_SIZE);
     123       11499 :     key.Encode(data.data() + size);
     124       11499 :     std::string ret = EncodeBase58Check(data);
     125       11499 :     return ret;
     126       11499 : }
     127             : 
     128         162 : CExtKey DecodeExtKey(const std::string& str)
     129             : {
     130         162 :     CExtKey key;
     131         162 :     std::vector<unsigned char> data;
     132         162 :     if (DecodeBase58Check(str, data, 78)) {
     133         161 :         const std::vector<unsigned char>& prefix = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
     134         161 :         if (data.size() == BIP32_EXTKEY_SIZE + prefix.size() && std::equal(prefix.begin(), prefix.end(), data.begin())) {
     135          53 :             key.Decode(data.data() + prefix.size());
     136          53 :         }
     137         161 :     }
     138         162 :     return key;
     139         162 : }
     140             : 
     141          83 : std::string EncodeExtKey(const CExtKey& key)
     142             : {
     143          83 :     std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::EXT_SECRET_KEY);
     144          83 :     size_t size = data.size();
     145          83 :     data.resize(size + BIP32_EXTKEY_SIZE);
     146          83 :     key.Encode(data.data() + size);
     147          83 :     std::string ret = EncodeBase58Check(data);
     148          83 :     if (!data.empty()) {
     149          83 :         memory_cleanse(data.data(), data.size());
     150          83 :     }
     151          83 :     return ret;
     152          83 : }
     153             : 
     154       38698 : std::string EncodeDestination(const CTxDestination& dest)
     155             : {
     156       38698 :     return std::visit(DestinationEncoder(Params()), dest);
     157             : }
     158             : 
     159        6476 : CTxDestination DecodeDestination(const std::string& str, std::string& error_msg)
     160             : {
     161        6476 :     return DecodeDestination(str, Params(), error_msg);
     162             : }
     163             : 
     164        6474 : CTxDestination DecodeDestination(const std::string& str)
     165             : {
     166        6474 :     std::string error_msg;
     167        6474 :     return DecodeDestination(str, error_msg);
     168        6474 : }
     169             : 
     170           0 : bool IsValidDestinationString(const std::string& str, const CChainParams& params)
     171             : {
     172           0 :     std::string error_msg;
     173           0 :     return IsValidDestination(DecodeDestination(str, params, error_msg));
     174           0 : }
     175             : 
     176           0 : bool IsValidDestinationString(const std::string& str)
     177             : {
     178           0 :     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