/Users/eugenesiegel/btc/bitcoin/src/pubkey.cpp
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | // Copyright (c) 2009-present The Bitcoin Core developers | 
| 2 |  | // Copyright (c) 2017 The Zcash developers | 
| 3 |  | // Distributed under the MIT software license, see the accompanying | 
| 4 |  | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | 
| 5 |  |  | 
| 6 |  | #include <pubkey.h> | 
| 7 |  |  | 
| 8 |  | #include <hash.h> | 
| 9 |  | #include <secp256k1.h> | 
| 10 |  | #include <secp256k1_ellswift.h> | 
| 11 |  | #include <secp256k1_extrakeys.h> | 
| 12 |  | #include <secp256k1_recovery.h> | 
| 13 |  | #include <secp256k1_schnorrsig.h> | 
| 14 |  | #include <span.h> | 
| 15 |  | #include <uint256.h> | 
| 16 |  | #include <util/strencodings.h> | 
| 17 |  |  | 
| 18 |  | #include <algorithm> | 
| 19 |  | #include <cassert> | 
| 20 |  |  | 
| 21 |  | using namespace util::hex_literals; | 
| 22 |  |  | 
| 23 |  | namespace { | 
| 24 |  |  | 
| 25 |  | struct Secp256k1SelfTester | 
| 26 |  | { | 
| 27 | 0 |     Secp256k1SelfTester() { | 
| 28 |  |         /* Run libsecp256k1 self-test before using the secp256k1_context_static. */ | 
| 29 | 0 |         secp256k1_selftest(); | 
| 30 | 0 |     } | 
| 31 |  | } SECP256K1_SELFTESTER; | 
| 32 |  |  | 
| 33 |  | } // namespace | 
| 34 |  |  | 
| 35 |  | /** This function is taken from the libsecp256k1 distribution and implements | 
| 36 |  |  *  DER parsing for ECDSA signatures, while supporting an arbitrary subset of | 
| 37 |  |  *  format violations. | 
| 38 |  |  * | 
| 39 |  |  *  Supported violations include negative integers, excessive padding, garbage | 
| 40 |  |  *  at the end, and overly long length descriptors. This is safe to use in | 
| 41 |  |  *  Bitcoin because since the activation of BIP66, signatures are verified to be | 
| 42 |  |  *  strict DER before being passed to this module, and we know it supports all | 
| 43 |  |  *  violations present in the blockchain before that point. | 
| 44 |  |  */ | 
| 45 | 0 | int ecdsa_signature_parse_der_lax(secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { | 
| 46 | 0 |     size_t rpos, rlen, spos, slen; | 
| 47 | 0 |     size_t pos = 0; | 
| 48 | 0 |     size_t lenbyte; | 
| 49 | 0 |     unsigned char tmpsig[64] = {0}; | 
| 50 | 0 |     int overflow = 0; | 
| 51 |  |  | 
| 52 |  |     /* Hack to initialize sig with a correctly-parsed but invalid signature. */ | 
| 53 | 0 |     secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig); | 
| 54 |  |  | 
| 55 |  |     /* Sequence tag byte */ | 
| 56 | 0 |     if (pos == inputlen || input[pos] != 0x30) { | 
| 57 | 0 |         return 0; | 
| 58 | 0 |     } | 
| 59 | 0 |     pos++; | 
| 60 |  |  | 
| 61 |  |     /* Sequence length bytes */ | 
| 62 | 0 |     if (pos == inputlen) { | 
| 63 | 0 |         return 0; | 
| 64 | 0 |     } | 
| 65 | 0 |     lenbyte = input[pos++]; | 
| 66 | 0 |     if (lenbyte & 0x80) { | 
| 67 | 0 |         lenbyte -= 0x80; | 
| 68 | 0 |         if (lenbyte > inputlen - pos) { | 
| 69 | 0 |             return 0; | 
| 70 | 0 |         } | 
| 71 | 0 |         pos += lenbyte; | 
| 72 | 0 |     } | 
| 73 |  |  | 
| 74 |  |     /* Integer tag byte for R */ | 
| 75 | 0 |     if (pos == inputlen || input[pos] != 0x02) { | 
| 76 | 0 |         return 0; | 
| 77 | 0 |     } | 
| 78 | 0 |     pos++; | 
| 79 |  |  | 
| 80 |  |     /* Integer length for R */ | 
| 81 | 0 |     if (pos == inputlen) { | 
| 82 | 0 |         return 0; | 
| 83 | 0 |     } | 
| 84 | 0 |     lenbyte = input[pos++]; | 
| 85 | 0 |     if (lenbyte & 0x80) { | 
| 86 | 0 |         lenbyte -= 0x80; | 
| 87 | 0 |         if (lenbyte > inputlen - pos) { | 
| 88 | 0 |             return 0; | 
| 89 | 0 |         } | 
| 90 | 0 |         while (lenbyte > 0 && input[pos] == 0) { | 
| 91 | 0 |             pos++; | 
| 92 | 0 |             lenbyte--; | 
| 93 | 0 |         } | 
| 94 | 0 |         static_assert(sizeof(size_t) >= 4, "size_t too small"); | 
| 95 | 0 |         if (lenbyte >= 4) { | 
| 96 | 0 |             return 0; | 
| 97 | 0 |         } | 
| 98 | 0 |         rlen = 0; | 
| 99 | 0 |         while (lenbyte > 0) { | 
| 100 | 0 |             rlen = (rlen << 8) + input[pos]; | 
| 101 | 0 |             pos++; | 
| 102 | 0 |             lenbyte--; | 
| 103 | 0 |         } | 
| 104 | 0 |     } else { | 
| 105 | 0 |         rlen = lenbyte; | 
| 106 | 0 |     } | 
| 107 | 0 |     if (rlen > inputlen - pos) { | 
| 108 | 0 |         return 0; | 
| 109 | 0 |     } | 
| 110 | 0 |     rpos = pos; | 
| 111 | 0 |     pos += rlen; | 
| 112 |  |  | 
| 113 |  |     /* Integer tag byte for S */ | 
| 114 | 0 |     if (pos == inputlen || input[pos] != 0x02) { | 
| 115 | 0 |         return 0; | 
| 116 | 0 |     } | 
| 117 | 0 |     pos++; | 
| 118 |  |  | 
| 119 |  |     /* Integer length for S */ | 
| 120 | 0 |     if (pos == inputlen) { | 
| 121 | 0 |         return 0; | 
| 122 | 0 |     } | 
| 123 | 0 |     lenbyte = input[pos++]; | 
| 124 | 0 |     if (lenbyte & 0x80) { | 
| 125 | 0 |         lenbyte -= 0x80; | 
| 126 | 0 |         if (lenbyte > inputlen - pos) { | 
| 127 | 0 |             return 0; | 
| 128 | 0 |         } | 
| 129 | 0 |         while (lenbyte > 0 && input[pos] == 0) { | 
| 130 | 0 |             pos++; | 
| 131 | 0 |             lenbyte--; | 
| 132 | 0 |         } | 
| 133 | 0 |         static_assert(sizeof(size_t) >= 4, "size_t too small"); | 
| 134 | 0 |         if (lenbyte >= 4) { | 
| 135 | 0 |             return 0; | 
| 136 | 0 |         } | 
| 137 | 0 |         slen = 0; | 
| 138 | 0 |         while (lenbyte > 0) { | 
| 139 | 0 |             slen = (slen << 8) + input[pos]; | 
| 140 | 0 |             pos++; | 
| 141 | 0 |             lenbyte--; | 
| 142 | 0 |         } | 
| 143 | 0 |     } else { | 
| 144 | 0 |         slen = lenbyte; | 
| 145 | 0 |     } | 
| 146 | 0 |     if (slen > inputlen - pos) { | 
| 147 | 0 |         return 0; | 
| 148 | 0 |     } | 
| 149 | 0 |     spos = pos; | 
| 150 |  |  | 
| 151 |  |     /* Ignore leading zeroes in R */ | 
| 152 | 0 |     while (rlen > 0 && input[rpos] == 0) { | 
| 153 | 0 |         rlen--; | 
| 154 | 0 |         rpos++; | 
| 155 | 0 |     } | 
| 156 |  |     /* Copy R value */ | 
| 157 | 0 |     if (rlen > 32) { | 
| 158 | 0 |         overflow = 1; | 
| 159 | 0 |     } else { | 
| 160 | 0 |         memcpy(tmpsig + 32 - rlen, input + rpos, rlen); | 
| 161 | 0 |     } | 
| 162 |  |  | 
| 163 |  |     /* Ignore leading zeroes in S */ | 
| 164 | 0 |     while (slen > 0 && input[spos] == 0) { | 
| 165 | 0 |         slen--; | 
| 166 | 0 |         spos++; | 
| 167 | 0 |     } | 
| 168 |  |     /* Copy S value */ | 
| 169 | 0 |     if (slen > 32) { | 
| 170 | 0 |         overflow = 1; | 
| 171 | 0 |     } else { | 
| 172 | 0 |         memcpy(tmpsig + 64 - slen, input + spos, slen); | 
| 173 | 0 |     } | 
| 174 |  | 
 | 
| 175 | 0 |     if (!overflow) { | 
| 176 | 0 |         overflow = !secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig); | 
| 177 | 0 |     } | 
| 178 | 0 |     if (overflow) { | 
| 179 |  |         /* Overwrite the result again with a correctly-parsed but invalid | 
| 180 |  |            signature if parsing failed. */ | 
| 181 | 0 |         memset(tmpsig, 0, 64); | 
| 182 | 0 |         secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig); | 
| 183 | 0 |     } | 
| 184 | 0 |     return 1; | 
| 185 | 0 | } | 
| 186 |  |  | 
| 187 |  | /** Nothing Up My Sleeve (NUMS) point | 
| 188 |  |  * | 
| 189 |  |  *  NUMS_H is a point with an unknown discrete logarithm, constructed by taking the sha256 of 'g' | 
| 190 |  |  *  (uncompressed encoding), which happens to be a point on the curve. | 
| 191 |  |  * | 
| 192 |  |  *  For an example script for calculating H, refer to the unit tests in | 
| 193 |  |  *  ./test/functional/test_framework/crypto/secp256k1.py | 
| 194 |  |  */ | 
| 195 |  | constexpr XOnlyPubKey XOnlyPubKey::NUMS_H{ | 
| 196 |  |     // Use immediate lambda to work around GCC-14 bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117966 | 
| 197 |  |     []() consteval { return XOnlyPubKey{"50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0"_hex_u8}; }(), | 
| 198 |  | }; | 
| 199 |  |  | 
| 200 |  | std::vector<CPubKey> XOnlyPubKey::GetCPubKeys() const | 
| 201 | 0 | { | 
| 202 | 0 |     std::vector<CPubKey> out; | 
| 203 | 0 |     unsigned char b[33] = {0x02}; | 
| 204 | 0 |     std::copy(m_keydata.begin(), m_keydata.end(), b + 1); | 
| 205 | 0 |     CPubKey fullpubkey; | 
| 206 | 0 |     fullpubkey.Set(b, b + 33); | 
| 207 | 0 |     out.push_back(fullpubkey); | 
| 208 | 0 |     b[0] = 0x03; | 
| 209 | 0 |     fullpubkey.Set(b, b + 33); | 
| 210 | 0 |     out.push_back(fullpubkey); | 
| 211 | 0 |     return out; | 
| 212 | 0 | } | 
| 213 |  |  | 
| 214 |  | std::vector<CKeyID> XOnlyPubKey::GetKeyIDs() const | 
| 215 | 0 | { | 
| 216 | 0 |     std::vector<CKeyID> out; | 
| 217 | 0 |     for (const CPubKey& pk : GetCPubKeys()) { | 
| 218 | 0 |         out.push_back(pk.GetID()); | 
| 219 | 0 |     } | 
| 220 | 0 |     return out; | 
| 221 | 0 | } | 
| 222 |  |  | 
| 223 |  | CPubKey XOnlyPubKey::GetEvenCorrespondingCPubKey() const | 
| 224 | 0 | { | 
| 225 | 0 |     unsigned char full_key[CPubKey::COMPRESSED_SIZE] = {0x02}; | 
| 226 | 0 |     std::copy(begin(), end(), full_key + 1); | 
| 227 | 0 |     return CPubKey{full_key}; | 
| 228 | 0 | } | 
| 229 |  |  | 
| 230 |  | bool XOnlyPubKey::IsFullyValid() const | 
| 231 | 0 | { | 
| 232 | 0 |     secp256k1_xonly_pubkey pubkey; | 
| 233 | 0 |     return secp256k1_xonly_pubkey_parse(secp256k1_context_static, &pubkey, m_keydata.data()); | 
| 234 | 0 | } | 
| 235 |  |  | 
| 236 |  | bool XOnlyPubKey::VerifySchnorr(const uint256& msg, std::span<const unsigned char> sigbytes) const | 
| 237 | 0 | { | 
| 238 | 0 |     assert(sigbytes.size() == 64); | 
| 239 | 0 |     secp256k1_xonly_pubkey pubkey; | 
| 240 | 0 |     if (!secp256k1_xonly_pubkey_parse(secp256k1_context_static, &pubkey, m_keydata.data())) return false; | 
| 241 | 0 |     return secp256k1_schnorrsig_verify(secp256k1_context_static, sigbytes.data(), msg.begin(), 32, &pubkey); | 
| 242 | 0 | } | 
| 243 |  |  | 
| 244 |  | static const HashWriter HASHER_TAPTWEAK{TaggedHash("TapTweak")}; | 
| 245 |  |  | 
| 246 |  | uint256 XOnlyPubKey::ComputeTapTweakHash(const uint256* merkle_root) const | 
| 247 | 0 | { | 
| 248 | 0 |     if (merkle_root == nullptr) { | 
| 249 |  |         // We have no scripts. The actual tweak does not matter, but follow BIP341 here to | 
| 250 |  |         // allow for reproducible tweaking. | 
| 251 | 0 |         return (HashWriter{HASHER_TAPTWEAK} << m_keydata).GetSHA256(); | 
| 252 | 0 |     } else { | 
| 253 | 0 |         return (HashWriter{HASHER_TAPTWEAK} << m_keydata << *merkle_root).GetSHA256(); | 
| 254 | 0 |     } | 
| 255 | 0 | } | 
| 256 |  |  | 
| 257 |  | bool XOnlyPubKey::CheckTapTweak(const XOnlyPubKey& internal, const uint256& merkle_root, bool parity) const | 
| 258 | 0 | { | 
| 259 | 0 |     secp256k1_xonly_pubkey internal_key; | 
| 260 | 0 |     if (!secp256k1_xonly_pubkey_parse(secp256k1_context_static, &internal_key, internal.data())) return false; | 
| 261 | 0 |     uint256 tweak = internal.ComputeTapTweakHash(&merkle_root); | 
| 262 | 0 |     return secp256k1_xonly_pubkey_tweak_add_check(secp256k1_context_static, m_keydata.begin(), parity, &internal_key, tweak.begin()); | 
| 263 | 0 | } | 
| 264 |  |  | 
| 265 |  | std::optional<std::pair<XOnlyPubKey, bool>> XOnlyPubKey::CreateTapTweak(const uint256* merkle_root) const | 
| 266 | 0 | { | 
| 267 | 0 |     secp256k1_xonly_pubkey base_point; | 
| 268 | 0 |     if (!secp256k1_xonly_pubkey_parse(secp256k1_context_static, &base_point, data())) return std::nullopt; | 
| 269 | 0 |     secp256k1_pubkey out; | 
| 270 | 0 |     uint256 tweak = ComputeTapTweakHash(merkle_root); | 
| 271 | 0 |     if (!secp256k1_xonly_pubkey_tweak_add(secp256k1_context_static, &out, &base_point, tweak.data())) return std::nullopt; | 
| 272 | 0 |     int parity = -1; | 
| 273 | 0 |     std::pair<XOnlyPubKey, bool> ret; | 
| 274 | 0 |     secp256k1_xonly_pubkey out_xonly; | 
| 275 | 0 |     if (!secp256k1_xonly_pubkey_from_pubkey(secp256k1_context_static, &out_xonly, &parity, &out)) return std::nullopt; | 
| 276 | 0 |     secp256k1_xonly_pubkey_serialize(secp256k1_context_static, ret.first.begin(), &out_xonly); | 
| 277 | 0 |     assert(parity == 0 || parity == 1); | 
| 278 | 0 |     ret.second = parity; | 
| 279 | 0 |     return ret; | 
| 280 | 0 | } | 
| 281 |  |  | 
| 282 |  |  | 
| 283 | 0 | bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const { | 
| 284 | 0 |     if (!IsValid()) | 
| 285 | 0 |         return false; | 
| 286 | 0 |     secp256k1_pubkey pubkey; | 
| 287 | 0 |     secp256k1_ecdsa_signature sig; | 
| 288 | 0 |     if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) { | 
| 289 | 0 |         return false; | 
| 290 | 0 |     } | 
| 291 | 0 |     if (!ecdsa_signature_parse_der_lax(&sig, vchSig.data(), vchSig.size())) { | 
| 292 | 0 |         return false; | 
| 293 | 0 |     } | 
| 294 |  |     /* libsecp256k1's ECDSA verification requires lower-S signatures, which have | 
| 295 |  |      * not historically been enforced in Bitcoin, so normalize them first. */ | 
| 296 | 0 |     secp256k1_ecdsa_signature_normalize(secp256k1_context_static, &sig, &sig); | 
| 297 | 0 |     return secp256k1_ecdsa_verify(secp256k1_context_static, &sig, hash.begin(), &pubkey); | 
| 298 | 0 | } | 
| 299 |  |  | 
| 300 | 0 | bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) { | 
| 301 | 0 |     if (vchSig.size() != COMPACT_SIGNATURE_SIZE) | 
| 302 | 0 |         return false; | 
| 303 | 0 |     int recid = (vchSig[0] - 27) & 3; | 
| 304 | 0 |     bool fComp = ((vchSig[0] - 27) & 4) != 0; | 
| 305 | 0 |     secp256k1_pubkey pubkey; | 
| 306 | 0 |     secp256k1_ecdsa_recoverable_signature sig; | 
| 307 | 0 |     if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_static, &sig, &vchSig[1], recid)) { | 
| 308 | 0 |         return false; | 
| 309 | 0 |     } | 
| 310 | 0 |     if (!secp256k1_ecdsa_recover(secp256k1_context_static, &pubkey, &sig, hash.begin())) { | 
| 311 | 0 |         return false; | 
| 312 | 0 |     } | 
| 313 | 0 |     unsigned char pub[SIZE]; | 
| 314 | 0 |     size_t publen = SIZE; | 
| 315 | 0 |     secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); | Line | Count | Source |  | 224 | 0 | #define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) | Line | Count | Source |  | 205 | 0 | #define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) | 
 | #define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) | Line | Count | Source |  | 210 | 0 | #define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) | 
 | 
 |     secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED); | Line | Count | Source |  | 225 | 0 | #define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) | Line | Count | Source |  | 205 | 0 | #define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) | 
 | 
 | 
| 316 | 0 |     Set(pub, pub + publen); | 
| 317 | 0 |     return true; | 
| 318 | 0 | } | 
| 319 |  |  | 
| 320 | 0 | bool CPubKey::IsFullyValid() const { | 
| 321 | 0 |     if (!IsValid()) | 
| 322 | 0 |         return false; | 
| 323 | 0 |     secp256k1_pubkey pubkey; | 
| 324 | 0 |     return secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size()); | 
| 325 | 0 | } | 
| 326 |  |  | 
| 327 | 0 | bool CPubKey::Decompress() { | 
| 328 | 0 |     if (!IsValid()) | 
| 329 | 0 |         return false; | 
| 330 | 0 |     secp256k1_pubkey pubkey; | 
| 331 | 0 |     if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) { | 
| 332 | 0 |         return false; | 
| 333 | 0 |     } | 
| 334 | 0 |     unsigned char pub[SIZE]; | 
| 335 | 0 |     size_t publen = SIZE; | 
| 336 | 0 |     secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED); | Line | Count | Source |  | 225 | 0 | #define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) | Line | Count | Source |  | 205 | 0 | #define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) | 
 | 
 | 
| 337 | 0 |     Set(pub, pub + publen); | 
| 338 | 0 |     return true; | 
| 339 | 0 | } | 
| 340 |  |  | 
| 341 | 0 | bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const { | 
| 342 | 0 |     assert(IsValid()); | 
| 343 | 0 |     assert((nChild >> 31) == 0); | 
| 344 | 0 |     assert(size() == COMPRESSED_SIZE); | 
| 345 | 0 |     unsigned char out[64]; | 
| 346 | 0 |     BIP32Hash(cc, nChild, *begin(), begin()+1, out); | 
| 347 | 0 |     memcpy(ccChild.begin(), out+32, 32); | 
| 348 | 0 |     secp256k1_pubkey pubkey; | 
| 349 | 0 |     if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) { | 
| 350 | 0 |         return false; | 
| 351 | 0 |     } | 
| 352 | 0 |     if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_static, &pubkey, out)) { | 
| 353 | 0 |         return false; | 
| 354 | 0 |     } | 
| 355 | 0 |     unsigned char pub[COMPRESSED_SIZE]; | 
| 356 | 0 |     size_t publen = COMPRESSED_SIZE; | 
| 357 | 0 |     secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED); | Line | Count | Source |  | 224 | 0 | #define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) | Line | Count | Source |  | 205 | 0 | #define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) | 
 | #define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) | Line | Count | Source |  | 210 | 0 | #define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) | 
 | 
 | 
| 358 | 0 |     pubkeyChild.Set(pub, pub + publen); | 
| 359 | 0 |     return true; | 
| 360 | 0 | } | 
| 361 |  |  | 
| 362 |  | EllSwiftPubKey::EllSwiftPubKey(std::span<const std::byte> ellswift) noexcept | 
| 363 | 0 | { | 
| 364 | 0 |     assert(ellswift.size() == SIZE); | 
| 365 | 0 |     std::copy(ellswift.begin(), ellswift.end(), m_pubkey.begin()); | 
| 366 | 0 | } | 
| 367 |  |  | 
| 368 |  | CPubKey EllSwiftPubKey::Decode() const | 
| 369 | 0 | { | 
| 370 | 0 |     secp256k1_pubkey pubkey; | 
| 371 | 0 |     secp256k1_ellswift_decode(secp256k1_context_static, &pubkey, UCharCast(m_pubkey.data())); | 
| 372 |  | 
 | 
| 373 | 0 |     size_t sz = CPubKey::COMPRESSED_SIZE; | 
| 374 | 0 |     std::array<uint8_t, CPubKey::COMPRESSED_SIZE> vch_bytes; | 
| 375 |  | 
 | 
| 376 | 0 |     secp256k1_ec_pubkey_serialize(secp256k1_context_static, vch_bytes.data(), &sz, &pubkey, SECP256K1_EC_COMPRESSED); | Line | Count | Source |  | 224 | 0 | #define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) | Line | Count | Source |  | 205 | 0 | #define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) | 
 | #define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) | Line | Count | Source |  | 210 | 0 | #define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) | 
 | 
 | 
| 377 | 0 |     assert(sz == vch_bytes.size()); | 
| 378 |  |  | 
| 379 | 0 |     return CPubKey{vch_bytes.begin(), vch_bytes.end()}; | 
| 380 | 0 | } | 
| 381 |  |  | 
| 382 | 0 | void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const { | 
| 383 | 0 |     code[0] = nDepth; | 
| 384 | 0 |     memcpy(code+1, vchFingerprint, 4); | 
| 385 | 0 |     WriteBE32(code+5, nChild); | 
| 386 | 0 |     memcpy(code+9, chaincode.begin(), 32); | 
| 387 | 0 |     assert(pubkey.size() == CPubKey::COMPRESSED_SIZE); | 
| 388 | 0 |     memcpy(code+41, pubkey.begin(), CPubKey::COMPRESSED_SIZE); | 
| 389 | 0 | } | 
| 390 |  |  | 
| 391 | 0 | void CExtPubKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) { | 
| 392 | 0 |     nDepth = code[0]; | 
| 393 | 0 |     memcpy(vchFingerprint, code+1, 4); | 
| 394 | 0 |     nChild = ReadBE32(code+5); | 
| 395 | 0 |     memcpy(chaincode.begin(), code+9, 32); | 
| 396 | 0 |     pubkey.Set(code+41, code+BIP32_EXTKEY_SIZE); | 
| 397 | 0 |     if ((nDepth == 0 && (nChild != 0 || ReadLE32(vchFingerprint) != 0)) || !pubkey.IsFullyValid()) pubkey = CPubKey(); | 
| 398 | 0 | } | 
| 399 |  |  | 
| 400 |  | void CExtPubKey::EncodeWithVersion(unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]) const | 
| 401 | 0 | { | 
| 402 | 0 |     memcpy(code, version, 4); | 
| 403 | 0 |     Encode(&code[4]); | 
| 404 | 0 | } | 
| 405 |  |  | 
| 406 |  | void CExtPubKey::DecodeWithVersion(const unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]) | 
| 407 | 0 | { | 
| 408 | 0 |     memcpy(version, code, 4); | 
| 409 | 0 |     Decode(&code[4]); | 
| 410 | 0 | } | 
| 411 |  |  | 
| 412 | 0 | bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const { | 
| 413 | 0 |     if (nDepth == std::numeric_limits<unsigned char>::max()) return false; | 
| 414 | 0 |     out.nDepth = nDepth + 1; | 
| 415 | 0 |     CKeyID id = pubkey.GetID(); | 
| 416 | 0 |     memcpy(out.vchFingerprint, &id, 4); | 
| 417 | 0 |     out.nChild = _nChild; | 
| 418 | 0 |     return pubkey.Derive(out.pubkey, out.chaincode, _nChild, chaincode); | 
| 419 | 0 | } | 
| 420 |  |  | 
| 421 | 0 | /* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) { | 
| 422 | 0 |     secp256k1_ecdsa_signature sig; | 
| 423 | 0 |     if (!ecdsa_signature_parse_der_lax(&sig, vchSig.data(), vchSig.size())) { | 
| 424 | 0 |         return false; | 
| 425 | 0 |     } | 
| 426 | 0 |     return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_static, nullptr, &sig)); | 
| 427 | 0 | } |