Coverage Report

Created: 2026-06-16 16:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/pubkey.h
Line
Count
Source
1
// Copyright (c) 2009-2010 Satoshi Nakamoto
2
// Copyright (c) 2009-present 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 <span.h>
13
#include <uint256.h>
14
15
#include <cstring>
16
#include <optional>
17
#include <vector>
18
19
const unsigned int BIP32_EXTKEY_SIZE = 74;
20
const unsigned int BIP32_EXTKEY_WITH_VERSION_SIZE = 78;
21
22
/** A reference to a CKey: the Hash160 of its serialized public key */
23
class CKeyID : public uint160
24
{
25
public:
26
491k
    CKeyID() : uint160() {}
27
6.22M
    explicit CKeyID(const uint160& in) : uint160(in) {}
28
};
29
30
/** An encapsulated public key. */
31
class CPubKey
32
{
33
public:
34
    /**
35
     * secp256k1:
36
     */
37
    static constexpr unsigned int SIZE                   = 65;
38
    static constexpr unsigned int COMPRESSED_SIZE        = 33;
39
    static constexpr unsigned int SIGNATURE_SIZE         = 72;
40
    static constexpr unsigned int COMPACT_SIGNATURE_SIZE = 65;
41
    /**
42
     * see www.keylength.com
43
     * script supports up to 75 for single byte push
44
     */
45
    static_assert(
46
        SIZE >= COMPRESSED_SIZE,
47
        "COMPRESSED_SIZE is larger than SIZE");
48
49
private:
50
51
    /**
52
     * Just store the serialized data.
53
     * Its length can very cheaply be computed from the first byte.
54
     */
55
    unsigned char vch[SIZE];
56
57
    //! Compute the length of a pubkey with a given first byte.
58
    unsigned int static GetLen(unsigned char chHeader)
59
25.0M
    {
60
25.0M
        if (chHeader == 2 || chHeader == 3)
61
24.8M
            return COMPRESSED_SIZE;
62
122k
        if (chHeader == 4 || chHeader == 6 || chHeader == 7)
63
59.6k
            return SIZE;
64
63.2k
        return 0;
65
122k
    }
66
67
    //! Set this key data to be invalid
68
    void Invalidate()
69
3.17M
    {
70
3.17M
        vch[0] = 0xFF;
71
3.17M
    }
72
73
public:
74
75
28.2k
    bool static ValidSize(const std::vector<unsigned char> &vch) {
76
28.2k
      return vch.size() > 0 && GetLen(vch[0]) == vch.size();
77
28.2k
    }
78
79
    //! Construct an invalid public key.
80
    CPubKey()
81
3.15M
    {
82
3.15M
        Invalidate();
83
3.15M
    }
84
85
    //! Initialize a public key using begin/end iterators to byte data.
86
    template <typename T>
87
    void Set(const T pbegin, const T pend)
88
1.97M
    {
89
1.97M
        int len = pend == pbegin ? 0 : GetLen(pbegin[0]);
90
1.97M
        if (len && len == (pend - pbegin))
91
1.95M
            memcpy(vch, (unsigned char*)&pbegin[0], len);
92
22.2k
        else
93
22.2k
            Invalidate();
94
1.97M
    }
void CPubKey::Set<__gnu_cxx::__normal_iterator<unsigned char const*, std::span<unsigned char const, 18446744073709551615ul>::__iter_tag>>(__gnu_cxx::__normal_iterator<unsigned char const*, std::span<unsigned char const, 18446744073709551615ul>::__iter_tag>, __gnu_cxx::__normal_iterator<unsigned char const*, std::span<unsigned char const, 18446744073709551615ul>::__iter_tag>)
Line
Count
Source
88
416k
    {
89
416k
        int len = pend == pbegin ? 0 : GetLen(pbegin[0]);
90
416k
        if (len && len == (pend - pbegin))
91
394k
            memcpy(vch, (unsigned char*)&pbegin[0], len);
92
22.2k
        else
93
22.2k
            Invalidate();
94
416k
    }
void CPubKey::Set<__gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char, std::allocator<unsigned char>>>>(__gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char, std::allocator<unsigned char>>>, __gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char, std::allocator<unsigned char>>>)
Line
Count
Source
88
2.44k
    {
89
2.44k
        int len = pend == pbegin ? 0 : GetLen(pbegin[0]);
90
2.44k
        if (len && len == (pend - pbegin))
91
2.44k
            memcpy(vch, (unsigned char*)&pbegin[0], len);
92
4
        else
93
4
            Invalidate();
94
2.44k
    }
void CPubKey::Set<__gnu_cxx::__normal_iterator<unsigned char const*, std::vector<unsigned char, std::allocator<unsigned char>>>>(__gnu_cxx::__normal_iterator<unsigned char const*, std::vector<unsigned char, std::allocator<unsigned char>>>, __gnu_cxx::__normal_iterator<unsigned char const*, std::vector<unsigned char, std::allocator<unsigned char>>>)
Line
Count
Source
88
848
    {
89
848
        int len = pend == pbegin ? 0 : GetLen(pbegin[0]);
90
848
        if (len && len == (pend - pbegin))
91
848
            memcpy(vch, (unsigned char*)&pbegin[0], len);
92
0
        else
93
0
            Invalidate();
94
848
    }
void CPubKey::Set<unsigned char*>(unsigned char*, unsigned char*)
Line
Count
Source
88
1.53M
    {
89
1.53M
        int len = pend == pbegin ? 0 : GetLen(pbegin[0]);
90
1.53M
        if (len && len == (pend - pbegin))
91
1.53M
            memcpy(vch, (unsigned char*)&pbegin[0], len);
92
4
        else
93
4
            Invalidate();
94
1.53M
    }
void CPubKey::Set<unsigned char const*>(unsigned char const*, unsigned char const*)
Line
Count
Source
88
24.7k
    {
89
24.7k
        int len = pend == pbegin ? 0 : GetLen(pbegin[0]);
90
24.7k
        if (len && len == (pend - pbegin))
91
24.7k
            memcpy(vch, (unsigned char*)&pbegin[0], len);
92
3
        else
93
3
            Invalidate();
94
24.7k
    }
95
96
    //! Construct a public key using begin/end iterators to byte data.
97
    template <typename T>
98
    CPubKey(const T pbegin, const T pend)
99
4.15k
    {
100
4.15k
        Set(pbegin, pend);
101
4.15k
    }
CPubKey::CPubKey<__gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char, std::allocator<unsigned char>>>>(__gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char, std::allocator<unsigned char>>>, __gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char, std::allocator<unsigned char>>>)
Line
Count
Source
99
2.44k
    {
100
2.44k
        Set(pbegin, pend);
101
2.44k
    }
CPubKey::CPubKey<__gnu_cxx::__normal_iterator<unsigned char const*, std::vector<unsigned char, std::allocator<unsigned char>>>>(__gnu_cxx::__normal_iterator<unsigned char const*, std::vector<unsigned char, std::allocator<unsigned char>>>, __gnu_cxx::__normal_iterator<unsigned char const*, std::vector<unsigned char, std::allocator<unsigned char>>>)
Line
Count
Source
99
848
    {
100
848
        Set(pbegin, pend);
101
848
    }
CPubKey::CPubKey<unsigned char*>(unsigned char*, unsigned char*)
Line
Count
Source
99
864
    {
100
864
        Set(pbegin, pend);
101
864
    }
102
103
    //! Construct a public key from a byte vector.
104
    explicit CPubKey(std::span<const uint8_t> _vch)
105
416k
    {
106
416k
        Set(_vch.begin(), _vch.end());
107
416k
    }
108
109
    //! Simple read-only vector-like interface to the pubkey data.
110
23.0M
    unsigned int size() const { return GetLen(vch[0]); }
111
2.19M
    const unsigned char* data() const { return vch; }
112
2.05M
    const unsigned char* begin() const { return vch; }
113
158k
    const unsigned char* end() const { return vch + size(); }
114
43.1k
    const unsigned char& operator[](unsigned int pos) const { return vch[pos]; }
115
116
    //! Comparator implementation.
117
    friend bool operator==(const CPubKey& a, const CPubKey& b)
118
70.9k
    {
119
70.9k
        return a.vch[0] == b.vch[0] &&
120
70.9k
               memcmp(a.vch, b.vch, a.size()) == 0;
121
70.9k
    }
122
    friend bool operator<(const CPubKey& a, const CPubKey& b)
123
11.8M
    {
124
11.8M
        return a.vch[0] < b.vch[0] ||
125
11.8M
               (a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) < 0);
126
11.8M
    }
127
    friend bool operator>(const CPubKey& a, const CPubKey& b)
128
702
    {
129
702
        return a.vch[0] > b.vch[0] ||
130
702
               (a.vch[0] == b.vch[0] && memcmp(a.vch, b.vch, a.size()) > 0);
131
702
    }
132
133
    //! Implement serialization, as if this was a byte vector.
134
    template <typename Stream>
135
    void Serialize(Stream& s) const
136
5.64k
    {
137
5.64k
        unsigned int len = size();
138
5.64k
        ::WriteCompactSize(s, len);
139
5.64k
        s << std::span{vch, len};
140
5.64k
    }
void CPubKey::Serialize<DataStream>(DataStream&) const
Line
Count
Source
136
4.84k
    {
137
4.84k
        unsigned int len = size();
138
4.84k
        ::WriteCompactSize(s, len);
139
4.84k
        s << std::span{vch, len};
140
4.84k
    }
void CPubKey::Serialize<HashWriter>(HashWriter&) const
Line
Count
Source
136
798
    {
137
798
        unsigned int len = size();
138
798
        ::WriteCompactSize(s, len);
139
798
        s << std::span{vch, len};
140
798
    }
141
    template <typename Stream>
142
    void Unserialize(Stream& s)
143
2.87k
    {
144
2.87k
        const unsigned int len(::ReadCompactSize(s));
145
2.87k
        if (len <= SIZE) {
146
2.87k
            s >> std::span{vch, len};
147
2.87k
            if (len != size()) {
148
6
                Invalidate();
149
6
            }
150
2.87k
        } else {
151
            // invalid pubkey, skip available data
152
0
            s.ignore(len);
153
0
            Invalidate();
154
0
        }
155
2.87k
    }
156
157
    //! Get the KeyID of this public key (hash of its serialization)
158
    CKeyID GetID() const
159
5.83M
    {
160
5.83M
        return CKeyID(Hash160(std::span{vch}.first(size())));
161
5.83M
    }
162
163
    //! Get the 256-bit hash of this public key.
164
    uint256 GetHash() const
165
3.28k
    {
166
3.28k
        return Hash(std::span{vch}.first(size()));
167
3.28k
    }
168
169
    /*
170
     * Check syntactic correctness.
171
     *
172
     * When setting a pubkey (Set()) or deserializing fails (its header bytes
173
     * don't match the length of the data), the size is set to 0. Thus,
174
     * by checking size, one can observe whether Set() or deserialization has
175
     * failed.
176
     *
177
     * This does not check for more than that. In particular, it does not verify
178
     * that the coordinates correspond to a point on the curve (see IsFullyValid()
179
     * for that instead).
180
     *
181
     * Note that this is consensus critical as CheckECDSASignature() calls it!
182
     */
183
    bool IsValid() const
184
1.49M
    {
185
1.49M
        return size() > 0;
186
1.49M
    }
187
188
    /** Check if a public key is a syntactically valid compressed or uncompressed key. */
189
    bool IsValidNonHybrid() const noexcept
190
327k
    {
191
327k
        return size() > 0 && (vch[0] == 0x02 || vch[0] == 0x03 || vch[0] == 0x04);
192
327k
    }
193
194
    //! fully validate whether this is a valid public key (more expensive than IsValid())
195
    bool IsFullyValid() const;
196
197
    //! Check whether this is a compressed public key.
198
    bool IsCompressed() const
199
231k
    {
200
231k
        return size() == COMPRESSED_SIZE;
201
231k
    }
202
203
    /**
204
     * Verify a DER signature (~72 bytes).
205
     * If this public key is not fully valid, the return value will be false.
206
     */
207
    bool Verify(const uint256& hash, const std::vector<unsigned char>& vchSig) const;
208
209
    /**
210
     * Check whether a signature is normalized (lower-S).
211
     */
212
    static bool CheckLowS(const std::vector<unsigned char>& vchSig);
213
214
    //! Recover a public key from a compact signature.
215
    bool RecoverCompact(const uint256& hash, const std::vector<unsigned char>& vchSig);
216
217
    //! Turn this public key into an uncompressed public key.
218
    bool Decompress();
219
220
    //! Derive BIP32 child pubkey.
221
    [[nodiscard]] bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc, uint256* bip32_tweak_out = nullptr) const;
222
};
223
224
class XOnlyPubKey
225
{
226
private:
227
    uint256 m_keydata;
228
229
public:
230
    /** Nothing Up My Sleeve point H
231
     *  Used as an internal key for provably disabling the key path spend
232
     *  see BIP341 for more details */
233
    static const XOnlyPubKey NUMS_H;
234
235
    /** Construct an empty x-only pubkey. */
236
1.49M
    XOnlyPubKey() = default;
237
238
    XOnlyPubKey(const XOnlyPubKey&) = default;
239
    XOnlyPubKey& operator=(const XOnlyPubKey&) = default;
240
241
    /** Determine if this pubkey is fully valid. This is true for approximately 50% of all
242
     *  possible 32-byte arrays. If false, VerifySchnorr, CheckTapTweak and CreateTapTweak
243
     *  will always fail. */
244
    bool IsFullyValid() const;
245
246
    /** Test whether this is the 0 key (the result of default construction). This implies
247
     *  !IsFullyValid(). */
248
54.0k
    bool IsNull() const { return m_keydata.IsNull(); }
249
250
    /** Construct an x-only pubkey from exactly 32 bytes. */
251
1.98M
    constexpr explicit XOnlyPubKey(std::span<const unsigned char> bytes) : m_keydata{bytes} {}
252
253
    /** Construct an x-only pubkey from a normal pubkey. */
254
1.40M
    explicit XOnlyPubKey(const CPubKey& pubkey) : XOnlyPubKey(std::span{pubkey}.subspan(1, 32)) {}
255
256
    /** Verify a Schnorr signature against this public key.
257
     *
258
     * sigbytes must be exactly 64 bytes.
259
     */
260
    bool VerifySchnorr(const uint256& msg, std::span<const unsigned char> sigbytes) const;
261
262
    /** Compute the Taproot tweak as specified in BIP341, with *this as internal
263
     * key:
264
     *  - if merkle_root == nullptr: H_TapTweak(xonly_pubkey)
265
     *  - otherwise:                 H_TapTweak(xonly_pubkey || *merkle_root)
266
     *
267
     * Note that the behavior of this function with merkle_root != nullptr is
268
     * consensus critical.
269
     */
270
    uint256 ComputeTapTweakHash(const uint256* merkle_root) const;
271
272
    /** Verify that this is a Taproot tweaked output point, against a specified internal key,
273
     *  Merkle root, and parity. */
274
    bool CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool parity) const;
275
276
    /** Construct a Taproot tweaked output point with this point as internal key. */
277
    std::optional<std::pair<XOnlyPubKey, bool>> CreateTapTweak(const uint256* merkle_root) const;
278
279
    /** Returns a list of CKeyIDs for the CPubKeys that could have been used to create this XOnlyPubKey.
280
     * As the CKeyID is the Hash160(full pubkey), the produced CKeyIDs are for the versions of this
281
     * XOnlyPubKey with 0x02 and 0x03 prefixes.
282
     * This is needed for key lookups since keys are indexed by CKeyID.
283
     */
284
    std::vector<CKeyID> GetKeyIDs() const;
285
    /** Returns this XOnlyPubKey with 0x02 and 0x03 prefixes */
286
    std::vector<CPubKey> GetCPubKeys() const;
287
288
    CPubKey GetEvenCorrespondingCPubKey() const;
289
290
0
    const unsigned char& operator[](int pos) const { return *(m_keydata.begin() + pos); }
291
287k
    static constexpr size_t size() { return decltype(m_keydata)::size(); }
292
510k
    const unsigned char* data() const { return m_keydata.begin(); }
293
1.34M
    const unsigned char* begin() const { return m_keydata.begin(); }
294
1.34M
    const unsigned char* end() const { return m_keydata.end(); }
295
7
    unsigned char* data() { return m_keydata.begin(); }
296
269k
    unsigned char* begin() { return m_keydata.begin(); }
297
6
    unsigned char* end() { return m_keydata.end(); }
298
20.6k
    bool operator==(const XOnlyPubKey& other) const { return m_keydata == other.m_keydata; }
299
2.94M
    bool operator<(const XOnlyPubKey& other) const { return m_keydata < other.m_keydata; }
300
301
    //! Implement serialization without length prefixes since it is a fixed length
302
19.4k
    SERIALIZE_METHODS(XOnlyPubKey, obj) { READWRITE(obj.m_keydata); }
void XOnlyPubKey::SerializationOps<SpanReader, XOnlyPubKey, ActionUnserialize>(XOnlyPubKey&, SpanReader&, ActionUnserialize)
Line
Count
Source
302
7.91k
    SERIALIZE_METHODS(XOnlyPubKey, obj) { READWRITE(obj.m_keydata); }
Unexecuted instantiation: void XOnlyPubKey::SerializationOps<DataStream, XOnlyPubKey, ActionUnserialize>(XOnlyPubKey&, DataStream&, ActionUnserialize)
void XOnlyPubKey::SerializationOps<SizeComputer, XOnlyPubKey const, ActionSerialize>(XOnlyPubKey const&, SizeComputer&, ActionSerialize)
Line
Count
Source
302
5.75k
    SERIALIZE_METHODS(XOnlyPubKey, obj) { READWRITE(obj.m_keydata); }
void XOnlyPubKey::SerializationOps<DataStream, XOnlyPubKey const, ActionSerialize>(XOnlyPubKey const&, DataStream&, ActionSerialize)
Line
Count
Source
302
5.75k
    SERIALIZE_METHODS(XOnlyPubKey, obj) { READWRITE(obj.m_keydata); }
303
};
304
305
/** An ElligatorSwift-encoded public key. */
306
struct EllSwiftPubKey
307
{
308
private:
309
    static constexpr size_t SIZE = 64;
310
    std::array<std::byte, SIZE> m_pubkey;
311
312
public:
313
    /** Default constructor creates all-zero pubkey (which is valid). */
314
    EllSwiftPubKey() noexcept = default;
315
316
    /** Construct a new ellswift public key from a given serialization. */
317
    EllSwiftPubKey(std::span<const std::byte> ellswift) noexcept;
318
319
    /** Decode to normal compressed CPubKey (for debugging purposes). */
320
    CPubKey Decode() const;
321
322
    // Read-only access for serialization.
323
941
    const std::byte* data() const { return m_pubkey.data(); }
324
2.21k
    static constexpr size_t size() { return SIZE; }
325
277
    auto begin() const { return m_pubkey.cbegin(); }
326
277
    auto end() const { return m_pubkey.cend(); }
327
328
    bool friend operator==(const EllSwiftPubKey& a, const EllSwiftPubKey& b)
329
98
    {
330
98
        return a.m_pubkey == b.m_pubkey;
331
98
    }
332
};
333
334
struct CExtPubKey {
335
    unsigned char version[4];
336
    unsigned char nDepth;
337
    unsigned char vchFingerprint[4];
338
    unsigned int nChild;
339
    ChainCode chaincode;
340
    CPubKey pubkey;
341
342
    friend bool operator==(const CExtPubKey &a, const CExtPubKey &b)
343
33
    {
344
33
        return a.nDepth == b.nDepth &&
345
33
            memcmp(a.vchFingerprint, b.vchFingerprint, sizeof(vchFingerprint)) == 0 &&
346
33
            a.nChild == b.nChild &&
347
33
            a.chaincode == b.chaincode &&
348
33
            a.pubkey == b.pubkey;
349
33
    }
350
351
    friend bool operator<(const CExtPubKey &a, const CExtPubKey &b)
352
731
    {
353
731
        if (a.pubkey < b.pubkey) {
354
29
            return true;
355
702
        } else if (a.pubkey > b.pubkey) {
356
38
            return false;
357
38
        }
358
664
        return a.chaincode < b.chaincode;
359
731
    }
360
361
    void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const;
362
    void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]);
363
    void EncodeWithVersion(unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]) const;
364
    void DecodeWithVersion(const unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]);
365
    [[nodiscard]] bool Derive(CExtPubKey& out, unsigned int nChild, uint256* bip32_tweak_out = nullptr) const;
366
};
367
368
#endif // BITCOIN_PUBKEY_H