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