public static UInt256 ComputeSignatureHash ( Script scriptCode, Transaction txTo, int nIn, SignatureHashType sigHashType, Amount amount, ScriptFlags flags = ScriptFlags.ENABLE_SIGHASH_FORKID ) { if (sigHashType.HasForkId && (flags & ScriptFlags.ENABLE_SIGHASH_FORKID) != 0) { var hashPrevOuts = new UInt256(); var hashSequence = new UInt256(); var hashOutputs = new UInt256(); if (!sigHashType.HasAnyoneCanPay) { hashPrevOuts = GetPrevOutHash(txTo); } var baseNotSingleOrNone = (sigHashType.GetBaseType() != BaseSignatureHashEnum.Single) && (sigHashType.GetBaseType() != BaseSignatureHashEnum.None); if (!sigHashType.HasAnyoneCanPay && baseNotSingleOrNone) { hashSequence = GetSequenceHash(txTo); } if (baseNotSingleOrNone) { hashOutputs = GetOutputsHash(txTo); } else if (sigHashType.GetBaseType() == BaseSignatureHashEnum.Single && nIn < txTo.Outputs.Length) { using var hw = new HashWriter(); hw.Add(txTo.Outputs[nIn]); hashOutputs = hw.GetHashFinal(); } using var writer = new HashWriter(); writer // Version .Add(txTo.Version) // Input prevouts/nSequence (none/all, depending on flags) .Add(hashPrevOuts) .Add(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. .Add(txTo.Inputs[nIn].PrevOut) .Add(scriptCode) .Add(amount) .Add(txTo.Inputs[nIn].Sequence) // Outputs (none/one/all, depending on flags) .Add(hashOutputs) // Locktime .Add(txTo.LockTime) // Sighash type .Add(sigHashType.RawSigHashType); return(writer.GetHashFinal()); } if (nIn >= txTo.Inputs.Length) { // nIn out of range return(UInt256.One); } // Check for invalid use of SIGHASH_SINGLE if (sigHashType.GetBaseType() == BaseSignatureHashEnum.Single && nIn >= txTo.Outputs.Length) { // nOut out of range return(UInt256.One); } { // Original digest algorithm... var hasAnyoneCanPay = sigHashType.HasAnyoneCanPay; // ReSharper disable once UnusedVariable var numberOfInputs = hasAnyoneCanPay ? 1 : txTo.Inputs.Length; using var writer = new HashWriter(); // Start with the version... writer.Add(txTo.Version); // Add Input(s)... if (hasAnyoneCanPay) { // AnyoneCanPay serializes only the input being signed. var i = txTo.Inputs[nIn]; writer .Add((byte)1) .Add(i.PrevOut) .Add(scriptCode, true) .Add(i.Sequence); } else { // Non-AnyoneCanPay case. Process all inputs but handle input being signed in its own way. var isSingleOrNone = sigHashType.IsBaseSingle || sigHashType.IsBaseNone; writer.Add(txTo.Inputs.Length.AsVarIntBytes()); for (var nInput = 0; nInput < txTo.Inputs.Length; nInput++) { var i = txTo.Inputs[nInput]; writer.Add(i.PrevOut); if (nInput != nIn) { writer.Add(Script.None); } else { writer.Add(scriptCode, true); } if (nInput != nIn && isSingleOrNone) { writer.Add(0); } else { writer.Add(i.Sequence); } } } // Add Output(s)... var nOutputs = sigHashType.IsBaseNone ? 0 : sigHashType.IsBaseSingle ? nIn + 1 : txTo.Outputs.Length; writer.Add(nOutputs.AsVarIntBytes()); for (var nOutput = 0; nOutput < nOutputs; nOutput++) { if (sigHashType.IsBaseSingle && nOutput != nIn) { writer.Add(TxOut.Null); } else { writer.Add(txTo.Outputs[nOutput]); } } // Finish up... writer .Add(txTo.LockTime) .Add(sigHashType.RawSigHashType) ; return(writer.GetHashFinal()); } }