Bitcoin Core 31.99.0
P2P Digital Currency
multisig_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-present 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#include <policy/policy.h>
8#include <script/script.h>
10#include <script/sign.h>
12#include <test/util/common.h>
15#include <tinyformat.h>
16#include <uint256.h>
17
18
19#include <boost/test/unit_test.hpp>
20
22
23static CScript
24sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const CTransaction& transaction, int whichIn)
25{
26 uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SigVersion::BASE);
27
28 CScript result;
29 result << OP_0; // CHECKMULTISIG bug workaround
30 for (const CKey &key : keys)
31 {
32 std::vector<unsigned char> vchSig;
33 BOOST_CHECK(key.Sign(hash, vchSig));
34 vchSig.push_back((unsigned char)SIGHASH_ALL);
35 result << vchSig;
36 }
37 return result;
38}
39
40BOOST_AUTO_TEST_CASE(multisig_verify)
41{
43
44 ScriptError err;
45 CKey key[4];
46 CAmount amount = 0;
47 for (int i = 0; i < 4; i++)
48 key[i].MakeNewKey(true);
49
50 CScript a_and_b;
51 a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
52
53 CScript a_or_b;
54 a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
55
56 CScript escrow;
57 escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
58
59 CMutableTransaction txFrom; // Funding transaction
60 txFrom.vout.resize(3);
61 txFrom.vout[0].scriptPubKey = a_and_b;
62 txFrom.vout[1].scriptPubKey = a_or_b;
63 txFrom.vout[2].scriptPubKey = escrow;
64
65 CMutableTransaction txTo[3]; // Spending transaction
66 for (int i = 0; i < 3; i++)
67 {
68 txTo[i].vin.resize(1);
69 txTo[i].vout.resize(1);
70 txTo[i].vin[0].prevout.n = i;
71 txTo[i].vin[0].prevout.hash = txFrom.GetHash();
72 txTo[i].vout[0].nValue = 1;
73 }
74
75 std::vector<CKey> keys;
76 CScript s;
77
78 // Test a AND b:
79 keys.assign(1,key[0]);
80 keys.push_back(key[1]);
81 s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);
83 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
84
85 for (int i = 0; i < 4; i++)
86 {
87 keys.assign(1,key[i]);
88 s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);
89 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));
90 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
91
92 keys.assign(1,key[1]);
93 keys.push_back(key[i]);
94 s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);
95 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));
96 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
97 }
98
99 // Test a OR b:
100 for (int i = 0; i < 4; i++)
101 {
102 keys.assign(1,key[i]);
103 s = sign_multisig(a_or_b, keys, CTransaction(txTo[1]), 0);
104 if (i == 0 || i == 1)
105 {
106 BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a|b: %d", i));
107 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
108 }
109 else
110 {
111 BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a|b: %d", i));
112 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
113 }
114 }
115 s.clear();
116 s << OP_0 << OP_1;
118 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
119
120
121 for (int i = 0; i < 4; i++)
122 for (int j = 0; j < 4; j++)
123 {
124 keys.assign(1,key[i]);
125 keys.push_back(key[j]);
126 s = sign_multisig(escrow, keys, CTransaction(txTo[2]), 0);
127 if (i < j && i < 3 && j < 3)
128 {
129 BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, nullptr, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("escrow 1: %d %d", i, j));
130 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
131 }
132 else
133 {
134 BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, nullptr, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("escrow 2: %d %d", i, j));
135 BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
136 }
137 }
138}
139
140BOOST_AUTO_TEST_CASE(multisig_IsStandard)
141{
142 CKey key[4];
143 for (int i = 0; i < 4; i++)
144 key[i].MakeNewKey(true);
145
146 const auto is_standard{[](const CScript& spk) {
147 TxoutType type;
148 bool res{::IsStandard(spk, type)};
149 if (res) {
151 }
152 return res;
153 }};
154
155 CScript a_and_b;
156 a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
157 BOOST_CHECK(is_standard(a_and_b));
158
159 CScript a_or_b;
160 a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
161 BOOST_CHECK(is_standard(a_or_b));
162
163 CScript escrow;
164 escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
165 BOOST_CHECK(is_standard(escrow));
166
167 CScript one_of_four;
168 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;
169 BOOST_CHECK(!is_standard(one_of_four));
170
171 CScript malformed[6];
172 malformed[0] << OP_3 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
173 malformed[1] << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
174 malformed[2] << OP_0 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
175 malformed[3] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_0 << OP_CHECKMULTISIG;
176 malformed[4] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_CHECKMULTISIG;
177 malformed[5] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey());
178
179 for (int i = 0; i < 6; i++) {
180 BOOST_CHECK(!is_standard(malformed[i]));
181 }
182}
183
185{
186 // Test SignSignature() (and therefore the version of Solver() that signs transactions)
188 CKey key[4];
189 for (int i = 0; i < 4; i++)
190 {
191 key[i].MakeNewKey(true);
192 BOOST_CHECK(keystore.AddKey(key[i]));
193 }
194
195 CScript a_and_b;
196 a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
197
198 CScript a_or_b;
199 a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
200
201 CScript escrow;
202 escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
203
204 CMutableTransaction txFrom; // Funding transaction
205 txFrom.vout.resize(3);
206 txFrom.vout[0].scriptPubKey = a_and_b;
207 txFrom.vout[1].scriptPubKey = a_or_b;
208 txFrom.vout[2].scriptPubKey = escrow;
209
210 CMutableTransaction txTo[3]; // Spending transaction
211 for (int i = 0; i < 3; i++)
212 {
213 txTo[i].vin.resize(1);
214 txTo[i].vout.resize(1);
215 txTo[i].vin[0].prevout.n = i;
216 txTo[i].vin[0].prevout.hash = txFrom.GetHash();
217 txTo[i].vout[0].nValue = 1;
218 }
219
220 for (int i = 0; i < 3; i++)
221 {
222 SignatureData empty;
223 BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL, empty), strprintf("SignSignature %d", i));
224 }
225}
226
227
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
int flags
Definition: bitcoin-tx.cpp:529
An encapsulated private key.
Definition: key.h:36
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition: key.cpp:162
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:405
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:281
Fillable signing provider that keeps keys in an address->secret map.
virtual bool AddKey(const CKey &key)
256-bit opaque blob.
Definition: uint256.h:195
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
uint256 SignatureHash(const CScript &scriptCode, const T &txTo, unsigned int nIn, int32_t nHashType, const CAmount &amount, SigVersion sigversion, const PrecomputedTransactionData *cache, SigHashCache *sighash_cache)
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, const CScriptWitness *witness, script_verify_flags flags, const BaseSignatureChecker &checker, ScriptError *serror)
@ BASE
Bare scripts and BIP16 P2SH-wrapped redeemscripts.
GenericTransactionSignatureChecker< CMutableTransaction > MutableTransactionSignatureChecker
Definition: interpreter.h:337
@ SIGHASH_ALL
Definition: interpreter.h:31
@ ASSERT_FAIL
Abort execution through assertion failure (for consensus code)
BOOST_AUTO_TEST_CASE(multisig_verify)
static CScript sign_multisig(const CScript &scriptPubKey, const std::vector< CKey > &keys, const CTransaction &transaction, int whichIn)
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:17
#define BOOST_CHECK(expr)
Definition: object.cpp:16
bool IsStandard(const CScript &scriptPubKey, TxoutType &whichType)
Definition: policy.cpp:79
@ OP_2
Definition: script.h:85
@ OP_CHECKMULTISIG
Definition: script.h:192
@ OP_4
Definition: script.h:87
@ OP_1
Definition: script.h:83
@ OP_3
Definition: script.h:86
@ OP_0
Definition: script.h:76
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:67
std::string ScriptErrorString(const ScriptError serror)
enum ScriptError_t ScriptError
@ SCRIPT_ERR_EVAL_FALSE
Definition: script_error.h:15
@ SCRIPT_ERR_INVALID_STACK_OPERATION
Definition: script_error.h:37
@ SCRIPT_ERR_SIG_DER
Definition: script_error.h:47
@ SCRIPT_ERR_OK
Definition: script_error.h:13
static bool GetPubKey(const SigningProvider &provider, const SignatureData &sigdata, const CKeyID &address, CPubKey &pubkey)
Definition: sign.cpp:221
TxoutType
Definition: solver.h:22
Basic testing setup.
Definition: setup_common.h:64
A mutable version of CTransaction.
Definition: transaction.h:358
std::vector< CTxOut > vout
Definition: transaction.h:360
Txid GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:69
std::vector< CTxIn > vin
Definition: transaction.h:359
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
bool SignSignature(const SigningProvider &provider, const CScript &fromPubKey, CMutableTransaction &txTo, unsigned int nIn, const CAmount &amount, int nHashType, SignatureData &sig_data)
Produce a satisfying script (scriptSig or witness).