LCOV - code coverage report
Current view: top level - src/test - key_tests.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 197 202 97.5 %
Date: 2026-06-25 07:23:51 Functions: 50 50 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2012-2021 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <key.h>
       6             : 
       7             : #include <key_io.h>
       8             : #include <streams.h>
       9             : #include <test/util/random.h>
      10             : #include <test/util/setup_common.h>
      11             : #include <uint256.h>
      12             : #include <util/strencodings.h>
      13             : #include <util/string.h>
      14             : #include <util/system.h>
      15             : 
      16             : #include <string>
      17             : #include <vector>
      18             : 
      19             : #include <boost/test/unit_test.hpp>
      20             : 
      21         146 : static const std::string strSecret1 = "7qh6LYnLN2w2ntz2wwUhRUEgkQ2j8XB16FGw77ZRDZmC29bn7cD";
      22         146 : static const std::string strSecret2 = "7rve4MxeWFQHGbSYH6J2yaaZd3MBUqoDEwN6ZAZ6ZHmhTT4r3hW";
      23         146 : static const std::string strSecret1C = "XBuxZHH6TqXUuaSjbVTFR1DQSYecxCB9QA1Koyx5tTc3ddhqEnhm";
      24         146 : static const std::string strSecret2C = "XHMkZqWcY6Zkoq1j42NBijD8z5N5FtNy2Wx7WyAfXX2HZgxry8cr";
      25         146 : static const std::string addr1 = "Xywgfc872nn5CKtpATCoAjZCc4v96pJczy";
      26         146 : static const std::string addr2 = "XpmouUj9KKJ99ZuU331ZS1KqsboeFnLGgK";
      27         146 : static const std::string addr1C = "XxV9h4Xmv6Pup8tVAQmH97K6grzvDwMG9F";
      28         146 : static const std::string addr2C = "Xn7ZrYdExuk79Dm7CJCw7sfUWi2qWJSbRy";
      29             : 
      30         146 : static const std::string strAddressBad = "Xta1praZQjyELweyMByXyiREw1ZRsjXzVP";
      31             : 
      32             : 
      33         146 : BOOST_FIXTURE_TEST_SUITE(key_tests, BasicTestingSetup)
      34             : 
      35         149 : BOOST_AUTO_TEST_CASE(key_test1)
      36             : {
      37           1 :     CKey key1  = DecodeSecret(strSecret1);
      38           1 :     BOOST_CHECK(key1.IsValid() && !key1.IsCompressed());
      39           1 :     CKey key2  = DecodeSecret(strSecret2);
      40           1 :     BOOST_CHECK(key2.IsValid() && !key2.IsCompressed());
      41           1 :     CKey key1C = DecodeSecret(strSecret1C);
      42           2 :     BOOST_CHECK(key1C.IsValid() && key1C.IsCompressed());
      43           1 :     CKey key2C = DecodeSecret(strSecret2C);
      44           2 :     BOOST_CHECK(key2C.IsValid() && key2C.IsCompressed());
      45           1 :     CKey bad_key = DecodeSecret(strAddressBad);
      46           1 :     BOOST_CHECK(!bad_key.IsValid());
      47             : 
      48           1 :     CPubKey pubkey1  = key1. GetPubKey();
      49           1 :     CPubKey pubkey2  = key2. GetPubKey();
      50           1 :     CPubKey pubkey1C = key1C.GetPubKey();
      51           1 :     CPubKey pubkey2C = key2C.GetPubKey();
      52             : 
      53           1 :     BOOST_CHECK(key1.VerifyPubKey(pubkey1));
      54           1 :     BOOST_CHECK(!key1.VerifyPubKey(pubkey1C));
      55           1 :     BOOST_CHECK(!key1.VerifyPubKey(pubkey2));
      56           1 :     BOOST_CHECK(!key1.VerifyPubKey(pubkey2C));
      57             : 
      58           1 :     BOOST_CHECK(!key1C.VerifyPubKey(pubkey1));
      59           1 :     BOOST_CHECK(key1C.VerifyPubKey(pubkey1C));
      60           1 :     BOOST_CHECK(!key1C.VerifyPubKey(pubkey2));
      61           1 :     BOOST_CHECK(!key1C.VerifyPubKey(pubkey2C));
      62             : 
      63           1 :     BOOST_CHECK(!key2.VerifyPubKey(pubkey1));
      64           1 :     BOOST_CHECK(!key2.VerifyPubKey(pubkey1C));
      65           1 :     BOOST_CHECK(key2.VerifyPubKey(pubkey2));
      66           1 :     BOOST_CHECK(!key2.VerifyPubKey(pubkey2C));
      67             : 
      68           1 :     BOOST_CHECK(!key2C.VerifyPubKey(pubkey1));
      69           1 :     BOOST_CHECK(!key2C.VerifyPubKey(pubkey1C));
      70           1 :     BOOST_CHECK(!key2C.VerifyPubKey(pubkey2));
      71           1 :     BOOST_CHECK(key2C.VerifyPubKey(pubkey2C));
      72             : 
      73           1 :     BOOST_CHECK(DecodeDestination(addr1)  == CTxDestination(PKHash(pubkey1)));
      74           1 :     BOOST_CHECK(DecodeDestination(addr2)  == CTxDestination(PKHash(pubkey2)));
      75           1 :     BOOST_CHECK(DecodeDestination(addr1C) == CTxDestination(PKHash(pubkey1C)));
      76           1 :     BOOST_CHECK(DecodeDestination(addr2C) == CTxDestination(PKHash(pubkey2C)));
      77             : 
      78          17 :     for (int n=0; n<16; n++)
      79             :     {
      80          16 :         std::string strMsg = strprintf("Very secret message %i: 11", n);
      81          16 :         uint256 hashMsg = Hash(strMsg);
      82             : 
      83             :         // normal signatures
      84             : 
      85          16 :         std::vector<unsigned char> sign1, sign2, sign1C, sign2C;
      86             : 
      87          16 :         BOOST_CHECK(key1.Sign (hashMsg, sign1));
      88          16 :         BOOST_CHECK(key2.Sign (hashMsg, sign2));
      89          16 :         BOOST_CHECK(key1C.Sign(hashMsg, sign1C));
      90          16 :         BOOST_CHECK(key2C.Sign(hashMsg, sign2C));
      91             : 
      92          16 :         BOOST_CHECK( pubkey1.Verify(hashMsg, sign1));
      93          16 :         BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2));
      94          16 :         BOOST_CHECK( pubkey1.Verify(hashMsg, sign1C));
      95          16 :         BOOST_CHECK(!pubkey1.Verify(hashMsg, sign2C));
      96             : 
      97          16 :         BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1));
      98          16 :         BOOST_CHECK( pubkey2.Verify(hashMsg, sign2));
      99          16 :         BOOST_CHECK(!pubkey2.Verify(hashMsg, sign1C));
     100          16 :         BOOST_CHECK( pubkey2.Verify(hashMsg, sign2C));
     101             : 
     102          16 :         BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1));
     103          16 :         BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2));
     104          16 :         BOOST_CHECK( pubkey1C.Verify(hashMsg, sign1C));
     105          16 :         BOOST_CHECK(!pubkey1C.Verify(hashMsg, sign2C));
     106             : 
     107          16 :         BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1));
     108          16 :         BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2));
     109          16 :         BOOST_CHECK(!pubkey2C.Verify(hashMsg, sign1C));
     110          16 :         BOOST_CHECK( pubkey2C.Verify(hashMsg, sign2C));
     111             : 
     112             :         // compact signatures (with key recovery)
     113             : 
     114          16 :         std::vector<unsigned char> csign1, csign2, csign1C, csign2C;
     115             : 
     116          16 :         BOOST_CHECK(key1.SignCompact (hashMsg, csign1));
     117          16 :         BOOST_CHECK(key2.SignCompact (hashMsg, csign2));
     118          16 :         BOOST_CHECK(key1C.SignCompact(hashMsg, csign1C));
     119          16 :         BOOST_CHECK(key2C.SignCompact(hashMsg, csign2C));
     120             : 
     121          16 :         CPubKey rkey1, rkey2, rkey1C, rkey2C;
     122             : 
     123          16 :         BOOST_CHECK(rkey1.RecoverCompact (hashMsg, csign1));
     124          16 :         BOOST_CHECK(rkey2.RecoverCompact (hashMsg, csign2));
     125          16 :         BOOST_CHECK(rkey1C.RecoverCompact(hashMsg, csign1C));
     126          16 :         BOOST_CHECK(rkey2C.RecoverCompact(hashMsg, csign2C));
     127             : 
     128          16 :         BOOST_CHECK(rkey1  == pubkey1);
     129          16 :         BOOST_CHECK(rkey2  == pubkey2);
     130          16 :         BOOST_CHECK(rkey1C == pubkey1C);
     131          16 :         BOOST_CHECK(rkey2C == pubkey2C);
     132          16 :     }
     133             : 
     134             :     // test deterministic signing
     135             : 
     136           1 :     std::vector<unsigned char> detsig, detsigc;
     137           1 :     std::string strMsg = "Very deterministic message";
     138           1 :     uint256 hashMsg = Hash(strMsg);
     139           1 :     BOOST_CHECK(key1.Sign(hashMsg, detsig));
     140           1 :     BOOST_CHECK(key1C.Sign(hashMsg, detsigc));
     141           1 :     BOOST_CHECK(detsig == detsigc);
     142           1 :     BOOST_CHECK(detsig == ParseHex("304402205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d022014ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"));
     143           1 :     BOOST_CHECK(key2.Sign(hashMsg, detsig));
     144           1 :     BOOST_CHECK(key2C.Sign(hashMsg, detsigc));
     145           1 :     BOOST_CHECK(detsig == detsigc);
     146           1 :     BOOST_CHECK(detsig == ParseHex("3044022052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd5022061d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"));
     147           1 :     BOOST_CHECK(key1.SignCompact(hashMsg, detsig));
     148           1 :     BOOST_CHECK(key1C.SignCompact(hashMsg, detsigc));
     149           1 :     BOOST_CHECK(detsig == ParseHex("1c5dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"));
     150           1 :     BOOST_CHECK(detsigc == ParseHex("205dbbddda71772d95ce91cd2d14b592cfbc1dd0aabd6a394b6c2d377bbe59d31d14ddda21494a4e221f0824f0b8b924c43fa43c0ad57dccdaa11f81a6bd4582f6"));
     151           1 :     BOOST_CHECK(key2.SignCompact(hashMsg, detsig));
     152           1 :     BOOST_CHECK(key2C.SignCompact(hashMsg, detsigc));
     153           1 :     BOOST_CHECK(detsig == ParseHex("1c52d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"));
     154           1 :     BOOST_CHECK(detsigc == ParseHex("2052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d"));
     155           1 : }
     156             : 
     157         149 : BOOST_AUTO_TEST_CASE(key_signature_tests)
     158             : {
     159             :     // When entropy is specified, we should see at least one high R signature within 20 signatures
     160           1 :     CKey key = DecodeSecret(strSecret1);
     161           1 :     std::string msg = "A message to be signed";
     162           1 :     uint256 msg_hash = Hash(msg);
     163           1 :     std::vector<unsigned char> sig;
     164           1 :     bool found = false;
     165             : 
     166           1 :     for (int i = 1; i <=20; ++i) {
     167           1 :         sig.clear();
     168           1 :         BOOST_CHECK(key.Sign(msg_hash, sig, false, i));
     169           1 :         found = sig[3] == 0x21 && sig[4] == 0x00;
     170           1 :         if (found) {
     171           1 :             break;
     172             :         }
     173           0 :     }
     174           1 :     BOOST_CHECK(found);
     175             : 
     176             :     // When entropy is not specified, we should always see low R signatures that are less than or equal to 70 bytes in 256 tries
     177             :     // The low R signatures should always have the value of their "length of R" byte less than or equal to 32
     178             :     // We should see at least one signature that is less than 70 bytes.
     179           1 :     bool found_small = false;
     180           1 :     bool found_big = false;
     181           1 :     bool bad_sign = false;
     182         257 :     for (int i = 0; i < 256; ++i) {
     183         256 :         sig.clear();
     184         256 :         std::string msg = "A message to be signed" + ToString(i);
     185         256 :         msg_hash = Hash(msg);
     186         256 :         if (!key.Sign(msg_hash, sig)) {
     187           0 :             bad_sign = true;
     188           0 :             break;
     189             :         }
     190             :         // sig.size() > 70 implies sig[3] > 32, because S is always low.
     191             :         // But check both conditions anyway, just in case this implication is broken for some reason
     192         256 :         if (sig[3] > 32 || sig.size() > 70) {
     193           0 :             found_big = true;
     194           0 :             break;
     195             :         }
     196         256 :         found_small |= sig.size() < 70;
     197         256 :     }
     198           1 :     BOOST_CHECK(!bad_sign);
     199           1 :     BOOST_CHECK(!found_big);
     200           1 :     BOOST_CHECK(found_small);
     201           1 : }
     202             : 
     203         149 : BOOST_AUTO_TEST_CASE(key_key_negation)
     204             : {
     205             :     // create a dummy hash for signature comparison
     206             :     unsigned char rnd[8];
     207           1 :     std::string str = "Bitcoin key verification\n";
     208           1 :     GetRandBytes(rnd);
     209           1 :     uint256 hash{Hash(str, rnd)};
     210             : 
     211             :     // import the static test key
     212           1 :     CKey key = DecodeSecret(strSecret1C);
     213             : 
     214             :     // create a signature
     215           1 :     std::vector<unsigned char> vch_sig;
     216           1 :     std::vector<unsigned char> vch_sig_cmp;
     217           1 :     key.Sign(hash, vch_sig);
     218             : 
     219             :     // negate the key twice
     220           1 :     BOOST_CHECK(key.GetPubKey().data()[0] == 0x03);
     221           1 :     key.Negate();
     222             :     // after the first negation, the signature must be different
     223           1 :     key.Sign(hash, vch_sig_cmp);
     224           1 :     BOOST_CHECK(vch_sig_cmp != vch_sig);
     225           1 :     BOOST_CHECK(key.GetPubKey().data()[0] == 0x02);
     226           1 :     key.Negate();
     227             :     // after the second negation, we should have the original key and thus the
     228             :     // same signature
     229           1 :     key.Sign(hash, vch_sig_cmp);
     230           1 :     BOOST_CHECK(vch_sig_cmp == vch_sig);
     231           1 :     BOOST_CHECK(key.GetPubKey().data()[0] == 0x03);
     232           1 : }
     233             : 
     234          12 : static CPubKey UnserializePubkey(const std::vector<uint8_t>& data)
     235             : {
     236          12 :     CDataStream stream{SER_NETWORK, INIT_PROTO_VERSION};
     237          12 :     stream << data;
     238          12 :     CPubKey pubkey;
     239          12 :     stream >> pubkey;
     240             :     return pubkey;
     241          12 : }
     242             : 
     243           6 : static unsigned int GetLen(unsigned char chHeader)
     244             : {
     245           6 :     if (chHeader == 2 || chHeader == 3)
     246           2 :         return CPubKey::COMPRESSED_SIZE;
     247           4 :     if (chHeader == 4 || chHeader == 6 || chHeader == 7)
     248           3 :         return CPubKey::SIZE;
     249           1 :     return 0;
     250           6 : }
     251             : 
     252          12 : static void CmpSerializationPubkey(const CPubKey& pubkey)
     253             : {
     254          12 :     CDataStream stream{SER_NETWORK, INIT_PROTO_VERSION};
     255          12 :     stream << pubkey;
     256          12 :     CPubKey pubkey2;
     257          12 :     stream >> pubkey2;
     258          12 :     BOOST_CHECK(pubkey == pubkey2);
     259          12 : }
     260             : 
     261         149 : BOOST_AUTO_TEST_CASE(pubkey_unserialize)
     262             : {
     263           7 :     for (uint8_t i = 2; i <= 7; ++i) {
     264           6 :         CPubKey key = UnserializePubkey({0x02});
     265           6 :         BOOST_CHECK(!key.IsValid());
     266           6 :         CmpSerializationPubkey(key);
     267           6 :         key = UnserializePubkey(std::vector<uint8_t>(GetLen(i), i));
     268           6 :         CmpSerializationPubkey(key);
     269           6 :         if (i == 5) {
     270           1 :             BOOST_CHECK(!key.IsValid());
     271           1 :         } else {
     272           5 :             BOOST_CHECK(key.IsValid());
     273             :         }
     274           6 :     }
     275           1 : }
     276             : 
     277         149 : BOOST_AUTO_TEST_CASE(key_ellswift)
     278             : {
     279           5 :     for (const auto& secret : {strSecret1, strSecret2, strSecret1C, strSecret2C}) {
     280           4 :         CKey key = DecodeSecret(secret);
     281           4 :         BOOST_CHECK(key.IsValid());
     282             : 
     283           4 :         uint256 ent32 = InsecureRand256();
     284           4 :         auto ellswift = key.EllSwiftCreate(AsBytes(Span{ent32}));
     285             : 
     286           4 :         CPubKey decoded_pubkey = ellswift.Decode();
     287           4 :         if (!key.IsCompressed()) {
     288             :             // The decoding constructor returns a compressed pubkey. If the
     289             :             // original was uncompressed, we must decompress the decoded one
     290             :             // to compare.
     291           2 :             decoded_pubkey.Decompress();
     292           2 :         }
     293           4 :         BOOST_CHECK(key.GetPubKey() == decoded_pubkey);
     294           4 :     }
     295           1 : }
     296             : 
     297         146 : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.16