public void TestCreateCoinbaseAndSpend() { var keyPair = TransactionManager.CreateKeyPair(); var privateKey = keyPair.Item1; var publicKey = keyPair.Item2; var coinbaseTx = TransactionManager.CreateCoinbaseTransaction(publicKey, Encoding.ASCII.GetBytes("coinbase text!")); var publicKeyScript = TransactionManager.CreatePublicKeyScript(publicKey); var privateKeyScript = TransactionManager.CreatePrivateKeyScript(coinbaseTx, 0, (byte)ScriptHashType.SIGHASH_ALL, privateKey, publicKey); var script = privateKeyScript.Concat(publicKeyScript); var scriptEngine = new ScriptEngine(); Assert.IsTrue(scriptEngine.VerifyScript(0, 0, publicKeyScript.ToArray(), coinbaseTx, 0, script)); }
public static byte[] CreatePrivateKeyScript(Transaction tx, int inputIndex, byte hashType, ECPrivateKeyParameters privateKey, ECPublicKeyParameters publicKey) { //TODO var scriptEngine = new ScriptEngine(); var publicAddress = CreatePublicAddress(publicKey); var publicKeyScript = CreatePublicKeyScript(publicAddress); var txSignature = scriptEngine.TxSignature(publicKeyScript.ToImmutableArray(), tx, inputIndex, hashType); var txSignatureHash = Crypto.DoubleSHA256(txSignature); //Debug.WriteLine("Signing Tx: {0}".Format2(txSignature.ToHexDataString())); //Debug.WriteLine("Signing Tx Hash: {0}".Format2(txSignatureHash.ToHexDataString())); var signer = new ECDsaSigner(); signer.Init(forSigning: true, parameters: privateKey); var signature = signer.GenerateSignature(txSignatureHash); var r = signature[0]; var s = signature[1]; byte[] sigEncoded; using (var stream = new MemoryStream()) { using (var asn1Stream = new Asn1OutputStream(stream)) { asn1Stream.WriteObject(new DerSequence(new DerInteger(r), new DerInteger(s))); } sigEncoded = stream.ToArray().Concat(hashType); } //Debug.WriteLine("Sig R: {0}".Format2(r.ToHexNumberStringUnsigned())); //Debug.WriteLine("Sig S: {0}".Format2(s.ToHexNumberStringUnsigned())); //Debug.WriteLine("Sig Encoded: {0}".Format2(sigEncoded.ToHexDataString())); var privateKeyScript = new ScriptBuilder(); privateKeyScript.WritePushData(sigEncoded); privateKeyScript.WritePushData(publicAddress); //Debug.WriteLine("Private Script: {0}".Format2(privateKeyScript.GetScript().ToHexDataString())); return privateKeyScript.GetScript(); }
//TODO utxo needs to be as-at transaction, with regards to a transaction being fully spent and added back in in the same block public virtual void ValidateTransactionScripts(Block block, ImmutableDictionary<UInt256, UnspentTx> utxo, ImmutableDictionary<UInt256, ImmutableHashSet<int>> newTransactions) { if (BypassExecuteScript) return; // lookup all previous outputs var prevOutputMissing = false; var previousOutputs = new Dictionary<TxOutputKey, Tuple<Transaction, TxInput, int, TxOutput>>(); for (var txIndex = 1; txIndex < block.Transactions.Length; txIndex++) { var tx = block.Transactions[txIndex]; for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++) { var input = tx.Inputs[inputIndex]; // find previous transaction var prevTx = GetPreviousTransaction(block, txIndex, input.PreviousTxOutputKey, utxo, newTransactions); // find previous transaction output if (input.PreviousTxOutputKey.TxOutputIndex >= prevTx.Outputs.Length) throw new ValidationException(); var prevOutput = prevTx.Outputs[input.PreviousTxOutputKey.TxOutputIndex.ToIntChecked()]; previousOutputs.Add(input.PreviousTxOutputKey, Tuple.Create(tx, input, inputIndex, prevOutput)); } } if (prevOutputMissing) { throw new ValidationException(); } var exceptions = new ConcurrentBag<Exception>(); var scriptEngine = new ScriptEngine(); Parallel.ForEach(previousOutputs.Values, (tuple, loopState) => { try { var tx = tuple.Item1; var input = tuple.Item2; var inputIndex = tuple.Item3; var prevOutput = tuple.Item4; // create the transaction script from the input and output var script = input.ScriptSignature.AddRange(prevOutput.ScriptPublicKey); if (!scriptEngine.VerifyScript(0 /*TODO blockHash*/, 0 /*TODO txIndex*/, prevOutput.ScriptPublicKey.ToArray(), tx, inputIndex, script.ToArray())) { exceptions.Add(new ValidationException()); loopState.Break(); } } catch (Exception e) { exceptions.Add(e); loopState.Break(); } }); if (exceptions.Count > 0) throw new AggregateException(exceptions.ToArray()); }
private void TestTransactionVerifySignature(byte[] expectedHashTypes, byte[][] expectedSignatures, byte[][] expectedSignatureHashes, byte[][] expectedX, byte[][] expectedY, byte[][] expectedR, byte[][] expectedS, Transaction tx, IDictionary<UInt256, Transaction> txLookup) { var scriptEngine = new ScriptEngine(); for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++) { var input = tx.Inputs[inputIndex]; var prevOutput = txLookup[input.PreviousTxOutputKey.TxHash].Outputs[input.PreviousTxOutputKey.TxOutputIndex.ToIntChecked()]; var hashType = GetHashTypeFromScriptSig(input.ScriptSignature); var sig = GetSigFromScriptSig(input.ScriptSignature); var pubKey = GetPubKeyFromScripts(input.ScriptSignature, prevOutput.ScriptPublicKey); byte[] txSignature, txSignatureHash; BigInteger x, y, r, s; var result = scriptEngine.VerifySignature(prevOutput.ScriptPublicKey, tx, sig.ToArray(), pubKey.ToArray(), inputIndex, out hashType, out txSignature, out txSignatureHash, out x, out y, out r, out s); Debug.WriteLine(hashType); Debug.WriteLine(txSignature.ToHexDataString()); Debug.WriteLine(txSignatureHash.ToHexNumberString()); Debug.WriteLine(x.ToHexNumberString()); Debug.WriteLine(y.ToHexNumberString()); Debug.WriteLine(r.ToHexNumberString()); Debug.WriteLine(s.ToHexNumberString()); Assert.AreEqual(expectedHashTypes[inputIndex], hashType); CollectionAssert.AreEqual(expectedSignatures[inputIndex].ToList(), txSignature.ToList()); CollectionAssert.AreEqual(expectedSignatureHashes[inputIndex].ToList(), txSignatureHash.ToList()); CollectionAssert.AreEqual(expectedX[inputIndex], x.ToByteArrayUnsigned()); CollectionAssert.AreEqual(expectedY[inputIndex], y.ToByteArrayUnsigned()); CollectionAssert.AreEqual(expectedR[inputIndex], r.ToByteArrayUnsigned()); CollectionAssert.AreEqual(expectedS[inputIndex], s.ToByteArrayUnsigned()); Assert.IsTrue(result); } }
private void TestTransactionVerifyScript(Transaction tx, IDictionary<UInt256, Transaction> txLookup) { var scriptEngine = new ScriptEngine(); for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++) { var input = tx.Inputs[inputIndex]; var prevOutput = txLookup[input.PreviousTxOutputKey.TxHash].Outputs[input.PreviousTxOutputKey.TxOutputIndex.ToIntChecked()]; var script = GetScriptFromInputPrevOutput(input, prevOutput); var result = scriptEngine.VerifyScript(0 /*blockIndex*/, -1 /*txIndex*/, prevOutput.ScriptPublicKey.ToArray(), tx, inputIndex, script.ToArray()); Assert.IsTrue(result); } }
private void TestTransactionSignature(byte[][] expectedSignatures, Transaction tx, IDictionary<UInt256, Transaction> txLookup) { var scriptEngine = new ScriptEngine(); for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++) { var input = tx.Inputs[inputIndex]; var prevOutput = txLookup[input.PreviousTxOutputKey.TxHash].Outputs[input.PreviousTxOutputKey.TxOutputIndex.ToIntChecked()]; var hashType = GetHashTypeFromScriptSig(input.ScriptSignature); var actual = scriptEngine.TxSignature(prevOutput.ScriptPublicKey, tx, inputIndex, hashType); CollectionAssert.AreEqual(expectedSignatures[inputIndex].ToList(), actual.ToList()); } }