From 698c6abb25c1fbbc7fa4ba46b60e9f17d97332ef Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 8 Oct 2014 18:48:59 -0700 Subject: Add SCRIPT_VERIFY_MINIMALDATA (BIP62 rules 3 and 4) Also use the new flag as a standard rule, and replace the IsCanonicalPush standardness check with it (as it is more complete). --- src/script/interpreter.cpp | 51 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 11 deletions(-) (limited to 'src/script/interpreter.cpp') diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index e463de8cc2..11c909472a 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -157,6 +157,29 @@ bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags) { return true; } +bool static CheckMinimalPush(const valtype& data, opcodetype opcode) { + if (data.size() == 0) { + // Could have used OP_0. + return opcode == OP_0; + } else if (data.size() == 1 && data[0] >= 1 && data[0] <= 16) { + // Could have used OP_1 .. OP_16. + return opcode == OP_1 + (data[0] - 1); + } else if (data.size() == 1 && data[0] == 0x81) { + // Could have used OP_1NEGATE. + return opcode == OP_1NEGATE; + } else if (data.size() <= 75) { + // Could have used a direct push (opcode indicating number of bytes pushed + those bytes). + return opcode == data.size(); + } else if (data.size() <= 255) { + // Could have used OP_PUSHDATA. + return opcode == OP_PUSHDATA1; + } else if (data.size() <= 65535) { + // Could have used OP_PUSHDATA2. + return opcode == OP_PUSHDATA2; + } + return true; +} + bool EvalScript(vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker) { CScript::const_iterator pc = script.begin(); @@ -169,6 +192,7 @@ bool EvalScript(vector >& stack, const CScript& script, un if (script.size() > 10000) return false; int nOpCount = 0; + bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; try { @@ -205,9 +229,12 @@ bool EvalScript(vector >& stack, const CScript& script, un opcode == OP_RSHIFT) return false; // Disabled opcodes. - if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) + if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) { + if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) { + return false; + } stack.push_back(vchPushValue); - else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) + } else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) switch (opcode) { // @@ -234,6 +261,8 @@ bool EvalScript(vector >& stack, const CScript& script, un // ( -- value) CScriptNum bn((int)opcode - (int)(OP_1 - 1)); stack.push_back(bn.getvch()); + // The result of these opcodes should always be the minimal way to push the data + // they push, so no need for a CheckMinimalPush here. } break; @@ -458,7 +487,7 @@ bool EvalScript(vector >& stack, const CScript& script, un // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) if (stack.size() < 2) return false; - int n = CScriptNum(stacktop(-1)).getint(); + int n = CScriptNum(stacktop(-1), fRequireMinimal).getint(); popstack(stack); if (n < 0 || n >= (int)stack.size()) return false; @@ -557,7 +586,7 @@ bool EvalScript(vector >& stack, const CScript& script, un // (in -- out) if (stack.size() < 1) return false; - CScriptNum bn(stacktop(-1)); + CScriptNum bn(stacktop(-1), fRequireMinimal); switch (opcode) { case OP_1ADD: bn += bnOne; break; @@ -590,8 +619,8 @@ bool EvalScript(vector >& stack, const CScript& script, un // (x1 x2 -- out) if (stack.size() < 2) return false; - CScriptNum bn1(stacktop(-2)); - CScriptNum bn2(stacktop(-1)); + CScriptNum bn1(stacktop(-2), fRequireMinimal); + CScriptNum bn2(stacktop(-1), fRequireMinimal); CScriptNum bn(0); switch (opcode) { @@ -635,9 +664,9 @@ bool EvalScript(vector >& stack, const CScript& script, un // (x min max -- out) if (stack.size() < 3) return false; - CScriptNum bn1(stacktop(-3)); - CScriptNum bn2(stacktop(-2)); - CScriptNum bn3(stacktop(-1)); + CScriptNum bn1(stacktop(-3), fRequireMinimal); + CScriptNum bn2(stacktop(-2), fRequireMinimal); + CScriptNum bn3(stacktop(-1), fRequireMinimal); bool fValue = (bn2 <= bn1 && bn1 < bn3); popstack(stack); popstack(stack); @@ -727,7 +756,7 @@ bool EvalScript(vector >& stack, const CScript& script, un if ((int)stack.size() < i) return false; - int nKeysCount = CScriptNum(stacktop(-i)).getint(); + int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); if (nKeysCount < 0 || nKeysCount > 20) return false; nOpCount += nKeysCount; @@ -738,7 +767,7 @@ bool EvalScript(vector >& stack, const CScript& script, un if ((int)stack.size() < i) return false; - int nSigsCount = CScriptNum(stacktop(-i)).getint(); + int nSigsCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); if (nSigsCount < 0 || nSigsCount > nKeysCount) return false; int isig = ++i; -- cgit v1.2.3