public static Transaction CopyForSigning(this Transaction tx, UInt32 txInIndex, Script subScript, HashType hashType)
        {
            Transaction txCopy = new Transaction(tx.ToBytes());

            for (int i = 0; i < txCopy.inputs.Length; i++)
            {
                if (i == txInIndex)
                    txCopy.inputs[txInIndex].scriptSig = subScript.ToBytes();
                else
                    txCopy.inputs[i].scriptSig = new Byte[0];
            }

            if (((Byte)hashType & 0x1F) == (Byte)HashType.SIGHASH_NONE)
            {
                txCopy.outputs = new TxOut[0];

                for (int i = 0; i < txCopy.inputs.Length; i++)
                    if (i != txInIndex)
                        txCopy.inputs[i].sequenceNo = 0;
            }
            else if (((Byte)hashType & 0x1F) == (Byte)HashType.SIGHASH_SINGLE)
            {
                TxOut txOut = txCopy.outputs[txInIndex];
                txCopy.outputs = new TxOut[txInIndex + 1];

                for (int i = 0; i < txCopy.outputs.Length; i++)
                {
                    if (i == txInIndex)
                        txCopy.outputs[i] = txOut;
                    else
                    {
                        txCopy.outputs[i].value = UInt64.MaxValue;
                        txCopy.outputs[i].scriptPubKey = new Byte[0];
                    }
                }

                for (int i = 0; i < txCopy.inputs.Length; i++)
                    if (i != txInIndex)
                        txCopy.inputs[i].sequenceNo = 0;
            }

            if (((Byte)hashType & (Byte)HashType.SIGHASH_ANYONECANPAY) == (Byte)HashType.SIGHASH_ANYONECANPAY)
            {
                txCopy.inputs = new TxIn[] { txCopy.inputs[txInIndex] };
            }

            return txCopy;
        }
        public static void Sign(this TxIn txin, Transaction tx, TxOut prevOut, PrivateKey key, HashType hashType = HashType.SIGHASH_ALL)
        {
            SHA256 sha256 = new SHA256Managed();
            UInt32 txInIndex;
            for (txInIndex = 0; txInIndex < tx.inputs.Length; txInIndex++)
            {
                if (TxIn.ReferenceEquals(txin, tx.inputs[txInIndex]))
                    break;
            }
            if (txInIndex == tx.inputs.Length)
                throw new ArgumentException("Input not part of transaction.");

            // Only know how to sign if output does not contain OP_CODESEPERATOR for now.
            Script subScript = new Script(prevOut.scriptPubKey);
            Transaction txCopy = tx.CopyForSigning(txInIndex, subScript, hashType);

            Byte[] txHash = txCopy.ToBytes().Concat(new Byte[] { (Byte)hashType, 0x00, 0x00, 0x00 }).ToArray();
            txHash = sha256.ComputeHash(sha256.ComputeHash(txHash));

            Byte[] sig = key.Sign(txHash);
            sig = sig.Concat(new Byte[] { (Byte)hashType }).ToArray();

            Script s = new Script();

            if (subScript.IsPayToAddress())
            {
                s.elements.Add(new ScriptElement(sig));
                s.elements.Add(new ScriptElement(key.pubKey.ToBytes()));
            }
            else if (subScript.IsPayToPublicKey())
            {
                s.elements.Add(new ScriptElement(sig));
            }
            else
            {
                throw new ArgumentException("Unrecognized TxOut Script");
            }

            txin.scriptSig = s.ToBytes();
        }
Пример #3
0
        public bool Evaluate(Transaction tx = null, UInt32 txInIndex = 0)
        {
            Stack<IfElseExec> ifExec = new Stack<IfElseExec>();
            int lastCodeSeperator = 0;

            stack.Clear();
            altstack.Clear();

            for (int index = 0; index < elements.Count; index++)
            {
                ScriptElement se = elements[index];
                if (ifExec.Count > 0)
                    if ((ifExec.First() == IfElseExec.SKIP_IF && !(se.opCode == OpCode.OP_ELSE || se.opCode == OpCode.OP_ENDIF)) ||
                        (ifExec.First() == IfElseExec.SKIP_ELSE && !(se.opCode == OpCode.OP_ENDIF)))
                        continue;

                if (se.isData)
                {
                    stack.Push(se.data);
                    continue;
                }

                switch (se.opCode)
                {
                    case OpCode.OP_RESERVED:
                        {
                            return false;
                        }
                    case OpCode.OP_NOP:
                        {
                            // NOP, Dump stack for debug
                            /*
                            stack.ToList().ForEach(x => Console.WriteLine(HexString.FromByteArray(x)));
                            Console.WriteLine("---------------------------");
                            */
                            break;
                        }
                    case OpCode.OP_VER:
                        {
                            return false;
                        }
                    case OpCode.OP_IF:
                    case OpCode.OP_NOTIF:
                        {
                            if (stack.Count < 1)
                                return false;
                            Boolean stackIsZero = new ScriptVarInt(stack.Pop()).value.IsZero;
                            if ((se.opCode == OpCode.OP_IF && !stackIsZero) || (se.opCode == OpCode.OP_NOTIF && stackIsZero))
                            {
                                // Run to else or endif
                                ifExec.Push(IfElseExec.RUN_IF);
                            }
                            else
                            {
                                // Skip to else or endif
                                ifExec.Push(IfElseExec.SKIP_IF);
                            }
                            break;
                        }
                    case OpCode.OP_VERIF:
                    case OpCode.OP_VERNOTIF:
                        {
                            return false;
                        }
                    case OpCode.OP_ELSE:
                        {
                            if (ifExec.Count == 0)
                                // No preceding if statement!
                                return false;
                            if (ifExec.First() == IfElseExec.RUN_IF)
                            {
                                // If ran, skip else
                                ifExec.Push(IfElseExec.SKIP_ELSE);
                            }
                            else if (ifExec.First() == IfElseExec.SKIP_IF)
                            {
                                // If did not run, run else
                                ifExec.Push(IfElseExec.RUN_ELSE);
                            }
                            break;
                        }
                    case OpCode.OP_ENDIF:
                        {
                            if (ifExec.Count == 0)
                                // No preceding if statement!
                                return false;
                            if (ifExec.First() == IfElseExec.RUN_IF ||
                                ifExec.First() == IfElseExec.SKIP_IF)
                            {
                                ifExec.Pop();
                            }
                            else if (ifExec.First() == IfElseExec.RUN_ELSE ||
                               ifExec.First() == IfElseExec.SKIP_ELSE)
                            {
                                ifExec.Pop();
                                ifExec.Pop();
                            }
                            break;
                        }
                    case OpCode.OP_VERIFY:
                        {
                            if (stack.Count < 1 || new ScriptVarInt(stack.First()).value.IsZero)
                                return false;
                            stack.Pop();
                            break;
                        }
                    case OpCode.OP_RETURN:
                        {
                            return false;
                        }
                    case OpCode.OP_TOALTSTACK:
                        {
                            if (stack.Count < 1)
                                return false;
                            altstack.Push(stack.Pop());
                            break;
                        }
                    case OpCode.OP_FROMALTSTACK:
                        {
                            if (altstack.Count < 1)
                                return false;
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_2DROP:
                        {
                            if (stack.Count < 2)
                                return false;
                            stack.Pop();
                            stack.Pop();
                            break;
                        }
                    case OpCode.OP_2DUP:
                        {
                            if (stack.Count < 2)
                                return false;
                            stack.Push(stack.Skip(1).First());
                            stack.Push(stack.Skip(1).First());
                            break;
                        }
                    case OpCode.OP_3DUP:
                        {
                            if (stack.Count < 3)
                                return false;
                            stack.Push(stack.Skip(2).First());
                            stack.Push(stack.Skip(2).First());
                            stack.Push(stack.Skip(2).First());
                            break;
                        }
                    case OpCode.OP_2OVER:
                        {
                            if (stack.Count < 4)
                                return false;
                            stack.Push(stack.Skip(3).First());
                            stack.Push(stack.Skip(3).First());
                            break;
                        }
                    case OpCode.OP_2ROT:
                        {
                            if (stack.Count < 6)
                                return false;
                            altstack.Push(stack.Skip(4).First());
                            altstack.Push(stack.Skip(5).First());
                            altstack.Push(stack.Pop());
                            altstack.Push(stack.Pop());
                            altstack.Push(stack.Pop());
                            altstack.Push(stack.Pop());
                            stack.Pop();
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_2SWAP:
                        {
                            if (stack.Count < 4)
                                return false;
                            altstack.Push(stack.Skip(2).First());
                            altstack.Push(stack.Skip(3).First());
                            altstack.Push(stack.Pop());
                            altstack.Push(stack.Pop());
                            stack.Pop();
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_IFDUP:
                        {
                            if (stack.Count < 1)
                                return false;
                            if (!new ScriptVarInt(stack.First()).value.IsZero)
                                stack.Push(stack.First());
                            break;
                        }
                    case OpCode.OP_DEPTH:
                        {
                            stack.Push(new ScriptVarInt((UInt64)stack.Count).ToBytes());
                            break;
                        }
                    case OpCode.OP_DROP:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Pop();
                            break;
                        }
                    case OpCode.OP_DUP:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(stack.First());
                            break;
                        }
                    case OpCode.OP_NIP:
                        {
                            if (stack.Count < 2)
                                return false;
                            altstack.Push(stack.Pop());
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_OVER:
                        {
                            if (stack.Count < 2)
                                return false;
                            stack.Push(stack.Skip(1).First());
                            break;
                        }
                    case OpCode.OP_PICK:
                        {
                            if (stack.Count < 2)
                                return false;
                            int pick = new ScriptVarInt(stack.Pop()).intValue;
                            if (pick < 0 || stack.Count <= pick)
                                return false;
                            stack.Push(stack.Skip(pick).First());
                            break;
                        }
                    case OpCode.OP_ROLL:
                        {
                            if (stack.Count < 2)
                                return false;
                            int roll = new ScriptVarInt(stack.Pop()).intValue;
                            if (roll < 0 || stack.Count <= roll)
                                return false;
                            altstack.Push(stack.Skip(roll).First());
                            for (int i = 0; i < roll; i++)
                                altstack.Push(stack.Pop());
                            stack.Pop();
                            for (int i = 0; i < roll + 1; i++)
                                stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_ROT:
                        {
                            if (stack.Count < 3)
                                return false;
                            altstack.Push(stack.Skip(2).First());
                            altstack.Push(stack.Pop());
                            altstack.Push(stack.Pop());
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_SWAP:
                        {
                            if (stack.Count < 2)
                                return false;
                            altstack.Push(stack.Skip(1).First());
                            altstack.Push(stack.Pop());
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_TUCK:
                        {
                            if (stack.Count < 2)
                                return false;
                            altstack.Push(stack.Pop());
                            altstack.Push(stack.Pop());
                            stack.Push(altstack.Skip(1).First());
                            stack.Push(altstack.Pop());
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_CAT:
                        {
                            if (stack.Count < 2)
                                return false;
                            altstack.Push(stack.Skip(1).First().Concat(stack.First()).ToArray());
                            stack.Pop();
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_SUBSTR:
                        {
                            if (stack.Count < 3)
                                return false;
                            altstack.Push(stack.Skip(2).First()
                                .Skip(new ScriptVarInt(stack.Skip(1).First()).intValue)
                                .Take(new ScriptVarInt(stack.First()).intValue).ToArray());
                            stack.Pop();
                            stack.Pop();
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_LEFT:
                        {
                            if (stack.Count < 2)
                                return false;
                            altstack.Push(stack.Skip(1).First()
                                .Take(new ScriptVarInt(stack.First()).intValue).ToArray());
                            stack.Pop();
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_RIGHT:
                        {
                            if (stack.Count < 2)
                                return false;
                            int count = new ScriptVarInt(stack.First()).intValue;
                            altstack.Push(stack.Skip(1).First()
                                .Skip(stack.Skip(1).First().Length - count).ToArray());
                            stack.Pop();
                            stack.Pop();
                            stack.Push(altstack.Pop());
                            break;
                        }
                    case OpCode.OP_SIZE:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(new ScriptVarInt((UInt64)stack.First().Length).ToBytes());
                            break;
                        }
                    case OpCode.OP_INVERT:
                        {
                            if (stack.Count < 1)
                                return false;
                            Byte[] data = stack.Pop();
                            for (int i = 0; i < data.Length; i++)
                                data[i] ^= 0xFF;
                            stack.Push(data);
                            break;
                        }
                    case OpCode.OP_AND:
                    case OpCode.OP_OR:
                    case OpCode.OP_XOR:
                        {
                            if (stack.Count < 2)
                                return false;
                            Byte[] data = stack.Pop();
                            Byte[] data2 = stack.Pop();
                            int length = new int[] { data.Length, data2.Length }.Max();
                            data = data.Concat(new Byte[length - data.Length]).ToArray();
                            data2 = data2.Concat(new Byte[length - data2.Length]).ToArray();
                            switch (se.opCode)
                            {
                                case OpCode.OP_AND:
                                    {
                                        for (int i = 0; i < length; i++)
                                            data[i] &= data2[i];
                                        break;
                                    }
                                case OpCode.OP_OR:
                                    {
                                        for (int i = 0; i < length; i++)
                                            data[i] |= data2[i];
                                        break;
                                    }
                                case OpCode.OP_XOR:
                                    {
                                        for (int i = 0; i < length; i++)
                                            data[i] ^= data2[i];
                                        break;
                                    }
                            }
                            stack.Push(data);
                            break;
                        }
                    case OpCode.OP_EQUAL:
                    case OpCode.OP_EQUALVERIFY:
                        {
                            if (stack.Count < 2)
                                return false;
                            if (stack.Pop().SequenceEqual(stack.Pop()))
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });

                            if (se.opCode == OpCode.OP_EQUALVERIFY)
                            {
                                if (stack.First().Single() == 0x00)
                                    return false;
                                stack.Pop();
                            }
                            break;
                        }
                    case OpCode.OP_RESERVED1:
                    case OpCode.OP_RESERVED2:
                        {
                            return false;
                        }
                    case OpCode.OP_1ADD:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(((ScriptVarInt)BigInteger.Add(new ScriptVarInt(stack.Pop()), 1)).ToBytes());
                            break;
                        }
                    case OpCode.OP_1SUB:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(((ScriptVarInt)BigInteger.Subtract(new ScriptVarInt(stack.Pop()), 1)).ToBytes());
                            break;
                        }
                    case OpCode.OP_2MUL:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(((ScriptVarInt)BigInteger.Multiply(new ScriptVarInt(stack.Pop()), 2)).ToBytes());
                            break;
                        }
                    case OpCode.OP_2DIV:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(((ScriptVarInt)BigInteger.Divide(new ScriptVarInt(stack.Pop()), 2)).ToBytes());
                            break;
                        }
                    case OpCode.OP_NEGATE:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(((ScriptVarInt)BigInteger.Negate(new ScriptVarInt(stack.Pop()))).ToBytes());
                            break;
                        }
                    case OpCode.OP_ABS:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(((ScriptVarInt)BigInteger.Abs(new ScriptVarInt(stack.Pop()))).ToBytes());
                            break;
                        }
                    case OpCode.OP_NOT:
                        {
                            if (stack.Count < 1)
                                return false;
                            if (new ScriptVarInt(stack.Pop()).value.IsZero)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_0NOTEQUAL:
                        {
                            if (stack.Count < 1)
                                return false;
                            if (new ScriptVarInt(stack.Pop()).value.IsZero)
                                stack.Push(new Byte[] { 0x00 });
                            else
                                stack.Push(new Byte[] { 0x01 });
                            break;
                        }
                    case OpCode.OP_ADD:
                    case OpCode.OP_SUB:
                    case OpCode.OP_MUL:
                    case OpCode.OP_DIV:
                    case OpCode.OP_MOD:
                    case OpCode.OP_LSHIFT:
                    case OpCode.OP_RSHIFT:
                        {
                            if (stack.Count < 2)
                                return false;
                            ScriptVarInt b = new ScriptVarInt(stack.Pop());
                            ScriptVarInt a = new ScriptVarInt(stack.Pop());
                            switch (se.opCode)
                            {
                                case OpCode.OP_ADD:
                                    a = (BigInteger)a + b;
                                    break;
                                case OpCode.OP_SUB:
                                    a = (BigInteger)a - b;
                                    break;
                                case OpCode.OP_MUL:
                                    a = (BigInteger)a * b;
                                    break;
                                case OpCode.OP_DIV:
                                    a = (BigInteger)a / b;
                                    break;
                                case OpCode.OP_MOD:
                                    a = (BigInteger)a % b;
                                    break;
                                case OpCode.OP_LSHIFT:
                                    a = (BigInteger)a << b.intValue;
                                    break;
                                case OpCode.OP_RSHIFT:
                                    a = (BigInteger)a >> b.intValue;
                                    break;
                            }
                            stack.Push(a.ToBytes());
                            break;
                        }
                    case OpCode.OP_BOOLAND:
                        {
                            if (stack.Count < 2)
                                return false;
                            if (!new ScriptVarInt(stack.Pop()).value.IsZero && !new ScriptVarInt(stack.Pop()).value.IsZero)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_BOOLOR:
                        {
                            if (stack.Count < 2)
                                return false;
                            if (!new ScriptVarInt(stack.Pop()).value.IsZero || !new ScriptVarInt(stack.Pop()).value.IsZero)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_NUMEQUAL:
                    case OpCode.OP_NUMEQUALVERIFY:
                        {
                            if (stack.Count < 2)
                                return false;
                            if (new ScriptVarInt(stack.Pop()).value == new ScriptVarInt(stack.Pop()).value)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            if (se.opCode == OpCode.OP_NUMEQUALVERIFY)
                            {
                                if (stack.First().Single() == 0x00)
                                    return false;
                                stack.Pop();
                            }
                            break;
                        }
                    case OpCode.OP_NUMNOTEQUAL:
                        {
                            if (stack.Count < 2)
                                return false;
                            if (new ScriptVarInt(stack.Pop()).value != new ScriptVarInt(stack.Pop()).value)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_LESSTHAN:
                        {
                            if (stack.Count < 2)
                                return false;
                            ScriptVarInt b = new ScriptVarInt(stack.Pop());
                            ScriptVarInt a = new ScriptVarInt(stack.Pop());
                            if ((BigInteger)a < b)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_GREATERTHAN:
                        {
                            if (stack.Count < 2)
                                return false;
                            ScriptVarInt b = new ScriptVarInt(stack.Pop());
                            ScriptVarInt a = new ScriptVarInt(stack.Pop());
                            if ((BigInteger)a > b)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_LESSTHANOREQUAL:
                        {
                            if (stack.Count < 2)
                                return false;
                            ScriptVarInt b = new ScriptVarInt(stack.Pop());
                            ScriptVarInt a = new ScriptVarInt(stack.Pop());
                            if ((BigInteger)a <= b)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_GREATERTHANOREQUAL:
                        {
                            if (stack.Count < 2)
                                return false;
                            ScriptVarInt b = new ScriptVarInt(stack.Pop());
                            ScriptVarInt a = new ScriptVarInt(stack.Pop());
                            if ((BigInteger)a >= b)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_MIN:
                        {
                            if (stack.Count < 2)
                                return false;
                            Byte[] b = stack.Pop();
                            Byte[] a = stack.Pop();
                            if (new ScriptVarInt(a).value < new ScriptVarInt(b).value)
                                stack.Push(a);
                            else
                                stack.Push(b);
                            break;
                        }
                    case OpCode.OP_MAX:
                        {
                            if (stack.Count < 2)
                                return false;
                            Byte[] b = stack.Pop();
                            Byte[] a = stack.Pop();
                            if (new ScriptVarInt(a).value > new ScriptVarInt(b).value)
                                stack.Push(a);
                            else
                                stack.Push(b);
                            break;
                        }
                    case OpCode.OP_WITHIN:
                        {
                            if (stack.Count < 3)
                                return false;
                            ScriptVarInt max = new ScriptVarInt(stack.Pop());
                            ScriptVarInt min = new ScriptVarInt(stack.Pop());
                            ScriptVarInt x = new ScriptVarInt(stack.Pop());
                            if ((BigInteger)min <= x && (BigInteger)x <= max)
                                stack.Push(new Byte[] { 0x01 });
                            else
                                stack.Push(new Byte[] { 0x00 });
                            break;
                        }
                    case OpCode.OP_RIPEMD160:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(ripemd160.ComputeHash(stack.Pop()));
                            break;
                        }
                    case OpCode.OP_SHA1:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(sha1.ComputeHash(stack.Pop()));
                            break;
                        }
                    case OpCode.OP_SHA256:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(sha256.ComputeHash(stack.Pop()));
                            break;
                        }
                    case OpCode.OP_HASH160:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(ripemd160.ComputeHash(sha256.ComputeHash(stack.Pop())));
                            break;
                        }
                    case OpCode.OP_HASH256:
                        {
                            if (stack.Count < 1)
                                return false;
                            stack.Push(sha256.ComputeHash(sha256.ComputeHash(stack.Pop())));
                            break;
                        }
                    case OpCode.OP_CODESEPARATOR:
                        {
                            lastCodeSeperator = index;
                            break;
                        }
                    case OpCode.OP_CHECKSIG:
                    case OpCode.OP_CHECKSIGVERIFY:
                        {
                            if (tx == null)
                                throw new ArgumentNullException("Transaction is required if script contains OP_CHECKSIG[VERIFY]");
                            if (stack.Count < 2)
                                return false;

                            PublicKey pubKey = new PublicKey(stack.Pop());
                            Byte[] sig = stack.Pop();

                            Script subScript = new Script(elements.Skip(lastCodeSeperator)
                                .Where(x => x.opCode != OpCode.OP_CODESEPARATOR).ToArray());

                            stack.Push(new ScriptVarInt(CheckSig(sig, pubKey, txInIndex, subScript, tx) ? 1 : 0).ToBytes());

                            if (se.opCode == OpCode.OP_CHECKSIGVERIFY)
                            {
                                if (stack.First().Single() == 0x00)
                                    return false;
                                stack.Pop();
                            }
                            break;
                        }
                    case OpCode.OP_CHECKMULTISIG:
                    case OpCode.OP_CHECKMULTISIGVERIFY:
                        {
                            if (tx == null)
                                throw new ArgumentNullException("Transaction is required if script contains OP_CHECKMULTISIG[VERIFY]");
                            if (stack.Count < 2)
                                return false;

                            PublicKey[] pubKeys = new PublicKey[new ScriptVarInt(stack.Pop()).intValue];

                            if (stack.Count < pubKeys.Length + 1)
                                return false;

                            for (int i = 0; i < pubKeys.Length; i++)
                            {
                                pubKeys[i] = new PublicKey(stack.Pop());
                            }

                            Byte[][] sigs = new Byte[new ScriptVarInt(stack.Pop()).intValue][];

                            if (stack.Count < sigs.Length)
                                return false;

                            for (int i = 0; i < sigs.Length; i++)
                            {
                                sigs[i] = stack.Pop();
                            }

                            // Remove extra unused value from stack
                            stack.Pop();

                            Script subScript = new Script(elements.Skip(lastCodeSeperator)
                                .Where(x => x.opCode != OpCode.OP_CODESEPARATOR).ToArray());

                            int validSigs = 0;
                            foreach (Byte[] sig in sigs)
                            {
                                foreach (PublicKey pubKey in pubKeys)
                                {
                                    if (CheckSig(sig, pubKey, txInIndex, subScript, tx))
                                    {
                                        pubKeys = pubKeys.Where(x => x != pubKey).ToArray();
                                        validSigs++;
                                        break;
                                    }
                                }
                            }

                            stack.Push(new ScriptVarInt((validSigs >= sigs.Length) ? 1 : 0).ToBytes());

                            if (se.opCode == OpCode.OP_CHECKMULTISIGVERIFY)
                            {
                                if (stack.First().Single() == 0x00)
                                    return false;
                                stack.Pop();
                            }
                            break;
                        }
                    case OpCode.OP_NOP1:
                    case OpCode.OP_NOP2:
                    case OpCode.OP_NOP3:
                    case OpCode.OP_NOP4:
                    case OpCode.OP_NOP5:
                    case OpCode.OP_NOP6:
                    case OpCode.OP_NOP7:
                    case OpCode.OP_NOP8:
                    case OpCode.OP_NOP9:
                    case OpCode.OP_NOP10:
                        {
                            break;
                        }
                    case OpCode.OP_SMALLINTEGER:
                    case OpCode.OP_PUBKEYS:
                    case OpCode.OP_PUBKEYHASH:
                    case OpCode.OP_PUBKEY:
                    case OpCode.OP_INVALIDOPCODE:
                    default:
                        {
                            return false;
                        }

                }
            }
            if (ifExec.Count > 0)
                // Missing endif
                return false;
            if (stack.Count > 0 && new ScriptVarInt(stack.First()).value.IsZero)
                return false;
            return true;
        }
Пример #4
0
        private Boolean CheckSig(Byte[] sig, PublicKey pubKey, UInt32 txInIndex, Script subScript, Transaction tx)
        {
            HashType hashType = (HashType)sig.Last();
            sig = sig.Take(sig.Length - 1).ToArray();

            Transaction txCopy = tx.CopyForSigning(txInIndex, subScript, hashType);

            Byte[] txHash = txCopy.ToBytes().Concat(new Byte[] { (Byte)hashType, 0x00, 0x00, 0x00 }).ToArray();
            txHash = sha256.ComputeHash(sha256.ComputeHash(txHash));

            return pubKey.VerifySignature(txHash, sig);
        }
Пример #5
0
        public static void Sign(this TxIn txin, Transaction tx, TxOut prevOut, PrivateKey key, HashType hashType = HashType.SIGHASH_ALL, Script redeemScript = null)
        {
            SHA256 sha256 = new SHA256Managed();
            UInt32 txInIndex;
            for (txInIndex = 0; txInIndex < tx.inputs.Length; txInIndex++)
            {
                if (TxIn.ReferenceEquals(txin, tx.inputs[txInIndex]))
                    break;
            }
            if (txInIndex == tx.inputs.Length)
                throw new ArgumentException("Input not part of transaction.");

            // Only know how to sign if output does not contain OP_CODESEPERATOR for now
            Script subScript = new Script(prevOut.scriptPubKey);

            //// Still don't fully handle codeseperator, but we remove them all as in the spec.
            //// Might be all we need to do, scriptSig will never contain OP_CODESEPERATOR since we are creating it.
            ////subScript.elements.RemoveAll(x => x.opCode == OpCode.OP_CODESEPARATOR);
            // Actually, those would be nonstandard anyway

            Transaction txCopy = tx.CopyForSigning(txInIndex, subScript, hashType);

            Byte[] txHash = txCopy.ToBytes().Concat(new Byte[] { (Byte)hashType, 0x00, 0x00, 0x00 }).ToArray();
            txHash = sha256.ComputeHash(sha256.ComputeHash(txHash));

            Script s = new Script();

            if (subScript.IsPayToScriptHash())
            {
                if (redeemScript == null)
                    throw new ArgumentNullException("P2SH transaction requires serialied script");

                s.elements.Add(new ScriptElement(redeemScript.ToBytes()));
                subScript = redeemScript;
            }

            if (subScript.IsPayToPubKeyHash())
            {
                Byte[] sig = key.Sign(txHash).Concat(new Byte[] { (Byte)hashType }).ToArray();
                s.elements.Insert(0, new ScriptElement(sig));
                s.elements.Insert(1, new ScriptElement(key.pubKey.ToBytes()));
            }
            else if (subScript.IsPayToPublicKey())
            {
                Byte[] sig = key.Sign(txHash).Concat(new Byte[] { (Byte)hashType }).ToArray();
                s.elements.Insert(0, new ScriptElement(sig));
            }
            else if (subScript.IsPayToMultiSig())
            {
                Script scriptSig = new Script(txin.scriptSig);

                if (scriptSig.elements.Count == 0)
                    scriptSig.elements.Add(new ScriptElement(OpCode.OP_0));

                Byte[] sig = key.Sign(txHash).Concat(new Byte[] { (Byte)hashType }).ToArray();
                s.elements.Insert(0, new ScriptElement(sig));
            }
            else
            {
                throw new ArgumentException("Unrecognized TxOut Script");
            }

            txin.scriptSig = s.ToBytes();
        }
Пример #6
0
 public static Transaction FromStream(Stream s)
 {
     Transaction x = new Transaction();
     x.Read(s);
     return x;
 }