multisig_tests.cpp raw

   1  // Copyright (c) 2011-2022 The Limenka 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 <test/util/transaction_utils.h>
  14  #include <tinyformat.h>
  15  #include <uint256.h>
  16  
  17  
  18  #include <boost/test/unit_test.hpp>
  19  
  20  BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)
  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  
  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  
  39  BOOST_AUTO_TEST_CASE(multisig_verify)
  40  {
  41      unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
  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);
  81      BOOST_CHECK(VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err));
  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;
 116      BOOST_CHECK(!VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err));
 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) {
 149              BOOST_CHECK_EQUAL(type, TxoutType::MULTISIG);
 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  
 227  BOOST_AUTO_TEST_SUITE_END()
 228