Example #1
0
		//https://en.bitcoin.it/wiki/OP_CHECKSIG
		public uint256 SignatureHash(Transaction txTo, int nIn, SigHash nHashType)
		{
			if(nIn >= txTo.Inputs.Count)
			{
				Utils.log("ERROR: SignatureHash() : nIn=" + nIn + " out of range\n");
				return uint256.One;
			}

			// Check for invalid use of SIGHASH_SINGLE
			if(nHashType == SigHash.Single)
			{
				if(nIn >= txTo.Outputs.Count)
				{
					Utils.log("ERROR: SignatureHash() : nOut=" + nIn + " out of range\n");
					return uint256.One;
				}
			}

			var scriptCopy = new Script(_Script);
			scriptCopy.FindAndDelete(OpcodeType.OP_CODESEPARATOR);

			var txCopy = new Transaction(txTo.ToBytes());

			//Set all TxIn script to empty string
			foreach(var txin in txCopy.Inputs)
			{
				txin.ScriptSig = new Script();
			}
			//Copy subscript into the txin script you are checking
			txCopy.Inputs[nIn].ScriptSig = scriptCopy;

			var hashType = nHashType & (SigHash)31;
			if(hashType == SigHash.None)
			{
				//The output of txCopy is set to a vector of zero size.
				txCopy.Outputs.Clear();

				//All other inputs aside from the current input in txCopy have their nSequence index set to zero
				foreach(var input in txCopy.Inputs.Where((x, i) => i != nIn))
					input.Sequence = 0;
			}
			else if(hashType == SigHash.Single)
			{
				//The output of txCopy is resized to the size of the current input index+1.
				txCopy.Outputs.RemoveRange(nIn + 1, txCopy.Outputs.Count - (nIn + 1));
				//All other txCopy outputs aside from the output that is the same as the current input index are set to a blank script and a value of (long) -1.
				for(var i = 0 ; i < txCopy.Outputs.Count ; i++)
				{
					if(i == nIn)
						continue;
					txCopy.Outputs[i] = new TxOut();
				}
				//All other txCopy inputs aside from the current input are set to have an nSequence index of zero.
				foreach(var input in txCopy.Inputs.Where((x, i) => i != nIn))
					input.Sequence = 0;
			}


			if((nHashType & SigHash.AnyoneCanPay) != 0)
			{
				//The txCopy input vector is resized to a length of one.
				var script = txCopy.Inputs[nIn];
				txCopy.Inputs.Clear();
				txCopy.Inputs.Add(script);
				//The subScript (lead in by its length as a var-integer encoded!) is set as the first and only member of this vector.
				txCopy.Inputs[0].ScriptSig = scriptCopy;
			}


			//Serialize TxCopy, append 4 byte hashtypecode
			var ms = new MemoryStream();
			var bitcoinStream = new BitcoinStream(ms, true);
			txCopy.ReadWrite(bitcoinStream);
			bitcoinStream.ReadWrite((uint)nHashType);

			var hashed = ms.ToArray();
			return Hashes.Hash256(hashed);
		}
Example #2
0
        //https://en.bitcoin.it/wiki/OP_CHECKSIG
        public static uint256 SignatureHash(Script scriptCode, Transaction txTo, int nIn, SigHash nHashType, Money amount, HashVersion sigversion, PrecomputedTransactionData precomputedTransactionData)
        {
            if (sigversion == HashVersion.Witness)
            {
                if (amount == null)
                {
                    throw new ArgumentException("The amount of the output being signed must be provided", "amount");
                }
                uint256 hashPrevouts = uint256.Zero;
                uint256 hashSequence = uint256.Zero;
                uint256 hashOutputs  = uint256.Zero;

                if ((nHashType & SigHash.AnyoneCanPay) == 0)
                {
                    hashPrevouts = precomputedTransactionData == null?
                                   GetHashPrevouts(txTo) : precomputedTransactionData.HashPrevouts;
                }

                if ((nHashType & SigHash.AnyoneCanPay) == 0 && ((uint)nHashType & 0x1f) != (uint)SigHash.Single && ((uint)nHashType & 0x1f) != (uint)SigHash.None)
                {
                    hashSequence = precomputedTransactionData == null?
                                   GetHashSequence(txTo) : precomputedTransactionData.HashSequence;
                }

                if (((uint)nHashType & 0x1f) != (uint)SigHash.Single && ((uint)nHashType & 0x1f) != (uint)SigHash.None)
                {
                    hashOutputs = precomputedTransactionData == null?
                                  GetHashOutputs(txTo) : precomputedTransactionData.HashOutputs;
                }
                else if (((uint)nHashType & 0x1f) == (uint)SigHash.Single && nIn < txTo.Outputs.Count)
                {
                    BitcoinStream ss = CreateHashWriter(sigversion);
                    ss.ReadWrite(txTo.Outputs[nIn]);
                    hashOutputs = GetHash(ss);
                }

                BitcoinStream sss = CreateHashWriter(sigversion);
                // Version
                sss.ReadWrite(txTo.Version);
                // Input prevouts/nSequence (none/all, depending on flags)
                sss.ReadWrite(hashPrevouts);
                sss.ReadWrite(hashSequence);
                // The input being signed (replacing the scriptSig with scriptCode + amount)
                // The prevout may already be contained in hashPrevout, and the nSequence
                // may already be contain in hashSequence.
                sss.ReadWrite(txTo.Inputs[nIn].PrevOut);
                sss.ReadWrite(scriptCode);
                sss.ReadWrite(amount.Satoshi);
                sss.ReadWrite((uint)txTo.Inputs[nIn].Sequence);
                // Outputs (none/one/all, depending on flags)
                sss.ReadWrite(hashOutputs);
                // Locktime
                sss.ReadWriteStruct(txTo.LockTime);
                // Sighash type
                sss.ReadWrite((uint)nHashType);

                return(GetHash(sss));
            }



            if (nIn >= txTo.Inputs.Count)
            {
                Utils.log("ERROR: SignatureHash() : nIn=" + nIn + " out of range\n");
                return(uint256.One);
            }

            // Check for invalid use of SIGHASH_SINGLE
            if (nHashType == SigHash.Single)
            {
                if (nIn >= txTo.Outputs.Count)
                {
                    Utils.log("ERROR: SignatureHash() : nOut=" + nIn + " out of range\n");
                    return(uint256.One);
                }
            }

            var scriptCopy = new Script(scriptCode._Script);

            scriptCopy.FindAndDelete(OpcodeType.OP_CODESEPARATOR);

            var txCopy = new Transaction(txTo.ToBytes());

            //Set all TxIn script to empty string
            foreach (var txin in txCopy.Inputs)
            {
                txin.ScriptSig = new Script();
            }
            //Copy subscript into the txin script you are checking
            txCopy.Inputs[nIn].ScriptSig = scriptCopy;

            var hashType = nHashType & (SigHash)31;

            if (hashType == SigHash.None)
            {
                //The output of txCopy is set to a vector of zero size.
                txCopy.Outputs.Clear();

                //All other inputs aside from the current input in txCopy have their nSequence index set to zero
                foreach (var input in txCopy.Inputs.Where((x, i) => i != nIn))
                {
                    input.Sequence = 0;
                }
            }
            else if (hashType == SigHash.Single)
            {
                //The output of txCopy is resized to the size of the current input index+1.
                txCopy.Outputs.RemoveRange(nIn + 1, txCopy.Outputs.Count - (nIn + 1));
                //All other txCopy outputs aside from the output that is the same as the current input index are set to a blank script and a value of (long) -1.
                for (var i = 0; i < txCopy.Outputs.Count; i++)
                {
                    if (i == nIn)
                    {
                        continue;
                    }
                    txCopy.Outputs[i] = new TxOut();
                }
                //All other txCopy inputs aside from the current input are set to have an nSequence index of zero.
                foreach (var input in txCopy.Inputs.Where((x, i) => i != nIn))
                {
                    input.Sequence = 0;
                }
            }


            if ((nHashType & SigHash.AnyoneCanPay) != 0)
            {
                //The txCopy input vector is resized to a length of one.
                var script = txCopy.Inputs[nIn];
                txCopy.Inputs.Clear();
                txCopy.Inputs.Add(script);
                //The subScript (lead in by its length as a var-integer encoded!) is set as the first and only member of this vector.
                txCopy.Inputs[0].ScriptSig = scriptCopy;
            }


            //Serialize TxCopy, append 4 byte hashtypecode
            var stream = CreateHashWriter(sigversion);

            txCopy.ReadWrite(stream);
            stream.ReadWrite((uint)nHashType);
            return(GetHash(stream));
        }
Example #3
0
		//https://en.bitcoin.it/wiki/OP_CHECKSIG
		public static uint256 SignatureHash(Script scriptCode, Transaction txTo, int nIn, SigHash nHashType, Money amount = null, HashVersion sigversion = HashVersion.Original)
		{
			if(sigversion == HashVersion.Witness)
			{
				if(amount == null)
					throw new ArgumentException("The amount of the output being signed must be provided", "amount");
				uint256 hashPrevouts = uint256.Zero;
				uint256 hashSequence = uint256.Zero;
				uint256 hashOutputs = uint256.Zero;

				if((nHashType & SigHash.AnyoneCanPay) == 0)
				{
					BitcoinStream ss = CreateHashWriter(sigversion);
					foreach(var input in txTo.Inputs)
					{
						ss.ReadWrite(input.PrevOut);
					}
					hashPrevouts = GetHash(ss); // TODO: cache this value for all signatures in a transaction
				}

				if((nHashType & SigHash.AnyoneCanPay) == 0 && ((uint)nHashType & 0x1f) != (uint)SigHash.Single && ((uint)nHashType & 0x1f) != (uint)SigHash.None)
				{
					BitcoinStream ss = CreateHashWriter(sigversion);
					foreach(var input in txTo.Inputs)
					{
						ss.ReadWrite((uint)input.Sequence);
					}
					hashSequence = GetHash(ss); // TODO: cache this value for all signatures in a transaction
				}

				if(((uint)nHashType & 0x1f) != (uint)SigHash.Single && ((uint)nHashType & 0x1f) != (uint)SigHash.None)
				{
					BitcoinStream ss = CreateHashWriter(sigversion);
					foreach(var txout in txTo.Outputs)
					{
						ss.ReadWrite(txout);
					}
					hashOutputs = GetHash(ss); // TODO: cache this value for all signatures in a transaction
				}
				else if(((uint)nHashType & 0x1f) == (uint)SigHash.Single && nIn < txTo.Outputs.Count)
				{
					BitcoinStream ss = CreateHashWriter(sigversion);
					ss.ReadWrite(txTo.Outputs[nIn]);
					hashOutputs = GetHash(ss);
				}

				BitcoinStream sss = CreateHashWriter(sigversion);
				// Version
				sss.ReadWrite(txTo.Version);
				// Input prevouts/nSequence (none/all, depending on flags)
				sss.ReadWrite(hashPrevouts);
				sss.ReadWrite(hashSequence);
				// The input being signed (replacing the scriptSig with scriptCode + amount)
				// The prevout may already be contained in hashPrevout, and the nSequence
				// may already be contain in hashSequence.
				sss.ReadWrite(txTo.Inputs[nIn].PrevOut);
				sss.ReadWrite(scriptCode);
				sss.ReadWrite(amount.Satoshi);
				sss.ReadWrite((uint)txTo.Inputs[nIn].Sequence);
				// Outputs (none/one/all, depending on flags)
				sss.ReadWrite(hashOutputs);
				// Locktime
				sss.ReadWriteStruct(txTo.LockTime);
				// Sighash type
				sss.ReadWrite((uint)nHashType);

				return GetHash(sss);
			}




			if(nIn >= txTo.Inputs.Count)
			{
				Utils.log("ERROR: SignatureHash() : nIn=" + nIn + " out of range\n");
				return uint256.One;
			}

			// Check for invalid use of SIGHASH_SINGLE
			if(nHashType == SigHash.Single)
			{
				if(nIn >= txTo.Outputs.Count)
				{
					Utils.log("ERROR: SignatureHash() : nOut=" + nIn + " out of range\n");
					return uint256.One;
				}
			}

			var scriptCopy = new Script(scriptCode._Script);
			scriptCopy.FindAndDelete(OpcodeType.OP_CODESEPARATOR);

			var txCopy = new Transaction(txTo.ToBytes());

			//Set all TxIn script to empty string
			foreach(var txin in txCopy.Inputs)
			{
				txin.ScriptSig = new Script();
			}
			//Copy subscript into the txin script you are checking
			txCopy.Inputs[nIn].ScriptSig = scriptCopy;

			var hashType = nHashType & (SigHash)31;
			if(hashType == SigHash.None)
			{
				//The output of txCopy is set to a vector of zero size.
				txCopy.Outputs.Clear();

				//All other inputs aside from the current input in txCopy have their nSequence index set to zero
				foreach(var input in txCopy.Inputs.Where((x, i) => i != nIn))
					input.Sequence = 0;
			}
			else if(hashType == SigHash.Single)
			{
				//The output of txCopy is resized to the size of the current input index+1.
				txCopy.Outputs.RemoveRange(nIn + 1, txCopy.Outputs.Count - (nIn + 1));
				//All other txCopy outputs aside from the output that is the same as the current input index are set to a blank script and a value of (long) -1.
				for(var i = 0 ; i < txCopy.Outputs.Count ; i++)
				{
					if(i == nIn)
						continue;
					txCopy.Outputs[i] = new TxOut();
				}
				//All other txCopy inputs aside from the current input are set to have an nSequence index of zero.
				foreach(var input in txCopy.Inputs.Where((x, i) => i != nIn))
					input.Sequence = 0;
			}


			if((nHashType & SigHash.AnyoneCanPay) != 0)
			{
				//The txCopy input vector is resized to a length of one.
				var script = txCopy.Inputs[nIn];
				txCopy.Inputs.Clear();
				txCopy.Inputs.Add(script);
				//The subScript (lead in by its length as a var-integer encoded!) is set as the first and only member of this vector.
				txCopy.Inputs[0].ScriptSig = scriptCopy;
			}


			//Serialize TxCopy, append 4 byte hashtypecode
			var stream = CreateHashWriter(sigversion);
			txCopy.ReadWrite(stream);
			stream.ReadWrite((uint)nHashType);
			return GetHash(stream);
		}
Example #4
0
        //https://en.bitcoin.it/wiki/OP_CHECKSIG
        public uint256 SignatureHash(Transaction txTo, int nIn, SigHash nHashType)
        {
            if (nIn >= txTo.Inputs.Count)
            {
                Utils.log("ERROR: SignatureHash() : nIn=" + nIn + " out of range\n");
                return(1);
            }

            // Check for invalid use of SIGHASH_SINGLE
            if (nHashType == SigHash.Single)
            {
                if (nIn >= txTo.Outputs.Count)
                {
                    Utils.log("ERROR: SignatureHash() : nOut=" + nIn + " out of range\n");
                    return(1);
                }
            }

            var scriptCopy = new Script(_Script);

            scriptCopy.FindAndDelete(OpcodeType.OP_CODESEPARATOR);

            var txCopy = new Transaction(txTo.ToBytes());

            //Set all TxIn script to empty string
            foreach (var txin in txCopy.Inputs)
            {
                txin.ScriptSig = new Script();
            }
            //Copy subscript into the txin script you are checking
            txCopy.Inputs[nIn].ScriptSig = scriptCopy;

            if (((int)nHashType & 31) == (int)SigHash.None)
            {
                //The output of txCopy is set to a vector of zero size.
                txCopy.Outputs.Clear();
                //All other inputs aside from the current input in txCopy have their nSequence index set to zero
                for (int i = 0; i < txCopy.Inputs.Count; i++)
                {
                    if (i == nIn)
                    {
                        continue;
                    }
                    txCopy.Inputs[i].Sequence = 0;
                }
            }

            if (((int)nHashType & 31) == (int)SigHash.Single)
            {
                //The output of txCopy is resized to the size of the current input index+1.
                var remainingOut = txCopy.Outputs.Take(nIn + 1).ToArray();
                txCopy.Outputs.Clear();
                txCopy.Outputs.AddRange(remainingOut);
                //All other txCopy outputs aside from the output that is the same as the current input index are set to a blank script and a value of (long) -1.
                for (int i = 0; i < txCopy.Outputs.Count; i++)
                {
                    if (i == nIn)
                    {
                        continue;
                    }
                    txCopy.Outputs[i] = new TxOut();
                }
                for (int i = 0; i < txCopy.Inputs.Count; i++)
                {
                    //All other txCopy inputs aside from the current input are set to have an nSequence index of zero.
                    if (i == nIn)
                    {
                        continue;
                    }
                    txCopy.Inputs[i].Sequence = 0;
                }
            }

            if (((int)nHashType & (int)SigHash.AnyoneCanPay) != 0)
            {
                //The txCopy input vector is resized to a length of one.
                var script = txCopy.Inputs[nIn];
                txCopy.Inputs.Clear();
                txCopy.Inputs.Add(script);
                //The subScript (lead in by its length as a var-integer encoded!) is set as the first and only member of this vector.
                txCopy.Inputs[0].ScriptSig = scriptCopy;
            }


            //Serialize TxCopy, append 4 byte hashtypecode
            MemoryStream  ms            = new MemoryStream();
            BitcoinStream bitcoinStream = new BitcoinStream(ms, true);

            txCopy.ReadWrite(bitcoinStream);
            bitcoinStream.ReadWrite((uint)nHashType);

            var hashed = ms.ToArray();

            return(Hashes.Hash256(hashed));
        }
Example #5
0
        public bool EvalScript(Script s, Transaction txTo, int nIn)
        {
            var script = s.CreateReader();
            int pend   = (int)script.Inner.Length;

            int            pbegincodehash = 0;
            Stack <bool>   vfExec         = new Stack <bool>();
            Stack <byte[]> altstack       = new Stack <byte[]>();
            Op             opcode         = null;

            if (s.Length > 10000)
            {
                return(false);
            }
            int nOpCount = 0;

            try
            {
                while ((opcode = script.Read()) != null)
                {
                    bool fExec = vfExec.All(o => o);                     //!count(vfExec.begin(), vfExec.end(), false);

                    //
                    // Read instruction
                    //

                    if (opcode.PushData != null && opcode.PushData.Length > 520)
                    {
                        return(false);
                    }

                    // Note how OP_RESERVED does not count towards the opcode limit.
                    if (opcode.Code > OpcodeType.OP_16 && ++nOpCount > 201)
                    {
                        return(false);
                    }

                    if (opcode.Code == OpcodeType.OP_CAT ||
                        opcode.Code == OpcodeType.OP_SUBSTR ||
                        opcode.Code == OpcodeType.OP_LEFT ||
                        opcode.Code == OpcodeType.OP_RIGHT ||
                        opcode.Code == OpcodeType.OP_INVERT ||
                        opcode.Code == OpcodeType.OP_AND ||
                        opcode.Code == OpcodeType.OP_OR ||
                        opcode.Code == OpcodeType.OP_XOR ||
                        opcode.Code == OpcodeType.OP_2MUL ||
                        opcode.Code == OpcodeType.OP_2DIV ||
                        opcode.Code == OpcodeType.OP_MUL ||
                        opcode.Code == OpcodeType.OP_DIV ||
                        opcode.Code == OpcodeType.OP_MOD ||
                        opcode.Code == OpcodeType.OP_LSHIFT ||
                        opcode.Code == OpcodeType.OP_RSHIFT)
                    {
                        return(false);                        // Disabled opcodes.
                    }
                    if (fExec && opcode.PushData != null)
                    {
                        _Stack.Push(opcode.PushData);
                    }
                    else if (fExec || (OpcodeType.OP_IF <= opcode.Code && opcode.Code <= OpcodeType.OP_ENDIF))
                    {
                        switch (opcode.Code)
                        {
                        //
                        // 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.Code - (int)(OpcodeType.OP_1 - 1));
                            _Stack.Push(Utils.BigIntegerToBytes(bn));
                        }
                        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);
                                }
                                var vch = top(_Stack, -1);
                                fValue = CastToBool(vch);
                                if (opcode.Code == OpcodeType.OP_NOTIF)
                                {
                                    fValue = !fValue;
                                }
                                _Stack.Pop();
                            }
                            vfExec.Push(fValue);
                        }
                        break;

                        case OpcodeType.OP_ELSE:
                        {
                            if (vfExec.Count == 0)
                            {
                                return(false);
                            }
                            var v = vfExec.Pop();
                            vfExec.Push(!v);
                            //vfExec.Peek() = !vfExec.Peek();
                        }
                        break;

                        case OpcodeType.OP_ENDIF:
                        {
                            if (vfExec.Count == 0)
                            {
                                return(false);
                            }
                            vfExec.Pop();
                        }
                        break;

                        case OpcodeType.OP_VERIFY:
                        {
                            // (true -- ) or
                            // (false -- false) and return
                            if (_Stack.Count < 1)
                            {
                                return(false);
                            }
                            bool fValue = CastToBool(top(_Stack, -1));
                            if (fValue)
                            {
                                _Stack.Pop();
                            }
                            else
                            {
                                return(false);
                            }
                        }
                        break;

                        case OpcodeType.OP_RETURN:
                        {
                            return(false);
                        }


                        //
                        // Stack ops
                        //
                        case OpcodeType.OP_TOALTSTACK:
                        {
                            if (_Stack.Count < 1)
                            {
                                return(false);
                            }
                            altstack.Push(top(_Stack, -1));
                            _Stack.Pop();
                        }
                        break;

                        case OpcodeType.OP_FROMALTSTACK:
                        {
                            if (altstack.Count < 1)
                            {
                                return(false);
                            }
                            _Stack.Push(top(altstack, -1));
                            altstack.Pop();
                        }
                        break;

                        case OpcodeType.OP_2DROP:
                        {
                            // (x1 x2 -- )
                            if (_Stack.Count < 2)
                            {
                                return(false);
                            }
                            _Stack.Pop();
                            _Stack.Pop();
                        }
                        break;

                        case OpcodeType.OP_2DUP:
                        {
                            // (x1 x2 -- x1 x2 x1 x2)
                            if (_Stack.Count < 2)
                            {
                                return(false);
                            }
                            var vch1 = top(_Stack, -2);
                            var vch2 = top(_Stack, -1);
                            _Stack.Push(vch1);
                            _Stack.Push(vch2);
                        }
                        break;

                        case OpcodeType.OP_3DUP:
                        {
                            // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)
                            if (_Stack.Count < 3)
                            {
                                return(false);
                            }
                            var vch1 = top(_Stack, -3);
                            var vch2 = top(_Stack, -2);
                            var vch3 = top(_Stack, -1);
                            _Stack.Push(vch1);
                            _Stack.Push(vch2);
                            _Stack.Push(vch3);
                        }
                        break;

                        case OpcodeType.OP_2OVER:
                        {
                            // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
                            if (_Stack.Count < 4)
                            {
                                return(false);
                            }
                            var vch1 = top(_Stack, -4);
                            var vch2 = top(_Stack, -3);
                            _Stack.Push(vch1);
                            _Stack.Push(vch2);
                        }
                        break;

                        case OpcodeType.OP_2ROT:
                        {
                            // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
                            if (_Stack.Count < 6)
                            {
                                return(false);
                            }
                            var vch1 = top(_Stack, -6);
                            var vch2 = top(_Stack, -5);
                            erase(ref _Stack, _Stack.Count - 6, _Stack.Count - 4);
                            _Stack.Push(vch1);
                            _Stack.Push(vch2);
                        }
                        break;

                        case OpcodeType.OP_2SWAP:
                        {
                            // (x1 x2 x3 x4 -- x3 x4 x1 x2)
                            if (_Stack.Count < 4)
                            {
                                return(false);
                            }
                            swap(ref _Stack, -4, -2);
                            swap(ref _Stack, -3, -1);
                        }
                        break;

                        case OpcodeType.OP_IFDUP:
                        {
                            // (x - 0 | x x)
                            if (_Stack.Count < 1)
                            {
                                return(false);
                            }
                            var vch = top(_Stack, -1);
                            if (CastToBool(vch))
                            {
                                _Stack.Push(vch);
                            }
                        }
                        break;

                        case OpcodeType.OP_DEPTH:
                        {
                            // -- stacksize
                            BigInteger bn = new BigInteger(_Stack.Count);
                            _Stack.Push(Utils.BigIntegerToBytes(bn));
                        }
                        break;

                        case OpcodeType.OP_DROP:
                        {
                            // (x -- )
                            if (_Stack.Count < 1)
                            {
                                return(false);
                            }
                            _Stack.Pop();
                        }
                        break;

                        case OpcodeType.OP_DUP:
                        {
                            // (x -- x x)
                            if (_Stack.Count < 1)
                            {
                                return(false);
                            }
                            var vch = top(_Stack, -1);
                            _Stack.Push(vch);
                        }
                        break;

                        case OpcodeType.OP_NIP:
                        {
                            // (x1 x2 -- x2)
                            if (_Stack.Count < 2)
                            {
                                return(false);
                            }
                            erase(ref _Stack, _Stack.Count - 2);
                        }
                        break;

                        case OpcodeType.OP_OVER:
                        {
                            // (x1 x2 -- x1 x2 x1)
                            if (_Stack.Count < 2)
                            {
                                return(false);
                            }
                            var vch = top(_Stack, -2);
                            _Stack.Push(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)
                            if (_Stack.Count < 2)
                            {
                                return(false);
                            }
                            int n = (int)CastToBigNum(top(_Stack, -1));
                            _Stack.Pop();
                            if (n < 0 || n >= _Stack.Count)
                            {
                                return(false);
                            }
                            var vch = top(_Stack, -n - 1);
                            if (opcode.Code == OpcodeType.OP_ROLL)
                            {
                                erase(ref _Stack, _Stack.Count - n - 1);
                            }
                            _Stack.Push(vch);
                        }
                        break;

                        case OpcodeType.OP_ROT:
                        {
                            // (x1 x2 x3 -- x2 x3 x1)
                            //  x2 x1 x3  after first swap
                            //  x2 x3 x1  after second swap
                            if (_Stack.Count < 3)
                            {
                                return(false);
                            }
                            swap(ref _Stack, -3, -2);
                            swap(ref _Stack, -2, -1);
                        }
                        break;

                        case OpcodeType.OP_SWAP:
                        {
                            // (x1 x2 -- x2 x1)
                            if (_Stack.Count < 2)
                            {
                                return(false);
                            }
                            swap(ref _Stack, -2, -1);
                        }
                        break;

                        case OpcodeType.OP_TUCK:
                        {
                            // (x1 x2 -- x2 x1 x2)
                            if (_Stack.Count < 2)
                            {
                                return(false);
                            }
                            var vch = top(_Stack, -1);
                            insert(ref _Stack, _Stack.Count - 2, vch);
                        }
                        break;


                        case OpcodeType.OP_SIZE:
                        {
                            // (in -- in size)
                            if (_Stack.Count < 1)
                            {
                                return(false);
                            }
                            BigInteger bn = new BigInteger(top(_Stack, -1).Length);
                            _Stack.Push(Utils.BigIntegerToBytes(bn));
                        }
                        break;


                        //
                        // Bitwise logic
                        //
                        case OpcodeType.OP_EQUAL:
                        case OpcodeType.OP_EQUALVERIFY:
                            //case OpcodeType.OP_NOTEQUAL: // use OpcodeType.OP_NUMNOTEQUAL
                        {
                            // (x1 x2 - bool)
                            if (_Stack.Count < 2)
                            {
                                return(false);
                            }
                            var  vch1   = top(_Stack, -2);
                            var  vch2   = top(_Stack, -1);
                            bool fEqual = Utils.ArrayEqual(vch1, vch2);
                            // OpcodeType.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;
                            _Stack.Pop();
                            _Stack.Pop();
                            _Stack.Push(fEqual ? vchTrue : vchFalse);
                            if (opcode.Code == OpcodeType.OP_EQUALVERIFY)
                            {
                                if (fEqual)
                                {
                                    _Stack.Pop();
                                }
                                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);
                            }
                            var bn = CastToBigNum(top(_Stack, -1));
                            switch (opcode.Code)
                            {
                            case OpcodeType.OP_1ADD:
                                bn += BigInteger.One;
                                break;

                            case OpcodeType.OP_1SUB:
                                bn -= BigInteger.One;
                                break;

                            case OpcodeType.OP_NEGATE:
                                bn = -bn;
                                break;

                            case OpcodeType.OP_ABS:
                                if (bn < BigInteger.Zero)
                                {
                                    bn = -bn;
                                }
                                break;

                            case OpcodeType.OP_NOT:
                                bn = CastToBigNum(bn == BigInteger.Zero);
                                break;

                            case OpcodeType.OP_0NOTEQUAL:
                                bn = CastToBigNum(bn != BigInteger.Zero);
                                break;

                            default:
                                throw new NotSupportedException("invalid opcode");
                            }
                            _Stack.Pop();
                            _Stack.Push(Utils.BigIntegerToBytes(bn));
                        }
                        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);
                            }
                            var        bn1 = CastToBigNum(top(_Stack, -2));
                            var        bn2 = CastToBigNum(top(_Stack, -1));
                            BigInteger bn;
                            switch (opcode.Code)
                            {
                            case OpcodeType.OP_ADD:
                                bn = bn1 + bn2;
                                break;

                            case OpcodeType.OP_SUB:
                                bn = bn1 - bn2;
                                break;

                            case OpcodeType.OP_BOOLAND:
                                bn = CastToBigNum(bn1 != BigInteger.Zero && bn2 != BigInteger.Zero);
                                break;

                            case OpcodeType.OP_BOOLOR:
                                bn = CastToBigNum(bn1 != BigInteger.Zero || bn2 != BigInteger.Zero);
                                break;

                            case OpcodeType.OP_NUMEQUAL:
                                bn = CastToBigNum(bn1 == bn2);
                                break;

                            case OpcodeType.OP_NUMEQUALVERIFY:
                                bn = CastToBigNum(bn1 == bn2);
                                break;

                            case OpcodeType.OP_NUMNOTEQUAL:
                                bn = CastToBigNum(bn1 != bn2);
                                break;

                            case OpcodeType.OP_LESSTHAN:
                                bn = CastToBigNum(bn1 < bn2);
                                break;

                            case OpcodeType.OP_GREATERTHAN:
                                bn = CastToBigNum(bn1 > bn2);
                                break;

                            case OpcodeType.OP_LESSTHANOREQUAL:
                                bn = CastToBigNum(bn1 <= bn2);
                                break;

                            case OpcodeType.OP_GREATERTHANOREQUAL:
                                bn = CastToBigNum(bn1 >= bn2);
                                break;

                            case OpcodeType.OP_MIN:
                                bn = (bn1 < bn2 ? bn1 : bn2);
                                break;

                            case OpcodeType.OP_MAX:
                                bn = (bn1 > bn2 ? bn1 : bn2);
                                break;

                            default:
                                throw new NotSupportedException("invalid opcode");
                            }
                            _Stack.Pop();
                            _Stack.Pop();
                            _Stack.Push(Utils.BigIntegerToBytes(bn));

                            if (opcode.Code == OpcodeType.OP_NUMEQUALVERIFY)
                            {
                                if (CastToBool(top(_Stack, -1)))
                                {
                                    _Stack.Pop();
                                }
                                else
                                {
                                    return(false);
                                }
                            }
                        }
                        break;

                        case OpcodeType.OP_WITHIN:
                        {
                            // (x min max -- out)
                            if (_Stack.Count < 3)
                            {
                                return(false);
                            }
                            var  bn1    = CastToBigNum(top(_Stack, -3));
                            var  bn2    = CastToBigNum(top(_Stack, -2));
                            var  bn3    = CastToBigNum(top(_Stack, -1));
                            bool fValue = (bn2 <= bn1 && bn1 < bn3);
                            _Stack.Pop();
                            _Stack.Pop();
                            _Stack.Pop();
                            _Stack.Push(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);
                            }
                            var    vch     = top(_Stack, -1);
                            byte[] vchHash = null;                                            //((opcode == OpcodeType.OP_RIPEMD160 || opcode == OpcodeType.OP_SHA1 || opcode == OpcodeType.OP_HASH160) ? 20 : 32);
                            if (opcode.Code == OpcodeType.OP_RIPEMD160)
                            {
                                vchHash = Hashes.RIPEMD160(vch, vch.Length);
                            }
                            else if (opcode.Code == OpcodeType.OP_SHA1)
                            {
                                vchHash = Hashes.SHA1(vch, vch.Length);
                            }
                            else if (opcode.Code == OpcodeType.OP_SHA256)
                            {
                                vchHash = Hashes.SHA256(vch, vch.Length);
                            }
                            else if (opcode.Code == OpcodeType.OP_HASH160)
                            {
                                vchHash = Hashes.Hash160(vch, vch.Length).ToBytes();
                            }
                            else if (opcode.Code == OpcodeType.OP_HASH256)
                            {
                                vchHash = Hashes.Hash256(vch, vch.Length).ToBytes();
                            }
                            _Stack.Pop();
                            _Stack.Push(vchHash);
                        }
                        break;

                        case OpcodeType.OP_CODESEPARATOR:
                        {
                            // Hash starts after the code separator
                            pbegincodehash = (int)script.Inner.Position;
                        }
                        break;

                        case OpcodeType.OP_CHECKSIG:
                        case OpcodeType.OP_CHECKSIGVERIFY:
                        {
                            // (sig pubkey -- bool)
                            if (_Stack.Count < 2)
                            {
                                return(false);
                            }

                            var vchSig    = top(_Stack, -2);
                            var vchPubKey = top(_Stack, -1);

                            ////// debug print
                            //PrintHex(vchSig.begin(), vchSig.end(), "sig: %s\n");
                            //PrintHex(vchPubKey.begin(), vchPubKey.end(), "pubkey: %s\n");

                            // Subset of script starting at the most recent codeseparator
                            var scriptCode = new Script(s._Script.Skip(pbegincodehash).ToArray());
                            // Drop the signature, since there's no way for a signature to sign itself
                            scriptCode.FindAndDelete(vchSig);


                            bool fSuccess = IsCanonicalSignature(vchSig) && IsCanonicalPubKey(vchPubKey) &&
                                            CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn);

                            _Stack.Pop();
                            _Stack.Pop();
                            _Stack.Push(fSuccess ? vchTrue : vchFalse);
                            if (opcode.Code == OpcodeType.OP_CHECKSIGVERIFY)
                            {
                                if (fSuccess)
                                {
                                    _Stack.Pop();
                                }
                                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 ((int)_Stack.Count < i)
                            {
                                return(false);
                            }

                            int nKeysCount = (int)CastToBigNum(top(_Stack, -i));
                            if (nKeysCount < 0 || nKeysCount > 20)
                            {
                                return(false);
                            }
                            nOpCount += nKeysCount;
                            if (nOpCount > 201)
                            {
                                return(false);
                            }
                            int ikey = ++i;
                            i += nKeysCount;
                            if ((int)_Stack.Count < i)
                            {
                                return(false);
                            }

                            int nSigsCount = (int)CastToBigNum(top(_Stack, -i));
                            if (nSigsCount < 0 || nSigsCount > nKeysCount)
                            {
                                return(false);
                            }
                            int isig = ++i;
                            i += nSigsCount;
                            if ((int)_Stack.Count < i)
                            {
                                return(false);
                            }

                            // Subset of script starting at the most recent codeseparator
                            Script scriptCode = new Script(s._Script.Skip(pbegincodehash).ToArray());
                            // Drop the signatures, since there's no way for a signature to sign itself
                            for (int k = 0; k < nSigsCount; k++)
                            {
                                var vchSig = top(_Stack, -isig - k);
                                scriptCode.FindAndDelete(vchSig);
                            }

                            bool fSuccess = true;
                            while (fSuccess && nSigsCount > 0)
                            {
                                var vchSig    = top(_Stack, -isig);
                                var vchPubKey = top(_Stack, -ikey);

                                // Check signature
                                bool fOk = IsCanonicalSignature(vchSig) && IsCanonicalPubKey(vchPubKey) &&
                                           CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn);

                                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)
                            {
                                _Stack.Pop();
                            }

                            // 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 (((ScriptVerify & ScriptVerify.NullDummy) != 0) && top(_Stack, -1).Length != 0)
                            {
                                return(Utils.error("CHECKMULTISIG dummy argument not null"));
                            }
                            _Stack.Pop();

                            _Stack.Push(fSuccess ? vchTrue : vchFalse);

                            if (opcode.Code == OpcodeType.OP_CHECKMULTISIGVERIFY)
                            {
                                if (fSuccess)
                                {
                                    _Stack.Pop();
                                }
                                else
                                {
                                    return(false);
                                }
                            }
                        }
                        break;

                        default:
                            return(false);
                        }
                    }

                    // Size limits
                    if (_Stack.Count + altstack.Count > 1000)
                    {
                        return(false);
                    }
                }
            }
            catch (Exception ex)
            {
                Utils.error("Error in EvalScript " + ex.Message + " on opcode " + opcode);
                return(false);
            }


            if (vfExec.Count != 0)
            {
                return(false);
            }

            return(true);
        }