/ src / test / multisig_tests.cpp
multisig_tests.cpp
  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  {
 40      unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
 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) {
148              BOOST_CHECK_EQUAL(type, TxoutType::MULTISIG);
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          SignatureData empty;
221          BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL, empty), strprintf("SignSignature %d", i));
222      }
223  }
224  
225  
226  BOOST_AUTO_TEST_SUITE_END()