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()
|