Bitcoin Core 22.99.0
P2P Digital Currency
multisig_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-2020 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
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 TxoutType whichType;
145
146 CScript a_and_b;
147 a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
148 BOOST_CHECK(::IsStandard(a_and_b, whichType));
149
150 CScript a_or_b;
151 a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
152 BOOST_CHECK(::IsStandard(a_or_b, whichType));
153
154 CScript escrow;
155 escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
156 BOOST_CHECK(::IsStandard(escrow, whichType));
157
158 CScript one_of_four;
159 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;
160 BOOST_CHECK(!::IsStandard(one_of_four, whichType));
161
162 CScript malformed[6];
163 malformed[0] << OP_3 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
164 malformed[1] << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
165 malformed[2] << OP_0 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
166 malformed[3] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_0 << OP_CHECKMULTISIG;
167 malformed[4] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_CHECKMULTISIG;
168 malformed[5] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey());
169
170 for (int i = 0; i < 6; i++)
171 BOOST_CHECK(!::IsStandard(malformed[i], whichType));
172}
173
175{
176 // Test SignSignature() (and therefore the version of Solver() that signs transactions)
178 CKey key[4];
179 for (int i = 0; i < 4; i++)
180 {
181 key[i].MakeNewKey(true);
182 BOOST_CHECK(keystore.AddKey(key[i]));
183 }
184
185 CScript a_and_b;
186 a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
187
188 CScript a_or_b;
189 a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
190
191 CScript escrow;
192 escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;
193
194 CMutableTransaction txFrom; // Funding transaction
195 txFrom.vout.resize(3);
196 txFrom.vout[0].scriptPubKey = a_and_b;
197 txFrom.vout[1].scriptPubKey = a_or_b;
198 txFrom.vout[2].scriptPubKey = escrow;
199
200 CMutableTransaction txTo[3]; // Spending transaction
201 for (int i = 0; i < 3; i++)
202 {
203 txTo[i].vin.resize(1);
204 txTo[i].vout.resize(1);
205 txTo[i].vin[0].prevout.n = i;
206 txTo[i].vin[0].prevout.hash = txFrom.GetHash();
207 txTo[i].vout[0].nValue = 1;
208 }
209
210 for (int i = 0; i < 3; i++)
211 {
212 BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i));
213 }
214}
215
216
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
int flags
Definition: bitcoin-tx.cpp:525
An encapsulated private key.
Definition: key.h:27
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition: key.cpp:160
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:406
void clear()
Definition: script.h:549
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:260
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:218
256-bit opaque blob.
Definition: uint256.h:124
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.
@ SCRIPT_VERIFY_P2SH
Definition: interpreter.h:46
@ SCRIPT_VERIFY_STRICTENC
Definition: interpreter.h:51
GenericTransactionSignatureChecker< CMutableTransaction > MutableTransactionSignatureChecker
Definition: interpreter.h:300
@ SIGHASH_ALL
Definition: interpreter.h:27
@ 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_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
#define BOOST_CHECK(expr)
Definition: object.cpp:17
bool IsStandard(const CScript &scriptPubKey, TxoutType &whichType)
Definition: policy.cpp:58
@ OP_2
Definition: script.h:78
@ OP_CHECKMULTISIG
Definition: script.h:185
@ OP_4
Definition: script.h:80
@ OP_1
Definition: script.h:76
@ OP_3
Definition: script.h:79
@ OP_0
Definition: script.h:69
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:60
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:36
@ SCRIPT_ERR_SIG_DER
Definition: script_error.h:46
@ SCRIPT_ERR_OK
Definition: script_error.h:13
bool SignSignature(const SigningProvider &provider, const CScript &fromPubKey, CMutableTransaction &txTo, unsigned int nIn, const CAmount &amount, int nHashType)
Produce a script signature for a transaction.
Definition: sign.cpp:514
static bool GetPubKey(const SigningProvider &provider, const SignatureData &sigdata, const CKeyID &address, CPubKey &pubkey)
Definition: sign.cpp:105
TxoutType
Definition: standard.h:59
Basic testing setup.
Definition: setup_common.h:76
A mutable version of CTransaction.
Definition: transaction.h:345
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:63
std::vector< CTxOut > vout
Definition: transaction.h:347
std::vector< CTxIn > vin
Definition: transaction.h:346
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164