Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2011-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.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/common.h>13#include <test/util/setup_common.h>14#include <test/util/transaction_utils.h>15#include <tinyformat.h>16#include <uint256.h>19#include <boost/test/unit_test.hpp>21BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup)23static CScript24sign_multisig(const CScript& scriptPubKey, const std::vector<CKey>& keys, const CTransaction& transaction, int whichIn)25{26uint256 hash = SignatureHash(scriptPubKey, transaction, whichIn, SIGHASH_ALL, 0, SigVersion::BASE);28CScript result;29result << OP_0; // CHECKMULTISIG bug workaround30for (const CKey &key : keys)31{32std::vector<unsigned char> vchSig;33BOOST_CHECK(key.Sign(hash, vchSig));34vchSig.push_back((unsigned char)SIGHASH_ALL);35result << vchSig;36}37return result;38}40BOOST_AUTO_TEST_CASE(multisig_verify)41{42script_verify_flags flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;44ScriptError err;45CKey key[4];46CAmount amount = 0;47for (int i = 0; i < 4; i++)48key[i].MakeNewKey(true);50CScript a_and_b;51a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;53CScript a_or_b;54a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;56CScript escrow;57escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;59CMutableTransaction txFrom; // Funding transaction60txFrom.vout.resize(3);61txFrom.vout[0].scriptPubKey = a_and_b;62txFrom.vout[1].scriptPubKey = a_or_b;63txFrom.vout[2].scriptPubKey = escrow;65CMutableTransaction txTo[3]; // Spending transaction66for (int i = 0; i < 3; i++)67{68txTo[i].vin.resize(1);69txTo[i].vout.resize(1);70txTo[i].vin[0].prevout.n = i;71txTo[i].vin[0].prevout.hash = txFrom.GetHash();72txTo[i].vout[0].nValue = 1;73}75std::vector<CKey> keys;76CScript s;78// Test a AND b:79keys.assign(1,key[0]);80keys.push_back(key[1]);81s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);82BOOST_CHECK(VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err));83BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));85for (int i = 0; i < 4; i++)86{87keys.assign(1,key[i]);88s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);89BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a&b 1: %d", i));90BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));92keys.assign(1,key[1]);93keys.push_back(key[i]);94s = sign_multisig(a_and_b, keys, CTransaction(txTo[0]), 0);95BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[0], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a&b 2: %d", i));96BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));97}99// Test a OR b:100for (int i = 0; i < 4; i++)101{102keys.assign(1,key[i]);103s = sign_multisig(a_or_b, keys, CTransaction(txTo[1]), 0);104if (i == 0 || i == 1)105{106BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a|b: %d", i));107BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));108}109else110{111BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("a|b: %d", i));112BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));113}114}115s.clear();116s << OP_0 << OP_1;117BOOST_CHECK(!VerifyScript(s, a_or_b, nullptr, flags, MutableTransactionSignatureChecker(&txTo[1], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err));118BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));121for (int i = 0; i < 4; i++)122for (int j = 0; j < 4; j++)123{124keys.assign(1,key[i]);125keys.push_back(key[j]);126s = sign_multisig(escrow, keys, CTransaction(txTo[2]), 0);127if (i < j && i < 3 && j < 3)128{129BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, nullptr, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("escrow 1: %d %d", i, j));130BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));131}132else133{134BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, nullptr, flags, MutableTransactionSignatureChecker(&txTo[2], 0, amount, MissingDataBehavior::ASSERT_FAIL), &err), strprintf("escrow 2: %d %d", i, j));135BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));136}137}138}140BOOST_AUTO_TEST_CASE(multisig_IsStandard)141{142CKey key[4];143for (int i = 0; i < 4; i++)144key[i].MakeNewKey(true);146const auto is_standard{[](const CScript& spk) {147TxoutType type;148bool res{::IsStandard(spk, type)};149if (res) {150BOOST_CHECK_EQUAL(type, TxoutType::MULTISIG);151}152return res;153}};155CScript a_and_b;156a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;157BOOST_CHECK(is_standard(a_and_b));159CScript a_or_b;160a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;161BOOST_CHECK(is_standard(a_or_b));163CScript escrow;164escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;165BOOST_CHECK(is_standard(escrow));167CScript one_of_four;168one_of_four << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << ToByteVector(key[3].GetPubKey()) << OP_4 << OP_CHECKMULTISIG;169BOOST_CHECK(!is_standard(one_of_four));171CScript malformed[6];172malformed[0] << OP_3 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;173malformed[1] << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;174malformed[2] << OP_0 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;175malformed[3] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_0 << OP_CHECKMULTISIG;176malformed[4] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_CHECKMULTISIG;177malformed[5] << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey());179for (int i = 0; i < 6; i++) {180BOOST_CHECK(!is_standard(malformed[i]));181}182}184BOOST_AUTO_TEST_CASE(multisig_Sign)185{186// Test SignSignature() (and therefore the version of Solver() that signs transactions)187FillableSigningProvider keystore;188CKey key[4];189for (int i = 0; i < 4; i++)190{191key[i].MakeNewKey(true);192BOOST_CHECK(keystore.AddKey(key[i]));193}195CScript a_and_b;196a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;198CScript a_or_b;199a_or_b << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;201CScript escrow;202escrow << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG;204CMutableTransaction txFrom; // Funding transaction205txFrom.vout.resize(3);206txFrom.vout[0].scriptPubKey = a_and_b;207txFrom.vout[1].scriptPubKey = a_or_b;208txFrom.vout[2].scriptPubKey = escrow;210CMutableTransaction txTo[3]; // Spending transaction211for (int i = 0; i < 3; i++)212{213txTo[i].vin.resize(1);214txTo[i].vout.resize(1);215txTo[i].vin[0].prevout.n = i;216txTo[i].vin[0].prevout.hash = txFrom.GetHash();217txTo[i].vout[0].nValue = 1;218}220for (int i = 0; i < 3; i++)221{222SignatureData empty;223BOOST_CHECK_MESSAGE(SignSignature(keystore, CTransaction(txFrom), txTo[i], 0, SIGHASH_ALL, empty), strprintf("SignSignature %d", i));224}225}228BOOST_AUTO_TEST_SUITE_END()
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.