diff --git a/src/script/script_flags.h b/src/script/script_flags.h
--- a/src/script/script_flags.h
+++ b/src/script/script_flags.h
@@ -106,6 +106,10 @@
     // The exception to CLEANSTACK and P2SH for the recovery of coins sent
     // to p2sh segwit addresses is not allowed.
     SCRIPT_DISALLOW_SEGWIT_RECOVERY = (1U << 20),
+
+    // Whether to allow new OP_CHECKMULTISIG logic to trigger. (new multisig
+    // logic verifies faster, and only allows Schnorr signatures)
+    SCRIPT_ENABLE_SCHNORR_MULTISIG = (1U << 21),
 };
 
 #endif // BITCOIN_SCRIPT_SCRIPT_FLAGS_H
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
--- a/src/test/data/script_tests.json
+++ b/src/test/data/script_tests.json
@@ -2930,6 +2930,55 @@
     "SIG_BADLENGTH",
     "recovered-pubkey CHECKMULTISIG with 64-byte DER"
 ],
+[
+    "0 0x47 0x30440220379db2a13c8c679bda7f500c93bae36e0d75c96b8af1754316a9c80e843f2923022046ee947cd3b916ab78f95be6ae29cc2f037ddb47f8e59c966b1e6813b270648001",
+    "1 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
+    "MINIMALDATA,NULLFAIL,SCHNORR_MULTISIG,STRICTENC",
+    "OK",
+    "1-of-2 with unchecked hybrid pubkey with SCHNORR_MULTISIG"
+],
+[
+    "0 0x47 0x304402202d4dd56f6dee2eccc049a4ebd65e77e4325aa3f2940130412b9f96fd28fa8c5a022074963950dd250d2fc943e60c7a4133cc8b1fcc46253e9b19f71c9723d1d894ef01",
+    "1 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 2 CHECKMULTISIG",
+    "MINIMALDATA,NULLFAIL,SCHNORR_MULTISIG,STRICTENC",
+    "PUBKEYTYPE",
+    "1-of-2 with checked hybrid pubkey with SCHNORR_MULTISIG"
+],
+[
+    "0 0x41 0x105e4fed395e64ca013ac1ce020ef69b9990a577fe4b74648faafb69e499f76dd53d5c64aa866924361dd3aadde9b7184bbcb4f79520396c9ed17c4d8489a59701",
+    "1 0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 1 CHECKMULTISIG",
+    "MINIMALDATA,NULLFAIL,SCHNORR_MULTISIG",
+    "SIG_BADLENGTH",
+    "Legacy 1-of-1 Schnorr w/ SCHNORR_MULTISIG but no STRICTENC"
+],
+[
+    "0 0x41 0x105e4fed395e64ca013ac1ce020ef69b9990a577fe4b74648faafb69e499f76dd53d5c64aa866924361dd3aadde9b7184bbcb4f79520396c9ed17c4d8489a59701",
+    "1 0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 1 CHECKMULTISIG",
+    "MINIMALDATA,NULLFAIL,SCHNORR_MULTISIG,STRICTENC",
+    "SIG_BADLENGTH",
+    "Legacy 1-of-1 Schnorr w/ SCHNORR_MULTISIG"
+],
+[
+    "0 0x41 0x833682d4f60cc916a22a2c263e658fa662c49badb1e2a8c6208987bf99b1abd740498371480069e7a7a6e7471bf78c27bd9a1fd04fb212a92017346250ac187b01 0x41 0xea4a8d20562a950f4695dc24804565482e9fa111704886179d0c348f2b8a15fe691a305cd599c59c131677146661d5b98cb935330989a85f33afc70d0a21add101 0x41 0xce9011d76a4df05d6280b2382b4d91490dbec7c3e72dc826be1fc9b4718f627955190745cac96521ea46d6d324c7376461e225310e6cd605b9f266d170769b7901",
+    "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
+    "MINIMALDATA,NULLFAIL,SCHNORR_MULTISIG,STRICTENC",
+    "SIG_BADLENGTH",
+    "Legacy 3-of-3 Schnorr w/ SCHNORR_MULTISIG"
+],
+[
+    "0 0x47 0x304402204d69d5caa4dbab259f79fce89d3b459bbd91697c1c052a1554ff3b08b2241cbd0220330a8e17a90d51996e363cb8902fce6278c6350fa59ae12832db2f6a44d64dce01 0x47 0x3044022031a1e5289b0d9c33ec182a7f67210b9997187c710f7d3f0f28bdfb618c4e025c02205d95fe63ee83a20ec44159a06f7c0b43b61d5f0c346ca4a2cc7b91878ad1a85001 0x41 0xce9011d76a4df05d6280b2382b4d91490dbec7c3e72dc826be1fc9b4718f627955190745cac96521ea46d6d324c7376461e225310e6cd605b9f266d170769b7901",
+    "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
+    "MINIMALDATA,NULLFAIL,SCHNORR_MULTISIG,STRICTENC",
+    "SIG_BADLENGTH",
+    "Legacy 3-of-3 mixed Schnorr-ECDSA w/ SCHNORR_MULTISIG"
+],
+[
+    "0 0x41 0x303e021d776879206d757374207765207375666665722077697468206563647361021d212121212121212121212121212121212121212121212121212121212101 0x21 0x036cd1f91735dda2d984cfbc17ab0e9e7d754d7e4e1fceb691751cdd5c26b0aecc",
+    "1 SWAP 1 CHECKMULTISIG",
+    "MINIMALDATA,NULLFAIL,SCHNORR_MULTISIG,STRICTENC",
+    "SIG_BADLENGTH",
+    "recovered-pubkey CHECKMULTISIG with 64-byte DER w/ SCHNORR_MULTISIG"
+],
 
 ["CHECKSEQUENCEVERIFY tests"],
 ["", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on an empty stack"],
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1763,6 +1763,88 @@
                 .ScriptError(SCRIPT_ERR_SIG_BADLENGTH));
     }
 
+    // New-multisig tests follow. New multisig will activate with a bunch of
+    // related flags active from other upgrades, so we do tests with this group
+    // of flags turned on:
+    uint32_t newmultisigflags =
+        SCRIPT_ENABLE_SCHNORR_MULTISIG | SCRIPT_VERIFY_NULLFAIL |
+        SCRIPT_VERIFY_MINIMALDATA | SCRIPT_VERIFY_STRICTENC;
+
+    // Tests of the legacy multisig (null dummy element), but with the
+    // SCRIPT_ENABLE_SCHNORR_MULTISIG flag turned on. These show the desired
+    // legacy behaviour that should be retained.
+    tests.push_back(
+        TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0H)
+                              << ToByteVector(keys.pubkey1C) << OP_2
+                              << OP_CHECKMULTISIG,
+                    "1-of-2 with unchecked hybrid pubkey with SCHNORR_MULTISIG",
+                    newmultisigflags)
+            .Num(0)
+            .PushSigECDSA(keys.key1));
+    tests.push_back(
+        TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C)
+                              << ToByteVector(keys.pubkey0H) << OP_2
+                              << OP_CHECKMULTISIG,
+                    "1-of-2 with checked hybrid pubkey with SCHNORR_MULTISIG",
+                    newmultisigflags)
+            .Num(0)
+            .PushSigECDSA(keys.key1)
+            .ScriptError(SCRIPT_ERR_PUBKEYTYPE));
+    tests.push_back(
+        TestBuilder(
+            CScript() << OP_1 << ToByteVector(keys.pubkey0) << OP_1
+                      << OP_CHECKMULTISIG,
+            "Legacy 1-of-1 Schnorr w/ SCHNORR_MULTISIG but no STRICTENC",
+            newmultisigflags & ~SCRIPT_VERIFY_STRICTENC)
+            .Num(0)
+            .PushSigSchnorr(keys.key0)
+            .ScriptError(SCRIPT_ERR_SIG_BADLENGTH));
+    tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey0)
+                                          << OP_1 << OP_CHECKMULTISIG,
+                                "Legacy 1-of-1 Schnorr w/ SCHNORR_MULTISIG",
+                                newmultisigflags)
+                        .Num(0)
+                        .PushSigSchnorr(keys.key0)
+                        .ScriptError(SCRIPT_ERR_SIG_BADLENGTH));
+    tests.push_back(TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C)
+                                          << ToByteVector(keys.pubkey1C)
+                                          << ToByteVector(keys.pubkey2C) << OP_3
+                                          << OP_CHECKMULTISIG,
+                                "Legacy 3-of-3 Schnorr w/ SCHNORR_MULTISIG",
+                                newmultisigflags)
+                        .Num(0)
+                        .PushSigSchnorr(keys.key0)
+                        .PushSigSchnorr(keys.key1)
+                        .PushSigSchnorr(keys.key2)
+                        .ScriptError(SCRIPT_ERR_SIG_BADLENGTH));
+    tests.push_back(
+        TestBuilder(CScript() << OP_3 << ToByteVector(keys.pubkey0C)
+                              << ToByteVector(keys.pubkey1C)
+                              << ToByteVector(keys.pubkey2C) << OP_3
+                              << OP_CHECKMULTISIG,
+                    "Legacy 3-of-3 mixed Schnorr-ECDSA w/ SCHNORR_MULTISIG",
+                    newmultisigflags)
+            .Num(0)
+            .PushSigECDSA(keys.key0)
+            .PushSigECDSA(keys.key1)
+            .PushSigSchnorr(keys.key2)
+            .ScriptError(SCRIPT_ERR_SIG_BADLENGTH));
+    {
+        // Try valid 64-byte ECDSA sig in multisig.
+        std::vector<uint8_t> rdata = ParseHex(
+            "776879206d757374207765207375666665722077697468206563647361");
+        std::vector<uint8_t> sdata(58 - rdata.size(), 33);
+        tests.push_back(TestBuilder(CScript() << OP_1 << OP_SWAP << OP_1
+                                              << OP_CHECKMULTISIG,
+                                    "recovered-pubkey CHECKMULTISIG with "
+                                    "64-byte DER w/ SCHNORR_MULTISIG",
+                                    newmultisigflags)
+                            .Num(0)
+                            .PushECDSASigFromParts(rdata, sdata)
+                            .PushECDSARecoveredPubKey(rdata, sdata)
+                            .ScriptError(SCRIPT_ERR_SIG_BADLENGTH));
+    }
+
     std::set<std::string> tests_set;
 
     {
diff --git a/src/test/scriptflags.cpp b/src/test/scriptflags.cpp
--- a/src/test/scriptflags.cpp
+++ b/src/test/scriptflags.cpp
@@ -33,6 +33,7 @@
     {"REPLAY_PROTECTION", SCRIPT_ENABLE_REPLAY_PROTECTION},
     {"CHECKDATASIG", SCRIPT_VERIFY_CHECKDATASIG_SIGOPS},
     {"DISALLOW_SEGWIT_RECOVERY", SCRIPT_DISALLOW_SEGWIT_RECOVERY},
+    {"SCHNORR_MULTISIG", SCRIPT_ENABLE_SCHNORR_MULTISIG},
 };
 
 uint32_t ParseScriptFlags(std::string strFlags) {