EvaluateScript and IsCanonicalPubKey implementation, IsCanonicalSignature/CheckSig...
authorCryptoManiac <balthazar@yandex.ru>
Sat, 22 Aug 2015 03:33:17 +0000 (06:33 +0300)
committerCryptoManiac <balthazar@yandex.ru>
Sat, 22 Aug 2015 03:33:17 +0000 (06:33 +0300)
Novacoin/ByteQueue.cs [moved from Novacoin/WrappedList.cs with 75% similarity]
Novacoin/CScript.cs
Novacoin/Hash256.cs
Novacoin/IListExtensions.cs [new file with mode: 0644]
Novacoin/Novacoin.csproj
Novacoin/RIPEMD160.cs [new file with mode: 0644]
Novacoin/SHA1.cs [new file with mode: 0644]
Novacoin/SHA256.cs [new file with mode: 0644]
Novacoin/ScriptCode.cs

similarity index 75%
rename from Novacoin/WrappedList.cs
rename to Novacoin/ByteQueue.cs
index b8c1656..be1b639 100644 (file)
@@ -6,18 +6,18 @@ using System.Threading.Tasks;
 
 namespace Novacoin
 {
-    public class WrappedListException : Exception
+    public class ByteQueueException : Exception
     {
-        public WrappedListException()
+        public ByteQueueException()
         {
         }
 
-        public WrappedListException(string message)
+        public ByteQueueException(string message)
             : base(message)
         {
         }
 
-        public WrappedListException(string message, Exception inner)
+        public ByteQueueException(string message, Exception inner)
             : base(message, inner)
         {
         }
@@ -44,7 +44,7 @@ namespace Novacoin
         {
             if (Elements.Count <= Index)
             {
-                throw new WrappedListException("No elements left.");
+                throw new ByteQueueException("No elements left.");
             }
 
             return Elements[Index++];
@@ -59,7 +59,7 @@ namespace Novacoin
         {
             if (Elements.Count - Index < Count)
             {
-                throw new WrappedListException("Unable to read requested amount of data.");
+                throw new ByteQueueException("Unable to read requested amount of data.");
             }
 
             byte[] result = Elements.Skip(Index).Take(Count).ToArray();
@@ -72,7 +72,7 @@ namespace Novacoin
         {
             if (Elements.Count - Index < Count)
             {
-                throw new WrappedListException("Unable to read requested amount of data.");
+                throw new ByteQueueException("Unable to read requested amount of data.");
             }
 
             byte[] result = Elements.Skip(Index).Take(Count).ToArray();
@@ -80,11 +80,19 @@ namespace Novacoin
             return result;
         }
 
+        /// <summary>
+        /// Current index value
+        /// </summary>
+        public int CurrentIndex
+        {
+            get { return Index; }
+        }
+
         public IEnumerable<byte> GetEnumerable(int Count)
         {
             if (Elements.Count - Index < Count)
             {
-                throw new WrappedListException("Unable to read requested amount of data.");
+                throw new ByteQueueException("Unable to read requested amount of data.");
             }
 
             IEnumerable<byte> result = Elements.Skip(Index).Take(Count);
index 777793b..e50b2da 100644 (file)
@@ -50,7 +50,7 @@ namespace Novacoin
         /// Return a new instance of ByteQueue object for current code bytes
         /// </summary>
         /// <returns></returns>
-        public ByteQueue GetWrappedList()
+        public ByteQueue GetByteQUeue()
         {
              return new ByteQueue(codeBytes);
         }
@@ -340,7 +340,7 @@ namespace Novacoin
             // This is a pay-to-script-hash scriptPubKey;
             // get the last item that the scriptSig
             // pushes onto the stack:
-            ByteQueue wScriptSig = scriptSig.GetWrappedList();
+            ByteQueue wScriptSig = scriptSig.GetByteQUeue();
 
             opcodetype opcode; // Current opcode
             IEnumerable<byte> pushArgs; // OP_PUSHDATAn argument
index bad52d7..71de8a5 100644 (file)
@@ -8,7 +8,7 @@ using System.Security.Cryptography;
 namespace Novacoin
 {
        /// <summary>
-       /// Representation of SHA-256 hash
+       /// Representation of Double SHA-256 hash
        /// </summary>
     public class Hash256 : Hash
     {
diff --git a/Novacoin/IListExtensions.cs b/Novacoin/IListExtensions.cs
new file mode 100644 (file)
index 0000000..a8ccfd2
--- /dev/null
@@ -0,0 +1,31 @@
+\feffusing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Diagnostics.Contracts;
+
+namespace Novacoin
+{
+    static class IListExtensions
+    {
+        public static void Swap<T>(
+            this IList<T> list,
+            int firstIndex,
+            int secondIndex
+        )
+        {
+            Contract.Requires(list != null);
+            Contract.Requires(firstIndex >= 0 && firstIndex < list.Count);
+            Contract.Requires(secondIndex >= 0 && secondIndex < list.Count);
+            if (firstIndex == secondIndex)
+            {
+                return;
+            }
+            T temp = list[firstIndex];
+            list[firstIndex] = list[secondIndex];
+            list[secondIndex] = temp;
+        }
+    }
+}
index f2705ee..b8a93a9 100644 (file)
@@ -41,6 +41,7 @@
     <Compile Include="CKey.cs" />
     <Compile Include="CKeyID.cs" />
     <Compile Include="CKeyPair.cs" />
+    <Compile Include="IListExtensions.cs" />
     <Compile Include="CNovacoinAddress.cs" />
     <Compile Include="COutPoint.cs" />
     <Compile Include="CPubKey.cs" />
     <Compile Include="CScriptID.cs" />
     <Compile Include="Hash.cs" />
     <Compile Include="Interop.cs" />
+    <Compile Include="RIPEMD160.cs" />
     <Compile Include="ScryptHash256.cs" />
+    <Compile Include="SHA1.cs" />
+    <Compile Include="SHA256.cs" />
     <Compile Include="VarInt.cs" />
-    <Compile Include="WrappedList.cs" />
+    <Compile Include="ByteQueue.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="CTxIn.cs" />
     <Compile Include="CTransaction.cs" />
diff --git a/Novacoin/RIPEMD160.cs b/Novacoin/RIPEMD160.cs
new file mode 100644 (file)
index 0000000..28f5ebf
--- /dev/null
@@ -0,0 +1,39 @@
+\feffusing System;
+using System.Security.Cryptography;
+using System.Collections.Generic;
+using System.Text;
+using System.Linq;
+
+namespace Novacoin
+{
+    /// <summary>
+    /// Representation of RIPEMD-160 hash.
+    /// </summary>
+    public class RIPEMD160 : Hash
+    {
+        /// <summary>
+        /// Computes RIPEMD160 hash using managed library
+        /// </summary>
+        private static readonly RIPEMD160Managed _hasher160 = new RIPEMD160Managed();
+
+        // 20 bytes
+        public override int hashSize
+        {
+            get { return 20; }
+        }
+
+        public RIPEMD160() : base() { }
+        public RIPEMD160(byte[] bytes, int offset = 0) : base(bytes, offset) { }
+        public RIPEMD160(IEnumerable<byte> bytes, int skip = 0) : base(bytes, skip) { }
+        public RIPEMD160(RIPEMD160 h) : base(h) { }
+
+        public static RIPEMD160 Compute160(IEnumerable<byte> inputBytes)
+        {
+            byte[] dataBytes = inputBytes.ToArray();
+            byte[] digest1 = _hasher160.ComputeHash(dataBytes, 0, dataBytes.Length);
+
+            return new RIPEMD160(digest1);
+        }
+    }
+}
+
diff --git a/Novacoin/SHA1.cs b/Novacoin/SHA1.cs
new file mode 100644 (file)
index 0000000..6d60d1c
--- /dev/null
@@ -0,0 +1,41 @@
+\feffusing System;
+using System.Text;
+using System.Linq;
+using System.Collections.Generic;
+
+using System.Security.Cryptography;
+
+namespace Novacoin
+{
+    /// <summary>
+    /// Representation of SHA-256 hash
+    /// </summary>
+    public class SHA1 : Hash
+    {
+        /// <summary>
+        /// Computes RIPEMD160 hash using managed library
+        /// </summary>
+        private static readonly SHA1Managed _hasher1 = new SHA1Managed();
+
+        // 32 bytes
+        public override int hashSize
+        {
+            get { return 20; }
+        }
+
+        public SHA1() : base() { }
+        public SHA1(byte[] bytes, int offset = 0) : base(bytes, offset) { }
+        public SHA1(IEnumerable<byte> bytes, int skip = 0) : base(bytes, skip) { }
+        public SHA1(SHA1 h) : base(h) { }
+
+
+        public static SHA1 Compute1(IEnumerable<byte> inputBytes)
+        {
+            byte[] dataBytes = inputBytes.ToArray();
+            byte[] digest1 = _hasher1.ComputeHash(dataBytes, 0, dataBytes.Length);
+
+            return new SHA1(digest1);
+        }
+    }
+}
+
diff --git a/Novacoin/SHA256.cs b/Novacoin/SHA256.cs
new file mode 100644 (file)
index 0000000..b8b6086
--- /dev/null
@@ -0,0 +1,36 @@
+\feffusing System;
+using System.Text;
+using System.Linq;
+using System.Collections.Generic;
+
+using System.Security.Cryptography;
+
+namespace Novacoin
+{
+    /// <summary>
+    /// Representation of SHA-256 hash
+    /// </summary>
+    public class SHA256 : Hash
+    {
+        // 32 bytes
+        public override int hashSize
+        {
+            get { return 32; }
+        }
+
+        public SHA256() : base() { }
+        public SHA256(byte[] bytes, int offset = 0) : base(bytes, offset) { }
+        public SHA256(IEnumerable<byte> bytes, int skip = 0) : base(bytes, skip) { }
+        public SHA256(SHA256 h) : base(h) { }
+
+
+        public static SHA256 Compute256(IEnumerable<byte> inputBytes)
+        {
+            byte[] dataBytes = inputBytes.ToArray();
+            byte[] digest1 = _hasher256.ComputeHash(dataBytes, 0, dataBytes.Length);
+
+            return new SHA256(digest1);
+        }
+    }
+}
+
index 45f8098..9936f72 100644 (file)
@@ -2,8 +2,11 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
+
 using System.Numerics;
 
+// using Org.BouncyCastle.Math;
+
 namespace Novacoin
 {
     /// <summary>
@@ -179,6 +182,17 @@ namespace Novacoin
         SIGHASH_ANYONECANPAY = 0x80,
     };
 
+    /** Script verification flags */
+    public enum scriptflag
+    {
+        SCRIPT_VERIFY_NONE = 0,
+        SCRIPT_VERIFY_P2SH = (1 << 0), // evaluate P2SH (BIP16) subscripts
+        SCRIPT_VERIFY_STRICTENC = (1 << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys
+        SCRIPT_VERIFY_LOW_S = (1 << 2), // enforce low S values in signatures (depends on STRICTENC)
+        SCRIPT_VERIFY_NOCACHE = (1 << 3), // do not store results in signature cache (but do query it)
+        SCRIPT_VERIFY_NULLDUMMY = (1 << 4), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length
+    };
+
     public static class ScriptCode
     {
         public static string GetTxnOutputType(txnouttype t)
@@ -476,7 +490,7 @@ namespace Novacoin
                 // Read instruction
                 opcode = (opcodetype)codeBytes.Get();
             }
-            catch (WrappedListException)
+            catch (ByteQueueException)
             {
                 // No instruction found there
                 return false;
@@ -513,7 +527,7 @@ namespace Novacoin
                         szBytes = codeBytes.Get(4);
                     }
                 }
-                catch (WrappedListException)
+                catch (ByteQueueException)
                 {
                     // Unable to read operand length
                     return false;
@@ -529,7 +543,7 @@ namespace Novacoin
                         // Read found number of bytes into list of OP_PUSHDATAn arguments.
                         bytesRet = codeBytes.GetEnumerable(nSize);
                     }
-                    catch (WrappedListException)
+                    catch (ByteQueueException)
                     {
                         // Unable to read data
                         return false;
@@ -748,8 +762,8 @@ namespace Novacoin
                 opcodetype opcode1, opcode2;
 
                 // Compare
-                ByteQueue wl1 = script1.GetWrappedList();
-                ByteQueue wl2 = script2.GetWrappedList();
+                ByteQueue wl1 = script1.GetByteQUeue();
+                ByteQueue wl2 = script2.GetByteQUeue();
 
                 IEnumerable<byte> args1, args2;
 
@@ -1028,10 +1042,916 @@ namespace Novacoin
         {
             if (value.Count() > 4)
             {
-                throw new StackMachineException("CastToBigNum() : overflow");
+                throw new StackMachineException("CastToBigInteger() : overflow");
             }
 
             return new BigInteger(value.ToArray());
         }
-    };
+
+        static bool EvalScript(ref List<IEnumerable<byte>> stack, CScript script, CTransaction txTo, int nIn, int flags, int nHashType)
+        {
+            ByteQueue pc = script.GetByteQUeue();
+
+            ByteQueue pbegincodehash = script.GetByteQUeue();
+
+            opcodetype opcode;
+            IEnumerable<byte> vchPushValue;
+
+            List<bool> vfExec = new List<bool>();
+            List<IEnumerable<byte>> altstack = new List<IEnumerable<byte>>();
+
+            byte[] vchFalse = new byte[0];
+            byte[] vchTrue = new byte[] { 0x01 };
+
+            if (script.Bytes.Count() > 10000)
+            {
+                return false;
+            }
+
+            int nOpCount = 0;
+
+            while (true)
+            {
+                bool fExec = false;
+                foreach (bool fValue in vfExec)
+                {
+                    if (!fValue)
+                    {
+                        fExec = true;
+                        break;
+                    }
+                }
+
+                //
+                // Read instruction
+                //
+                if (!GetOp(ref pc, out opcode, out vchPushValue))
+                    return false;
+                if (vchPushValue.Count() > 520) // Check against MAX_SCRIPT_ELEMENT_SIZE
+                    return false;
+                if (opcode > opcodetype.OP_16 && ++nOpCount > 201)
+                    return false;
+
+                if (opcode == opcodetype.OP_CAT ||
+                    opcode == opcodetype.OP_SUBSTR ||
+                    opcode == opcodetype.OP_LEFT ||
+                    opcode == opcodetype.OP_RIGHT ||
+                    opcode == opcodetype.OP_INVERT ||
+                    opcode == opcodetype.OP_AND ||
+                    opcode == opcodetype.OP_OR ||
+                    opcode == opcodetype.OP_XOR ||
+                    opcode == opcodetype.OP_2MUL ||
+                    opcode == opcodetype.OP_2DIV ||
+                    opcode == opcodetype.OP_MUL ||
+                    opcode == opcodetype.OP_DIV ||
+                    opcode == opcodetype.OP_MOD ||
+                    opcode == opcodetype.OP_LSHIFT ||
+                    opcode == opcodetype.OP_RSHIFT)
+                    return false; // Disabled opcodes.
+
+                if (fExec && 0 <= opcode && opcode <= opcodetype.OP_PUSHDATA4)
+                {
+                    stack.Add(vchPushValue);
+                }
+                else if (fExec || (opcodetype.OP_IF <= opcode && opcode <= opcodetype.OP_ENDIF))
+                    switch (opcode)
+                    {
+                        //
+                        // Push value
+                        //
+                        case opcodetype.OP_1NEGATE:
+                        case opcodetype.OP_1:
+                        case opcodetype.OP_2:
+                        case opcodetype.OP_3:
+                        case opcodetype.OP_4:
+                        case opcodetype.OP_5:
+                        case opcodetype.OP_6:
+                        case opcodetype.OP_7:
+                        case opcodetype.OP_8:
+                        case opcodetype.OP_9:
+                        case opcodetype.OP_10:
+                        case opcodetype.OP_11:
+                        case opcodetype.OP_12:
+                        case opcodetype.OP_13:
+                        case opcodetype.OP_14:
+                        case opcodetype.OP_15:
+                        case opcodetype.OP_16:
+                            {
+                                // ( -- value)
+                                BigInteger bn = new BigInteger((int)opcode - (int)(opcodetype.OP_1 - 1));
+                                stack.Add(bn.ToByteArray());
+                            }
+                            break;
+
+
+                        //
+                        // Control
+                        //
+                        case opcodetype.OP_NOP:
+                        case opcodetype.OP_NOP1:
+                        case opcodetype.OP_NOP2:
+                        case opcodetype.OP_NOP3:
+                        case opcodetype.OP_NOP4:
+                        case opcodetype.OP_NOP5:
+                        case opcodetype.OP_NOP6:
+                        case opcodetype.OP_NOP7:
+                        case opcodetype.OP_NOP8:
+                        case opcodetype.OP_NOP9:
+                        case opcodetype.OP_NOP10:
+                            break;
+
+                        case opcodetype.OP_IF:
+                        case opcodetype.OP_NOTIF:
+                            {
+                                // <expression> if [statements] [else [statements]] endif
+                                bool fValue = false;
+                                if (fExec)
+                                {
+                                    if (stack.Count() < 1)
+                                    {
+                                        return false;
+                                    }
+                                    IEnumerable<byte> vch = stacktop(ref stack, -1);
+                                    fValue = CastToBool(vch);
+                                    if (opcode == opcodetype.OP_NOTIF)
+                                    {
+                                        fValue = !fValue;
+                                    }
+                                    popstack(ref stack);
+                                }
+                                vfExec.Add(fValue);
+                            }
+                            break;
+
+                        case opcodetype.OP_ELSE:
+                            {
+                                int nExecCount = vfExec.Count();
+                                if (nExecCount == 0)
+                                {
+                                    return false;
+                                }
+                                vfExec[nExecCount - 1] = !vfExec[nExecCount - 1];
+                            }
+                            break;
+
+                        case opcodetype.OP_ENDIF:
+                            {
+                                int nExecCount = vfExec.Count();
+                                if (nExecCount == 0)
+                                {
+                                    return false;
+                                }
+                                vfExec.RemoveAt(nExecCount - 1);
+                            }
+                            break;
+
+                        case opcodetype.OP_VERIFY:
+                            {
+                                // (true -- ) or
+                                // (false -- false) and return
+                                if (stack.Count() < 1)
+                                {
+                                    return false;
+                                }
+
+                                bool fValue = CastToBool(stacktop(ref stack, -1));
+                                if (fValue)
+                                {
+                                    popstack(ref stack);
+                                }
+                                else
+                                {
+                                    return false;
+                                }
+                            }
+                            break;
+
+                        case opcodetype.OP_RETURN:
+                            return false;
+                        //
+                        // Stack ops
+                        //
+                        case opcodetype.OP_TOALTSTACK:
+                            {
+                                if (stack.Count() < 1)
+                                {
+                                    return false;
+                                }
+                                altstack.Add(stacktop(ref stack, -1));
+                                popstack(ref stack);
+                            }
+                            break;
+
+                        case opcodetype.OP_FROMALTSTACK:
+                            {
+                                if (altstack.Count() < 1)
+                                {
+                                    return false;
+                                }
+                                stack.Add(stacktop(ref stack, -1));
+                                popstack(ref altstack);
+                            }
+                            break;
+
+                        case opcodetype.OP_2DROP:
+                            {
+                                // (x1 x2 -- )
+                                if (stack.Count() < 2)
+                                {
+                                    return false;
+                                }
+                                popstack(ref stack);
+                                popstack(ref stack);
+                            }
+                            break;
+
+                        case opcodetype.OP_2DUP:
+                            {
+                                // (x1 x2 -- x1 x2 x1 x2)
+                                if (stack.Count() < 2)
+                                {
+                                    return false;
+                                }
+                                IEnumerable<byte> vch1 = stacktop(ref stack, -2);
+                                IEnumerable<byte> vch2 = stacktop(ref stack, -1);
+                                stack.Add(vch1);
+                                stack.Add(vch2);
+                            }
+                            break;
+
+                        case opcodetype.OP_3DUP:
+                            {
+                                // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)
+                                if (stack.Count() < 3)
+                                {
+                                    return false;
+                                }
+                                IEnumerable<byte> vch1 = stacktop(ref stack, -3);
+                                IEnumerable<byte> vch2 = stacktop(ref stack, -2);
+                                IEnumerable<byte> vch3 = stacktop(ref stack, -1);
+                                stack.Add(vch1);
+                                stack.Add(vch2);
+                                stack.Add(vch3);
+                            }
+                            break;
+
+                        case opcodetype.OP_2OVER:
+                            {
+                                // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
+                                if (stack.Count() < 4)
+                                {
+                                    return false;
+                                }
+                                IEnumerable<byte> vch1 = stacktop(ref stack, -4);
+                                IEnumerable<byte> vch2 = stacktop(ref stack, -3);
+                                stack.Add(vch1);
+                                stack.Add(vch2);
+                            }
+                            break;
+
+                        case opcodetype.OP_2ROT:
+                            {
+                                int nStackDepth = stack.Count();
+                                // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
+                                if (nStackDepth < 6)
+                                {
+                                    return false;
+                                }
+                                IEnumerable<byte> vch1 = stacktop(ref stack, -6);
+                                IEnumerable<byte> vch2 = stacktop(ref stack, -5);
+                                stack.RemoveRange(nStackDepth - 6, 2);
+                                stack.Add(vch1);
+                                stack.Add(vch2);
+                            }
+                            break;
+
+                        case opcodetype.OP_2SWAP:
+                            {
+                                // (x1 x2 x3 x4 -- x3 x4 x1 x2)
+                                int nStackDepth = stack.Count();
+                                if (nStackDepth < 4)
+                                {
+                                    return false;
+                                }
+                                stack.Swap(nStackDepth - 4, nStackDepth - 2);
+                                stack.Swap(nStackDepth - 3, nStackDepth - 1);
+                            }
+                            break;
+
+                        case opcodetype.OP_IFDUP:
+                            {
+                                // (x - 0 | x x)
+                                if (stack.Count() < 1)
+                                {
+                                    return false;
+                                }
+
+                                IEnumerable<byte> vch = stacktop(ref stack, -1);
+
+                                if (CastToBool(vch))
+                                {
+                                    stack.Add(vch);
+                                }
+                            }
+                            break;
+
+                        case opcodetype.OP_DEPTH:
+                            {
+                                // -- stacksize
+                                BigInteger bn = new BigInteger((ushort)stack.Count());
+                                stack.Add(bn.ToByteArray());
+                            }
+                            break;
+
+                        case opcodetype.OP_DROP:
+                            {
+                                // (x -- )
+                                if (stack.Count() < 1)
+                                {
+                                    return false;
+                                }
+
+                                popstack(ref stack);
+                            }
+                            break;
+
+                        case opcodetype.OP_DUP:
+                            {
+                                // (x -- x x)
+                                if (stack.Count() < 1)
+                                {
+                                    return false;
+                                }
+
+                                IEnumerable<byte> vch = stacktop(ref stack, -1);
+                                stack.Add(vch);
+                            }
+                            break;
+
+                        case opcodetype.OP_NIP:
+                            {
+                                // (x1 x2 -- x2)
+                                int nStackDepth = stack.Count();
+                                if (nStackDepth < 2)
+                                {
+                                    return false;
+                                }
+
+                                stack.RemoveAt(nStackDepth - 2);
+                            }
+                            break;
+
+                        case opcodetype.OP_OVER:
+                            {
+                                // (x1 x2 -- x1 x2 x1)
+                                if (stack.Count() < 2)
+                                {
+                                    return false;
+                                }
+
+                                IEnumerable<byte> vch = stacktop(ref stack, -2);
+                                stack.Add(vch);
+                            }
+                            break;
+
+                        case opcodetype.OP_PICK:
+                        case opcodetype.OP_ROLL:
+                            {
+                                // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
+                                // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
+
+                                int nStackDepth = stack.Count();
+                                if (nStackDepth < 2)
+                                {
+                                    return false;
+                                }
+
+                                int n = (int)CastToBigInteger(stacktop(ref stack, -1));
+                                popstack(ref stack);
+
+                                if (n < 0 || n >= stack.Count())
+                                {
+                                    return false;
+                                }
+
+                                IEnumerable<byte> vch = stacktop(ref stack, -n - 1);
+                                if (opcode == opcodetype.OP_ROLL)
+                                {
+                                    stack.RemoveAt(nStackDepth - n - 1);
+                                }
+
+                                stack.Add(vch);
+                            }
+                            break;
+
+                        case opcodetype.OP_ROT:
+                            {
+                                // (x1 x2 x3 -- x2 x3 x1)
+                                //  x2 x1 x3  after first swap
+                                //  x2 x3 x1  after second swap
+                                int nStackDepth = stack.Count();
+                                if (nStackDepth < 3)
+                                {
+                                    return false;
+                                }
+                                stack.Swap(nStackDepth - 3, nStackDepth - 2);
+                                stack.Swap(nStackDepth - 2, nStackDepth - 1);
+
+                            }
+                            break;
+
+                        case opcodetype.OP_SWAP:
+                            {
+                                // (x1 x2 -- x2 x1)
+                                int nStackDepth = stack.Count();
+                                if (nStackDepth < 2)
+                                {
+                                    return false;
+                                }
+                                stack.Swap(nStackDepth - 2, nStackDepth - 1);
+                            }
+                            break;
+
+                        case opcodetype.OP_TUCK:
+                            {
+                                // (x1 x2 -- x2 x1 x2)
+                                int nStackDepth = stack.Count();
+                                if (nStackDepth < 2)
+                                {
+                                    return false;
+                                }
+                                IEnumerable<byte> vch = stacktop(ref stack, -1);
+                                stack.Insert(nStackDepth - 2, vch);
+                            }
+                            break;
+
+
+                        case opcodetype.OP_SIZE:
+                            {
+                                // (in -- in size)
+                                if (stack.Count() < 1)
+                                {
+                                    return false;
+                                }
+
+                                BigInteger bnSize = new BigInteger((ushort)stacktop(ref stack, -1).Count());
+                                stack.Add(bnSize.ToByteArray());
+                            }
+                            break;
+
+
+                        //
+                        // Bitwise logic
+                        //
+                        case opcodetype.OP_EQUAL:
+                        case opcodetype.OP_EQUALVERIFY:
+                            //case opcodetype.OP_NOTEQUAL: // use OP_NUMNOTEQUAL
+                            {
+                                // (x1 x2 - bool)
+                                if (stack.Count() < 2)
+                                {
+                                    return false;
+                                }
+
+                                IEnumerable<byte> vch1 = stacktop(ref stack, -2);
+                                IEnumerable<byte> vch2 = stacktop(ref stack, -1);
+                                bool fEqual = (vch1 == vch2);
+                                // OP_NOTEQUAL is disabled because it would be too easy to say
+                                // something like n != 1 and have some wiseguy pass in 1 with extra
+                                // zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001)
+                                //if (opcode == opcodetype.OP_NOTEQUAL)
+                                //    fEqual = !fEqual;
+                                popstack(ref stack);
+                                popstack(ref stack);
+                                stack.Add(fEqual ? vchTrue : vchFalse);
+
+                                if (opcode == opcodetype.OP_EQUALVERIFY)
+                                {
+                                    if (fEqual)
+                                    {
+                                        popstack(ref stack);
+                                    }
+                                    else
+                                    {
+                                        return false;
+                                    }
+                                }
+                            }
+                            break;
+
+
+                        //
+                        // Numeric
+                        //
+                        case opcodetype.OP_1ADD:
+                        case opcodetype.OP_1SUB:
+                        case opcodetype.OP_NEGATE:
+                        case opcodetype.OP_ABS:
+                        case opcodetype.OP_NOT:
+                        case opcodetype.OP_0NOTEQUAL:
+                            {
+                                // (in -- out)
+                                if (stack.Count() < 1)
+                                {
+                                    return false;
+                                }
+
+                                BigInteger bn = CastToBigInteger(stacktop(ref stack, -1));
+                                switch (opcode)
+                                {
+                                    case opcodetype.OP_1ADD:
+                                        bn = bn + 1;
+                                        break;
+                                    case opcodetype.OP_1SUB:
+                                        bn = bn - 1;
+                                        break;
+                                    case opcodetype.OP_NEGATE:
+                                        bn = -bn;
+                                        break;
+                                    case opcodetype.OP_ABS:
+                                        bn = BigInteger.Abs(bn);
+                                        break;
+                                    case opcodetype.OP_NOT:
+                                        bn = bn == 0 ? 1 : 0;
+                                        break;
+                                    case opcodetype.OP_0NOTEQUAL:
+                                        bn = bn != 0 ? 1 : 0;
+                                        break;
+
+                                    default:
+                                        throw new StackMachineException("invalid opcode");
+                                        break;
+                                }
+
+                                popstack(ref stack);
+                                stack.Add(bn.ToByteArray());
+                            }
+                            break;
+
+                        case opcodetype.OP_ADD:
+                        case opcodetype.OP_SUB:
+                        case opcodetype.OP_BOOLAND:
+                        case opcodetype.OP_BOOLOR:
+                        case opcodetype.OP_NUMEQUAL:
+                        case opcodetype.OP_NUMEQUALVERIFY:
+                        case opcodetype.OP_NUMNOTEQUAL:
+                        case opcodetype.OP_LESSTHAN:
+                        case opcodetype.OP_GREATERTHAN:
+                        case opcodetype.OP_LESSTHANOREQUAL:
+                        case opcodetype.OP_GREATERTHANOREQUAL:
+                        case opcodetype.OP_MIN:
+                        case opcodetype.OP_MAX:
+                            {
+                                // (x1 x2 -- out)
+                                if (stack.Count() < 2)
+                                {
+                                    return false;
+                                }
+
+                                BigInteger bn1 = CastToBigInteger(stacktop(ref stack, -2));
+                                BigInteger bn2 = CastToBigInteger(stacktop(ref stack, -1));
+                                BigInteger bn = 0;
+
+                                switch (opcode)
+                                {
+                                    case opcodetype.OP_ADD:
+                                        bn = bn1 + bn2;
+                                        break;
+                                    case opcodetype.OP_SUB:
+                                        bn = bn1 - bn2;
+                                        break;
+                                    case opcodetype.OP_BOOLAND:
+                                        bn = (bn1 != 0 && bn2 != 0) ? 1 : 0;
+                                        break;
+                                    case opcodetype.OP_BOOLOR:
+                                        bn = (bn1 != 0 || bn2 != 0) ? 1 : 0;
+                                        break;
+                                    case opcodetype.OP_NUMEQUAL:
+                                        bn = (bn1 == bn2) ? 1 : 0;
+                                        break;
+                                    case opcodetype.OP_NUMEQUALVERIFY:
+                                        bn = (bn1 == bn2) ? 1 : 0;
+                                        break;
+                                    case opcodetype.OP_NUMNOTEQUAL:
+                                        bn = (bn1 != bn2) ? 1 : 0;
+                                        break;
+                                    case opcodetype.OP_LESSTHAN:
+                                        bn = (bn1 < bn2) ? 1 : 0;
+                                        break;
+                                    case opcodetype.OP_GREATERTHAN:
+                                        bn = (bn1 > bn2) ? 1 : 0;
+                                        break;
+                                    case opcodetype.OP_LESSTHANOREQUAL:
+                                        bn = (bn1 <= bn2) ? 1 : 0;
+                                        break;
+                                    case opcodetype.OP_GREATERTHANOREQUAL:
+                                        bn = (bn1 >= bn2) ? 1 : 0;
+                                        break;
+                                    case opcodetype.OP_MIN:
+                                        bn = (bn1 < bn2 ? bn1 : bn2);
+                                        break;
+                                    case opcodetype.OP_MAX:
+                                        bn = (bn1 > bn2 ? bn1 : bn2);
+                                        break;
+
+                                    default:
+                                        throw new StackMachineException("invalid opcode");
+                                        break;
+                                }
+
+                                popstack(ref stack);
+                                popstack(ref stack);
+                                stack.Add(bn.ToByteArray());
+
+                                if (opcode == opcodetype.OP_NUMEQUALVERIFY)
+                                {
+                                    if (CastToBool(stacktop(ref stack, -1)))
+                                    {
+                                        popstack(ref stack);
+                                    }
+                                    else
+                                    {
+                                        return false;
+                                    }
+                                }
+                            }
+                            break;
+
+                        case opcodetype.OP_WITHIN:
+                            {
+                                // (x min max -- out)
+                                if (stack.Count() < 3)
+                                    return false;
+                                BigInteger bn1 = CastToBigInteger(stacktop(ref stack, -3));
+                                BigInteger bn2 = CastToBigInteger(stacktop(ref stack, -2));
+                                BigInteger bn3 = CastToBigInteger(stacktop(ref stack, -1));
+                                bool fValue = (bn2 <= bn1 && bn1 < bn3);
+                                popstack(ref stack);
+                                popstack(ref stack);
+                                popstack(ref stack);
+                                stack.Add(fValue ? vchTrue : vchFalse);
+                            }
+                            break;
+
+
+                        //
+                        // Crypto
+                        //
+                        case opcodetype.OP_RIPEMD160:
+                        case opcodetype.OP_SHA1:
+                        case opcodetype.OP_SHA256:
+                        case opcodetype.OP_HASH160:
+                        case opcodetype.OP_HASH256:
+                            {
+                                // (in -- hash)
+                                if (stack.Count() < 1)
+                                    return false;
+                                IEnumerable<byte> vch = stacktop(ref stack, -1);
+                                IEnumerable<byte> vchHash = null;
+                                if (opcode == opcodetype.OP_RIPEMD160)
+                                {
+                                    RIPEMD160 hash = RIPEMD160.Compute160(vch);
+                                    vchHash = hash.hashBytes;
+                                }
+                                else if (opcode == opcodetype.OP_SHA1)
+                                {
+                                    SHA1 hash = SHA1.Compute1(vch);
+                                    vchHash = hash.hashBytes;
+                                }
+                                else if (opcode == opcodetype.OP_SHA256)
+                                {
+                                    SHA256 hash = SHA256.Compute256(vch);
+                                    vchHash = hash.hashBytes;
+                                }
+                                else if (opcode == opcodetype.OP_HASH160)
+                                {
+                                    Hash160 hash = Hash160.Compute160(vch);
+                                    vchHash = hash.hashBytes;
+                                }
+                                else if (opcode == opcodetype.OP_HASH256)
+                                {
+                                    Hash256 hash = Hash256.Compute256(vch);
+                                    vchHash = hash.hashBytes;
+                                }
+                                popstack(ref stack);
+                                stack.Add(vchHash);
+                            }
+                            break;
+
+                        case opcodetype.OP_CODESEPARATOR:
+                            {
+                                // Hash starts after the code separator
+                                pbegincodehash = pc;
+                            }
+                            break;
+
+                        case opcodetype.OP_CHECKSIG:
+                        case opcodetype.OP_CHECKSIGVERIFY:
+                            {
+                                // (sig pubkey -- bool)
+                                if (stack.Count() < 2)
+                                {
+                                    return false;
+                                }
+
+                                IList<byte> sigBytes = stacktop(ref stack, -2).ToList();
+                                IList<byte> pubkeyBytes = stacktop(ref stack, -1).ToList();
+
+                                // Subset of script starting at the most recent codeseparator
+                                CScript scriptCode = new CScript(script.Bytes.Skip(pbegincodehash.CurrentIndex));
+
+                                // There's no way for a signature to sign itself
+                                scriptCode.RemovePattern(sigBytes);
+
+                                bool fSuccess = IsCanonicalSignature(sigBytes, flags) && IsCanonicalPubKey(pubkeyBytes.ToList(), flags) && CheckSig(sigBytes, pubkeyBytes, scriptCode, txTo, nIn, nHashType, flags);
+
+                                popstack(ref stack);
+                                popstack(ref stack);
+                                stack.Add(fSuccess ? vchTrue : vchFalse);
+                                if (opcode == opcodetype.OP_CHECKSIGVERIFY)
+                                {
+                                    if (fSuccess)
+                                    {
+                                        popstack(ref stack);
+                                    }
+                                    else
+                                    {
+                                        return false;
+                                    }
+                                }
+                            }
+                            break;
+
+                        case opcodetype.OP_CHECKMULTISIG:
+                        case opcodetype.OP_CHECKMULTISIGVERIFY:
+                            {
+                                // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool)
+
+                                int i = 1;
+                                if (stack.Count() < i)
+                                {
+                                    return false;
+                                }
+
+                                int nKeysCount = (int)CastToBigInteger(stacktop(ref stack, -i));
+                                if (nKeysCount < 0 || nKeysCount > 20)
+                                {
+                                    return false;
+                                }
+                                nOpCount += nKeysCount;
+                                if (nOpCount > 201)
+                                {
+                                    return false;
+                                }
+                                int ikey = ++i;
+                                i += nKeysCount;
+                                if (stack.Count() < i)
+                                {
+                                    return false;
+                                }
+
+                                int nSigsCount = (int)CastToBigInteger(stacktop(ref stack, -i));
+                                if (nSigsCount < 0 || nSigsCount > nKeysCount)
+                                {
+                                    return false;
+                                }
+                                int isig = ++i;
+                                i += nSigsCount;
+                                if (stack.Count() < i)
+                                {
+                                    return false;
+                                }
+
+                                // Subset of script starting at the most recent codeseparator
+                                CScript scriptCode = new CScript(script.Bytes.Skip(pbegincodehash.CurrentIndex));
+
+                                // There is no way for a signature to sign itself, so we need to drop the signatures
+                                for (int k = 0; k < nSigsCount; k++)
+                                {
+                                    IEnumerable<byte> vchSig = stacktop(ref stack, -isig - k);
+                                    scriptCode.RemovePattern(vchSig.ToList());
+                                }
+
+                                bool fSuccess = true;
+                                while (fSuccess && nSigsCount > 0)
+                                {
+                                    IList<byte> sigBytes = stacktop(ref stack, -isig).ToList();
+                                    IList<byte> pubKeyBytes = stacktop(ref stack, -ikey).ToList();
+
+                                    // Check signature
+                                    bool fOk = IsCanonicalSignature(sigBytes, flags) && IsCanonicalPubKey(pubKeyBytes.ToList(), flags) && CheckSig(sigBytes, pubKeyBytes, scriptCode, txTo, nIn, nHashType, flags);
+
+                                    if (fOk)
+                                    {
+                                        isig++;
+                                        nSigsCount--;
+                                    }
+                                    ikey++;
+                                    nKeysCount--;
+
+                                    // If there are more signatures left than keys left,
+                                    // then too many signatures have failed
+                                    if (nSigsCount > nKeysCount)
+                                    {
+                                        fSuccess = false;
+                                    }
+                                }
+
+                                while (i-- > 1)
+                                {
+                                    popstack(ref stack);
+                                }
+
+                                // A bug causes CHECKMULTISIG to consume one extra argument
+                                // whose contents were not checked in any way.
+                                //
+                                // Unfortunately this is a potential source of mutability,
+                                // so optionally verify it is exactly equal to zero prior
+                                // to removing it from the stack.
+                                if (stack.Count() < 1)
+                                {
+                                    return false;
+                                }
+                                if ((flags & (int)scriptflag.SCRIPT_VERIFY_NULLDUMMY) != 0 && stacktop(ref stack, -1).Count() != 0)
+                                {
+                                    return false; // CHECKMULTISIG dummy argument not null
+                                }
+                                popstack(ref stack);
+
+                                stack.Add(fSuccess ? vchTrue : vchFalse);
+
+                                if (opcode == opcodetype.OP_CHECKMULTISIGVERIFY)
+                                {
+                                    if (fSuccess)
+                                    {
+                                        popstack(ref stack);
+                                    }
+                                    else
+                                    {
+                                        return false;
+                                    }
+                                }
+                            }
+                            break;
+
+                        default:
+                            return false;
+                    }
+
+                // Size limits
+                if (stack.Count() + altstack.Count() > 1000)
+                {
+                    return false;
+                }
+            }
+
+
+            if (vfExec.Count() == 0)
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+
+        static bool IsCanonicalPubKey(IList<byte> pubKeyBytes, int flags)
+        {
+            if ((flags & (int)scriptflag.SCRIPT_VERIFY_STRICTENC) == 0)
+                return true;
+
+            if (pubKeyBytes.Count() < 33)
+                return false;  // Non-canonical public key: too short
+            if (pubKeyBytes[0] == 0x04)
+            {
+                if (pubKeyBytes.Count() != 65)
+                    return false; // Non-canonical public key: invalid length for uncompressed key
+            }
+            else if (pubKeyBytes[0] == 0x02 || pubKeyBytes[0] == 0x03)
+            {
+                if (pubKeyBytes.Count() != 33)
+                    return false; // Non-canonical public key: invalid length for compressed key
+            }
+            else
+            {
+                return false; // Non-canonical public key: compressed nor uncompressed
+            }
+            return true;
+        }
+
+        static bool IsCanonicalSignature(IList<byte> sigBytes, int flags)
+        {
+            // STUB
+
+            return true;
+        }
+
+
+        static bool CheckSig(IList<byte> sigBytes, IList<byte> pubKeyBytes, CScript scriptCode, CTransaction txTo, int nIn, int nHashType, int flags)
+        {
+            // STUB
+            return true;
+        }
+
+};
 }