Пример #1
0
        private static BitcoinStream CreateHashWriter(HashVersion version)
        {
            BitcoinStream stream = new BitcoinStream(new MemoryStream(), true);

            stream.Type = SerializationType.Hash;
            stream.TransactionOptions = version == HashVersion.Original ? TransactionOptions.None : TransactionOptions.Witness;
            return(stream);
        }
Пример #2
0
		private static BitcoinStream CreateHashWriter(HashVersion version)
		{
			HashStream hs = new HashStream();
			BitcoinStream stream = new BitcoinStream(hs, true);
			stream.Type = SerializationType.Hash;
			stream.TransactionOptions = version == HashVersion.Original ? TransactionOptions.None : TransactionOptions.Witness;
			return stream;
		}
Пример #3
0
        private BitcoinStream CreateHashWriter(HashVersion version)
        {
            var           hs     = CreateSignatureHashStream();
            BitcoinStream stream = new BitcoinStream(hs, true);

            stream.Type = SerializationType.Hash;
            stream.TransactionOptions =
                version == HashVersion.Original ? TransactionOptions.None : TransactionOptions.Witness;
            return(stream);
        }
Пример #4
0
        public static ScriptSigs CombineSignatures(Script scriptPubKey, TransactionChecker checker, ScriptSigs input1, ScriptSigs input2)
        {
            if (scriptPubKey == null)
            {
                scriptPubKey = new Script();
            }

            var         scriptSig1  = input1.ScriptSig;
            var         scriptSig2  = input2.ScriptSig;
            HashVersion hashVersion = HashVersion.Original;
            var         isWitness   = input1.WitSig != WitScript.Empty || input2.WitSig != WitScript.Empty;

            if (isWitness)
            {
                scriptSig1  = input1.WitSig.ToScript();
                scriptSig2  = input2.WitSig.ToScript();
                hashVersion = HashVersion.Witness;
            }

            var context = new ScriptEvaluationContext();

            context.ScriptVerify = ScriptVerify.StrictEnc;
            context.EvalScript(scriptSig1, checker, hashVersion);

            var stack1 = context.Stack.AsInternalArray();

            context = new ScriptEvaluationContext();
            context.ScriptVerify = ScriptVerify.StrictEnc;
            context.EvalScript(scriptSig2, checker, hashVersion);

            var stack2 = context.Stack.AsInternalArray();
            var result = CombineSignatures(scriptPubKey, checker, stack1, stack2, hashVersion);

            if (result == null)
            {
                return(scriptSig1.Length < scriptSig2.Length ? input2 : input1);
            }
            if (!isWitness)
            {
                return new ScriptSigs()
                       {
                           ScriptSig = result,
                           WitSig    = WitScript.Empty
                       }
            }
            ;
            else
            {
                return(new ScriptSigs()
                {
                    ScriptSig = input1.ScriptSig.Length < input2.ScriptSig.Length ? input2.ScriptSig : input1.ScriptSig,
                    WitSig = new WitScript(result)
                });
            }
        }
        protected static BitcoinStream CreateHashWriter(HashVersion version)
        {
            var hs     = new HashStream();
            var stream = new BitcoinStream(hs, true)
            {
                Type = SerializationType.Hash,
                TransactionOptions =
                    version == HashVersion.Original ? TransactionOptions.None : TransactionOptions.Witness
            };

            return(stream);
        }
Пример #6
0
        public static byte[] GenerateHash(byte[] input, HashVersion version)
        {
            byte[] output = null;

            switch (version)
            {
            case HashVersion.SHA1:
                output = GenerateSHA1Hash(input);
                break;

            case HashVersion.SHA512:
                output = GenerateSHA512Hash(input);
                break;

            default:
                output = null;
                break;
            }
            return(output);
        }
Пример #7
0
            public override uint256 GetSignatureHash(Script scriptCode, int nIn, SigHash nHashType, TxOut spentOutput, HashVersion sigversion, PrecomputedTransactionData precomputedTransactionData)
            {
                if (sigversion == HashVersion.WitnessV0)
                {
                    if (spentOutput?.Value == null || spentOutput.Value == TxOut.NullMoney)
                    {
                        throw new ArgumentException("The output being signed with the amount must be provided", nameof(spentOutput));
                    }
                    uint256 hashPrevouts = uint256.Zero;
                    uint256 hashSequence = uint256.Zero;
                    uint256 hashOutputs  = uint256.Zero;

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

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

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

                    BitcoinStream sss = CreateHashWriter(sigversion);
                    // Version
                    sss.ReadWrite(this.Version);
                    // PoS Time
                    sss.ReadWrite(this.Time);
                    // 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(Inputs[nIn].PrevOut);
                    sss.ReadWrite(scriptCode);
                    sss.ReadWrite(spentOutput.Value.Satoshi);
                    sss.ReadWrite(Inputs[nIn].Sequence);
                    // Outputs (none/one/all, depending on flags)
                    sss.ReadWrite(hashOutputs);
                    // Locktime
                    sss.ReadWriteStruct(LockTime);
                    // Sighash type
                    sss.ReadWrite((uint)nHashType);

                    return(GetHash(sss));
                }

                bool fAnyoneCanPay = (nHashType & SigHash.AnyoneCanPay) != 0;
                bool fHashSingle   = ((byte)nHashType & 0x1f) == (byte)SigHash.Single;
                bool fHashNone     = ((byte)nHashType & 0x1f) == (byte)SigHash.None;

                if (nIn >= Inputs.Count)
                {
                    return(uint256.One);
                }
                if (fHashSingle)
                {
                    if (nIn >= Outputs.Count)
                    {
                        return(uint256.One);
                    }
                }

                var stream = CreateHashWriter(sigversion);

                stream.ReadWrite(Version);
                stream.ReadWrite(Time);
                uint nInputs = (uint)(fAnyoneCanPay ? 1 : Inputs.Count);

                stream.ReadWriteAsVarInt(ref nInputs);
                for (int nInput = 0; nInput < nInputs; nInput++)
                {
                    if (fAnyoneCanPay)
                    {
                        nInput = nIn;
                    }
                    stream.ReadWrite(Inputs[nInput].PrevOut);
                    if (nInput != nIn)
                    {
                        stream.ReadWrite(Script.Empty);
                    }
                    else
                    {
                        WriteScriptCode(stream, scriptCode);
                    }

                    if (nInput != nIn && (fHashSingle || fHashNone))
                    {
                        stream.ReadWrite((uint)0);
                    }
                    else
                    {
                        stream.ReadWrite(Inputs[nInput].Sequence);
                    }
                }

                uint nOutputs = (uint)(fHashNone ? 0 : (fHashSingle ? nIn + 1 : Outputs.Count));

                stream.ReadWriteAsVarInt(ref nOutputs);
                for (int nOutput = 0; nOutput < nOutputs; nOutput++)
                {
                    if (fHashSingle && nOutput != nIn)
                    {
                        this.Outputs.CreateNewTxOut().ReadWrite(stream);
                    }
                    else
                    {
                        Outputs[nOutput].ReadWrite(stream);
                    }
                }

                stream.ReadWriteStruct(LockTime);
                stream.ReadWrite((uint)nHashType);
                return(GetHash(stream));
            }
Пример #8
0
 public static uint256 SignatureHash(Script scriptCode, Transaction txTo, int nIn, SigHash nHashType, Money amount, HashVersion sigversion, PrecomputedTransactionData precomputedTransactionData)
 {
     return(txTo.GetSignatureHash(scriptCode, nIn, nHashType, amount, sigversion, precomputedTransactionData));
 }
Пример #9
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;
			}

			var hashType = nHashType & (SigHash)31;

			// Check for invalid use of SIGHASH_SINGLE
			if(hashType == 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;

			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);
		}
Пример #10
0
 public static uint256 SignatureHash(Script scriptCode, Transaction txTo, int nIn, SigHash nHashType, Money amount = null, HashVersion sigversion = HashVersion.Original)
 {
     return(SignatureHash(scriptCode, txTo, nIn, nHashType, amount, sigversion, null));
 }
Пример #11
0
		private static Script CombineMultisig(Script scriptPubKey, TransactionChecker checker, byte[][] sigs1, byte[][] sigs2, HashVersion hashVersion)
		{
			// Combine all the signatures we've got:
			List<TransactionSignature> allsigs = new List<TransactionSignature>();
			foreach(var v in sigs1)
			{
				if(TransactionSignature.IsValid(v))
				{
					allsigs.Add(new TransactionSignature(v));
				}
			}


			foreach(var v in sigs2)
			{
				if(TransactionSignature.IsValid(v))
				{
					allsigs.Add(new TransactionSignature(v));
				}
			}

			var multiSigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);
			if(multiSigParams == null)
				throw new InvalidOperationException("The scriptPubKey is not a valid multi sig");

			Dictionary<PubKey, TransactionSignature> sigs = new Dictionary<PubKey, TransactionSignature>();

			foreach(var sig in allsigs)
			{
				foreach(var pubkey in multiSigParams.PubKeys)
				{
					if(sigs.ContainsKey(pubkey))
						continue; // Already got a sig for this pubkey

					ScriptEvaluationContext eval = new ScriptEvaluationContext();
					if(eval.CheckSig(sig, pubkey, scriptPubKey, checker, hashVersion))
					{
						sigs.AddOrReplace(pubkey, sig);
					}
				}
			}


			// Now build a merged CScript:
			int nSigsHave = 0;
			Script result = new Script(OpcodeType.OP_0); // pop-one-too-many workaround
			foreach(var pubkey in multiSigParams.PubKeys)
			{
				if(sigs.ContainsKey(pubkey))
				{
					result += Op.GetPushOp(sigs[pubkey].ToBytes());
					nSigsHave++;
				}
				if(nSigsHave >= multiSigParams.SignatureCount)
					break;
			}

			// Fill any missing with OP_0:
			for(int i = nSigsHave ; i < multiSigParams.SignatureCount ; i++)
				result += OpcodeType.OP_0;

			return result;
		}
Пример #12
0
		private static Script CombineSignatures(Script scriptPubKey, TransactionChecker checker, byte[][] sigs1, byte[][] sigs2, HashVersion hashVersion)
		{
			var template = StandardScripts.GetTemplateFromScriptPubKey(scriptPubKey);

			if(template is PayToWitPubKeyHashTemplate)
			{
				scriptPubKey = new KeyId(scriptPubKey.ToBytes(true).SafeSubarray(1, 20)).ScriptPubKey;
				template = StandardScripts.GetTemplateFromScriptPubKey(scriptPubKey);
			}
			if(template == null || template is TxNullDataTemplate)
				return PushAll(Max(sigs1, sigs2));

			if(template is PayToPubkeyTemplate || template is PayToPubkeyHashTemplate)
				if(sigs1.Length == 0 || sigs1[0].Length == 0)
					return PushAll(sigs2);
				else
					return PushAll(sigs1);
			if(template is PayToScriptHashTemplate || template is PayToWitTemplate)
			{
				if(sigs1.Length == 0 || sigs1[sigs1.Length - 1].Length == 0)
					return PushAll(sigs2);

				if(sigs2.Length == 0 || sigs2[sigs2.Length - 1].Length == 0)
					return PushAll(sigs1);

				var redeemBytes = sigs1[sigs1.Length - 1];
				var redeem = new Script(redeemBytes);
				sigs1 = sigs1.Take(sigs1.Length - 1).ToArray();
				sigs2 = sigs2.Take(sigs2.Length - 1).ToArray();
				Script result = CombineSignatures(redeem, checker, sigs1, sigs2, hashVersion);
				result += Op.GetPushOp(redeemBytes);
				return result;
			}

			if(template is PayToMultiSigTemplate)
			{
				return CombineMultisig(scriptPubKey, checker, sigs1, sigs2, hashVersion);
			}

			return null;
		}
Пример #13
0
        public override uint256 GetSignatureHash(Script scriptCode, int nIn, SigHash nHashType, Money amount,
                                                 HashVersion sigversion, PrecomputedTransactionData precomputedTransactionData)
        {
            if (nIn >= Inputs.Count && (uint)nIn != NOT_AN_INPUT) // second condition is always true, NBitcoin restricts us to transparent txs only, left to match the original code
            {
                throw new InvalidOperationException("Input index is out of range");
            }

            if (fOverwintered && (nVersionGroupId == OVERWINTER_VERSION_GROUP_ID || nVersionGroupId == SAPLING_VERSION_GROUP_ID))
            {
                uint256 hashPrevouts        = uint256.Zero;
                uint256 hashSequence        = uint256.Zero;
                uint256 hashOutputs         = uint256.Zero;
                uint256 hashJoinSplits      = uint256.Zero;
                uint256 hashShieldedSpends  = uint256.Zero;
                uint256 hashShieldedOutputs = uint256.Zero;

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

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

                if (((uint)nHashType & 0x1f) != (uint)SigHash.Single && ((uint)nHashType & 0x1f) != (uint)SigHash.None)
                {
                    hashOutputs = precomputedTransactionData == null?
                                  GetHashOutputs() : precomputedTransactionData.HashOutputs;
                }
                else if (((uint)nHashType & 0x1f) == (uint)SigHash.Single && nIn < this.Outputs.Count)
                {
                    using (var ss = new BLAKE2bWriter(ZCASH_OUTPUTS_HASH_PERSONALIZATION))
                    {
                        ss.ReadWrite(Outputs[nIn]);
                        hashOutputs = ss.GetHash();
                    }
                }

                if (vjoinsplit.Any())
                {
                    hashJoinSplits = GetJoinSplitsHash();
                }

                if (vShieldedSpend.Any())
                {
                    hashShieldedSpends = GetShieldedSpendsHash();
                }

                if (vShieldedOutput.Any())
                {
                    hashShieldedOutputs = GetShieldedOutputsHash();
                }

                var branchId =
                    nBranchId.HasValue ? nBranchId.Value :
                    Version == OVERWINTER_VERSION ? OVERWINTER_BRANCH_ID :
                    Version == SAPLING_VERSION ? SAPLING_BRANCH_ID :
                    0;

                var branchIdData = BitConverter.IsLittleEndian ?
                                   BitConverter.GetBytes(branchId) :
                                   BitConverter.GetBytes(branchId).Reverse().ToArray();

                var personal = Encoding.ASCII.GetBytes("ZcashSigHash")
                               .Concat(branchIdData)
                               .ToArray();

                using (var ss = new BLAKE2bWriter(personal))
                {
                    // Version
                    var nVersion = Version;
                    ss.ReadWriteVersionEncoded(ref nVersion, ref fOverwintered);
                    ss.ReadWrite(nVersionGroupId);
                    // Input prevouts/nSequence (none/all, depending on flags)
                    ss.ReadWrite(hashPrevouts);
                    ss.ReadWrite(hashSequence);
                    // Outputs (none/one/all, depending on flags)
                    ss.ReadWrite(hashOutputs);
                    // JoinSplits
                    ss.ReadWrite(hashJoinSplits);

                    if (nVersionGroupId == SAPLING_VERSION_GROUP_ID)
                    {
                        // Spend descriptions
                        ss.ReadWrite(hashShieldedSpends);
                        // Output descriptions
                        ss.ReadWrite(hashShieldedOutputs);
                    }

                    // Locktime
                    ss.ReadWriteStruct(LockTime);
                    // Expiry height
                    ss.ReadWrite(nExpiryHeight);

                    if (nVersionGroupId == SAPLING_VERSION_GROUP_ID)
                    {
                        // Sapling value balance
                        ss.ReadWrite(valueBalance);
                    }

                    // Sighash type
                    ss.ReadWrite((uint)nHashType);


                    // If this hash is for a transparent input signature
                    // (i.e. not for txTo.joinSplitSig):
                    if ((uint)nIn != NOT_AN_INPUT) // always true, NBitcoin restricts us to transparent txs only, left to match the original code
                    {
                        // The input being signed (replacing the scriptSig with scriptCode + amount)
                        // The prevout may already be contained in hashPrevout, and the nSequence
                        // may already be contained in hashSequence.
                        ss.ReadWrite(Inputs[nIn].PrevOut);
                        ss.ReadWrite(scriptCode);
                        ss.ReadWrite(amount.Satoshi);
                        ss.ReadWrite(Inputs[nIn].Sequence.Value);
                    }

                    return(ss.GetHash());
                }
            }
            else
            {
                // Check for invalid use of SIGHASH_SINGLE
                if (((uint)nHashType & 0x1f) == (uint)SigHash.Single)
                {
                    if (nIn >= Outputs.Count)
                    {
                        throw new InvalidOperationException("No matching output for SIGHASH_SINGLE");
                    }
                }

                var scriptCopy = new Script(scriptCode.ToOps().Where(op => op.Code != OpcodeType.OP_CODESEPARATOR));
                var txCopy     = new ZcashTransaction(this.ToHex());

                //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 (nHashType == 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 (nHashType == 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;
                }

                // clean JS signature
                // see https://github.com/zcash/zcash/blob/e868f8247faea8cc74aef69262d93bdeacc82c53/src/script/interpreter.cpp#L1053
                txCopy.joinSplitSig = new byte[64];

                //Serialize TxCopy, append 4 byte hashtypecode
                using (var hs = CreateSignatureHashStream())
                {
                    BitcoinStream stream = new BitcoinStream(hs, true);
                    stream.Type = SerializationType.Hash;
                    stream.TransactionOptions = sigversion == HashVersion.Original ? TransactionOptions.None : TransactionOptions.Witness;
                    txCopy.ReadWrite(stream);
                    stream.ReadWrite((uint)nHashType);
                    return(hs.GetHash());
                }
            }
        }
Пример #14
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 (txTo.useForkID == true)
            {
                //Because Bitcoin Cash hashes similar to Segwit hashes (uses amount of input), treat it as a segwit transaction for hashing
                sigversion = HashVersion.Witness;
            }
            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
                uint write_nHashType = (uint)nHashType;
                if (txTo.useForkID == true)
                {
                    //Bitshift the hashtype with the zero-byte forkID if present for BCH
                    write_nHashType |= 0x00 << 8;                     //ForkID for BCH is 0, bitshift most significant digits
                }
                sss.ReadWrite(write_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(), txTo.hasTimeStamp);

            //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);
            if (txTo.useHASH256 == true)
            {
                return(GetHash(stream));
            }
            else
            {
                return(GetSHA256Hash(stream));
            }
        }
Пример #15
0
        private static Script CombineSignatures(Script scriptPubKey, TransactionChecker checker, byte[][] sigs1, byte[][] sigs2, HashVersion hashVersion)
        {
            var template = StandardScripts.GetTemplateFromScriptPubKey(scriptPubKey);

            if (template is PayToWitPubKeyHashTemplate)
            {
                scriptPubKey = new KeyId(scriptPubKey.ToBytes(true).SafeSubarray(1, 20)).ScriptPubKey;
                template     = StandardScripts.GetTemplateFromScriptPubKey(scriptPubKey);
            }
            if (template == null || template is TxNullDataTemplate)
            {
                return(PushAll(Max(sigs1, sigs2)));
            }

            if (template is PayToPubkeyTemplate || template is PayToPubkeyHashTemplate)
            {
                if (sigs1.Length == 0 || sigs1[0].Length == 0)
                {
                    return(PushAll(sigs2));
                }
                else
                {
                    return(PushAll(sigs1));
                }
            }
            if (template is PayToScriptHashTemplate || template is PayToWitTemplate)
            {
                if (sigs1.Length == 0 || sigs1[sigs1.Length - 1].Length == 0)
                {
                    return(PushAll(sigs2));
                }

                if (sigs2.Length == 0 || sigs2[sigs2.Length - 1].Length == 0)
                {
                    return(PushAll(sigs1));
                }

                var redeemBytes = sigs1[sigs1.Length - 1];
                var redeem      = new Script(redeemBytes);
                sigs1 = sigs1.Take(sigs1.Length - 1).ToArray();
                sigs2 = sigs2.Take(sigs2.Length - 1).ToArray();
                Script result = CombineSignatures(redeem, checker, sigs1, sigs2, hashVersion);
                result += Op.GetPushOp(redeemBytes);
                return(result);
            }

            if (template is PayToMultiSigTemplate)
            {
                return(CombineMultisig(scriptPubKey, checker, sigs1, sigs2, hashVersion));
            }

            return(null);
        }
Пример #16
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);
		}
Пример #17
0
        private static Script CombineMultisig(Script scriptPubKey, TransactionChecker checker, byte[][] sigs1, byte[][] sigs2, HashVersion hashVersion)
        {
            // Combine all the signatures we've got:
            List <TransactionSignature> allsigs = new List <TransactionSignature>();

            foreach (var v in sigs1)
            {
                if (TransactionSignature.IsValid(v))
                {
                    allsigs.Add(new TransactionSignature(v));
                }
            }


            foreach (var v in sigs2)
            {
                if (TransactionSignature.IsValid(v))
                {
                    allsigs.Add(new TransactionSignature(v));
                }
            }

            var multiSigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey);

            if (multiSigParams == null)
            {
                throw new InvalidOperationException("The scriptPubKey is not a valid multi sig");
            }

            Dictionary <PubKey, TransactionSignature> sigs = new Dictionary <PubKey, TransactionSignature>();

            foreach (var sig in allsigs)
            {
                foreach (var pubkey in multiSigParams.PubKeys)
                {
                    if (sigs.ContainsKey(pubkey))
                    {
                        continue;                         // Already got a sig for this pubkey
                    }
                    ScriptEvaluationContext eval = new ScriptEvaluationContext();
                    if (eval.CheckSig(sig, pubkey, scriptPubKey, checker, hashVersion))
                    {
                        sigs.AddOrReplace(pubkey, sig);
                    }
                }
            }


            // Now build a merged CScript:
            int    nSigsHave = 0;
            Script result    = new Script(OpcodeType.OP_0);          // pop-one-too-many workaround

            foreach (var pubkey in multiSigParams.PubKeys)
            {
                if (sigs.ContainsKey(pubkey))
                {
                    result += Op.GetPushOp(sigs[pubkey].ToBytes());
                    nSigsHave++;
                }
                if (nSigsHave >= multiSigParams.SignatureCount)
                {
                    break;
                }
            }

            // Fill any missing with OP_0:
            for (int i = nSigsHave; i < multiSigParams.SignatureCount; i++)
            {
                result += OpcodeType.OP_0;
            }

            return(result);
        }
Пример #18
0
		private static BitcoinStream CreateHashWriter(HashVersion version)
		{
			BitcoinStream stream = new BitcoinStream(new MemoryStream(), true);
			stream.Type = SerializationType.Hash;
			stream.TransactionOptions = version == HashVersion.Original ? TransactionOptions.None : TransactionOptions.Witness;
			return stream;
		}
Пример #19
0
        public override uint256 GetSignatureHash(Script scriptCode, int nIn, SigHash nHashType, TxOut spentOutput, HashVersion sigversion, PrecomputedTransactionData precomputedTransactionData)
        {
            uint nForkHashType = (uint)nHashType;

            if (UsesForkId(nHashType))
            {
                nForkHashType |= ForkId << 8;
            }

            if ((SupportSegwit && sigversion == HashVersion.Witness) || UsesForkId(nHashType))
            {
                if (spentOutput?.Value == null || spentOutput.Value == TxOut.NullMoney)
                {
                    throw new ArgumentException("The output being signed with the amount must be provided", nameof(spentOutput));
                }
                uint256 hashPrevouts = uint256.Zero;
                uint256 hashSequence = uint256.Zero;
                uint256 hashOutputs  = uint256.Zero;

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

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

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

                BitcoinStream sss = CreateHashWriter(sigversion);
                // Version
                sss.ReadWrite(this.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(Inputs[nIn].PrevOut);
                sss.ReadWrite(scriptCode);
                sss.ReadWrite(spentOutput.Value.Satoshi);
                sss.ReadWrite((uint)Inputs[nIn].Sequence);
                // Outputs (none/one/all, depending on flags)
                sss.ReadWrite(hashOutputs);
                // Locktime
                sss.ReadWriteStruct(LockTime);
                // Sighash type
                sss.ReadWrite((uint)nForkHashType);

                return(GetHash(sss));
            }



            if (nIn >= Inputs.Count)
            {
                return(uint256.One);
            }

            var hashType = nHashType & (SigHash)31;

            // Check for invalid use of SIGHASH_SINGLE
            if (hashType == SigHash.Single)
            {
                if (nIn >= Outputs.Count)
                {
                    return(uint256.One);
                }
            }

            var scriptCopy = scriptCode.Clone();

            scriptCode = scriptCopy.FindAndDelete(OpcodeType.OP_CODESEPARATOR);

            var txCopy = GetConsensusFactory().CreateTransaction();

            txCopy.FromBytes(this.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 (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)nForkHashType);
            return(GetHash(stream));
        }
Пример #20
0
        /*
         *  if (nIn >= txTo.vin.size())
         *  {
         *      printf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn);
         *      return 1;
         *  }
         *  CTransaction txTmp(txTo);
         *
         *  // In case concatenating two scripts ends up with two codeseparators,
         *  // or an extra one at the end, this prevents all those possible incompatibilities.
         *  scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR));
         *
         *  // Blank out other inputs' signatures
         *  for (unsigned int i = 0; i < txTmp.vin.size(); i++)
         *      txTmp.vin[i].scriptSig = CScript();
         *  txTmp.vin[nIn].scriptSig = scriptCode;
         *
         *  // Blank out some of the outputs
         *  if ((nHashType & 0x1f) == SIGHASH_NONE)
         *  {
         *      // Wildcard payee
         *      txTmp.vout.clear();
         *
         *      // Let the others update at will
         *      for (unsigned int i = 0; i < txTmp.vin.size(); i++)
         *          if (i != nIn)
         *              txTmp.vin[i].nSequence = 0;
         *  }
         *  else if ((nHashType & 0x1f) == SIGHASH_SINGLE)
         *  {
         *      // Only lock-in the txout payee at same index as txin
         *      unsigned int nOut = nIn;
         *      if (nOut >= txTmp.vout.size())
         *      {
         *          printf("ERROR: SignatureHash() : nOut=%d out of range\n", nOut);
         *          return 1;
         *      }
         *      txTmp.vout.resize(nOut+1);
         *      for (unsigned int i = 0; i < nOut; i++)
         *          txTmp.vout[i].SetNull();
         *
         *      // Let the others update at will
         *      for (unsigned int i = 0; i < txTmp.vin.size(); i++)
         *          if (i != nIn)
         *              txTmp.vin[i].nSequence = 0;
         *  }
         *
         *  // Blank out other inputs completely, not recommended for open transactions
         *  if (nHashType & SIGHASH_ANYONECANPAY)
         *  {
         *      txTmp.vin[0] = txTmp.vin[nIn];
         *      txTmp.vin.resize(1);
         *  }
         *
         *  // Serialize and hash
         *  CHashWriter ss(SER_GETHASH, 0);
         *  ss << txTmp << nHashType;
         *  return ss.GetHash();
         */
        public override uint256 GetSignatureHash(Script scriptCode, int nIn, SigHash nHashType, Money amount,
                                                 HashVersion sigversion, PrecomputedTransactionData precomputedTransactionData)
        {
            if (nIn >= Inputs.Count)
            {
                //Utils.log("ERROR: SignatureHash() : nIn=" + nIn + " out of range\n");
                return(uint256.One);
            }

            var scriptCopy = new Script(scriptCode.ToBytes());

            scriptCopy = scriptCopy.FindAndDelete(OpcodeType.OP_CODESEPARATOR);

            var hashType = nHashType & (SigHash)31;

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

            var txCopy = (SolarCoinTransaction)GetConsensusFactory().CreateTransaction();

            txCopy.FromBytes(this.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 (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)
            {
                if (nIn >= Outputs.Count)
                {
                    //Utils.log("ERROR: SignatureHash() : nOut=" + nIn + " out of range\n");
                    return(uint256.One);
                }
                //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 < nIn; 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;
            }

            var previousType = txCopy.NType;

            txCopy.NType = (uint)PrimaryActions.SER_GETHASH;
            //Serialize TxCopy, append 4 byte hashtypecode
            var stream = CreateHashWriter(sigversion);

            txCopy.ReadWrite(stream);
            stream.ReadWrite((uint)nHashType);
            var txHash = GetHash(stream);

            txCopy.NType = previousType;

            return(txHash);
        }