multisig_tests.cpp raw
1 // Copyright (c) 2011-2022 The Limenka 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 #include <policy/policy.h>
7 #include <script/interpreter.h>
8 #include <script/script.h>
9 #include <script/script_error.h>
10 #include <script/sign.h>
11 #include <script/signingprovider.h>
12 #include <test/util/setup_common.h>
13 #include <test/util/transaction_utils.h>
14 #include <tinyformat.h>
15 #include <uint256.h>
16
17
18 #include <boost/test/unit_test.hpp>
19
20 BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
21
22 static CScript
23 sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const CTransaction& transaction, int whichIn)
24 {
25 uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SigVersion::BASE);
26
27 CScript result;
28 result << OP_0; // CHECKMULTISIG bug workaround
29 for (const CKey &key : keys)
30 {
31 std::vector<unsigned char> vchSig;
32 BOOST_CHECK(key.Sign(hash, vchSig));
33 vchSig.push_back((unsigned char)SIGHASH_ALL);
34 result << vchSig;
35 }
36 return result;
37 }
38
39 BOOST_AUTO_TEST_CASE(multisig_verify)
40 {
41 unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
42
43 ScriptError err;
44 CKey key[4];
45 CAmount amount = 0;
46 for (int i = 0; i < 4; i++)
47 key[i].MakeNewKey(true);
48
49 CScript a_and_b;
50 a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
51
52 CScript a_or_b;
53 a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
54
55 CScript escrow;
56 escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
57
58 CMutableTransaction txFrom; // Funding transaction
59 txFrom.vout.resize(3);
60 txFrom.vout[0].scriptPubKey = a_and_b;
61 txFrom.vout[1].scriptPubKey = a_or_b;
62 txFrom.vout[2].scriptPubKey = escrow;
63
64 CMutableTransaction txTo[3]; // Spending transaction
65 for (int i = 0; i < 3; i++)
66 {
67 txTo[i].vin.resize(1);
68 txTo[i].vout.resize(1);
69 txTo[i].vin[0].prevout.n = i;
70 txTo[i].vin[0].prevout.hash = txFrom.GetHash();
71 txTo[i].vout[0].nValue = 1;
72 }
73
74 std::vector<CKey> keys;
75 CScript s;
76
77 // Test a AND b:
78 keys.assign(1,key[0]);
79 keys.push_back(key[1]);
80 s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);
81 BOOST_CHECK(VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err));
82 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
83
84 for (int i = 0; i < 4; i++)
85 {
86 keys.assign(1,key[i]);
87 s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);
88 BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a&b 1: %d", i));
89 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
90
91 keys.assign(1,key[1]);
92 keys.push_back(key[i]);
93 s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);
94 BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a&b 2: %d", i));
95 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
96 }
97
98 // Test a OR b:
99 for (int i = 0; i < 4; i++)
100 {
101 keys.assign(1,key[i]);
102 s = sign_multisig(a_or_b, keys, CTransaction(txTo[1]), 0);
103 if (i == 0 || i == 1)
104 {
105 BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a|b: %d", i));
106 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
107 }
108 else
109 {
110 BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a|b: %d", i));
111 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
112 }
113 }
114 s.clear();
115 s << OP_0 << OP_1;
116 BOOST_CHECK(!VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err));
117 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
118
119
120 for (int i = 0; i < 4; i++)
121 for (int j = 0; j < 4; j++)
122 {
123 keys.assign(1,key[i]);
124 keys.push_back(key[j]);
125 s = sign_multisig(escrow, keys, CTransaction(txTo[2]), 0);
126 if (i < j && i < 3 && j < 3)
127 {
128 BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, nullptr, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("escrow 1: %d %d", i, j));
129 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
130 }
131 else
132 {
133 BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, nullptr, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("escrow 2: %d %d", i, j));
134 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
135 }
136 }
137 }
138
139 BOOST_AUTO_TEST_CASE(multisig_IsStandard)
140 {
141 CKey key[4];
142 for (int i = 0; i < 4; i++)
143 key[i].MakeNewKey(true);
144
145 const auto is_standard{[](const CScript& spk) {
146 TxoutType type;
147 bool res{::IsStandard(spk, std::nullopt, type)};
148 if (res) {
149 BOOST_CHECK_EQUAL(type, TxoutType::MULTISIG);
150 }
151 return res;
152 }};
153
154 CScript a_and_b;
155 a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
156 BOOST_CHECK(is_standard(a_and_b));
157
158 CScript a_or_b;
159 a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
160 BOOST_CHECK(is_standard(a_or_b));
161
162 CScript escrow;
163 escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
164 BOOST_CHECK(is_standard(escrow));
165
166 CScript one_of_four;
167 one_of_four << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << ToByteVector(key[3].GetPubKey()) << OP_4 << OP_CHECKMULTISIG;
168 BOOST_CHECK(!is_standard(one_of_four));
169
170 CScript malformed[6];
171 malformed[0] << OP_3 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
172 malformed[1] << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
173 malformed[2] << OP_0 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
174 malformed[3] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_0 << OP_CHECKMULTISIG;
175 malformed[4] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_CHECKMULTISIG;
176 malformed[5] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey());
177
178 for (int i = 0; i < 6; i++) {
179 BOOST_CHECK(!is_standard(malformed[i]));
180 }
181 }
182
183 BOOST_AUTO_TEST_CASE(multisig_Sign)
184 {
185 // Test SignSignature() (and therefore the version of Solver() that signs transactions)
186 FillableSigningProvider keystore;
187 CKey key[4];
188 for (int i = 0; i < 4; i++)
189 {
190 key[i].MakeNewKey(true);
191 BOOST_CHECK(keystore.AddKey(key[i]));
192 }
193
194 CScript a_and_b;
195 a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
196
197 CScript a_or_b;
198 a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
199
200 CScript escrow;
201 escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
202
203 CMutableTransaction txFrom; // Funding transaction
204 txFrom.vout.resize(3);
205 txFrom.vout[0].scriptPubKey = a_and_b;
206 txFrom.vout[1].scriptPubKey = a_or_b;
207 txFrom.vout[2].scriptPubKey = escrow;
208
209 CMutableTransaction txTo[3]; // Spending transaction
210 for (int i = 0; i < 3; i++)
211 {
212 txTo[i].vin.resize(1);
213 txTo[i].vout.resize(1);
214 txTo[i].vin[0].prevout.n = i;
215 txTo[i].vin[0].prevout.hash = txFrom.GetHash();
216 txTo[i].vout[0].nValue = 1;
217 }
218
219 for (int i = 0; i < 3; i++)
220 {
221 SignatureData empty;
222 BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL, empty), strprintf("SignSignature %d", i));
223 }
224 }
225
226
227 BOOST_AUTO_TEST_SUITE_END()
228