Bitcoin Core  24.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>
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 <tinyformat.h>
14 #include <uint256.h>
15 
16 
17 #include <boost/test/unit_test.hpp>
18 
19 BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
20 
21 static CScript
22 sign_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 
38 BOOST_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);
80  BOOST_CHECK(VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err));
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;
115  BOOST_CHECK(!VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err));
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 
138 BOOST_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 
182 BOOST_AUTO_TEST_CASE(multisig_Sign)
183 {
184  // Test SignSignature() (and therefore the version of Solver() that signs transactions)
185  FillableSigningProvider keystore;
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  BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL), strprintf("SignSignature %d", i));
221  }
222 }
223 
224 
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:411
void clear()
Definition: script.h:554
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:295
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:220
256-bit opaque blob.
Definition: uint256.h:119
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:47
@ SCRIPT_VERIFY_STRICTENC
Definition: interpreter.h:52
GenericTransactionSignatureChecker< CMutableTransaction > MutableTransactionSignatureChecker
Definition: interpreter.h:305
@ SIGHASH_ALL
Definition: interpreter.h:28
@ 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
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:63
@ OP_2
Definition: script.h:81
@ OP_CHECKMULTISIG
Definition: script.h:188
@ OP_4
Definition: script.h:83
@ OP_1
Definition: script.h:79
@ OP_3
Definition: script.h:82
@ OP_0
Definition: script.h:72
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:566
static bool GetPubKey(const SigningProvider &provider, const SignatureData &sigdata, const CKeyID &address, CPubKey &pubkey)
Definition: sign.cpp:107
TxoutType
Definition: standard.h:51
Basic testing setup.
Definition: setup_common.h:85
A mutable version of CTransaction.
Definition: transaction.h:380
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:68
std::vector< CTxOut > vout
Definition: transaction.h:382
std::vector< CTxIn > vin
Definition: transaction.h:381
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1162