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 rdata = ParseHex( + "776879206d757374207765207375666665722077697468206563647361"); + std::vector 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 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) {