Bitcoin Core  29.1.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>
14 #include <tinyformat.h>
15 #include <uint256.h>
16 
17 
18 #include <boost/test/unit_test.hpp>
19 
21 
22 static CScript
23 sign_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 
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 
39 BOOST_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 
139 BOOST_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 
183 BOOST_AUTO_TEST_CASE(multisig_Sign)
184 {
185  // Test SignSignature() (and therefore the version of Solver() that signs transactions)
186  FillableSigningProvider keystore;
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 
enum ScriptError_t ScriptError
static CScript sign_multisig(const CScript &scriptPubKey, const std::vector< CKey > &keys, const CTransaction &transaction, int whichIn)
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, const CScriptWitness *witness, unsigned int flags, const BaseSignatureChecker &checker, ScriptError *serror)
std::vector< CTxIn > vin
Definition: transaction.h:379
Bare scripts and BIP16 P2SH-wrapped redeemscripts.
Definition: script.h:76
bool IsStandard(const CScript &scriptPubKey, const std::optional< unsigned > &max_datacarrier_bytes, TxoutType &whichType)
Definition: policy.cpp:79
Basic testing setup.
Definition: setup_common.h:64
Definition: script.h:83
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
Abort execution through assertion failure (for consensus code)
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
Fillable signing provider that keeps keys in an address->secret map.
std::string ScriptErrorString(const ScriptError serror)
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
Definition: key.cpp:161
GenericTransactionSignatureChecker< CMutableTransaction > MutableTransactionSignatureChecker
Definition: interpreter.h:307
Txid GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:69
std::vector< CTxOut > vout
Definition: transaction.h:380
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).
int flags
Definition: bitcoin-tx.cpp:536
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:67
256-bit opaque blob.
Definition: uint256.h:201
TxoutType
Definition: solver.h:22
auto result
Definition: common-types.h:74
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:414
static bool GetPubKey(const SigningProvider &provider, const SignatureData &sigdata, const CKeyID &address, CPubKey &pubkey)
Definition: sign.cpp:109
Definition: script.h:86
uint256 SignatureHash(const CScript &scriptCode, const T &txTo, unsigned int nIn, int32_t nHashType, const CAmount &amount, SigVersion sigversion, const PrecomputedTransactionData *cache)
BOOST_AUTO_TEST_CASE(multisig_verify)
A mutable version of CTransaction.
Definition: transaction.h:377
Definition: script.h:85
An encapsulated private key.
Definition: key.h:34
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: transaction.h:295
virtual bool AddKey(const CKey &key)
Definition: script.h:87
#define BOOST_CHECK(expr)
Definition: object.cpp:17