From d752ba86c1872f64a4641cf77008826d32bde65f Mon Sep 17 00:00:00 2001
From: Pieter Wuille <pieter.wuille@gmail.com>
Date: Wed, 8 Oct 2014 16:29:45 -0700
Subject: [PATCH 1/7] Add SCRIPT_VERIFY_SIGPUSHONLY (BIP62 rule 2)

---
 src/script/interpreter.cpp        |  4 ++++
 src/script/interpreter.h          |  3 +++
 src/script/script.cpp             |  2 +-
 src/script/script.h               |  2 +-
 src/test/data/script_invalid.json | 18 ++++++++++++++++++
 src/test/data/script_valid.json   | 12 ++++++++++++
 src/test/script_tests.cpp         | 23 +++++++++++++++++++++--
 src/test/transaction_tests.cpp    |  1 +
 8 files changed, 61 insertions(+), 4 deletions(-)

diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index cd73b8821..e463de8cc 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -980,6 +980,10 @@ bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vec
 
 bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker)
 {
+    if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) {
+        return false;
+    }
+
     vector<vector<unsigned char> > stack, stackCopy;
     if (!EvalScript(stack, scriptSig, flags, checker))
         return false;
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index de5ce2ced..085cd867d 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -46,6 +46,9 @@ enum
 
     // verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7).
     SCRIPT_VERIFY_NULLDUMMY = (1U << 4),
+
+    // Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2).
+    SCRIPT_VERIFY_SIGPUSHONLY = (1U << 5),
 };
 
 uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
diff --git a/src/script/script.cpp b/src/script/script.cpp
index 3e19d0c2b..bbcfe9dfd 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -230,7 +230,7 @@ bool CScript::IsPushOnly() const
             return false;
         // Note that IsPushOnly() *does* consider OP_RESERVED to be a
         // push-type opcode, however execution of OP_RESERVED fails, so
-        // it's not relevant to P2SH as the scriptSig would fail prior to
+        // it's not relevant to P2SH/BIP62 as the scriptSig would fail prior to
         // the P2SH special validation code being executed.
         if (opcode > OP_16)
             return false;
diff --git a/src/script/script.h b/src/script/script.h
index d450db5ca..706a85a29 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -551,7 +551,7 @@ public:
 
     bool IsPayToScriptHash() const;
 
-    // Called by IsStandardTx and P2SH VerifyScript (which makes it consensus-critical).
+    // Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical).
     bool IsPushOnly() const;
 
     // Called by IsStandardTx.
diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json
index b6447cb22..e4dd8fe9a 100644
--- a/src/test/data/script_invalid.json
+++ b/src/test/data/script_invalid.json
@@ -504,6 +504,24 @@ nSequences are max.
     "NULLDUMMY",
     "3-of-3 NOT with invalid sig with nonzero dummy"
 ],
+[
+    "0 0x47 0x3044022035341cc377b19138f944f90c45772cb06338c6d56a4c0c31a65bf1a8a105fadc022046dd232850b6bacb25879c9da82a7a628982aa19d055f1753468f68047662e0301 DUP",
+    "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
+    "SIGPUSHONLY",
+    "2-of-2 with two identical keys and sigs pushed using OP_DUP"
+],
+[
+    "0x47 0x304402204d8b99eea2f53382fd67e0dbc8ed0596bd614aa0dad6bc6843c7860c79b901c3022062f022a71993013e3d9b22302a8e4b40109d7bb057aeb250b9aab2197b3e96b801 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",
+    "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
+    "",
+    "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY"
+],
+[
+    "0x47 0x30440220078c887c33abc67fbbd827ceb3f661c1c459e78218161b652f23e3ca76cfabbd022047df245eacb8a88d8c5ca7b5228e3b4d070c102d2f542433362d3f443cd24eda01 0x23 0x2103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640ac",
+    "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG",
+    "SIGPUSHONLY",
+    "P2SH(P2PK) with non-push scriptSig"
+],
 
 ["The End"]
 ]
diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json
index 88bec7238..f7d153169 100644
--- a/src/test/data/script_valid.json
+++ b/src/test/data/script_valid.json
@@ -649,6 +649,18 @@ nSequences are max.
     "",
     "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY"
 ],
+[
+    "0 0x47 0x3044022002a27769ee33db258bdf7a3792e7da4143ec4001b551f73e6a190b8d1bde449d02206742c56ccd94a7a2e16ca52fc1ae4a0aa122b0014a867a80de104f9cb18e472c01 DUP",
+    "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
+    "",
+    "2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY"
+],
+[
+    "0 0x47 0x304402203acf75dd59bbef171aeeedae4f1020b824195820db82575c2b323b8899f95de9022067df297d3a5fad049ba0bb81255d0e495643cbcf9abae9e396988618bc0c6dfe01 0x47 0x304402205f8b859230c1cab7d4e8de38ff244d2ebe046b64e8d3f4219b01e483c203490a022071bdc488e31b557f7d9e5c8a8bec90dc92289ca70fa317685f4f140e38b30c4601",
+    "2 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 2 CHECKMULTISIG",
+    "SIGPUSHONLY",
+    "2-of-2 with two identical keys and sigs pushed"
+],
 
 ["The End"]
 ]
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index d3fc673a7..072911901 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1,5 +1,5 @@
-// Copyright (c) 2011-2013 The Bitcoin Core developers
-// Distributed under the MIT/X11 software license, see the accompanying
+// Copyright (c) 2011-2014 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include "data/script_invalid.json.h"
@@ -171,12 +171,14 @@ public:
 
     TestBuilder& Add(const CScript& script)
     {
+        DoPush();
         spendTx.vin[0].scriptSig += script;
         return *this;
     }
 
     TestBuilder& Num(int num)
     {
+        DoPush();
         spendTx.vin[0].scriptSig << CScriptNum(num);
         return *this;
     }
@@ -402,6 +404,23 @@ BOOST_AUTO_TEST_CASE(script_build)
                               "3-of-3 NOT with invalid sig with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY
                              ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10));
 
+    good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
+                               "2-of-2 with two identical keys and sigs pushed using OP_DUP but no SIGPUSHONLY", 0
+                              ).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP));
+    bad.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
+                              "2-of-2 with two identical keys and sigs pushed using OP_DUP", SCRIPT_VERIFY_SIGPUSHONLY
+                             ).Num(0).PushSig(keys.key1).Add(CScript() << OP_DUP));
+    bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
+                              "P2SH(P2PK) with non-push scriptSig but no SIGPUSHONLY", 0
+                             ).PushSig(keys.key2).PushRedeem());
+    bad.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey2C) << OP_CHECKSIG,
+                              "P2SH(P2PK) with non-push scriptSig", SCRIPT_VERIFY_SIGPUSHONLY
+                             ).PushSig(keys.key2).PushRedeem());
+    good.push_back(TestBuilder(CScript() << OP_2 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey1C) << OP_2 << OP_CHECKMULTISIG,
+                               "2-of-2 with two identical keys and sigs pushed", SCRIPT_VERIFY_SIGPUSHONLY
+                              ).Num(0).PushSig(keys.key1).PushSig(keys.key1));
+
+
     std::map<std::string, Array> tests_good;
     std::map<std::string, Array> tests_bad;
 
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 41ccaaac9..9209c6697 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -33,6 +33,7 @@ static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
     (string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC)
     (string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG)
     (string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S)
+    (string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY)
     (string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY);
 
 unsigned int ParseScriptFlags(string strFlags)

From 698c6abb25c1fbbc7fa4ba46b60e9f17d97332ef Mon Sep 17 00:00:00 2001
From: Pieter Wuille <pieter.wuille@gmail.com>
Date: Wed, 8 Oct 2014 18:48:59 -0700
Subject: [PATCH 2/7] 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/main.cpp                      |  4 ---
 src/script/interpreter.cpp        | 51 ++++++++++++++++++++++++-------
 src/script/interpreter.h          |  7 +++++
 src/script/script.cpp             | 29 +-----------------
 src/script/script.h               | 18 ++++++-----
 src/script/standard.h             |  1 +
 src/test/data/script_invalid.json |  4 +++
 src/test/data/script_valid.json   | 31 +++++++++++++++++--
 src/test/script_tests.cpp         | 10 +++---
 src/test/scriptnum_tests.cpp      |  4 +--
 src/test/transaction_tests.cpp    |  1 +
 11 files changed, 101 insertions(+), 59 deletions(-)

diff --git a/src/main.cpp b/src/main.cpp
index 0cfe90bed..008a05910 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -633,10 +633,6 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
             reason = "scriptsig-not-pushonly";
             return false;
         }
-        if (!txin.scriptSig.HasCanonicalPushes()) {
-            reason = "scriptsig-non-canonical-push";
-            return false;
-        }
     }
 
     unsigned int nDataOut = 0;
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index e463de8cc..11c909472 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<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker)
 {
     CScript::const_iterator pc = script.begin();
@@ -169,6 +192,7 @@ bool EvalScript(vector<vector<unsigned char> >& 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<vector<unsigned char> >& 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<vector<unsigned char> >& 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<vector<unsigned char> >& 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<vector<unsigned char> >& 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<vector<unsigned char> >& 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<vector<unsigned char> >& 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<vector<unsigned char> >& 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<vector<unsigned char> >& 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;
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index 085cd867d..5133c80aa 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -49,6 +49,13 @@ enum
 
     // Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2).
     SCRIPT_VERIFY_SIGPUSHONLY = (1U << 5),
+
+    // Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct
+    // pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating
+    // any other push causes the script to fail (BIP62 rule 3).
+    // In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4).
+    // (softfork safe)
+    SCRIPT_VERIFY_MINIMALDATA = (1U << 6)
 };
 
 uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
diff --git a/src/script/script.cpp b/src/script/script.cpp
index bbcfe9dfd..b879d72d6 100644
--- a/src/script/script.cpp
+++ b/src/script/script.cpp
@@ -12,7 +12,7 @@ namespace {
 inline std::string ValueString(const std::vector<unsigned char>& vch)
 {
     if (vch.size() <= 4)
-        return strprintf("%d", CScriptNum(vch).getint());
+        return strprintf("%d", CScriptNum(vch, false).getint());
     else
         return HexStr(vch);
 }
@@ -238,33 +238,6 @@ bool CScript::IsPushOnly() const
     return true;
 }
 
-bool CScript::HasCanonicalPushes() const
-{
-    const_iterator pc = begin();
-    while (pc < end())
-    {
-        opcodetype opcode;
-        std::vector<unsigned char> data;
-        if (!GetOp(pc, opcode, data))
-            return false;
-        if (opcode > OP_16)
-            continue;
-        if (opcode < OP_PUSHDATA1 && opcode > OP_0 && (data.size() == 1 && data[0] <= 16))
-            // Could have used an OP_n code, rather than a 1-byte push.
-            return false;
-        if (opcode == OP_PUSHDATA1 && data.size() < OP_PUSHDATA1)
-            // Could have used a normal n-byte push, rather than OP_PUSHDATA1.
-            return false;
-        if (opcode == OP_PUSHDATA2 && data.size() <= 0xFF)
-            // Could have used an OP_PUSHDATA1.
-            return false;
-        if (opcode == OP_PUSHDATA4 && data.size() <= 0xFFFF)
-            // Could have used an OP_PUSHDATA2.
-            return false;
-    }
-    return true;
-}
-
 std::string CScript::ToString() const
 {
     std::string str;
diff --git a/src/script/script.h b/src/script/script.h
index 706a85a29..e97967dce 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -192,10 +192,14 @@ public:
         m_value = n;
     }
 
-    explicit CScriptNum(const std::vector<unsigned char>& vch)
+    explicit CScriptNum(const std::vector<unsigned char>& vch, bool fRequireMinimal)
     {
-        if (vch.size() > nMaxNumSize)
-            throw scriptnum_error("CScriptNum(const std::vector<unsigned char>&) : overflow");
+        if (vch.size() > nMaxNumSize) {
+            throw scriptnum_error("script number overflow");
+        }
+        if (fRequireMinimal && vch.size() > 0 && (vch.back() & 0x7f) == 0 && (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0)) {
+            throw scriptnum_error("non-minimally encoded script number");
+        }
         m_value = set_vch(vch);
     }
 
@@ -319,7 +323,6 @@ private:
     int64_t m_value;
 };
 
-
 /** Serialized script, used inside transaction inputs and outputs */
 class CScript : public std::vector<unsigned char>
 {
@@ -330,6 +333,10 @@ protected:
         {
             push_back(n + (OP_1 - 1));
         }
+        else if (n == 0)
+        {
+            push_back(OP_0);
+        }
         else
         {
             *this << CScriptNum::serialize(n);
@@ -554,9 +561,6 @@ public:
     // Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical).
     bool IsPushOnly() const;
 
-    // Called by IsStandardTx.
-    bool HasCanonicalPushes() const;
-
     // Returns whether the script is guaranteed to fail at execution,
     // regardless of the initial stack. This allows outputs to be pruned
     // instantly when entering the UTXO set.
diff --git a/src/script/standard.h b/src/script/standard.h
index 961b214c8..248b941a6 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -41,6 +41,7 @@ static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
 // blocks and we must accept those blocks.
 static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
                                                          SCRIPT_VERIFY_STRICTENC |
+                                                         SCRIPT_VERIFY_MINIMALDATA |
                                                          SCRIPT_VERIFY_NULLDUMMY;
 
 // For convenience, standard but not mandatory verify flags.
diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json
index e4dd8fe9a..5ead65f17 100644
--- a/src/test/data/script_invalid.json
+++ b/src/test/data/script_invalid.json
@@ -384,6 +384,10 @@ nSequences are max.
 
 ["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],
 
+["1 IF 0x01 0x81 ENDIF 1", "", "MINIMALDATA", "evaluated non-minimal data"],
+["1 IF 0x01 0x05 ENDIF 1", "", "MINIMALDATA", "evaluated non-minimal data"],
+["1 IF 0x4c 0x03 0x222222 ENDIF 1", "", "MINIMALDATA", "evaluated non-minimal data"],
+
 [
     "0x47 0x30440220304eff7556bba9560df47873275e64db45f3cd735998ce3f00d2e57b1bb5f31302205c0c9d14b8b80d43e2ac9b87532f1af6d8a3271262bc694ec4e14068392bb0a001",
     "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json
index f7d153169..89619a9dd 100644
--- a/src/test/data/script_valid.json
+++ b/src/test/data/script_valid.json
@@ -529,6 +529,33 @@ nSequences are max.
 
 ["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],
 
+["0x01 0x81", "0x4f EQUAL", "", "direct push of 0x81 equals 1NEGATE"],
+["0x01 0x05", "5 EQUAL", "", "direct push of 0x05 equals 5"],
+["0x4c 0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL", "", "PUSHDATA1 of 75 bytes equals direct push of it"],
+["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "0x4c 0xFF 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL", "", "PUSHDATA2 of 255 bytes equals PUSHDATA1 of it"],
+["0x02 0x8000", "128 NUMEQUAL", "", "0x8000 equals 128"],
+["0x01 0x00", "0 NUMEQUAL", "", "0x00 numequals 0"],
+["0x01 0x80", "0 NUMEQUAL", "", "0x80 (negative zero) numequals 0"],
+["0x02 0x0080", "0 NUMEQUAL", "", "0x0080 numequals 0"],
+["0x02 0x0500", "5 NUMEQUAL", "", "0x0500 numequals 5"],
+["0x03 0xff7f80", "0x02 0xffff NUMEQUAL", "", ""],
+["0x03 0xff7f00", "0x02 0xff7f NUMEQUAL", "", ""],
+["0x04 0xffff7f80", "0x03 0xffffff NUMEQUAL", "", ""],
+["0x04 0xffff7f00", "0x03 0xffff7f NUMEQUAL", "", ""],
+["0 IF 0x01 0x81 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
+["0 IF 0x01 0x05 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
+["0 IF 0x02 0x8000 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
+["0 IF 0x01 0x00 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
+["0 IF 0x01 0x80 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
+["0 IF 0x02 0x0080 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
+["0 IF 0x02 0x0400 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
+["0 IF 0x03 0xff7f80 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
+["0 IF 0x03 0xff7f00 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
+["0 IF 0x04 0xffff7f80 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
+["0 IF 0x04 0xffff7f00 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
+["0 IF 0x4c 0x03 0x222222 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
+
+
 [
     "0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501",
     "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",
@@ -638,13 +665,13 @@ nSequences are max.
     "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC"
 ],
 [
-    "0x01 0x01 0x47 0x3044022046ce33d1771b0127dd4c4cef8fdc3218ebdfa60e3793ed700292d8ebd93fb1f402201029d47a414db83e96e31443c2d8b552f971469c4800f5eff7df2f0648521aed01 0x47 0x304402205c53911ad55b054920043962bbda98cf6e57e2db1cd5611138251490baabaa8702201dc80dfceae6007e7772dc13ff6e7ca66a983cb017fe5d46d30118462d83bcf801 0x47 0x304402201937e44a4ec12364f9d32f9d25e7ecbc68aee9ef90069af80efef4c05f6ace9602206c515101c00c75710b32ff7ff8dbaf7c9a0be6e86ed14a0755b47626604f31fd01",
+    "1 0x47 0x3044022046ce33d1771b0127dd4c4cef8fdc3218ebdfa60e3793ed700292d8ebd93fb1f402201029d47a414db83e96e31443c2d8b552f971469c4800f5eff7df2f0648521aed01 0x47 0x304402205c53911ad55b054920043962bbda98cf6e57e2db1cd5611138251490baabaa8702201dc80dfceae6007e7772dc13ff6e7ca66a983cb017fe5d46d30118462d83bcf801 0x47 0x304402201937e44a4ec12364f9d32f9d25e7ecbc68aee9ef90069af80efef4c05f6ace9602206c515101c00c75710b32ff7ff8dbaf7c9a0be6e86ed14a0755b47626604f31fd01",
     "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG",
     "",
     "3-of-3 with nonzero dummy but no NULLDUMMY"
 ],
 [
-    "0x01 0x01 0x47 0x30440220195038dbc6b2ae1199f86a6777824f7c5149789d85f655a3534a4422b8fba38c02204df9db87d2eb9fe06edc66870d9ac4c9ce673459f9d43cee0347ce4ffb02ee5a01 0x47 0x3044022010a45f30c6fa97a186eba9e6b595ab87d3dfcbf05dcaf1f1b8e3e7bf39515bb802203474e78d3d372e5f5c0f8c257ce8300c4bb8f37c51d4a894e11a91b5817da6ed01 0x47 0x30440220039cffd8e39850f95112662b1220b14b3c0d3d8a2772e13c947bfbf96345a64e02204154bfa77e2c0134d5434353bed82141e5da1cc479954aa288d5f0671480a04b01",
+    "1 0x47 0x30440220195038dbc6b2ae1199f86a6777824f7c5149789d85f655a3534a4422b8fba38c02204df9db87d2eb9fe06edc66870d9ac4c9ce673459f9d43cee0347ce4ffb02ee5a01 0x47 0x3044022010a45f30c6fa97a186eba9e6b595ab87d3dfcbf05dcaf1f1b8e3e7bf39515bb802203474e78d3d372e5f5c0f8c257ce8300c4bb8f37c51d4a894e11a91b5817da6ed01 0x47 0x30440220039cffd8e39850f95112662b1220b14b3c0d3d8a2772e13c947bfbf96345a64e02204154bfa77e2c0134d5434353bed82141e5da1cc479954aa288d5f0671480a04b01",
     "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT",
     "",
     "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY"
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 072911901..a41552fea 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -179,7 +179,7 @@ public:
     TestBuilder& Num(int num)
     {
         DoPush();
-        spendTx.vin[0].scriptSig << CScriptNum(num);
+        spendTx.vin[0].scriptSig << num;
         return *this;
     }
 
@@ -788,19 +788,19 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
 
 BOOST_AUTO_TEST_CASE(script_standard_push)
 {
-    for (int i=0; i<1000; i++) {
+    for (int i=0; i<67000; i++) {
         CScript script;
         script << i;
         BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push.");
-        BOOST_CHECK_MESSAGE(script.HasCanonicalPushes(), "Number " << i << " push is not canonical.");
+        BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker()), "Number " << i << " push is not minimal data.");
     }
 
-    for (int i=0; i<1000; i++) {
+    for (unsigned int i=0; i<=MAX_SCRIPT_ELEMENT_SIZE; i++) {
         std::vector<unsigned char> data(i, '\111');
         CScript script;
         script << data;
         BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push.");
-        BOOST_CHECK_MESSAGE(script.HasCanonicalPushes(), "Length " << i << " push is not canonical.");
+        BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker()), "Length " << i << " push is not minimal data.");
     }
 }
 
diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp
index ac60fa426..5621e1272 100644
--- a/src/test/scriptnum_tests.cpp
+++ b/src/test/scriptnum_tests.cpp
@@ -25,11 +25,11 @@ static void CheckCreateVch(const int64_t& num)
     BOOST_CHECK(verify(bignum, scriptnum));
 
     CBigNum bignum2(bignum.getvch());
-    CScriptNum scriptnum2(scriptnum.getvch());
+    CScriptNum scriptnum2(scriptnum.getvch(), false);
     BOOST_CHECK(verify(bignum2, scriptnum2));
 
     CBigNum bignum3(scriptnum2.getvch());
-    CScriptNum scriptnum3(bignum2.getvch());
+    CScriptNum scriptnum3(bignum2.getvch(), false);
     BOOST_CHECK(verify(bignum3, scriptnum3));
 }
 
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 9209c6697..c46c31e99 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -34,6 +34,7 @@ static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
     (string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG)
     (string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S)
     (string("SIGPUSHONLY"), (unsigned int)SCRIPT_VERIFY_SIGPUSHONLY)
+    (string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA)
     (string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY);
 
 unsigned int ParseScriptFlags(string strFlags)

From 6004e77b926b5588e4b8eebdff843fe6652e5885 Mon Sep 17 00:00:00 2001
From: Peter Todd <pete@petertodd.org>
Date: Tue, 14 Oct 2014 11:18:24 -0400
Subject: [PATCH 3/7] Improve CScriptNum() comment

Edited-by: Pieter Wuille <pieter.wuille@gmail.com>
---
 src/script/script.h | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/script/script.h b/src/script/script.h
index e97967dce..05f2e7e3a 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -197,8 +197,23 @@ public:
         if (vch.size() > nMaxNumSize) {
             throw scriptnum_error("script number overflow");
         }
-        if (fRequireMinimal && vch.size() > 0 && (vch.back() & 0x7f) == 0 && (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0)) {
-            throw scriptnum_error("non-minimally encoded script number");
+        if (fRequireMinimal && vch.size() > 0) {
+            // Check that the number is encoded with the minimum possible
+            // number of bytes.
+            //
+            // If the most-significant-byte - excluding the sign bit - is zero
+            // then we're not minimal. Note how this test also rejects the
+            // negative-zero encoding, 0x80.
+            if ((vch.back() & 0x7f) == 0) {
+                // One exception: if there's more than one byte and the most
+                // significant bit of the second-most-significant-byte is set
+                // it would conflict with the sign bit. An example of this case
+                // is +-255, which encode to 0xff00 and 0xff80 respectively.
+                // (big-endian).
+                if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) {
+                    throw scriptnum_error("non-minimally encoded script number");
+                }
+            }
         }
         m_value = set_vch(vch);
     }

From 554147ad9e6fee1c1d3827ca971647a97a5c0d66 Mon Sep 17 00:00:00 2001
From: Peter Todd <pete@petertodd.org>
Date: Tue, 14 Oct 2014 13:38:17 -0400
Subject: [PATCH 4/7] Ensure MINIMALDATA invalid tests can only fail one way

Removes the need for the 'negated' versions of the tests, and ensures
other failures don't mask what we're trying to test.
---
 src/test/data/script_invalid.json | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json
index 5ead65f17..c5d878102 100644
--- a/src/test/data/script_invalid.json
+++ b/src/test/data/script_invalid.json
@@ -384,6 +384,18 @@ nSequences are max.
 
 ["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],
 
+["0x01 0x81", "DROP 1", "MINIMALDATA", "direct push of 0x81 equals 1NEGATE"],
+["0x01 0x05", "DROP 1", "MINIMALDATA", "direct push of 0x05 equals 5"],
+["0x4c 0x48 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", "PUSHDATA1 of 72 bytes equals direct push of it"],
+["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", "PUSHDATA2 of 255 bytes equals PUSHDATA1 of it"],
+["0x01 0x00", "NOT DROP 1", "MINIMALDATA", "0x00 numequals 0"],
+["0x01 0x80", "NOT DROP 1", "MINIMALDATA", "0x80 (negative zero) numequals 0"],
+["0x02 0x0080", "NOT DROP 1", "MINIMALDATA", "0x0080 numequals 0"],
+["0x02 0x0500", "NOT DROP 1", "MINIMALDATA", "0x0500 numequals 5"],
+["0x03 0xff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is ffff"],
+["0x03 0xff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is ff7f"],
+["0x04 0xffff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is ffffff"],
+["0x04 0xffff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is ffff7f"],
 ["1 IF 0x01 0x81 ENDIF 1", "", "MINIMALDATA", "evaluated non-minimal data"],
 ["1 IF 0x01 0x05 ENDIF 1", "", "MINIMALDATA", "evaluated non-minimal data"],
 ["1 IF 0x4c 0x03 0x222222 ENDIF 1", "", "MINIMALDATA", "evaluated non-minimal data"],

From dfeec18b85a3a209899dddd6af0ca47dfe48c4d4 Mon Sep 17 00:00:00 2001
From: Peter Todd <pete@petertodd.org>
Date: Tue, 14 Oct 2014 14:24:13 -0400
Subject: [PATCH 5/7] Test every numeric-accepting opcode for correct handling
 of the numeric minimal encoding rule

---
 src/test/data/script_invalid.json | 50 +++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json
index c5d878102..3e7bbe73d 100644
--- a/src/test/data/script_invalid.json
+++ b/src/test/data/script_invalid.json
@@ -400,6 +400,56 @@ nSequences are max.
 ["1 IF 0x01 0x05 ENDIF 1", "", "MINIMALDATA", "evaluated non-minimal data"],
 ["1 IF 0x4c 0x03 0x222222 ENDIF 1", "", "MINIMALDATA", "evaluated non-minimal data"],
 
+
+["Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule"],
+
+["1 0x02 0x0000", "PICK DROP", "MINIMALDATA"],
+["1 0x02 0x0000", "ROLL DROP 1", "MINIMALDATA"],
+["0x02 0x0000", "1ADD DROP 1", "MINIMALDATA"],
+["0x02 0x0000", "1SUB DROP 1", "MINIMALDATA"],
+["0x02 0x0000", "NEGATE DROP 1", "MINIMALDATA"],
+["0x02 0x0000", "ABS DROP 1", "MINIMALDATA"],
+["0x02 0x0000", "NOT DROP 1", "MINIMALDATA"],
+["0x02 0x0000", "0NOTEQUAL DROP 1", "MINIMALDATA"],
+
+["0 0x02 0x0000", "ADD DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "ADD DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "SUB DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "SUB DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "BOOLAND DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "BOOLAND DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "BOOLOR DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "BOOLOR DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "NUMEQUAL DROP 1", "MINIMALDATA"],
+["0x02 0x0000 1", "NUMEQUAL DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "NUMEQUALVERIFY 1", "MINIMALDATA"],
+["0x02 0x0000 0", "NUMEQUALVERIFY 1", "MINIMALDATA"],
+["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "LESSTHAN DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "LESSTHAN DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "GREATERTHAN DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "GREATERTHAN DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "MIN DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "MIN DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000", "MAX DROP 1", "MINIMALDATA"],
+["0x02 0x0000 0", "MAX DROP 1", "MINIMALDATA"],
+
+["0x02 0x0000 0 0", "WITHIN DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000 0", "WITHIN DROP 1", "MINIMALDATA"],
+["0 0 0x02 0x0000", "WITHIN DROP 1", "MINIMALDATA"],
+
+["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", "MINIMALDATA"],
+["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", "MINIMALDATA"],
+["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", "MINIMALDATA"],
+["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", "MINIMALDATA"],
+
+
 [
     "0x47 0x30440220304eff7556bba9560df47873275e64db45f3cd735998ce3f00d2e57b1bb5f31302205c0c9d14b8b80d43e2ac9b87532f1af6d8a3271262bc694ec4e14068392bb0a001",
     "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",

From 2b62e1796bb58d1ef2e2a83e42958111467f0562 Mon Sep 17 00:00:00 2001
From: Peter Todd <pete@petertodd.org>
Date: Tue, 14 Oct 2014 15:08:48 -0400
Subject: [PATCH 6/7] Clearly separate PUSHDATA and numeric argument
 MINIMALDATA tests

---
 src/test/data/script_invalid.json | 59 +++++++++++++++------
 src/test/data/script_valid.json   | 85 +++++++++++++++++++++++++------
 2 files changed, 114 insertions(+), 30 deletions(-)

diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json
index 3e7bbe73d..6f451a36e 100644
--- a/src/test/data/script_invalid.json
+++ b/src/test/data/script_invalid.json
@@ -384,22 +384,51 @@ nSequences are max.
 
 ["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],
 
-["0x01 0x81", "DROP 1", "MINIMALDATA", "direct push of 0x81 equals 1NEGATE"],
-["0x01 0x05", "DROP 1", "MINIMALDATA", "direct push of 0x05 equals 5"],
-["0x4c 0x48 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", "PUSHDATA1 of 72 bytes equals direct push of it"],
-["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA", "PUSHDATA2 of 255 bytes equals PUSHDATA1 of it"],
-["0x01 0x00", "NOT DROP 1", "MINIMALDATA", "0x00 numequals 0"],
-["0x01 0x80", "NOT DROP 1", "MINIMALDATA", "0x80 (negative zero) numequals 0"],
-["0x02 0x0080", "NOT DROP 1", "MINIMALDATA", "0x0080 numequals 0"],
-["0x02 0x0500", "NOT DROP 1", "MINIMALDATA", "0x0500 numequals 5"],
-["0x03 0xff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is ffff"],
-["0x03 0xff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is ff7f"],
-["0x04 0xffff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is ffffff"],
-["0x04 0xffff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is ffff7f"],
-["1 IF 0x01 0x81 ENDIF 1", "", "MINIMALDATA", "evaluated non-minimal data"],
-["1 IF 0x01 0x05 ENDIF 1", "", "MINIMALDATA", "evaluated non-minimal data"],
-["1 IF 0x4c 0x03 0x222222 ENDIF 1", "", "MINIMALDATA", "evaluated non-minimal data"],
+["MINIMALDATA enforcement for PUSHDATAs"],
 
+["0x4c 0x00", "DROP 1", "MINIMALDATA", "Empty vector minimally represented by OP_0"],
+["0x01 0x81", "DROP 1", "MINIMALDATA", "-1 minimally represented by OP_1NEGATE"],
+["0x01 0x01", "DROP 1", "MINIMALDATA", "1 to 16 minimally represented by OP_1 to OP_16"],
+["0x01 0x02", "DROP 1", "MINIMALDATA"],
+["0x01 0x03", "DROP 1", "MINIMALDATA"],
+["0x01 0x04", "DROP 1", "MINIMALDATA"],
+["0x01 0x05", "DROP 1", "MINIMALDATA"],
+["0x01 0x06", "DROP 1", "MINIMALDATA"],
+["0x01 0x07", "DROP 1", "MINIMALDATA"],
+["0x01 0x08", "DROP 1", "MINIMALDATA"],
+["0x01 0x09", "DROP 1", "MINIMALDATA"],
+["0x01 0x0a", "DROP 1", "MINIMALDATA"],
+["0x01 0x0b", "DROP 1", "MINIMALDATA"],
+["0x01 0x0c", "DROP 1", "MINIMALDATA"],
+["0x01 0x0d", "DROP 1", "MINIMALDATA"],
+["0x01 0x0e", "DROP 1", "MINIMALDATA"],
+["0x01 0x0f", "DROP 1", "MINIMALDATA"],
+["0x01 0x10", "DROP 1", "MINIMALDATA"],
+
+["0x4c 0x48 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA",
+ "PUSHDATA1 of 72 bytes minimally represented by direct push"],
+
+["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA",
+ "PUSHDATA2 of 255 bytes minimally represented by PUSHDATA1"],
+
+["0x4f 0x00100000 0x11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "DROP 1", "MINIMALDATA",
+ "PUSHDATA4 of 256 bytes minimally represented by PUSHDATA2"],
+
+
+["MINIMALDATA enforcement for numeric arguments"],
+
+["0x01 0x00", "NOT DROP 1", "MINIMALDATA", "numequals 0"],
+["0x02 0x0000", "NOT DROP 1", "MINIMALDATA", "numequals 0"],
+["0x01 0x80", "NOT DROP 1", "MINIMALDATA", "0x80 (negative zero) numequals 0"],
+["0x02 0x0080", "NOT DROP 1", "MINIMALDATA", "numequals 0"],
+["0x02 0x0500", "NOT DROP 1", "MINIMALDATA", "numequals 5"],
+["0x03 0x050000", "NOT DROP 1", "MINIMALDATA", "numequals 5"],
+["0x02 0x0580", "NOT DROP 1", "MINIMALDATA", "numequals -5"],
+["0x03 0x050080", "NOT DROP 1", "MINIMALDATA", "numequals -5"],
+["0x03 0xff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff"],
+["0x03 0xff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xff7f"],
+["0x04 0xffff7f80", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffffff"],
+["0x04 0xffff7f00", "NOT DROP 1", "MINIMALDATA", "Minimal encoding is 0xffff7f"],
 
 ["Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule"],
 
diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json
index 89619a9dd..b2601deb5 100644
--- a/src/test/data/script_valid.json
+++ b/src/test/data/script_valid.json
@@ -527,12 +527,35 @@ nSequences are max.
 "P2SH,STRICTENC",
 "Basic PUSHDATA1 signedness check"],
 
-["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],
+["all PUSHDATA forms are equivalent"],
 
-["0x01 0x81", "0x4f EQUAL", "", "direct push of 0x81 equals 1NEGATE"],
-["0x01 0x05", "5 EQUAL", "", "direct push of 0x05 equals 5"],
 ["0x4c 0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "0x4b 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL", "", "PUSHDATA1 of 75 bytes equals direct push of it"],
 ["0x4d 0xFF00 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", "0x4c 0xFF 0x111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 EQUAL", "", "PUSHDATA2 of 255 bytes equals PUSHDATA1 of it"],
+
+["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"],
+
+["Numeric pushes"],
+
+["0x01 0x81", "0x4f EQUAL", "", "OP1_NEGATE pushes 0x81"],
+["0x01 0x01", "0x51 EQUAL", "", "OP_1  pushes 0x01"],
+["0x01 0x02", "0x52 EQUAL", "", "OP_2  pushes 0x02"],
+["0x01 0x03", "0x53 EQUAL", "", "OP_3  pushes 0x03"],
+["0x01 0x04", "0x54 EQUAL", "", "OP_4  pushes 0x04"],
+["0x01 0x05", "0x55 EQUAL", "", "OP_5  pushes 0x05"],
+["0x01 0x06", "0x56 EQUAL", "", "OP_6  pushes 0x06"],
+["0x01 0x07", "0x57 EQUAL", "", "OP_7  pushes 0x07"],
+["0x01 0x08", "0x58 EQUAL", "", "OP_8  pushes 0x08"],
+["0x01 0x09", "0x59 EQUAL", "", "OP_9  pushes 0x09"],
+["0x01 0x0a", "0x5a EQUAL", "", "OP_10 pushes 0x0a"],
+["0x01 0x0b", "0x5b EQUAL", "", "OP_11 pushes 0x0b"],
+["0x01 0x0c", "0x5c EQUAL", "", "OP_12 pushes 0x0c"],
+["0x01 0x0d", "0x5d EQUAL", "", "OP_13 pushes 0x0d"],
+["0x01 0x0e", "0x5e EQUAL", "", "OP_14 pushes 0x0e"],
+["0x01 0x0f", "0x5f EQUAL", "", "OP_15 pushes 0x0f"],
+["0x01 0x10", "0x60 EQUAL", "", "OP_16 pushes 0x10"],
+
+["Equivalency of different numeric encodings"],
+
 ["0x02 0x8000", "128 NUMEQUAL", "", "0x8000 equals 128"],
 ["0x01 0x00", "0 NUMEQUAL", "", "0x00 numequals 0"],
 ["0x01 0x80", "0 NUMEQUAL", "", "0x80 (negative zero) numequals 0"],
@@ -542,19 +565,51 @@ nSequences are max.
 ["0x03 0xff7f00", "0x02 0xff7f NUMEQUAL", "", ""],
 ["0x04 0xffff7f80", "0x03 0xffffff NUMEQUAL", "", ""],
 ["0x04 0xffff7f00", "0x03 0xffff7f NUMEQUAL", "", ""],
-["0 IF 0x01 0x81 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
-["0 IF 0x01 0x05 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
-["0 IF 0x02 0x8000 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
-["0 IF 0x01 0x00 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
-["0 IF 0x01 0x80 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
-["0 IF 0x02 0x0080 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
-["0 IF 0x02 0x0400 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
-["0 IF 0x03 0xff7f80 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
-["0 IF 0x03 0xff7f00 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
-["0 IF 0x04 0xffff7f80 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
-["0 IF 0x04 0xffff7f00 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
-["0 IF 0x4c 0x03 0x222222 ENDIF 1", "", "MINIMALDATA", "unevaluated non-minimal data"],
 
+["Unevaluated non-minimal pushes are ignored"],
+
+["0 IF 0x4c 0x00 ENDIF 1", "", "MINIMALDATA", "non-minimal PUSHDATA1 ignored"],
+["0 IF 0x4d 0x0000 ENDIF 1", "", "MINIMALDATA", "non-minimal PUSHDATA2 ignored"],
+["0 IF 0x4c 0x00000000 ENDIF 1", "", "MINIMALDATA", "non-minimal PUSHDATA4 ignored"],
+["0 IF 0x01 0x81 ENDIF 1", "", "MINIMALDATA", "1NEGATE equiv"],
+["0 IF 0x01 0x01 ENDIF 1", "", "MINIMALDATA", "OP_1  equiv"],
+["0 IF 0x01 0x02 ENDIF 1", "", "MINIMALDATA", "OP_2  equiv"],
+["0 IF 0x01 0x03 ENDIF 1", "", "MINIMALDATA", "OP_3  equiv"],
+["0 IF 0x01 0x04 ENDIF 1", "", "MINIMALDATA", "OP_4  equiv"],
+["0 IF 0x01 0x05 ENDIF 1", "", "MINIMALDATA", "OP_5  equiv"],
+["0 IF 0x01 0x06 ENDIF 1", "", "MINIMALDATA", "OP_6  equiv"],
+["0 IF 0x01 0x07 ENDIF 1", "", "MINIMALDATA", "OP_7  equiv"],
+["0 IF 0x01 0x08 ENDIF 1", "", "MINIMALDATA", "OP_8  equiv"],
+["0 IF 0x01 0x09 ENDIF 1", "", "MINIMALDATA", "OP_9  equiv"],
+["0 IF 0x01 0x0a ENDIF 1", "", "MINIMALDATA", "OP_10 equiv"],
+["0 IF 0x01 0x0b ENDIF 1", "", "MINIMALDATA", "OP_11 equiv"],
+["0 IF 0x01 0x0c ENDIF 1", "", "MINIMALDATA", "OP_12 equiv"],
+["0 IF 0x01 0x0d ENDIF 1", "", "MINIMALDATA", "OP_13 equiv"],
+["0 IF 0x01 0x0e ENDIF 1", "", "MINIMALDATA", "OP_14 equiv"],
+["0 IF 0x01 0x0f ENDIF 1", "", "MINIMALDATA", "OP_15 equiv"],
+["0 IF 0x01 0x10 ENDIF 1", "", "MINIMALDATA", "OP_16 equiv"],
+
+["Numeric minimaldata rules are only applied when a stack item is numerically evaluated; the push itself is allowed"],
+
+["0x01 0x00", "1", "MINIMALDATA"],
+["0x01 0x80", "1", "MINIMALDATA"],
+["0x02 0x0180", "1", "MINIMALDATA"],
+["0x02 0x0100", "1", "MINIMALDATA"],
+["0x02 0x0200", "1", "MINIMALDATA"],
+["0x02 0x0300", "1", "MINIMALDATA"],
+["0x02 0x0400", "1", "MINIMALDATA"],
+["0x02 0x0500", "1", "MINIMALDATA"],
+["0x02 0x0600", "1", "MINIMALDATA"],
+["0x02 0x0700", "1", "MINIMALDATA"],
+["0x02 0x0800", "1", "MINIMALDATA"],
+["0x02 0x0900", "1", "MINIMALDATA"],
+["0x02 0x0a00", "1", "MINIMALDATA"],
+["0x02 0x0b00", "1", "MINIMALDATA"],
+["0x02 0x0c00", "1", "MINIMALDATA"],
+["0x02 0x0d00", "1", "MINIMALDATA"],
+["0x02 0x0e00", "1", "MINIMALDATA"],
+["0x02 0x0f00", "1", "MINIMALDATA"],
+["0x02 0x1000", "1", "MINIMALDATA"],
 
 [
     "0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501",

From 16d78bd68e1488a2a84e368b50bf511c77392d2e Mon Sep 17 00:00:00 2001
From: Peter Todd <pete@petertodd.org>
Date: Tue, 14 Oct 2014 16:00:29 -0400
Subject: [PATCH 7/7] Add valid invert of invalid every numeric opcode tests

---
 src/test/data/script_valid.json | 49 +++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json
index b2601deb5..439c82ef3 100644
--- a/src/test/data/script_valid.json
+++ b/src/test/data/script_valid.json
@@ -611,6 +611,55 @@ nSequences are max.
 ["0x02 0x0f00", "1", "MINIMALDATA"],
 ["0x02 0x1000", "1", "MINIMALDATA"],
 
+["Valid version of the 'Test every numeric-accepting opcode for correct handling of the numeric minimal encoding rule' script_invalid test"],
+
+["1 0x02 0x0000", "PICK DROP", ""],
+["1 0x02 0x0000", "ROLL DROP 1", ""],
+["0x02 0x0000", "1ADD DROP 1", ""],
+["0x02 0x0000", "1SUB DROP 1", ""],
+["0x02 0x0000", "NEGATE DROP 1", ""],
+["0x02 0x0000", "ABS DROP 1", ""],
+["0x02 0x0000", "NOT DROP 1", ""],
+["0x02 0x0000", "0NOTEQUAL DROP 1", ""],
+
+["0 0x02 0x0000", "ADD DROP 1", ""],
+["0x02 0x0000 0", "ADD DROP 1", ""],
+["0 0x02 0x0000", "SUB DROP 1", ""],
+["0x02 0x0000 0", "SUB DROP 1", ""],
+["0 0x02 0x0000", "BOOLAND DROP 1", ""],
+["0x02 0x0000 0", "BOOLAND DROP 1", ""],
+["0 0x02 0x0000", "BOOLOR DROP 1", ""],
+["0x02 0x0000 0", "BOOLOR DROP 1", ""],
+["0 0x02 0x0000", "NUMEQUAL DROP 1", ""],
+["0x02 0x0000 1", "NUMEQUAL DROP 1", ""],
+["0 0x02 0x0000", "NUMEQUALVERIFY 1", ""],
+["0x02 0x0000 0", "NUMEQUALVERIFY 1", ""],
+["0 0x02 0x0000", "NUMNOTEQUAL DROP 1", ""],
+["0x02 0x0000 0", "NUMNOTEQUAL DROP 1", ""],
+["0 0x02 0x0000", "LESSTHAN DROP 1", ""],
+["0x02 0x0000 0", "LESSTHAN DROP 1", ""],
+["0 0x02 0x0000", "GREATERTHAN DROP 1", ""],
+["0x02 0x0000 0", "GREATERTHAN DROP 1", ""],
+["0 0x02 0x0000", "LESSTHANOREQUAL DROP 1", ""],
+["0x02 0x0000 0", "LESSTHANOREQUAL DROP 1", ""],
+["0 0x02 0x0000", "GREATERTHANOREQUAL DROP 1", ""],
+["0x02 0x0000 0", "GREATERTHANOREQUAL DROP 1", ""],
+["0 0x02 0x0000", "MIN DROP 1", ""],
+["0x02 0x0000 0", "MIN DROP 1", ""],
+["0 0x02 0x0000", "MAX DROP 1", ""],
+["0x02 0x0000 0", "MAX DROP 1", ""],
+
+["0x02 0x0000 0 0", "WITHIN DROP 1", ""],
+["0 0x02 0x0000 0", "WITHIN DROP 1", ""],
+["0 0 0x02 0x0000", "WITHIN DROP 1", ""],
+
+["0 0 0x02 0x0000", "CHECKMULTISIG DROP 1", ""],
+["0 0x02 0x0000 0", "CHECKMULTISIG DROP 1", ""],
+["0 0x02 0x0000 0 1", "CHECKMULTISIG DROP 1", ""],
+["0 0 0x02 0x0000", "CHECKMULTISIGVERIFY 1", ""],
+["0 0x02 0x0000 0", "CHECKMULTISIGVERIFY 1", ""],
+
+
 [
     "0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501",
     "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG",