Skip to content

Commit 9dabfe4

Browse files
committed
Add constant scriptCode policy in non-segwit scripts
This disables OP_CODESEPARATOR in non-segwit scripts (even in an unexecuted branch), and makes a positive FindAndDelete result invalid. This ensures that the scriptCode serialized in SignatureHash() is always the same as the script passing to the EvalScript.
1 parent 627c376 commit 9dabfe4

File tree

6 files changed

+29
-3
lines changed

6 files changed

+29
-3
lines changed

src/policy/policy.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VE
6363
SCRIPT_VERIFY_LOW_S |
6464
SCRIPT_VERIFY_WITNESS |
6565
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
66-
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE;
66+
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE |
67+
SCRIPT_VERIFY_CONST_SCRIPTCODE;
6768

6869
/** For convenience, standard but not mandatory verify flags. */
6970
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;

src/script/interpreter.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,10 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
336336
opcode == OP_RSHIFT)
337337
return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes.
338338

339+
// With SCRIPT_VERIFY_CONST_SCRIPTCODE, OP_CODESEPARATOR in non-segwit script is rejected even in an unexecuted branch
340+
if (opcode == OP_CODESEPARATOR && sigversion == SigVersion::BASE && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
341+
return set_error(serror, SCRIPT_ERR_OP_CODESEPARATOR);
342+
339343
if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) {
340344
if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) {
341345
return set_error(serror, SCRIPT_ERR_MINIMALDATA);
@@ -899,6 +903,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
899903

900904
case OP_CODESEPARATOR:
901905
{
906+
// If SCRIPT_VERIFY_CONST_SCRIPTCODE flag is set, use of OP_CODESEPARATOR is rejected in pre-segwit
907+
// script, even in an unexecuted branch (this is checked above the opcode case statement).
908+
902909
// Hash starts after the code separator
903910
pbegincodehash = pc;
904911
}
@@ -919,7 +926,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
919926

920927
// Drop the signature in pre-segwit scripts but not segwit scripts
921928
if (sigversion == SigVersion::BASE) {
922-
FindAndDelete(scriptCode, CScript(vchSig));
929+
int found = FindAndDelete(scriptCode, CScript(vchSig));
930+
if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
931+
return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE);
923932
}
924933

925934
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
@@ -983,7 +992,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
983992
{
984993
valtype& vchSig = stacktop(-isig-k);
985994
if (sigversion == SigVersion::BASE) {
986-
FindAndDelete(scriptCode, CScript(vchSig));
995+
int found = FindAndDelete(scriptCode, CScript(vchSig));
996+
if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
997+
return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE);
987998
}
988999
}
9891000

src/script/interpreter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ enum
111111
// Public keys in segregated witness scripts must be compressed
112112
//
113113
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1U << 15),
114+
115+
// Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts
116+
//
117+
SCRIPT_VERIFY_CONST_SCRIPTCODE = (1U << 16),
114118
};
115119

116120
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);

src/script/script_error.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ const char* ScriptErrorString(const ScriptError serror)
8989
return "Witness provided for non-witness script";
9090
case SCRIPT_ERR_WITNESS_PUBKEYTYPE:
9191
return "Using non-compressed keys in segwit";
92+
case SCRIPT_ERR_OP_CODESEPARATOR:
93+
return "Using OP_CODESEPARATOR in non-witness script";
94+
case SCRIPT_ERR_SIG_FINDANDDELETE:
95+
return "Signature is found in scriptCode";
9296
case SCRIPT_ERR_UNKNOWN_ERROR:
9397
case SCRIPT_ERR_ERROR_COUNT:
9498
default: break;

src/script/script_error.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ typedef enum ScriptError_t
6464
SCRIPT_ERR_WITNESS_UNEXPECTED,
6565
SCRIPT_ERR_WITNESS_PUBKEYTYPE,
6666

67+
/* Constant scriptCode */
68+
SCRIPT_ERR_OP_CODESEPARATOR,
69+
SCRIPT_ERR_SIG_FINDANDDELETE,
70+
6771
SCRIPT_ERR_ERROR_COUNT
6872
} ScriptError;
6973

src/test/script_tests.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ static ScriptErrorDesc script_errors[]={
9797
{SCRIPT_ERR_WITNESS_MALLEATED_P2SH, "WITNESS_MALLEATED_P2SH"},
9898
{SCRIPT_ERR_WITNESS_UNEXPECTED, "WITNESS_UNEXPECTED"},
9999
{SCRIPT_ERR_WITNESS_PUBKEYTYPE, "WITNESS_PUBKEYTYPE"},
100+
{SCRIPT_ERR_OP_CODESEPARATOR, "OP_CODESEPARATOR"},
101+
{SCRIPT_ERR_SIG_FINDANDDELETE, "SIG_FINDANDDELETE"},
100102
};
101103

102104
const char *FormatScriptError(ScriptError_t err)

0 commit comments

Comments
 (0)