Ejemplo n.º 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);
		}
Ejemplo n.º 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));
        }
Ejemplo n.º 3
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));
        }
Ejemplo n.º 4
0
        internal PSBT(BitcoinStream stream, Network network)
        {
            Network = network;
            Inputs  = new PSBTInputList();
            Outputs = new PSBTOutputList();
            var magicBytes = stream.Inner.ReadBytes(PSBT_MAGIC_BYTES.Length);

            if (!magicBytes.SequenceEqual(PSBT_MAGIC_BYTES))
            {
                throw new FormatException("Invalid PSBT magic bytes");
            }

            // It will be reassigned in `ReadWriteAsVarString` so no worry to assign 0 length array here.
            byte[] k       = new byte[0];
            byte[] v       = new byte[0];
            var    txFound = false;

            stream.ReadWriteAsVarString(ref k);
            while (k.Length != 0)
            {
                switch (k[0])
                {
                case PSBTConstants.PSBT_GLOBAL_UNSIGNED_TX:
                    if (k.Length != 1)
                    {
                        throw new FormatException("Invalid PSBT. Contains illegal value in key global tx");
                    }
                    if (tx != null)
                    {
                        throw new FormatException("Duplicate Key, unsigned tx already provided");
                    }
                    tx = stream.ConsensusFactory.CreateTransaction();
                    uint size = 0;
                    stream.ReadWriteAsVarInt(ref size);
                    var pos = stream.Counter.ReadenBytes;
                    tx.ReadWrite(stream);
                    if (stream.Counter.ReadenBytes - pos != size)
                    {
                        throw new FormatException("Malformed global tx. Unexpected size.");
                    }
                    if (tx.Inputs.Any(txin => txin.ScriptSig != Script.Empty || txin.WitScript != WitScript.Empty))
                    {
                        throw new FormatException("Malformed global tx. It should not contain any scriptsig or witness by itself");
                    }
                    txFound = true;
                    break;

                case PSBTConstants.PSBT_GLOBAL_XPUB when XPubVersionBytes != null:
                    if (k.Length != 1 + XPubVersionBytes.Length + 74)
                    {
                        throw new FormatException("Malformed global xpub.");
                    }
                    for (int ii = 0; ii < XPubVersionBytes.Length; ii++)
                    {
                        if (k[1 + ii] != XPubVersionBytes[ii])
                        {
                            throw new FormatException("Malformed global xpub.");
                        }
                    }
                    stream.ReadWriteAsVarString(ref v);
                    KeyPath path          = KeyPath.FromBytes(v.Skip(4).ToArray());
                    var     rootedKeyPath = new RootedKeyPath(new HDFingerprint(v.Take(4).ToArray()), path);
                    GlobalXPubs.Add(new ExtPubKey(k, 1 + XPubVersionBytes.Length, 74).GetWif(Network), rootedKeyPath);
                    break;

                default:
                    if (unknown.ContainsKey(k))
                    {
                        throw new FormatException("Invalid PSBTInput, duplicate key for unknown value");
                    }
                    stream.ReadWriteAsVarString(ref v);
                    unknown.Add(k, v);
                    break;
                }
                stream.ReadWriteAsVarString(ref k);
            }
            if (!txFound)
            {
                throw new FormatException("Invalid PSBT. No global TX");
            }

            int i = 0;

            while (stream.Inner.CanRead && i < tx.Inputs.Count)
            {
                var psbtin = new PSBTInput(stream, this, (uint)i, tx.Inputs[i]);
                Inputs.Add(psbtin);
                i++;
            }
            if (i != tx.Inputs.Count)
            {
                throw new FormatException("Invalid PSBT. Number of input does not match to the global tx");
            }

            i = 0;
            while (stream.Inner.CanRead && i < tx.Outputs.Count)
            {
                var psbtout = new PSBTOutput(stream, this, (uint)i, tx.Outputs[i]);
                Outputs.Add(psbtout);
                i++;
            }
            if (i != tx.Outputs.Count)
            {
                throw new FormatException("Invalid PSBT. Number of outputs does not match to the global tx");
            }
        }
Ejemplo n.º 5
0
        internal PSBT(BitcoinStream stream)
        {
            Inputs  = new PSBTInputList();
            Outputs = new PSBTOutputList();
            var magicBytes = stream.Inner.ReadBytes(PSBT_MAGIC_BYTES.Length);

            if (!magicBytes.SequenceEqual(PSBT_MAGIC_BYTES))
            {
                throw new FormatException("Invalid PSBT magic bytes");
            }

            // It will be reassigned in `ReadWriteAsVarString` so no worry to assign 0 length array here.
            byte[] k       = new byte[0];
            byte[] v       = new byte[0];
            var    txFound = false;

            stream.ReadWriteAsVarString(ref k);
            while (k.Length != 0)
            {
                switch (k.First())
                {
                case PSBTConstants.PSBT_GLOBAL_UNSIGNED_TX:
                    if (k.Length != 1)
                    {
                        throw new FormatException("Invalid PSBT. Contains illegal value in key global tx");
                    }
                    if (tx != null)
                    {
                        throw new FormatException("Duplicate Key, unsigned tx already provided");
                    }
                    tx = stream.ConsensusFactory.CreateTransaction();
                    uint size = 0;
                    stream.ReadWriteAsVarInt(ref size);
                    var pos = stream.Counter.ReadenBytes;
                    tx.ReadWrite(stream);
                    if (stream.Counter.ReadenBytes - pos != size)
                    {
                        throw new FormatException("Malformed global tx. Unexpected size.");
                    }
                    if (tx.Inputs.Any(txin => txin.ScriptSig != Script.Empty || txin.WitScript != WitScript.Empty))
                    {
                        throw new FormatException("Malformed global tx. It should not contain any scriptsig or witness by itself");
                    }
                    txFound = true;
                    break;

                default:
                    if (unknown.ContainsKey(k))
                    {
                        throw new FormatException("Invalid PSBTInput, duplicate key for unknown value");
                    }
                    stream.ReadWriteAsVarString(ref v);
                    unknown.Add(k, v);
                    break;
                }
                stream.ReadWriteAsVarString(ref k);
            }
            if (!txFound)
            {
                throw new FormatException("Invalid PSBT. No global TX");
            }

            int i = 0;

            while (stream.Inner.CanRead && i < tx.Inputs.Count)
            {
                var psbtin = new PSBTInput(stream, this, (uint)i, tx.Inputs[i]);
                Inputs.Add(psbtin);
                i++;
            }
            if (i != tx.Inputs.Count)
            {
                throw new FormatException("Invalid PSBT. Number of input does not match to the global tx");
            }

            i = 0;
            while (stream.Inner.CanRead && i < tx.Outputs.Count)
            {
                var psbtout = new PSBTOutput(stream, this, (uint)i, tx.Outputs[i]);
                Outputs.Add(psbtout);
                i++;
            }
            if (i != tx.Outputs.Count)
            {
                throw new FormatException("Invalid PSBT. Number of outputs does not match to the global tx");
            }
        }
Ejemplo n.º 6
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);
		}