private static bool VerifySignature(Transaction txFrom, Transaction txTo, int txToInN, ScriptVerify flagScriptVerify) { var input = txTo.Inputs[txToInN]; if (input.PrevOut.N >= txFrom.Outputs.Count) { return(false); } if (input.PrevOut.Hash != txFrom.GetHash()) { return(false); } var output = txFrom.Outputs[input.PrevOut.N]; var txData = new PrecomputedTransactionData(txFrom); var checker = new TransactionChecker(txTo, txToInN, output.Value, txData); var ctx = new ScriptEvaluationContext { ScriptVerify = flagScriptVerify }; return(ctx.VerifyScript(input.ScriptSig, output.ScriptPubKey, checker)); }
//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)); }