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