LCOV - code coverage report
Current view: top level - src - pubkey.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 144 197 73.1 %
Date: 2026-06-25 07:23:51 Functions: 16 18 88.9 %

          Line data    Source code
       1             : // Copyright (c) 2009-2021 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_extrakeys.h>
      11             : #include <secp256k1_ellswift.h>
      12             : #include <secp256k1_recovery.h>
      13             : #include <span.h>
      14             : #include <uint256.h>
      15             : 
      16             : #include <algorithm>
      17             : #include <cassert>
      18             : namespace {
      19             : 
      20             : struct Secp256k1SelfTester
      21             : {
      22         436 :     Secp256k1SelfTester() {
      23             :         /* Run libsecp256k1 self-test before using the secp256k1_context_static. */
      24         218 :         secp256k1_selftest();
      25         436 :     }
      26         218 : } SECP256K1_SELFTESTER;
      27             : 
      28             : } // namespace
      29             : 
      30             : /** This function is taken from the libsecp256k1 distribution and implements
      31             :  *  DER parsing for ECDSA signatures, while supporting an arbitrary subset of
      32             :  *  format violations.
      33             :  *
      34             :  *  Supported violations include negative integers, excessive padding, garbage
      35             :  *  at the end, and overly long length descriptors. This is safe to use in
      36             :  *  Bitcoin because since the activation of BIP66, signatures are verified to be
      37             :  *  strict DER before being passed to this module, and we know it supports all
      38             :  *  violations present in the blockchain before that point.
      39             :  */
      40       61026 : int ecdsa_signature_parse_der_lax(secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) {
      41             :     size_t rpos, rlen, spos, slen;
      42       61026 :     size_t pos = 0;
      43             :     size_t lenbyte;
      44       61026 :     unsigned char tmpsig[64] = {0};
      45       61026 :     int overflow = 0;
      46             : 
      47             :     /* Hack to initialize sig with a correctly-parsed but invalid signature. */
      48       61026 :     secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig);
      49             : 
      50             :     /* Sequence tag byte */
      51       61026 :     if (pos == inputlen || input[pos] != 0x30) {
      52          40 :         return 0;
      53             :     }
      54       60992 :     pos++;
      55             : 
      56             :     /* Sequence length bytes */
      57       60992 :     if (pos == inputlen) {
      58           0 :         return 0;
      59             :     }
      60       60992 :     lenbyte = input[pos++];
      61       60992 :     if (lenbyte & 0x80) {
      62        1002 :         lenbyte -= 0x80;
      63        1002 :         if (lenbyte > inputlen - pos) {
      64           0 :             return 0;
      65             :         }
      66        1002 :         pos += lenbyte;
      67        1002 :     }
      68             : 
      69             :     /* Integer tag byte for R */
      70       60992 :     if (pos == inputlen || input[pos] != 0x02) {
      71        1002 :         return 0;
      72             :     }
      73       59990 :     pos++;
      74             : 
      75             :     /* Integer length for R */
      76       59990 :     if (pos == inputlen) {
      77           0 :         return 0;
      78             :     }
      79       59990 :     lenbyte = input[pos++];
      80       59990 :     if (lenbyte & 0x80) {
      81           0 :         lenbyte -= 0x80;
      82           0 :         if (lenbyte > inputlen - pos) {
      83           0 :             return 0;
      84             :         }
      85           0 :         while (lenbyte > 0 && input[pos] == 0) {
      86           0 :             pos++;
      87           0 :             lenbyte--;
      88             :         }
      89             :         static_assert(sizeof(size_t) >= 4, "size_t too small");
      90           0 :         if (lenbyte >= 4) {
      91           0 :             return 0;
      92             :         }
      93           0 :         rlen = 0;
      94           0 :         while (lenbyte > 0) {
      95           0 :             rlen = (rlen << 8) + input[pos];
      96           0 :             pos++;
      97           0 :             lenbyte--;
      98             :         }
      99           0 :     } else {
     100       59990 :         rlen = lenbyte;
     101             :     }
     102       59990 :     if (rlen > inputlen - pos) {
     103           0 :         return 0;
     104             :     }
     105       59990 :     rpos = pos;
     106       59990 :     pos += rlen;
     107             : 
     108             :     /* Integer tag byte for S */
     109       59990 :     if (pos == inputlen || input[pos] != 0x02) {
     110          14 :         return 0;
     111             :     }
     112       59990 :     pos++;
     113             : 
     114             :     /* Integer length for S */
     115       59990 :     if (pos == inputlen) {
     116           0 :         return 0;
     117             :     }
     118       59990 :     lenbyte = input[pos++];
     119       59990 :     if (lenbyte & 0x80) {
     120           0 :         lenbyte -= 0x80;
     121           0 :         if (lenbyte > inputlen - pos) {
     122           0 :             return 0;
     123             :         }
     124           0 :         while (lenbyte > 0 && input[pos] == 0) {
     125           0 :             pos++;
     126           0 :             lenbyte--;
     127             :         }
     128             :         static_assert(sizeof(size_t) >= 4, "size_t too small");
     129           0 :         if (lenbyte >= 4) {
     130           0 :             return 0;
     131             :         }
     132           0 :         slen = 0;
     133           0 :         while (lenbyte > 0) {
     134           0 :             slen = (slen << 8) + input[pos];
     135           0 :             pos++;
     136           0 :             lenbyte--;
     137             :         }
     138           0 :     } else {
     139       59990 :         slen = lenbyte;
     140             :     }
     141       59990 :     if (slen > inputlen - pos) {
     142           0 :         return 0;
     143             :     }
     144       59990 :     spos = pos;
     145             : 
     146             :     /* Ignore leading zeroes in R */
     147       60990 :     while (rlen > 0 && input[rpos] == 0) {
     148        1000 :         rlen--;
     149        1000 :         rpos++;
     150             :     }
     151             :     /* Copy R value */
     152       59990 :     if (rlen > 32) {
     153           4 :         overflow = 1;
     154           4 :     } else {
     155       59986 :         memcpy(tmpsig + 32 - rlen, input + rpos, rlen);
     156             :     }
     157             : 
     158             :     /* Ignore leading zeroes in S */
     159       69097 :     while (slen > 0 && input[spos] == 0) {
     160        9107 :         slen--;
     161        9107 :         spos++;
     162             :     }
     163             :     /* Copy S value */
     164       59982 :     if (slen > 32) {
     165           0 :         overflow = 1;
     166           0 :     } else {
     167       59982 :         memcpy(tmpsig + 64 - slen, input + spos, slen);
     168             :     }
     169             : 
     170       59982 :     if (!overflow) {
     171       59985 :         overflow = !secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig);
     172       59985 :     }
     173       59988 :     if (overflow) {
     174             :         /* Overwrite the result again with a correctly-parsed but invalid
     175             :            signature if parsing failed. */
     176           1 :         memset(tmpsig, 0, 64);
     177           1 :         secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static, sig, tmpsig);
     178           1 :     }
     179       59988 :     return 1;
     180       61030 : }
     181             : 
     182       37200 : bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
     183       37200 :     if (!IsValid())
     184           0 :         return false;
     185             :     secp256k1_pubkey pubkey;
     186             :     secp256k1_ecdsa_signature sig;
     187       37200 :     if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) {
     188           0 :         return false;
     189             :     }
     190       37200 :     if (!ecdsa_signature_parse_der_lax(&sig, vchSig.data(), vchSig.size())) {
     191        1042 :         return false;
     192             :     }
     193             :     /* libsecp256k1's ECDSA verification requires lower-S signatures, which have
     194             :      * not historically been enforced in Bitcoin, so normalize them first. */
     195       36158 :     secp256k1_ecdsa_signature_normalize(secp256k1_context_static, &sig, &sig);
     196       36158 :     return secp256k1_ecdsa_verify(secp256k1_context_static, &sig, hash.begin(), &pubkey);
     197       37200 : }
     198             : 
     199          77 : bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned char>& vchSig) {
     200          77 :     if (vchSig.size() != COMPACT_SIGNATURE_SIZE)
     201           0 :         return false;
     202          77 :     int recid = (vchSig[0] - 27) & 3;
     203          77 :     bool fComp = ((vchSig[0] - 27) & 4) != 0;
     204             :     secp256k1_pubkey pubkey;
     205             :     secp256k1_ecdsa_recoverable_signature sig;
     206          77 :     if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_context_static, &sig, &vchSig[1], recid)) {
     207           0 :         return false;
     208             :     }
     209          77 :     if (!secp256k1_ecdsa_recover(secp256k1_context_static, &pubkey, &sig, hash.begin())) {
     210           1 :         return false;
     211             :     }
     212             :     unsigned char pub[SIZE];
     213          76 :     size_t publen = SIZE;
     214          76 :     secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
     215          76 :     Set(pub, pub + publen);
     216          76 :     return true;
     217          77 : }
     218             : 
     219         221 : bool CPubKey::IsFullyValid() const {
     220         221 :     if (!IsValid())
     221           4 :         return false;
     222             :     secp256k1_pubkey pubkey;
     223         217 :     return secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size());
     224         221 : }
     225             : 
     226           2 : bool CPubKey::Decompress() {
     227           2 :     if (!IsValid())
     228           0 :         return false;
     229             :     secp256k1_pubkey pubkey;
     230           2 :     if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) {
     231           0 :         return false;
     232             :     }
     233             :     unsigned char pub[SIZE];
     234           2 :     size_t publen = SIZE;
     235           2 :     secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
     236           2 :     Set(pub, pub + publen);
     237           2 :     return true;
     238           2 : }
     239             : 
     240       83611 : bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const {
     241       83611 :     assert(IsValid());
     242       83611 :     assert((nChild >> 31) == 0);
     243       83611 :     assert(size() == COMPRESSED_SIZE);
     244             :     unsigned char out[64];
     245       83611 :     BIP32Hash(cc, nChild, *begin(), begin()+1, out);
     246       83611 :     memcpy(ccChild.begin(), out+32, 32);
     247             :     secp256k1_pubkey pubkey;
     248       83611 :     if (!secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, vch, size())) {
     249           0 :         return false;
     250             :     }
     251       83611 :     if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_static, &pubkey, out)) {
     252           0 :         return false;
     253             :     }
     254             :     unsigned char pub[COMPRESSED_SIZE];
     255       83611 :     size_t publen = COMPRESSED_SIZE;
     256       83611 :     secp256k1_ec_pubkey_serialize(secp256k1_context_static, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED);
     257       83611 :     pubkeyChild.Set(pub, pub + publen);
     258       83611 :     return true;
     259       83611 : }
     260             : 
     261         652 : EllSwiftPubKey::EllSwiftPubKey(Span<const std::byte> ellswift) noexcept
     262         326 : {
     263         326 :     assert(ellswift.size() == SIZE);
     264         326 :     std::copy(ellswift.begin(), ellswift.end(), m_pubkey.begin());
     265         652 : }
     266             : 
     267           4 : CPubKey EllSwiftPubKey::Decode() const
     268             : {
     269             :     secp256k1_pubkey pubkey;
     270           4 :     secp256k1_ellswift_decode(secp256k1_context_static, &pubkey, UCharCast(m_pubkey.data()));
     271             : 
     272           4 :     size_t sz = CPubKey::COMPRESSED_SIZE;
     273             :     std::array<uint8_t, CPubKey::COMPRESSED_SIZE> vch_bytes;
     274             : 
     275           4 :     secp256k1_ec_pubkey_serialize(secp256k1_context_static, vch_bytes.data(), &sz, &pubkey, SECP256K1_EC_COMPRESSED);
     276           4 :     assert(sz == vch_bytes.size());
     277             : 
     278           4 :     return CPubKey{vch_bytes.begin(), vch_bytes.end()};
     279             : }
     280             : 
     281       12656 : void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {
     282       12656 :     code[0] = nDepth;
     283       12656 :     memcpy(code+1, vchFingerprint, 4);
     284       12656 :     WriteBE32(code+5, nChild);
     285       12656 :     memcpy(code+9, chaincode.begin(), 32);
     286       12656 :     assert(pubkey.size() == CPubKey::COMPRESSED_SIZE);
     287       12656 :     memcpy(code+41, pubkey.begin(), CPubKey::COMPRESSED_SIZE);
     288       12656 : }
     289             : 
     290         131 : void CExtPubKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) {
     291         131 :     nDepth = code[0];
     292         131 :     memcpy(vchFingerprint, code+1, 4);
     293         131 :     nChild = ReadBE32(code+5);
     294         131 :     memcpy(chaincode.begin(), code+9, 32);
     295         131 :     pubkey.Set(code+41, code+BIP32_EXTKEY_SIZE);
     296         131 :     if ((nDepth == 0 && (nChild != 0 || ReadLE32(vchFingerprint) != 0)) || !pubkey.IsFullyValid()) pubkey = CPubKey();
     297          47 : }
     298             : 
     299           0 : void CExtPubKey::EncodeWithVersion(unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE]) const
     300             : {
     301           0 :     memcpy(code, version, 4);
     302           0 :     Encode(&code[4]);
     303           0 : }
     304             : 
     305           0 : void CExtPubKey::DecodeWithVersion(const unsigned char code[BIP32_EXTKEY_WITH_VERSION_SIZE])
     306             : {
     307           0 :     memcpy(version, code, 4);
     308           0 :     Decode(&code[4]);
     309           0 : }
     310             : 
     311       83612 : bool CExtPubKey::Derive(CExtPubKey &out, unsigned int _nChild) const {
     312       83612 :     if (nDepth == std::numeric_limits<unsigned char>::max()) return false;
     313       83611 :     out.nDepth = nDepth + 1;
     314       83611 :     CKeyID id = pubkey.GetID();
     315       83611 :     memcpy(out.vchFingerprint, &id, 4);
     316       83611 :     out.nChild = _nChild;
     317       83611 :     return pubkey.Derive(out.pubkey, out.chaincode, _nChild, chaincode);
     318       83612 : }
     319             : 
     320       23828 : /* static */ bool CPubKey::CheckLowS(const std::vector<unsigned char>& vchSig) {
     321             :     secp256k1_ecdsa_signature sig;
     322       23828 :     if (!ecdsa_signature_parse_der_lax(&sig, vchSig.data(), vchSig.size())) {
     323           0 :         return false;
     324             :     }
     325       23828 :     return (!secp256k1_ecdsa_signature_normalize(secp256k1_context_static, nullptr, &sig));
     326       23828 : }

Generated by: LCOV version 1.16