Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2009-2010 Satoshi Nakamoto2// Copyright (c) 2009-present The Bitcoin Core developers3// Copyright (c) 2017 The Zcash developers4// Distributed under the MIT software license, see the accompanying5// file COPYING or http://www.opensource.org/licenses/mit-license.php.7#ifndef BITCOIN_PUBKEY_H8#define BITCOIN_PUBKEY_H10#include <hash.h>11#include <serialize.h>12#include <span.h>13#include <uint256.h>15#include <cstring>16#include <optional>17#include <vector>19inline constexpr unsigned int BIP32_EXTKEY_SIZE = 74;20inline constexpr unsigned int BIP32_EXTKEY_WITH_VERSION_SIZE = 78;22using KeyFingerprint = std::array<unsigned char, 4>;24/** A reference to a CKey: the Hash160 of its serialized public key */25class CKeyID : public uint16026{27public:28CKeyID() : uint160() {}29explicit CKeyID(const uint160& in) : uint160(in) {}30KeyFingerprint fingerprint() const31{32KeyFingerprint ret;33std::copy_n(begin(), ret.size(), ret.begin());34return ret;35}36};38/** An encapsulated public key. */39class CPubKey40{41public:42/**43* secp256k1:44*/45static constexpr unsigned int SIZE = 65;46static constexpr unsigned int COMPRESSED_SIZE = 33;47static constexpr unsigned int SIGNATURE_SIZE = 72;48static constexpr unsigned int COMPACT_SIGNATURE_SIZE = 65;49/**50* see www.keylength.com51* script supports up to 75 for single byte push52*/53static_assert(54SIZE >= COMPRESSED_SIZE,55"COMPRESSED_SIZE is larger than SIZE");57private:59/**60* Just store the serialized data.61* Its length can very cheaply be computed from the first byte.62*/63unsigned char vch[SIZE];65//! Compute the length of a pubkey with a given first byte.66unsigned int static GetLen(unsigned char chHeader)67{68if (chHeader == 2 || chHeader == 3)69return COMPRESSED_SIZE;70if (chHeader == 4 || chHeader == 6 || chHeader == 7)71return SIZE;72return 0;73}75//! Set this key data to be invalid76void Invalidate()77{78vch[0] = 0xFF;79}81public:83bool static ValidSize(const std::vector<unsigned char> &vch) {84return vch.size() > 0 && GetLen(vch[0]) == vch.size();85}87//! Construct an invalid public key.88CPubKey()89{90Invalidate();91}93//! Initialize a public key using begin/end iterators to byte data.94template <typename T>95void Set(const T pbegin, const T pend)96{97int len = pend == pbegin ? 0 : GetLen(pbegin[0]);98if (len && len == (pend - pbegin))99memcpy(vch, (unsigned char*)&pbegin[0], len);100else101Invalidate();102}104//! Construct a public key using begin/end iterators to byte data.105template <typename T>106CPubKey(const T pbegin, const T pend)107{108Set(pbegin, pend);109}111//! Construct a public key from a byte vector.112explicit CPubKey(std::span<const uint8_t> _vch)113{114Set(_vch.begin(), _vch.end());115}117//! Simple read-only vector-like interface to the pubkey data.118unsigned int size() const { return GetLen(vch[0]); }119const unsigned char* data() const { return vch; }120const unsigned char* begin() const { return vch; }121const unsigned char* end() const { return vch + size(); }122const unsigned char& operator[](unsigned int pos) const { return vch[pos]; }124//! Comparator implementation.125friend bool operator==(const CPubKey& a, const CPubKey& b)126{127return a.vch[0] == b.vch[0] &&128memcmp(a.vch, b.vch, a.size()) == 0;129}130friend bool operator<(const CPubKey& a, const CPubKey& b)131{132return a.vch[0] < b.vch[0] ||133(a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) < 0);134}135friend bool operator>(const CPubKey& a, const CPubKey& b)136{137return a.vch[0] > b.vch[0] ||138(a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) > 0);139}141//! Implement serialization, as if this was a byte vector.142template <typename Stream>143void Serialize(Stream& s) const144{145unsigned int len = size();146::WriteCompactSize(s, len);147s << std::span{vch, len};148}149template <typename Stream>150void Unserialize(Stream& s)151{152const unsigned int len(::ReadCompactSize(s));153if (len <= SIZE) {154s >> std::span{vch, len};155if (len != size()) {156Invalidate();157}158} else {159// invalid pubkey, skip available data160s.ignore(len);161Invalidate();162}163}165//! Get the KeyID of this public key (hash of its serialization)166CKeyID GetID() const167{168return CKeyID(Hash160(std::span{vch}.first(size())));169}171//! Get the 256-bit hash of this public key.172uint256 GetHash() const173{174return Hash(std::span{vch}.first(size()));175}177/*178* Check syntactic correctness.179*180* When setting a pubkey (Set()) or deserializing fails (its header bytes181* don't match the length of the data), the size is set to 0. Thus,182* by checking size, one can observe whether Set() or deserialization has183* failed.184*185* This does not check for more than that. In particular, it does not verify186* that the coordinates correspond to a point on the curve (see IsFullyValid()187* for that instead).188*189* Note that this is consensus critical as CheckECDSASignature() calls it!190*/191bool IsValid() const192{193return size() > 0;194}196/** Check if a public key is a syntactically valid compressed or uncompressed key. */197bool IsValidNonHybrid() const noexcept198{199return size() > 0 && (vch[0] == 0x02 || vch[0] == 0x03 || vch[0] == 0x04);200}202//! fully validate whether this is a valid public key (more expensive than IsValid())203bool IsFullyValid() const;205//! Check whether this is a compressed public key.206bool IsCompressed() const207{208return size() == COMPRESSED_SIZE;209}211/**212* Verify a DER signature (~72 bytes).213* If this public key is not fully valid, the return value will be false.214*/215bool Verify(const uint256& hash, const std::vector<unsigned char>& vchSig) const;217/**218* Check whether a signature is normalized (lower-S).219*/220static bool CheckLowS(const std::vector<unsigned char>& vchSig);222//! Recover a public key from a compact signature.223bool RecoverCompact(const uint256& hash, const std::vector<unsigned char>& vchSig);225//! Turn this public key into an uncompressed public key.226bool Decompress();228//! Derive BIP32 child pubkey.229[[nodiscard]] bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc, uint256* bip32_tweak_out = nullptr) const;230};232class XOnlyPubKey233{234private:235uint256 m_keydata;237public:238/** Nothing Up My Sleeve point H239* Used as an internal key for provably disabling the key path spend240* see BIP341 for more details */241static const XOnlyPubKey NUMS_H;243/** Construct an empty x-only pubkey. */244XOnlyPubKey() = default;246XOnlyPubKey(const XOnlyPubKey&) = default;247XOnlyPubKey& operator=(const XOnlyPubKey&) = default;249/** Determine if this pubkey is fully valid. This is true for approximately 50% of all250* possible 32-byte arrays. If false, VerifySchnorr, CheckTapTweak and CreateTapTweak
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.