public void CreateRawTransactionTest() { ExtPrivkey privkey = new ExtPrivkey("xprv9zt1onyw8BdEf7SQ6wUVH3bQQdGD9iy9QzXveQQRhX7i5iUN7jZgLbqFEe491LfjozztYa6bJAGZ65GmDCNcbjMdjZcgmdisPJwVjcfcDhV"); Address addr1 = new Address(privkey.DerivePubkey(1).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.Regtest); Address addr2 = new Address(privkey.DerivePubkey(2).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.Regtest); Address addr3 = new Address(privkey.DerivePubkey(3).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.Regtest); OutPoint outpoint1 = new OutPoint("0000000000000000000000000000000000000000000000000000000000000001", 2); OutPoint outpoint2 = new OutPoint("0000000000000000000000000000000000000000000000000000000000000001", 3); Transaction tx = new Transaction("02000000000000000000", new[] { new TxIn(outpoint1), new TxIn(outpoint2), }, new[] { new TxOut(10000, addr1.GetLockingScript()), new TxOut(10000, addr2.GetLockingScript()), }); tx.AddTxOut(50000, addr3); output.WriteLine("tx:\n" + tx.ToHexString()); Assert.Equal("020000000201000000000000000000000000000000000000000000000000000000000000000200000000ffffffff01000000000000000000000000000000000000000000000000000000000000000300000000ffffffff0310270000000000001600148b756cbd98f4f55e985f80437a619d47f0732a941027000000000000160014c0a3dd0b7c1b3281be91112e16ce931dbac2a97950c3000000000000160014ad3abd3c325e40e20d89aa054dd980b97494f16c00000000", tx.ToHexString()); Privkey privkey1 = privkey.DerivePrivkey(11).GetPrivkey(); Pubkey pubkey1 = privkey1.GetPubkey(); SignatureHashType sighashType = new SignatureHashType(CfdSighashType.All, false); ByteData sighash = tx.GetSignatureHash(outpoint1, CfdHashType.P2wpkh, pubkey1, 50000, sighashType); SignParameter signature = privkey1.CalculateEcSignature(sighash); signature.SetDerEncode(sighashType); tx.AddSign(outpoint1, CfdHashType.P2wpkh, signature, true); tx.AddSign(outpoint1, CfdHashType.P2wpkh, new SignParameter(pubkey1.ToHexString()), false); output.WriteLine("tx:\n" + tx.ToHexString()); Assert.Equal("0200000000010201000000000000000000000000000000000000000000000000000000000000000200000000ffffffff01000000000000000000000000000000000000000000000000000000000000000300000000ffffffff0310270000000000001600148b756cbd98f4f55e985f80437a619d47f0732a941027000000000000160014c0a3dd0b7c1b3281be91112e16ce931dbac2a97950c3000000000000160014ad3abd3c325e40e20d89aa054dd980b97494f16c02473044022034db802aad655cd9be589075fc8ef325b6ffb8c24e5b27eb87bde8ad38f5fd7a0220364c916c8e8fc0adf714d7148cd1c6dc6f3e67d55471e57233b1870c65ec2727012103782f0ea892d7000e5f0f82b6ff283382a76500137a542bb0a616530094a8f54c0000000000", tx.ToHexString()); Address addr11 = new Address(pubkey1, CfdAddressType.P2wpkh, CfdNetworkType.Regtest); try { tx.VerifySign(outpoint1, addr11, addr11.GetAddressType(), 50000); } catch (Exception e) { Assert.Null(e); } string json = Transaction.DecodeRawTransaction(tx); output.WriteLine(json); }
public void PrivkeySignTest() { ExtPrivkey privkey = new ExtPrivkey("xprv9zt1onyw8BdEf7SQ6wUVH3bQQdGD9iy9QzXveQQRhX7i5iUN7jZgLbqFEe491LfjozztYa6bJAGZ65GmDCNcbjMdjZcgmdisPJwVjcfcDhV"); Transaction tx = new Transaction("020000000201000000000000000000000000000000000000000000000000000000000000000200000000ffffffff01000000000000000000000000000000000000000000000000000000000000000300000000ffffffff0310270000000000001600148b756cbd98f4f55e985f80437a619d47f0732a941027000000000000160014c0a3dd0b7c1b3281be91112e16ce931dbac2a97950c3000000000000160014ad3abd3c325e40e20d89aa054dd980b97494f16c00000000"); OutPoint outpoint1 = new OutPoint("0000000000000000000000000000000000000000000000000000000000000001", 2); Privkey privkey1 = privkey.DerivePrivkey(11).GetPrivkey(); SignatureHashType sighashType = new SignatureHashType(CfdSighashType.All, false); tx.AddSignWithPrivkeySimple(outpoint1, CfdHashType.P2wpkh, privkey1, 50000, sighashType); // output.WriteLine("tx:\n" + tx.ToHexString()); Assert.Equal("0200000000010201000000000000000000000000000000000000000000000000000000000000000200000000ffffffff01000000000000000000000000000000000000000000000000000000000000000300000000ffffffff0310270000000000001600148b756cbd98f4f55e985f80437a619d47f0732a941027000000000000160014c0a3dd0b7c1b3281be91112e16ce931dbac2a97950c3000000000000160014ad3abd3c325e40e20d89aa054dd980b97494f16c02473044022034db802aad655cd9be589075fc8ef325b6ffb8c24e5b27eb87bde8ad38f5fd7a0220364c916c8e8fc0adf714d7148cd1c6dc6f3e67d55471e57233b1870c65ec2727012103782f0ea892d7000e5f0f82b6ff283382a76500137a542bb0a616530094a8f54c0000000000", tx.ToHexString()); }
public static byte[] SignTransaction(byte[] privateKey, Script script, Transaction transaction, int transactionInputIndex, SignatureHashType signatureType) { ContractsCommon.NotNull(privateKey, "privateKey"); ContractsCommon.NotNull(script, "script"); ContractsCommon.NotNull(transaction, "transaction"); ContractsCommon.ValidIndex(0, transaction.TransactionInputs.Count, transactionInputIndex, "transactionInputIndex"); ContractsCommon.ResultIsNonNull<byte[]>(); var hash = HashTransactionForSigning(script, transaction, transactionInputIndex, signatureType); var ecdsa = new ECDsaBouncyCastle(privateKey, true); return ecdsa.SignHash(hash.Bytes); }
public static Hash256 HashTransactionForSigning(Script script, Transaction transaction, int transactionInputIndex, SignatureHashType signatureType) { ContractsCommon.NotNull(script, "script"); ContractsCommon.NotNull(transaction, "transaction"); ContractsCommon.ValidIndex(0, transaction.TransactionInputs.Count, transactionInputIndex, "transactionInputIndex"); ContractsCommon.ResultIsNonNull<Hash256>(); var t = TransformTransactionForSigning(script, transaction, transactionInputIndex, signatureType); using (var ms = new MemoryStream(t.SerializedByteSize + BufferOperations.UINT32_SIZE)) { t.Serialize(ms); var sigType = (int)signatureType; ms.WriteByte((byte)sigType); ms.WriteByte((byte)(sigType >> 8)); ms.WriteByte((byte)(sigType >> 16)); ms.WriteByte((byte)(sigType >> 24)); return CryptoFunctionProviderFactory.Default.Hash256(ms.ToArray()); } }
/// <summary> /// encode by DER. /// </summary> /// <param name="signature">signature</param> /// <param name="sighashType">sighash type</param> /// <returns>DER encoded data</returns> public static ByteData EncodeToDer(ByteData signature, SignatureHashType sighashType) { if (signature is null) { throw new ArgumentNullException(nameof(signature)); } using (var handle = new ErrorHandle()) { var ret = NativeMethods.CfdEncodeSignatureByDer( handle.GetHandle(), signature.ToHexString(), sighashType.GetValue(), sighashType.IsSighashAnyoneCanPay, out IntPtr derSignature); if (ret != CfdErrorCode.Success) { handle.ThrowError(ret); } return(new ByteData(CCommon.ConvertToString(derSignature))); } }
public void TaprootSchnorrSignTest1() { var sk = new Privkey("305e293b010d29bf3c888b617763a438fee9054c8cab66eb12ad078f819d9f27"); var spk = SchnorrPubkey.GetPubkeyFromPrivkey(sk, out bool _); Assert.Equal("1777701648fa4dd93c74edd9d58cfcc7bdc2fa30a2f6fa908b6fd70c92833cfb", spk.ToHexString()); var addr = new Address(spk, CfdAddressType.Taproot, CfdNetworkType.Testnet); var txHex = "020000000116d975e4c2cea30f72f4f5fe528f5a0727d9ea149892a50c030d44423088ea2f0000000000ffffffff0130f1029500000000160014164e985d0fc92c927a66c0cbaf78e6ea389629d500000000"; var outpoint = new OutPoint("2fea883042440d030ca5929814ead927075a8f52fef5f4720fa3cec2e475d916", 0); var utxos = new UtxoData[] { new UtxoData(outpoint, 2499999000, new Descriptor(addr)), }; var tx = new Transaction(txHex); var feeData = tx.EstimateFee(utxos, 2.0); Assert.Equal(202, feeData.GetTotalFee()); tx.SetTxInUtxoData(utxos); var sighashType = new SignatureHashType(CfdSighashType.All); var sighash = tx.GetSigHashByUtxoData(outpoint, sighashType, spk); Assert.Equal("e5b11ddceab1e4fc49a8132ae589a39b07acf49cabb2b0fbf6104bc31da12c02", sighash.ToHexString()); var signature = SchnorrUtil.Sign(sighash, sk); var sig = signature.GetSignData(sighashType); Assert.Equal("61f75636003a870b7a1685abae84eedf8c9527227ac70183c376f7b3a35b07ebcbea14749e58ce1a87565b035b2f3963baa5ae3ede95e89fd607ab7849f2087201", sig.ToHexString()); tx.AddTaprootSchnorrSign(outpoint, sig); Assert.Equal("0200000000010116d975e4c2cea30f72f4f5fe528f5a0727d9ea149892a50c030d44423088ea2f0000000000ffffffff0130f1029500000000160014164e985d0fc92c927a66c0cbaf78e6ea389629d5014161f75636003a870b7a1685abae84eedf8c9527227ac70183c376f7b3a35b07ebcbea14749e58ce1a87565b035b2f3963baa5ae3ede95e89fd607ab7849f208720100000000", tx.ToHexString()); tx.VerifySignByUtxoList(outpoint); var isVerify = spk.Verify(signature, sighash); Assert.True(isVerify); }
public static bool VerifySignature(byte[] publicKey, byte[] sigHash, Script script, Transaction transaction, int transactionInputIndex, SignatureHashType signatureType) { ContractsCommon.NotNull(publicKey, "publicKey"); ContractsCommon.NotNull(sigHash, "sigHash"); ContractsCommon.NotNull(script, "script"); ContractsCommon.NotNull(transaction, "transaction"); ContractsCommon.ValidIndex(0, transaction.TransactionInputs.Count, transactionInputIndex, "transactionInputIndex"); // Cng ECC Public Key Blob format [72 bytes]: //6fbfcf5da60c7e59dfe724f4fb1b4e73f12bc48f17fb90f1e74f0d058c65e77c76aa75787f18ddd8be32b08014046ff62fef598011583e6f2d77e2b2ab850e5f0000002031534345 //coordY[cBytes]BIG-ENDIAN coordX[cBytes]BIG-ENDIAN cBytes[4]LITTLE-ENDIAN magic[4]LITTLE-ENDIAN // For ECDsaP256, that magic number is: 0x31534345U, and cBytes will be 0x00000020 // Bitcoin ECC Public Key Blob format [65 bytes]: //04e77ae594d5932f11547eea049b526044cbf8ac938fabfa97d3ab37732822572bd7d71c77a8ac1f5ca46fd73260f5aecc7270efbbf283bacd64ef0a9bb41e3ab9 //type[1] coordX[cBytes] coordY[cBytes] (all LITTLE-ENDIAN) // type = 04 means curve points are uncompressed. No other value is expected. // For secp256k1, cBytes = 0x00000020 // Probable issue here: Cng supports the NIST P-256 curve (alias of secp256r1), but Bitcoin uses the secp256k1 curve. if (signatureType == 0) { signatureType = (SignatureHashType)sigHash[sigHash.Length - 1]; } else if (signatureType != (SignatureHashType)sigHash[sigHash.Length - 1]) { return false; } var signature = new byte[72]; Array.Copy(sigHash, signature, signature.Length); var hash = HashTransactionForSigning(script, transaction, transactionInputIndex, signatureType); var ecdsa = new ECDsaBouncyCastle(publicKey, false); return ecdsa.VerifyHash(hash.Bytes, signature); }
/// <summary> /// Constructor. /// </summary> /// <param name="hex">hex string</param> public SchnorrSignature(string hex) { if (hex is null) { throw new ArgumentNullException(nameof(hex)); } if ((hex.Length != Size * 2) && (hex.Length != AddedSigHashTypeSize * 2)) { CfdCommon.ThrowError(CfdErrorCode.IllegalArgumentError, "Failed to signature size."); } data = hex; string[] list = Verify(data); nonce = new SchnorrPubkey(list[0]); key = new Privkey(list[1]); if (hex.Length == AddedSigHashTypeSize * 2) { sighashType = CollectSigHashType(data); } else { sighashType = new SignatureHashType(CfdSighashType.Default, false); } }
/// <summary> /// Calculate ec-signature. /// </summary> /// <param name="sighash">signature hash.</param> /// <param name="hasGrindR">use grind-R.</param> /// <returns></returns> public SignParameter CalculateEcSignature(ByteData sighash, bool hasGrindR) { if (sighash is null) { throw new ArgumentNullException(nameof(sighash)); } using (var handle = new ErrorHandle()) { var ret = NativeMethods.CfdCalculateEcSignature( handle.GetHandle(), sighash.ToHexString(), privkey, privkeyWif, (int)networkType, hasGrindR, out IntPtr signatureHex); if (ret != CfdErrorCode.Success) { handle.ThrowError(ret); } SignParameter signature = new SignParameter(CCommon.ConvertToString(signatureHex)); SignatureHashType sighashType = new SignatureHashType(CfdSighashType.All, false); signature.SetDerEncode(sighashType); signature.SetRelatedPubkey(GetPubkey()); return(signature); } }
public void TaprootSchnorrSignTest2() { var sk = new Privkey("305e293b010d29bf3c888b617763a438fee9054c8cab66eb12ad078f819d9f27"); var spk = SchnorrPubkey.GetPubkeyFromPrivkey(sk, out bool _); Assert.Equal("1777701648fa4dd93c74edd9d58cfcc7bdc2fa30a2f6fa908b6fd70c92833cfb", spk.ToHexString()); var addr = new Address(spk, CfdAddressType.Taproot, CfdNetworkType.Testnet); var txHex = "020000000116d975e4c2cea30f72f4f5fe528f5a0727d9ea149892a50c030d44423088ea2f0000000000ffffffff0130f1029500000000160014164e985d0fc92c927a66c0cbaf78e6ea389629d500000000"; var outpoint = new OutPoint("2fea883042440d030ca5929814ead927075a8f52fef5f4720fa3cec2e475d916", 0); var utxos = new UtxoData[] { new UtxoData(outpoint, 2499999000, new Descriptor(addr.GetLockingScript(), CfdNetworkType.Mainnet)), }; var tx = new Transaction(txHex); tx.SetTxInUtxoData(utxos); var sighashType = new SignatureHashType(CfdSighashType.All); tx.AddSignWithPrivkeyByUtxoList(outpoint, sk, sighashType); Assert.Equal("0200000000010116d975e4c2cea30f72f4f5fe528f5a0727d9ea149892a50c030d44423088ea2f0000000000ffffffff0130f1029500000000160014164e985d0fc92c927a66c0cbaf78e6ea389629d5014161f75636003a870b7a1685abae84eedf8c9527227ac70183c376f7b3a35b07ebcbea14749e58ce1a87565b035b2f3963baa5ae3ede95e89fd607ab7849f208720100000000", tx.ToHexString()); tx.VerifySignByUtxoList(outpoint); }
/// <summary> /// decode from DER. /// </summary> /// <param name="derSignature">DER encoded data</param> /// <returns>signature (SignParameter object)</returns> public static SignParameter DecodeFromDer(ByteData derSignature) { if (derSignature is null) { throw new ArgumentNullException(nameof(derSignature)); } using (var handle = new ErrorHandle()) { var ret = NativeMethods.CfdDecodeSignatureFromDer( handle.GetHandle(), derSignature.ToHexString(), out IntPtr signature, out int signatureHashType, out bool _); if (ret != CfdErrorCode.Success) { handle.ThrowError(ret); } string signatureStr = CCommon.ConvertToString(signature); SignatureHashType sighashType = new SignatureHashType(signatureHashType); SignParameter signParam = new SignParameter(signatureStr); signParam.SetDerEncode(sighashType); return(signParam); } }
public void GetTxInfoTest() { ExtPrivkey privkey = new ExtPrivkey("xprv9zt1onyw8BdEf7SQ6wUVH3bQQdGD9iy9QzXveQQRhX7i5iUN7jZgLbqFEe491LfjozztYa6bJAGZ65GmDCNcbjMdjZcgmdisPJwVjcfcDhV"); Address addr1 = new Address(privkey.DerivePubkey(1).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.Regtest); Address addr2 = new Address(privkey.DerivePubkey(2).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.Regtest); Address addr3 = new Address(privkey.DerivePubkey(3).GetPubkey(), CfdAddressType.P2wpkh, CfdNetworkType.Regtest); OutPoint outpoint1 = new OutPoint("0000000000000000000000000000000000000000000000000000000000000001", 2); OutPoint outpoint2 = new OutPoint("0000000000000000000000000000000000000000000000000000000000000001", 3); var txins = new[] { new TxIn(outpoint1), new TxIn(outpoint2), }; var txouts = new[] { new TxOut(10000, addr1.GetLockingScript()), new TxOut(10000, addr2.GetLockingScript()), }; Transaction tx = new Transaction("02000000000000000000", txins, txouts); tx.AddTxOut(50000, addr3); output.WriteLine("tx:\n" + tx.ToHexString()); Assert.Equal("020000000201000000000000000000000000000000000000000000000000000000000000000200000000ffffffff01000000000000000000000000000000000000000000000000000000000000000300000000ffffffff0310270000000000001600148b756cbd98f4f55e985f80437a619d47f0732a941027000000000000160014c0a3dd0b7c1b3281be91112e16ce931dbac2a97950c3000000000000160014ad3abd3c325e40e20d89aa054dd980b97494f16c00000000", tx.ToHexString()); Privkey privkey1 = privkey.DerivePrivkey(11).GetPrivkey(); SignatureHashType sighashType = new SignatureHashType(CfdSighashType.All, false); tx.AddSignWithPrivkeySimple(outpoint1, CfdHashType.P2wpkh, privkey1, 50000, sighashType); // output.WriteLine("tx:\n" + tx.ToHexString()); Assert.Equal("0200000000010201000000000000000000000000000000000000000000000000000000000000000200000000ffffffff01000000000000000000000000000000000000000000000000000000000000000300000000ffffffff0310270000000000001600148b756cbd98f4f55e985f80437a619d47f0732a941027000000000000160014c0a3dd0b7c1b3281be91112e16ce931dbac2a97950c3000000000000160014ad3abd3c325e40e20d89aa054dd980b97494f16c02473044022034db802aad655cd9be589075fc8ef325b6ffb8c24e5b27eb87bde8ad38f5fd7a0220364c916c8e8fc0adf714d7148cd1c6dc6f3e67d55471e57233b1870c65ec2727012103782f0ea892d7000e5f0f82b6ff283382a76500137a542bb0a616530094a8f54c0000000000", tx.ToHexString()); Txid txid = tx.GetTxid(); output.WriteLine("txid: " + txid.ToHexString()); Assert.Equal("67e1878d1621e77e166bed9d726bff27b2afcde9eb3dbb1ae3088d0387f40be4", txid.ToHexString()); Txid wtxid = tx.GetWtxid(); output.WriteLine("wtxid: " + wtxid.ToHexString()); Assert.Equal("24c66461b4b38c750fa4528d0cf3aea9a13d3156c0a73cfd6fca6958523b97f7", wtxid.ToHexString()); Assert.Equal((uint)295, tx.GetSize()); Assert.Equal((uint)213, tx.GetVsize()); Assert.Equal((uint)850, tx.GetWeight()); Assert.Equal((uint)2, tx.GetVersion()); Assert.Equal((uint)0, tx.GetLockTime()); Assert.Equal((uint)2, tx.GetTxInCount()); Assert.Equal((uint)3, tx.GetTxOutCount()); Assert.Equal((uint)1, tx.GetTxInIndex(outpoint2)); Assert.Equal((uint)2, tx.GetTxOutIndex(addr3)); Assert.Equal((uint)1, tx.GetTxOutIndex(addr2.GetLockingScript())); Assert.True(outpoint2.Equals(tx.GetTxIn(outpoint2).OutPoint)); Assert.True(outpoint2.Equals(tx.GetTxIn(1).OutPoint)); Assert.True(outpoint2.Equals(tx.GetTxInList()[1].OutPoint)); Assert.True(addr2.GetLockingScript().Equals(tx.GetTxOut(addr2).ScriptPubkey)); Assert.True(addr2.GetLockingScript().Equals(tx.GetTxOut(addr2.GetLockingScript()).ScriptPubkey)); Assert.True(addr2.GetLockingScript().Equals(tx.GetTxOut(1).ScriptPubkey)); Assert.True(addr2.GetLockingScript().Equals(tx.GetTxOutList()[1].ScriptPubkey)); }
public ByteData ToDerEncode(SignatureHashType sighashType) { return(EncodeToDer(new ByteData(data), sighashType)); }
public static Transaction TransformTransactionForSigning(Script script, Transaction transaction, int transactionInputIndex, SignatureHashType signatureType) { ContractsCommon.NotNull(script, "script"); ContractsCommon.NotNull(transaction, "transaction"); ContractsCommon.ValidIndex(0, transaction.TransactionInputs.Count, transactionInputIndex, "transactionInputIndex"); ContractsCommon.ResultIsNonNull <Transaction>(); var tb = transaction.ThawTree(); //script.Atoms.RemoveAllCopies(Scripting.Atoms.OpCodeSeparatorAtom.Atom); ClearAllScripts(tb.TransactionInputs); tb.TransactionInputs[transactionInputIndex].Script.Atoms.AddAll(script.Atoms); // By default, signing a transaction with SignatureHashType = 0 means the signer // agrees with the transaction only if the inputs and outputs are exactly the same // as they were when originally signed, except input scripts, which are cleared and // the input script for this index set as passed above. switch (signatureType & SignatureHashType.OutputMask) { // Signer accepts transaction regardless of the outputs specified in the transaction // or the sequence numbers of the other inputs. case SignatureHashType.None: tb.TransactionOutputs.Clear(); SetSequenceNumbersToZero(tb.TransactionInputs, transactionInputIndex); break; // Signer accepts transaction if the matching outputs index of this transaction is // as originally signed, regarless of the sequence numbers of the other inputs. case SignatureHashType.Single: OnlyUseSingleOutput(tb.TransactionOutputs, transactionInputIndex); SetSequenceNumbersToZero(tb.TransactionInputs, transactionInputIndex); break; } // Signer accepts all other inputs to this transaction, whatever they may be if ((signatureType & SignatureHashType.AnyoneCanPay) == SignatureHashType.AnyoneCanPay) { OnlyUseSingleInput(tb.TransactionInputs, transactionInputIndex); } tb.Freeze(); return(tb); }
public static Hash256 HashTransactionForSigning(Script script, Transaction transaction, int transactionInputIndex, SignatureHashType signatureType) { ContractsCommon.NotNull(script, "script"); ContractsCommon.NotNull(transaction, "transaction"); ContractsCommon.ValidIndex(0, transaction.TransactionInputs.Count, transactionInputIndex, "transactionInputIndex"); ContractsCommon.ResultIsNonNull <Hash256>(); var t = TransformTransactionForSigning(script, transaction, transactionInputIndex, signatureType); using (var ms = new MemoryStream(t.SerializedByteSize + BufferOperations.UINT32_SIZE)) { t.Serialize(ms); var sigType = (int)signatureType; ms.WriteByte((byte)sigType); ms.WriteByte((byte)(sigType >> 8)); ms.WriteByte((byte)(sigType >> 16)); ms.WriteByte((byte)(sigType >> 24)); return(CryptoFunctionProviderFactory.Default.Hash256(ms.ToArray())); } }
public static bool VerifySignature(byte[] publicKey, byte[] sigHash, Script script, Transaction transaction, int transactionInputIndex, SignatureHashType signatureType) { ContractsCommon.NotNull(publicKey, "publicKey"); ContractsCommon.NotNull(sigHash, "sigHash"); ContractsCommon.NotNull(script, "script"); ContractsCommon.NotNull(transaction, "transaction"); ContractsCommon.ValidIndex(0, transaction.TransactionInputs.Count, transactionInputIndex, "transactionInputIndex"); // Cng ECC Public Key Blob format [72 bytes]: //6fbfcf5da60c7e59dfe724f4fb1b4e73f12bc48f17fb90f1e74f0d058c65e77c76aa75787f18ddd8be32b08014046ff62fef598011583e6f2d77e2b2ab850e5f0000002031534345 //coordY[cBytes]BIG-ENDIAN coordX[cBytes]BIG-ENDIAN cBytes[4]LITTLE-ENDIAN magic[4]LITTLE-ENDIAN // For ECDsaP256, that magic number is: 0x31534345U, and cBytes will be 0x00000020 // Bitcoin ECC Public Key Blob format [65 bytes]: //04e77ae594d5932f11547eea049b526044cbf8ac938fabfa97d3ab37732822572bd7d71c77a8ac1f5ca46fd73260f5aecc7270efbbf283bacd64ef0a9bb41e3ab9 //type[1] coordX[cBytes] coordY[cBytes] (all LITTLE-ENDIAN) // type = 04 means curve points are uncompressed. No other value is expected. // For secp256k1, cBytes = 0x00000020 // Probable issue here: Cng supports the NIST P-256 curve (alias of secp256r1), but Bitcoin uses the secp256k1 curve. if (signatureType == 0) { signatureType = (SignatureHashType)sigHash[sigHash.Length - 1]; } else if (signatureType != (SignatureHashType)sigHash[sigHash.Length - 1]) { return(false); } var signature = new byte[72]; Array.Copy(sigHash, signature, signature.Length); var hash = HashTransactionForSigning(script, transaction, transactionInputIndex, signatureType); var ecdsa = new ECDsaBouncyCastle(publicKey, false); return(ecdsa.VerifyHash(hash.Bytes, signature)); }
public static byte[] SignTransaction(byte[] privateKey, Script script, Transaction transaction, int transactionInputIndex, SignatureHashType signatureType) { ContractsCommon.NotNull(privateKey, "privateKey"); ContractsCommon.NotNull(script, "script"); ContractsCommon.NotNull(transaction, "transaction"); ContractsCommon.ValidIndex(0, transaction.TransactionInputs.Count, transactionInputIndex, "transactionInputIndex"); ContractsCommon.ResultIsNonNull <byte[]>(); var hash = HashTransactionForSigning(script, transaction, transactionInputIndex, signatureType); var ecdsa = new ECDsaBouncyCastle(privateKey, true); return(ecdsa.SignHash(hash.Bytes)); }
public void TapScriptSignTest1() { var sk = new Privkey("305e293b010d29bf3c888b617763a438fee9054c8cab66eb12ad078f819d9f27"); var spk = SchnorrPubkey.GetPubkeyFromPrivkey(sk, out bool _); Assert.Equal("1777701648fa4dd93c74edd9d58cfcc7bdc2fa30a2f6fa908b6fd70c92833cfb", spk.ToHexString()); var scriptCheckSig = Script.CreateFromAsm(new string[] { spk.ToHexString(), "OP_CHECKSIG" }); var tree = new TaprootScriptTree(scriptCheckSig); tree.AddBranches(new string[] { "4d18084bb47027f47d428b2ed67e1ccace5520fdc36f308e272394e288d53b6d", "dc82121e4ff8d23745f3859e8939ecb0a38af63e6ddea2fff97a7fd61a1d2d54", }); var taprootData = tree.GetTaprootData(spk); Assert.Equal("3dee5a5387a2b57902f3a6e9da077726d19c6cc8c8c7b04bcf5a197b2a9b01d2", taprootData.Pubkey.ToHexString()); Assert.Equal("dfc43ba9fc5f8a9e1b6d6a50600c704bb9e41b741d9ed6de6559a53d2f38e513", taprootData.TapLeafHash.ToHexString()); Assert.Equal( "c01777701648fa4dd93c74edd9d58cfcc7bdc2fa30a2f6fa908b6fd70c92833cfb4d18084bb47027f47d428b2ed67e1ccace5520fdc36f308e272394e288d53b6ddc82121e4ff8d23745f3859e8939ecb0a38af63e6ddea2fff97a7fd61a1d2d54", taprootData.ControlBlock.ToHexString()); var tweakedPrivkey = tree.GetTweakedPrivkey(sk); Assert.Equal("a7d17bee0b6313cf864a1ac6f203aafd74a40703ffc050f66517e4f83ff41a03", tweakedPrivkey.ToHexString()); var addr = new Address(taprootData.Pubkey, CfdAddressType.Taproot, CfdNetworkType.Mainnet); Assert.Equal("bc1p8hh955u8526hjqhn5m5a5pmhymgecmxgerrmqj70tgvhk25mq8fqw77n40", addr.ToAddressString()); var txHex = "02000000015b80a1af0e00c700bee9c8e4442bec933fcdc0c686dac2dc336caaaf186c5d190000000000ffffffff0130f1029500000000160014164e985d0fc92c927a66c0cbaf78e6ea389629d500000000"; var outpoint = new OutPoint("195d6c18afaa6c33dcc2da86c6c0cd3f93ec2b44e4c8e9be00c7000eafa1805b", 0); var utxos = new UtxoData[] { new UtxoData(outpoint, 2499999000, new Descriptor(addr.GetLockingScript(), CfdNetworkType.Mainnet)), }; var tx = new Transaction(txHex); tx.SetTxInUtxoData(utxos); var sighashType = new SignatureHashType(CfdSighashType.All); var sighash = tx.GetSigHashByUtxoData(outpoint, sighashType, taprootData.TapLeafHash, Transaction.codeSeparatorPositionFinal); Assert.Equal("80e53eaee13048aee9c6c13fa5a8529aad7fe2c362bfc16f1e2affc71f591d36", sighash.ToHexString()); var signature = SchnorrUtil.Sign(sighash, sk); var sig = signature.GetSignData(sighashType); Assert.Equal( "f5aa6b260f9df687786cd3813ba83b476e195041bccea800f2571212f4aae9848a538b6175a4f8ea291d38e351ea7f612a3d700dca63cd3aff05d315c5698ee901", sig.ToHexString()); tx.AddTapScriptSign(outpoint, new SignParameter[] { sig }, taprootData.TapScript, taprootData.ControlBlock); Assert.Equal( "020000000001015b80a1af0e00c700bee9c8e4442bec933fcdc0c686dac2dc336caaaf186c5d190000000000ffffffff0130f1029500000000160014164e985d0fc92c927a66c0cbaf78e6ea389629d50341f5aa6b260f9df687786cd3813ba83b476e195041bccea800f2571212f4aae9848a538b6175a4f8ea291d38e351ea7f612a3d700dca63cd3aff05d315c5698ee90122201777701648fa4dd93c74edd9d58cfcc7bdc2fa30a2f6fa908b6fd70c92833cfbac61c01777701648fa4dd93c74edd9d58cfcc7bdc2fa30a2f6fa908b6fd70c92833cfb4d18084bb47027f47d428b2ed67e1ccace5520fdc36f308e272394e288d53b6ddc82121e4ff8d23745f3859e8939ecb0a38af63e6ddea2fff97a7fd61a1d2d5400000000", tx.ToHexString()); try { tx.VerifySignByUtxoList(outpoint); Assert.True(false); } catch (InvalidOperationException ae) { Assert.Equal("CFD error[IllegalStateError] message:The script analysis of tapscript is not supported.", ae.Message); } catch (Exception e) { Assert.Null(e); } var isVerify = spk.Verify(signature, sighash); Assert.True(isVerify); }
public void SetDerEncode(SignatureHashType signatureHashType) { SetSignatureHashType(signatureHashType); isSetDerEncode = true; }
public void SetSignatureHashType(SignatureHashType signatureHashType) { this.signatureHashType = signatureHashType; }
public static byte[] CalculateSignatureHash(ParsedOpCode[] subScript, SignatureHashType hashType, MsgTx transaction, int index) { const SignatureHashType mask = (SignatureHashType)0x1f; if ((hashType & mask) == SignatureHashType.Single && index >= transaction.TxOut.Length) { throw new InvalidSignatureException("SignatureHashType.Single index out of range"); } // Clear out signature scripts for input transactions not at index // transactionIndex for (var i = 0; i < transaction.TxIn.Length; i++) { transaction.TxIn[i].SignatureScript = i == index? subScript.SelectMany(s => s.Serialize()).ToArray() : new byte[0]; } switch (hashType & mask) { case SignatureHashType.None: transaction.TxOut = new TxOut[0]; for (var i = 0; i < transaction.TxIn.Length; i++) { if (i != index) { transaction.TxIn[i].Sequence = 0; } } break; case SignatureHashType.Single: transaction.TxOut = new TxOut[index]; for (var i = 0; i < index; i++) { transaction.TxOut[i].Value = -1; transaction.TxOut[i].PkScript = null; } for (var i = 0; i < transaction.TxIn.Length; i++) { if (i != index) { transaction.TxIn[i].Sequence = 0; } } break; case SignatureHashType.Old: break; case SignatureHashType.All: break; case SignatureHashType.AllValue: break; case SignatureHashType.AnyOneCanPay: break; default: throw new ArgumentOutOfRangeException(); } if ((hashType & SignatureHashType.AnyOneCanPay) != 0) { transaction.TxIn = transaction.TxIn .Skip(index) .Take(1) .ToArray(); } var wbuf = new List <byte>(32 * 2 + 4); wbuf.AddRange(BitConverter.GetBytes((uint)hashType)); var prefixHash = transaction.GetHash(TxSerializeType.NoWitness); var witnessHash = transaction.GetHash( (hashType & mask) != SignatureHashType.All ? TxSerializeType.WitnessSigning : TxSerializeType.WitnessValueSigning ); wbuf.AddRange(prefixHash); wbuf.AddRange(witnessHash); return(HashUtil.Blake256(wbuf.ToArray())); }
public static Transaction TransformTransactionForSigning(Script script, Transaction transaction, int transactionInputIndex, SignatureHashType signatureType) { ContractsCommon.NotNull(script, "script"); ContractsCommon.NotNull(transaction, "transaction"); ContractsCommon.ValidIndex(0, transaction.TransactionInputs.Count, transactionInputIndex, "transactionInputIndex"); ContractsCommon.ResultIsNonNull<Transaction>(); var tb = transaction.ThawTree(); //script.Atoms.RemoveAllCopies(Scripting.Atoms.OpCodeSeparatorAtom.Atom); ClearAllScripts(tb.TransactionInputs); tb.TransactionInputs[transactionInputIndex].Script.Atoms.AddAll(script.Atoms); // By default, signing a transaction with SignatureHashType = 0 means the signer // agrees with the transaction only if the inputs and outputs are exactly the same // as they were when originally signed, except input scripts, which are cleared and // the input script for this index set as passed above. switch (signatureType & SignatureHashType.OutputMask) { // Signer accepts transaction regardless of the outputs specified in the transaction // or the sequence numbers of the other inputs. case SignatureHashType.None: tb.TransactionOutputs.Clear(); SetSequenceNumbersToZero(tb.TransactionInputs, transactionInputIndex); break; // Signer accepts transaction if the matching outputs index of this transaction is // as originally signed, regarless of the sequence numbers of the other inputs. case SignatureHashType.Single: OnlyUseSingleOutput(tb.TransactionOutputs, transactionInputIndex); SetSequenceNumbersToZero(tb.TransactionInputs, transactionInputIndex); break; } // Signer accepts all other inputs to this transaction, whatever they may be if ((signatureType & SignatureHashType.AnyoneCanPay) == SignatureHashType.AnyoneCanPay) { OnlyUseSingleInput(tb.TransactionInputs, transactionInputIndex); } tb.Freeze(); return tb; }