Bitcoin Core 28.99.0
P2P Digital Currency
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>
14#include <tinyformat.h>
15#include <uint256.h>
16
17
18#include <boost/test/unit_test.hpp>
19
21
22static CScript
23sign_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
39BOOST_AUTO_TEST_CASE(multisig_verify)
40{
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);
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;
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
139BOOST_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) {
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
184{
185 // Test SignSignature() (and therefore the version of Solver() that signs transactions)
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
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
int flags
Definition: bitcoin-tx.cpp:536
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:415
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:296
Fillable signing provider that keeps keys in an address->secret map.
virtual bool AddKey(const CKey &key)
256-bit opaque blob.
Definition: uint256.h:201
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)
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
Definition: interpreter.h:307
@ 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: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:36
@ SCRIPT_ERR_SIG_DER
Definition: script_error.h:46
@ 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:109
TxoutType
Definition: solver.h:22
Basic testing setup.
Definition: setup_common.h:64
A mutable version of CTransaction.
Definition: transaction.h:378
std::vector< CTxOut > vout
Definition: transaction.h:380
Txid GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:69
std::vector< CTxIn > vin
Definition: transaction.h:379
#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).