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

          Line data    Source code
       1             : // Copyright (c) 2021-2025 The Dash 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 <policy/policy.h>
       6             : #include <script/interpreter.h>
       7             : 
       8             : #include <test/lcg.h>
       9             : #include <test/util/setup_common.h>
      10             : 
      11             : #include <boost/test/unit_test.hpp>
      12             : 
      13             : #include <array>
      14             : 
      15             : typedef std::vector<uint8_t> valtype;
      16             : typedef std::vector<valtype> stacktype;
      17             : 
      18         146 : BOOST_FIXTURE_TEST_SUITE(checkdatasig_tests, BasicTestingSetup)
      19             : 
      20             : std::array<uint32_t, 2> flagset{{0, STANDARD_SCRIPT_VERIFY_FLAGS}};
      21             : 
      22             : const uint8_t vchPrivkey[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      23             :                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
      24             : 
      25             : struct KeyData {
      26             :     CKey privkey, privkeyC;
      27             :     CPubKey pubkey, pubkeyC, pubkeyH;
      28             : 
      29           2 :     KeyData() {
      30           1 :         privkey.Set(vchPrivkey, vchPrivkey + 32, false);
      31           1 :         privkeyC.Set(vchPrivkey, vchPrivkey + 32, true);
      32           1 :         pubkey = privkey.GetPubKey();
      33           1 :         pubkeyH = privkey.GetPubKey();
      34           1 :         pubkeyC = privkeyC.GetPubKey();
      35           1 :         *const_cast<uint8_t *>(&pubkeyH[0]) = 0x06 | (pubkeyH[64] & 1);
      36           2 :     }
      37             : };
      38             : 
      39       37611 : static void CheckError(uint32_t flags, const stacktype& original_stack,
      40             :                        const CScript& script, ScriptError expected)
      41             : {
      42       37611 :     BaseSignatureChecker sigchecker;
      43       37611 :     ScriptError err = ScriptError::SCRIPT_ERR_OK;
      44       37611 :     stacktype stack{original_stack};
      45       37611 :     bool r = EvalScript(stack, script, flags, sigchecker, SigVersion::BASE, &err);
      46       37611 :     BOOST_CHECK(!r);
      47       37611 :     BOOST_CHECK(err == expected);
      48       37611 : }
      49             : 
      50       11565 : static void CheckPass(uint32_t flags, const stacktype& original_stack,
      51             :                       const CScript& script, const stacktype& expected)
      52             : {
      53       11565 :     BaseSignatureChecker sigchecker;
      54       11565 :     ScriptError err = ScriptError::SCRIPT_ERR_OK;
      55       11565 :     stacktype stack{original_stack};
      56       11565 :     bool r = EvalScript(stack, script, flags, sigchecker, SigVersion::BASE, &err);
      57       11565 :     BOOST_CHECK(r);
      58       11565 :     BOOST_CHECK(err == ScriptError::SCRIPT_ERR_OK);
      59       11565 :     BOOST_CHECK(stack == expected);
      60       11565 : }
      61             : 
      62             : /**
      63             :  * General utility functions to check for script passing/failing.
      64             :  */
      65           4 : static void CheckTestResultForAllFlags(const stacktype& original_stack,
      66             :                                        const CScript& script,
      67             :                                        const stacktype& expected)
      68             : {
      69          12 :     for (uint32_t flags : flagset) {
      70           8 :         CheckPass(flags, original_stack, script, expected);
      71             :     }
      72           4 : }
      73             : 
      74           8 : static void CheckErrorForAllFlags(const stacktype& original_stack,
      75             :                                   const CScript& script, ScriptError expected)
      76             : {
      77          24 :     for (uint32_t flags : flagset) {
      78          16 :         CheckError(flags, original_stack, script, expected);
      79             :     }
      80           8 : }
      81             : 
      82         149 : BOOST_AUTO_TEST_CASE(checkdatasig_test)
      83             : {
      84             :     // Empty stack.
      85           1 :     CheckErrorForAllFlags({}, CScript() << OP_CHECKDATASIG,
      86             :                           ScriptError::SCRIPT_ERR_INVALID_STACK_OPERATION);
      87           1 :     CheckErrorForAllFlags({{0x00}}, CScript() << OP_CHECKDATASIG,
      88             :                           ScriptError::SCRIPT_ERR_INVALID_STACK_OPERATION);
      89           1 :     CheckErrorForAllFlags({{0x00}, {0x00}}, CScript() << OP_CHECKDATASIG,
      90             :                           ScriptError::SCRIPT_ERR_INVALID_STACK_OPERATION);
      91           1 :     CheckErrorForAllFlags({}, CScript() << OP_CHECKDATASIGVERIFY,
      92             :                           ScriptError::SCRIPT_ERR_INVALID_STACK_OPERATION);
      93           1 :     CheckErrorForAllFlags({{0x00}}, CScript() << OP_CHECKDATASIGVERIFY,
      94             :                           ScriptError::SCRIPT_ERR_INVALID_STACK_OPERATION);
      95           1 :     CheckErrorForAllFlags({{0x00}, {0x00}}, CScript() << OP_CHECKDATASIGVERIFY,
      96             :                           ScriptError::SCRIPT_ERR_INVALID_STACK_OPERATION);
      97             : 
      98             :     // Check various pubkey encoding.
      99           1 :     const valtype message{};
     100           1 :     valtype vchHash(32);
     101           1 :     CSHA256().Write(message.data(), message.size()).Finalize(vchHash.data());
     102           1 :     uint256 messageHash(vchHash);
     103             : 
     104           1 :     KeyData kd;
     105           1 :     valtype pubkey = ToByteVector(kd.pubkey);
     106           1 :     valtype pubkeyC = ToByteVector(kd.pubkeyC);
     107           1 :     valtype pubkeyH = ToByteVector(kd.pubkeyH);
     108             : 
     109           2 :     CheckTestResultForAllFlags({{}, message, pubkey},
     110           1 :                                CScript() << OP_CHECKDATASIG, {{}});
     111           2 :     CheckTestResultForAllFlags({{}, message, pubkeyC},
     112           1 :                                CScript() << OP_CHECKDATASIG, {{}});
     113           2 :     CheckErrorForAllFlags({{}, message, pubkey},
     114           1 :                           CScript() << OP_CHECKDATASIGVERIFY,
     115             :                           ScriptError::SCRIPT_ERR_CHECKDATASIGVERIFY);
     116           2 :     CheckErrorForAllFlags({{}, message, pubkeyC},
     117           1 :                           CScript() << OP_CHECKDATASIGVERIFY,
     118             :                           ScriptError::SCRIPT_ERR_CHECKDATASIGVERIFY);
     119             : 
     120             :     // Flags dependent checks.
     121           1 :     const CScript script = CScript() << OP_CHECKDATASIG << OP_NOT << OP_VERIFY;
     122           1 :     const CScript scriptverify = CScript() << OP_CHECKDATASIGVERIFY;
     123             : 
     124             :     // Check valid signatures (as in the signature format is valid).
     125           1 :     valtype validsig;
     126           1 :     kd.privkey.Sign(messageHash, validsig);
     127           1 :     validsig.push_back(static_cast<unsigned char>(1));
     128             : 
     129           2 :     CheckTestResultForAllFlags({validsig, message, pubkey},
     130           1 :                                CScript() << OP_CHECKDATASIG, {{0x01}});
     131           2 :     CheckTestResultForAllFlags({validsig, message, pubkey},
     132           1 :                                CScript() << OP_CHECKDATASIGVERIFY, {});
     133             : 
     134           1 :     const valtype minimalsig{0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01};
     135           1 :     const valtype nondersig{0x30, 0x80, 0x06, 0x02, 0x01,
     136             :                             0x01, 0x02, 0x01, 0x01, 0x01};
     137           1 :     const valtype highSSig{
     138             :         0x30, 0x45, 0x02, 0x20, 0x3e, 0x45, 0x16, 0xda, 0x72, 0x53, 0xcf, 0x06,
     139             :         0x8e, 0xff, 0xec, 0x6b, 0x95, 0xc4, 0x12, 0x21, 0xc0, 0xcf, 0x3a, 0x8e,
     140             :         0x6c, 0xcb, 0x8c, 0xbf, 0x17, 0x25, 0xb5, 0x62, 0xe9, 0xaf, 0xde, 0x2c,
     141             :         0x02, 0x21, 0x00, 0xab, 0x1e, 0x3d, 0xa7, 0x3d, 0x67, 0xe3, 0x20, 0x45,
     142             :         0xa2, 0x0e, 0x0b, 0x99, 0x9e, 0x04, 0x99, 0x78, 0xea, 0x8d, 0x6e, 0xe5,
     143             :         0x48, 0x0d, 0x48, 0x5f, 0xcf, 0x2c, 0xe0, 0xd0, 0x3b, 0x2e, 0xf0, 0x01};
     144             : 
     145           1 :     MMIXLinearCongruentialGenerator lcg;
     146        4097 :     for (int i = 0; i < 4096; i++) {
     147        4096 :         uint32_t flags = lcg.next();
     148             : 
     149        4096 :         if (flags & SCRIPT_VERIFY_STRICTENC) {
     150             :             // When strict encoding is enforced, hybrid keys are invalid.
     151        2047 :             CheckError(flags, {{}, message, pubkeyH}, script,
     152             :                        ScriptError::SCRIPT_ERR_PUBKEYTYPE);
     153        2047 :             CheckError(flags, {{}, message, pubkeyH}, scriptverify,
     154             :                        ScriptError::SCRIPT_ERR_PUBKEYTYPE);
     155        2047 :         } else {
     156             :             // Otherwise, hybrid keys are valid.
     157        2049 :             CheckPass(flags, {{}, message, pubkeyH}, script, {});
     158        2049 :             CheckError(flags, {{}, message, pubkeyH}, scriptverify,
     159             :                        ScriptError::SCRIPT_ERR_CHECKDATASIGVERIFY);
     160             :         }
     161             : 
     162             :         // Uncompressed keys are valid.
     163        4096 :         CheckPass(flags, {{}, message, pubkey}, script, {});
     164        4096 :         CheckError(flags, {{}, message, pubkey}, scriptverify,
     165             :                    ScriptError::SCRIPT_ERR_CHECKDATASIGVERIFY);
     166             : 
     167        4096 :         if (flags & SCRIPT_VERIFY_NULLFAIL) {
     168             :             // Invalid signature causes checkdatasig to fail.
     169        2059 :             CheckError(flags, {minimalsig, message, pubkeyC}, script,
     170             :                        ScriptError::SCRIPT_ERR_SIG_NULLFAIL);
     171        2059 :             CheckError(flags, {minimalsig, message, pubkeyC}, scriptverify,
     172             :                        ScriptError::SCRIPT_ERR_SIG_NULLFAIL);
     173             : 
     174             :             // Invalid message causes checkdatasig to fail.
     175        2059 :             CheckError(flags, {validsig, {0x01}, pubkeyC}, script,
     176             :                        ScriptError::SCRIPT_ERR_SIG_NULLFAIL);
     177        2059 :             CheckError(flags, {validsig, {0x01}, pubkeyC}, scriptverify,
     178             :                        ScriptError::SCRIPT_ERR_SIG_NULLFAIL);
     179        2059 :         } else {
     180             :             // When nullfail is not enforced, invalid signature are just false.
     181        2037 :             CheckPass(flags, {minimalsig, message, pubkeyC}, script, {});
     182        2037 :             CheckError(flags, {minimalsig, message, pubkeyC}, scriptverify,
     183             :                        ScriptError::SCRIPT_ERR_CHECKDATASIGVERIFY);
     184             : 
     185             :             // Invalid message cause checkdatasig to fail.
     186        2037 :             CheckPass(flags, {validsig, {0x01}, pubkeyC}, script, {});
     187        2037 :             CheckError(flags, {validsig, {0x01}, pubkeyC}, scriptverify,
     188             :                        ScriptError::SCRIPT_ERR_CHECKDATASIGVERIFY);
     189             :         }
     190             : 
     191        4096 :         if (flags & SCRIPT_VERIFY_LOW_S) {
     192             :             // If we do enforce low S, then high S sigs are rejected.
     193        2004 :             CheckError(flags, {highSSig, message, pubkeyC}, script,
     194             :                        ScriptError::SCRIPT_ERR_SIG_HIGH_S);
     195        2004 :             CheckError(flags, {highSSig, message, pubkeyC}, scriptverify,
     196             :                        ScriptError::SCRIPT_ERR_SIG_HIGH_S);
     197        4096 :         } else if (flags & SCRIPT_VERIFY_NULLFAIL) {
     198             :             // If we do enforce nullfail, these invalid sigs hit this.
     199        1010 :             CheckError(flags, {highSSig, message, pubkeyC}, script,
     200             :                        ScriptError::SCRIPT_ERR_SIG_NULLFAIL);
     201        1010 :             CheckError(flags, {highSSig, message, pubkeyC}, scriptverify,
     202             :                        ScriptError::SCRIPT_ERR_SIG_NULLFAIL);
     203        1010 :         } else {
     204             :             // If we do not enforce low S, then high S sigs are accepted.
     205        1082 :             CheckPass(flags, {highSSig, message, pubkeyC}, script, {});
     206        1082 :             CheckError(flags, {highSSig, message, pubkeyC}, scriptverify,
     207             :                        ScriptError::SCRIPT_ERR_CHECKDATASIGVERIFY);
     208             :         }
     209             : 
     210        4096 :         if (flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S |
     211             :                      SCRIPT_VERIFY_STRICTENC)) {
     212             :             // If we get any of the dersig flags, the non canonical dersig
     213             :             // signature fails.
     214        3595 :             CheckError(flags, {nondersig, message, pubkeyC}, script,
     215             :                        ScriptError::SCRIPT_ERR_SIG_DER);
     216        3595 :             CheckError(flags, {nondersig, message, pubkeyC}, scriptverify,
     217             :                        ScriptError::SCRIPT_ERR_SIG_DER);
     218        4096 :         } else if (flags & SCRIPT_VERIFY_NULLFAIL) {
     219             :             // If we do enforce nullfail, these invalid sigs hit this.
     220         245 :             CheckError(flags, {nondersig, message, pubkeyC}, script,
     221             :                        ScriptError::SCRIPT_ERR_SIG_NULLFAIL);
     222         245 :             CheckError(flags, {nondersig, message, pubkeyC}, scriptverify,
     223             :                        ScriptError::SCRIPT_ERR_SIG_NULLFAIL);
     224         245 :         } else {
     225             :             // If we do not check, then it is accepted.
     226         256 :             CheckPass(flags, {nondersig, message, pubkeyC}, script, {});
     227         256 :             CheckError(flags, {nondersig, message, pubkeyC}, scriptverify,
     228             :                        ScriptError::SCRIPT_ERR_CHECKDATASIGVERIFY);
     229             :         }
     230        4096 :     }
     231           1 : }
     232             : 
     233         146 : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.16