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.
This commit is contained in:
parent
627c3762ce
commit
9dabfe49c0
6 changed files with 29 additions and 3 deletions
|
@ -63,7 +63,8 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VE
|
|||
SCRIPT_VERIFY_LOW_S |
|
||||
SCRIPT_VERIFY_WITNESS |
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
|
||||
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE;
|
||||
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE |
|
||||
SCRIPT_VERIFY_CONST_SCRIPTCODE;
|
||||
|
||||
/** For convenience, standard but not mandatory verify flags. */
|
||||
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
|
||||
|
|
|
@ -336,6 +336,10 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
|||
opcode == OP_RSHIFT)
|
||||
return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes.
|
||||
|
||||
// With SCRIPT_VERIFY_CONST_SCRIPTCODE, OP_CODESEPARATOR in non-segwit script is rejected even in an unexecuted branch
|
||||
if (opcode == OP_CODESEPARATOR && sigversion == SigVersion::BASE && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
|
||||
return set_error(serror, SCRIPT_ERR_OP_CODESEPARATOR);
|
||||
|
||||
if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) {
|
||||
if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) {
|
||||
return set_error(serror, SCRIPT_ERR_MINIMALDATA);
|
||||
|
@ -899,6 +903,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
|||
|
||||
case OP_CODESEPARATOR:
|
||||
{
|
||||
// If SCRIPT_VERIFY_CONST_SCRIPTCODE flag is set, use of OP_CODESEPARATOR is rejected in pre-segwit
|
||||
// script, even in an unexecuted branch (this is checked above the opcode case statement).
|
||||
|
||||
// Hash starts after the code separator
|
||||
pbegincodehash = pc;
|
||||
}
|
||||
|
@ -919,7 +926,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
|||
|
||||
// Drop the signature in pre-segwit scripts but not segwit scripts
|
||||
if (sigversion == SigVersion::BASE) {
|
||||
FindAndDelete(scriptCode, CScript(vchSig));
|
||||
int found = FindAndDelete(scriptCode, CScript(vchSig));
|
||||
if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
|
||||
return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE);
|
||||
}
|
||||
|
||||
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&
|
|||
{
|
||||
valtype& vchSig = stacktop(-isig-k);
|
||||
if (sigversion == SigVersion::BASE) {
|
||||
FindAndDelete(scriptCode, CScript(vchSig));
|
||||
int found = FindAndDelete(scriptCode, CScript(vchSig));
|
||||
if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
|
||||
return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -111,6 +111,10 @@ enum
|
|||
// Public keys in segregated witness scripts must be compressed
|
||||
//
|
||||
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1U << 15),
|
||||
|
||||
// Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts
|
||||
//
|
||||
SCRIPT_VERIFY_CONST_SCRIPTCODE = (1U << 16),
|
||||
};
|
||||
|
||||
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
|
||||
|
|
|
@ -89,6 +89,10 @@ const char* ScriptErrorString(const ScriptError serror)
|
|||
return "Witness provided for non-witness script";
|
||||
case SCRIPT_ERR_WITNESS_PUBKEYTYPE:
|
||||
return "Using non-compressed keys in segwit";
|
||||
case SCRIPT_ERR_OP_CODESEPARATOR:
|
||||
return "Using OP_CODESEPARATOR in non-witness script";
|
||||
case SCRIPT_ERR_SIG_FINDANDDELETE:
|
||||
return "Signature is found in scriptCode";
|
||||
case SCRIPT_ERR_UNKNOWN_ERROR:
|
||||
case SCRIPT_ERR_ERROR_COUNT:
|
||||
default: break;
|
||||
|
|
|
@ -64,6 +64,10 @@ typedef enum ScriptError_t
|
|||
SCRIPT_ERR_WITNESS_UNEXPECTED,
|
||||
SCRIPT_ERR_WITNESS_PUBKEYTYPE,
|
||||
|
||||
/* Constant scriptCode */
|
||||
SCRIPT_ERR_OP_CODESEPARATOR,
|
||||
SCRIPT_ERR_SIG_FINDANDDELETE,
|
||||
|
||||
SCRIPT_ERR_ERROR_COUNT
|
||||
} ScriptError;
|
||||
|
||||
|
|
|
@ -97,6 +97,8 @@ static ScriptErrorDesc script_errors[]={
|
|||
{SCRIPT_ERR_WITNESS_MALLEATED_P2SH, "WITNESS_MALLEATED_P2SH"},
|
||||
{SCRIPT_ERR_WITNESS_UNEXPECTED, "WITNESS_UNEXPECTED"},
|
||||
{SCRIPT_ERR_WITNESS_PUBKEYTYPE, "WITNESS_PUBKEYTYPE"},
|
||||
{SCRIPT_ERR_OP_CODESEPARATOR, "OP_CODESEPARATOR"},
|
||||
{SCRIPT_ERR_SIG_FINDANDDELETE, "SIG_FINDANDDELETE"},
|
||||
};
|
||||
|
||||
const char *FormatScriptError(ScriptError_t err)
|
||||
|
|
Loading…
Reference in a new issue