Coverage Report

Created: 2026-07-29 23:27

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