LCOV - code coverage report
Current view: top level - src - pubkey.h (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 75 106 70.8 %
Date: 2026-06-25 07:23:51 Functions: 38 48 79.2 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2021 The Bitcoin Core developers
       3             : // Copyright (c) 2017 The Zcash developers
       4             : // Distributed under the MIT software license, see the accompanying
       5             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       6             : 
       7             : #ifndef BITCOIN_PUBKEY_H
       8             : #define BITCOIN_PUBKEY_H
       9             : 
      10             : #include <hash.h>
      11             : #include <serialize.h>
      12             : #include <uint256.h>
      13             : 
      14             : #include <array>
      15             : #include <cstring>
      16             : #include <vector>
      17             : 
      18             : const unsigned int BIP32_EXTKEY_SIZE = 74;
      19             : const unsigned int BIP32_EXTKEY_WITH_VERSION_SIZE = 78;
      20             : 
      21             : /** A reference to a CKey: the Hash160 of its serialized public key */
      22             : class CKeyID : public uint160
      23             : {
      24             : public:
      25       91146 :     CKeyID() : uint160() {}
      26      883470 :     explicit CKeyID(const uint160& in) : uint160(in) {}
      27             : };
      28             : 
      29             : typedef uint256 ChainCode;
      30             : 
      31             : /** An encapsulated public key. */
      32             : class CPubKey
      33             : {
      34             : public:
      35             :     /**
      36             :      * secp256k1:
      37             :      */
      38             :     static constexpr unsigned int SIZE                   = 65;
      39             :     static constexpr unsigned int COMPRESSED_SIZE        = 33;
      40             :     static constexpr unsigned int SIGNATURE_SIZE         = 72;
      41             :     static constexpr unsigned int COMPACT_SIGNATURE_SIZE = 65;
      42             :     /**
      43             :      * see www.keylength.com
      44             :      * script supports up to 75 for single byte push
      45             :      */
      46             :     static_assert(
      47             :         SIZE >= COMPRESSED_SIZE,
      48             :         "COMPRESSED_SIZE is larger than SIZE");
      49             : 
      50             : private:
      51             : 
      52             :     /**
      53             :      * Just store the serialized data.
      54             :      * Its length can very cheaply be computed from the first byte.
      55             :      */
      56             :     unsigned char vch[SIZE];
      57             : 
      58             :     //! Compute the length of a pubkey with a given first byte.
      59     3071122 :     unsigned int static GetLen(unsigned char chHeader)
      60             :     {
      61     3071122 :         if (chHeader == 2 || chHeader == 3)
      62     2829039 :             return COMPRESSED_SIZE;
      63      242083 :         if (chHeader == 4 || chHeader == 6 || chHeader == 7)
      64      241478 :             return SIZE;
      65         605 :         return 0;
      66     3071122 :     }
      67             : 
      68             :     //! Set this key data to be invalid
      69      294581 :     void Invalidate()
      70             :     {
      71      294581 :         vch[0] = 0xFF;
      72      294581 :     }
      73             : 
      74             : public:
      75             : 
      76        3015 :     bool static ValidSize(const std::vector<unsigned char> &vch) {
      77        3015 :       return vch.size() > 0 && GetLen(vch[0]) == vch.size();
      78             :     }
      79             : 
      80             :     //! Construct an invalid public key.
      81      588518 :     CPubKey()
      82      294259 :     {
      83      294259 :         Invalidate();
      84      588518 :     }
      85             : 
      86             :     //! Initialize a public key using begin/end iterators to byte data.
      87             :     template <typename T>
      88      146526 :     void Set(const T pbegin, const T pend)
      89             :     {
      90      146526 :         int len = pend == pbegin ? 0 : GetLen(pbegin[0]);
      91      146526 :         if (len && len == (pend - pbegin))
      92      146199 :             memcpy(vch, (unsigned char*)&pbegin[0], len);
      93             :         else
      94         327 :             Invalidate();
      95      146526 :     }
      96             : 
      97             :     //! Construct a public key using begin/end iterators to byte data.
      98             :     template <typename T>
      99         256 :     CPubKey(const T pbegin, const T pend)
     100         128 :     {
     101         128 :         Set(pbegin, pend);
     102         256 :     }
     103             : 
     104             :     //! Construct a public key from a byte vector.
     105      120749 :     explicit CPubKey(Span<const uint8_t> _vch)
     106       60377 :     {
     107       60372 :         Set(_vch.begin(), _vch.end());
     108      120749 :     }
     109             : 
     110             :     //! Simple read-only vector-like interface to the pubkey data.
     111     2922043 :     unsigned int size() const { return GetLen(vch[0]); }
     112       30126 :     const unsigned char* data() const { return vch; }
     113      241026 :     const unsigned char* begin() const { return vch; }
     114       24976 :     const unsigned char* end() const { return vch + size(); }
     115        6604 :     const unsigned char& operator[](unsigned int pos) const { return vch[pos]; }
     116             : 
     117             :     //! Comparator implementation.
     118         928 :     friend bool operator==(const CPubKey& a, const CPubKey& b)
     119             :     {
     120        1856 :         return a.vch[0] == b.vch[0] &&
     121         928 :                memcmp(a.vch, b.vch, a.size()) == 0;
     122             :     }
     123           0 :     friend bool operator!=(const CPubKey& a, const CPubKey& b)
     124             :     {
     125           0 :         return !(a == b);
     126             :     }
     127     2112952 :     friend bool operator<(const CPubKey& a, const CPubKey& b)
     128             :     {
     129     4110158 :         return a.vch[0] < b.vch[0] ||
     130     1997206 :                (a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) < 0);
     131             :     }
     132           0 :     friend bool operator>(const CPubKey& a, const CPubKey& b)
     133             :     {
     134           0 :         return a.vch[0] > b.vch[0] ||
     135           0 :                (a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) > 0);
     136             :     }
     137             : 
     138             :     //! Implement serialization, as if this was a byte vector.
     139             :     template <typename Stream>
     140       28293 :     void Serialize(Stream& s) const
     141             :     {
     142       28293 :         unsigned int len = size();
     143       28293 :         ::WriteCompactSize(s, len);
     144       28293 :         s.write(AsBytes(Span{vch, len}));
     145       28293 :     }
     146             :     template <typename Stream>
     147        6492 :     void Unserialize(Stream& s)
     148             :     {
     149        6492 :         const unsigned int len(::ReadCompactSize(s));
     150        6492 :         if (len <= SIZE) {
     151        6492 :             s.read(AsWritableBytes(Span{vch, len}));
     152        6492 :             if (len != size()) {
     153           6 :                 Invalidate();
     154           6 :             }
     155        6492 :         } else {
     156             :             // invalid pubkey, skip available data
     157           0 :             s.ignore(len);
     158           0 :             Invalidate();
     159             :         }
     160        6492 :     }
     161             : 
     162             :     //! Get the KeyID of this public key (hash of its serialization)
     163      426158 :     CKeyID GetID() const
     164             :     {
     165      426158 :         return CKeyID(Hash160(Span{vch}.first(size())));
     166             :     }
     167             : 
     168             :     //! Get the 256-bit hash of this public key.
     169           0 :     uint256 GetHash() const
     170             :     {
     171           0 :         return Hash(Span{vch}.first(size()));
     172             :     }
     173             : 
     174             :     /*
     175             :      * Check syntactic correctness.
     176             :      *
     177             :      * Note that this is consensus critical as CheckSig() calls it!
     178             :      */
     179      199380 :     bool IsValid() const
     180             :     {
     181      199380 :         return size() > 0;
     182             :     }
     183             : 
     184             :     //! fully validate whether this is a valid public key (more expensive than IsValid())
     185             :     bool IsFullyValid() const;
     186             : 
     187             :     //! Check whether this is a compressed public key.
     188        9525 :     bool IsCompressed() const
     189             :     {
     190        9525 :         return size() == COMPRESSED_SIZE;
     191             :     }
     192             : 
     193             :     /**
     194             :      * Verify a DER signature (~72 bytes).
     195             :      * If this public key is not fully valid, the return value will be false.
     196             :      */
     197             :     bool Verify(const uint256& hash, const std::vector<unsigned char>& vchSig) const;
     198             : 
     199             :     /**
     200             :      * Check whether a signature is normalized (lower-S).
     201             :      */
     202             :     static bool CheckLowS(const std::vector<unsigned char>& vchSig);
     203             : 
     204             :     //! Recover a public key from a compact signature.
     205             :     bool RecoverCompact(const uint256& hash, const std::vector<unsigned char>& vchSig);
     206             : 
     207             :     //! Turn this public key into an uncompressed public key.
     208             :     bool Decompress();
     209             : 
     210             :     //! Derive BIP32 child pubkey.
     211             :     [[nodiscard]] bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;
     212             : };
     213             : 
     214             : /** An ElligatorSwift-encoded public key. */
     215             : struct EllSwiftPubKey
     216             : {
     217             : private:
     218             :     static constexpr size_t SIZE = 64;
     219             :     std::array<std::byte, SIZE> m_pubkey;
     220             : 
     221             : public:
     222             :     /** Default constructor creates all-zero pubkey (which is valid). */
     223             :     EllSwiftPubKey() noexcept = default;
     224             : 
     225             :     /** Construct a new ellswift public key from a given serialization. */
     226             :     EllSwiftPubKey(Span<const std::byte> ellswift) noexcept;
     227             : 
     228             :     /** Decode to normal compressed CPubKey (for debugging purposes). */
     229             :     CPubKey Decode() const;
     230             : 
     231             :     // Read-only access for serialization.
     232         576 :     const std::byte* data() const { return m_pubkey.data(); }
     233        1097 :     static constexpr size_t size() { return SIZE; }
     234          77 :     auto begin() const { return m_pubkey.cbegin(); }
     235          77 :     auto end() const { return m_pubkey.cend(); }
     236             : 
     237          98 :     bool friend operator==(const EllSwiftPubKey& a, const EllSwiftPubKey& b)
     238             :     {
     239          98 :         return a.m_pubkey == b.m_pubkey;
     240             :     }
     241             : 
     242             :     bool friend operator!=(const EllSwiftPubKey& a, const EllSwiftPubKey& b)
     243             :     {
     244             :         return a.m_pubkey != b.m_pubkey;
     245             :     }
     246             : };
     247             : 
     248             : struct CExtPubKey {
     249             :     unsigned char version[4];
     250             :     unsigned char nDepth;
     251             :     unsigned char vchFingerprint[4];
     252             :     unsigned int nChild;
     253             :     ChainCode chaincode;
     254             :     CPubKey pubkey;
     255             : 
     256          27 :     friend bool operator==(const CExtPubKey &a, const CExtPubKey &b)
     257             :     {
     258          54 :         return a.nDepth == b.nDepth &&
     259          27 :             memcmp(a.vchFingerprint, b.vchFingerprint, sizeof(vchFingerprint)) == 0 &&
     260          27 :             a.nChild == b.nChild &&
     261          27 :             a.chaincode == b.chaincode &&
     262          27 :             a.pubkey == b.pubkey;
     263             :     }
     264             : 
     265           0 :     friend bool operator!=(const CExtPubKey &a, const CExtPubKey &b)
     266             :     {
     267           0 :         return !(a == b);
     268             :     }
     269             : 
     270           0 :     friend bool operator<(const CExtPubKey &a, const CExtPubKey &b)
     271             :     {
     272           0 :         if (a.pubkey < b.pubkey) {
     273           0 :             return true;
     274           0 :         } else if (a.pubkey > b.pubkey) {
     275           0 :             return false;
     276             :         }
     277           0 :         return a.chaincode < b.chaincode;
     278           0 :     }
     279             : 
     280             :     void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const;
     281             :     void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);
     282             :     void EncodeWithVersion(unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]) const;
     283             :     void DecodeWithVersion(const unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]);
     284             :     [[nodiscard]] bool Derive(CExtPubKey& out, unsigned int nChild) const;
     285             : 
     286             :     void Serialize(CSizeComputer& s) const
     287             :     {
     288             :         // Optimized implementation for ::GetSerializeSize that avoids copying.
     289             :         s.seek(BIP32_EXTKEY_SIZE + 1); // add one byte for the size (compact int)
     290             :     }
     291             :     template <typename Stream>
     292           0 :     void Serialize(Stream& s) const
     293             :     {
     294           0 :         unsigned int len = BIP32_EXTKEY_SIZE;
     295           0 :         ::WriteCompactSize(s, len);
     296             :         unsigned char code[BIP32_EXTKEY_SIZE];
     297           0 :         Encode(code);
     298           0 :         s.write(AsBytes(Span{&code[0], len}));
     299           0 :     }
     300             :     template <typename Stream>
     301           0 :     void Unserialize(Stream& s)
     302             :     {
     303           0 :         unsigned int len = ::ReadCompactSize(s);
     304             :         unsigned char code[BIP32_EXTKEY_SIZE];
     305           0 :         if (len != BIP32_EXTKEY_SIZE)
     306           0 :             throw std::runtime_error("Invalid extended key size\n");
     307           0 :         s.read(AsWritableBytes(Span{&code[0], len}));
     308           0 :         Decode(code);
     309           0 :     }
     310             : };
     311             : 
     312             : #endif // BITCOIN_PUBKEY_H

Generated by: LCOV version 1.16