Transactions

C# BC,成功創建和簽署原始交易

  • January 1, 2022

第一次在stackexchange上尋求幫助,如果我犯了錯誤,對不起(英語不是我的母語)。

我嘗試使用 bouncycastle 在 C# 上創建一個有效的原始事務,但我似乎卡住了,無法找到我的錯誤在哪裡。我在 testnet 網路上進行了測試,並使用了許多資源來幫助自己,主要是這個。首先,我有下一個地址和私鑰

Address: mjhcWg5SvS96kk85R8G1wp7mru55UCNGY5
Public Key Hex: 0482052EF9560585ED62F046EE45C1B5F85448BCF1BD5CE36A7D35EB00C8A146C14BF99223907F9A8688E6F84B54FD747A637BB82F02E296203E735E7A6B40059F
Wif: 93U5P1qHPXAhXhiw1T15z3f1cBqFw9fWrd3Yzz1nDk8b2aRbrrM 
Private Key Hex: F7DBD21285F621F1C7A47AE7F63D06C276FE49839F4842DDEF805477936812A5

我想使用上一個(testnet)交易中的 6.49689241 btc

912a2c3d84c8572b39c173b2bcde950cfe4ae07756bac189ace98f198d5ccb7d

並將一些(作為測試)發送回水龍頭 mwCwTceJvYV27KXBc3NJZys6CjsgsoeHmf

首先,為了建構未簽名的原始交易,我添加了這些字節:

01000000 (version number)
01 (number of inputs)
7dcb5c8d198fe9ac89c1ba5677e04afe0c95debcb273c1392b57c8843d2c2a91 (reversed previous tx hash)
01000000 (output index)
1976a9142de490b09ef14673af2bb4998fcb9f6b8446a84e88ac (previous tx script with its length at start) 
ffffffff (sequence)
02 (number of outputs)
496ff50200000000 (first output little endian amount. The faucet)
1976a914ac19d3fd17710e6b9a331022fe92c693fdf6659588ac (first output script with its length at start)
0046c32300000000 (second output little endian amount. My address, for change)
1976a9142de490b09ef14673af2bb4998fcb9f6b8446a84e88ac  (second script with its length at start)
00000000 (locktime)
01000000 (hash code type)

結果是

01000000017dcb5c8d198fe9ac89c1ba5677e04afe0c95debcb273c1392b57c8843d2c2a91010000001976a9142de490b09ef14673af2bb4998fcb9f6b8446a84e88acffffffff02496ff502000000001976a914ac19d3fd17710e6b9a331022fe92c693fdf6659588ac0046c323000000001976a9142de490b09ef14673af2bb4998fcb9f6b8446a84e88ac0000000001000000

然後我通過將原始交易推送到返回給我的雙 SHA256 函式中來檢索交易雜湊

f64b6480a2888596636d4995153e990ce95582a1308c9c568d2698e6dc1f7893

然後,我使用私鑰十六進制 (prvkeyHex) 使用此函式對交易雜湊 (txHash) 進行簽名:

X9ECParameters curve = SecNamedCurves.GetByName("secp256k1");
ECDomainParameters dom = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H)
ECKeyParameters params = new ECPrivateKeyParameters(new BigInteger(1, prvkeyHex), dom);
ECDsaSigner signer = new ECDsaSigner();
signer.Init(true, params);
BigInteger[] sig = signer.GenerateSignature(txHash);
MemoryStream ms = new MemoryStream(72);
DerSequenceGenerator seq = new DerSequenceGenerator(ms);
seq.AddObject(new DerInteger(sig[0]));
seq.AddObject(new DerInteger(sig[1]));
seq.Close();
byte[] signature = ms.ToArray();

它返回我一個最大 72 字節長度的字節數組,從 30 開始。在我的最後一個測試中:

3045022100abceff62d3192b686c405d10516ff0e6f9ff221c00284d766200a6abb42361be02202972970369d6b9308467e15ebafd3f6b9faf111886071e3c429b34e9407e8d23

然後,我使用公鑰十六進制及其長度構造我的最終 scriptSig,結果為

483045022100abceff62d3192b686c405d10516ff0e6f9ff221c00284d766200a6abb42361be02202972970369d6b9308467e15ebafd3f6b9faf111886071e3c429b34e9407e8d2301410482052ef9560585ed62f046ee45c1b5f85448bcf1bd5ce36a7d35eb00c8a146c14bf99223907f9a8688e6f84b54fd747a637bb82f02e296203e735e7a6b40059f

我終於建立了我簽名的原始交易:

01000000 (version number)
01 (number of inputs)
7dcb5c8d198fe9ac89c1ba5677e04afe0c95debcb273c1392b57c8843d2c2a91 (reversed previous tx hash)
01000000 (output index)
8b (scriptSig length)
483045022100abceff62d3192b686c405d10516ff0e6f9ff221c00284d766200a6abb42361be02202972970369d6b9308467e15ebafd3f6b9faf111886071e3c429b34e9407e8d2301410482052ef9560585ed62f046ee45c1b5f85448bcf1bd5ce36a7d35eb00c8a146c14bf99223907f9a8688e6f84b54fd747a637bb82f02e296203e735e7a6b40059f (scriptSig)
ffffffff (sequence)
02 (number of outputs)
496ff50200000000 (first output little endian amount. The faucet)
1976a914ac19d3fd17710e6b9a331022fe92c693fdf6659588ac (first output script with its length at start)
0046c32300000000 (second output little endian amount. My address, for change)
1976a9142de490b09ef14673af2bb4998fcb9f6b8446a84e88ac  (second script with its length at start)
00000000 (locktime)

最終結果給了我簽署的原始交易

01000000017dcb5c8d198fe9ac89c1ba5677e04afe0c95debcb273c1392b57c8843d2c2a91010000008b483045022100abceff62d3192b686c405d10516ff0e6f9ff221c00284d766200a6abb42361be02202972970369d6b9308467e15ebafd3f6b9faf111886071e3c429b34e9407e8d2301410482052ef9560585ed62f046ee45c1b5f85448bcf1bd5ce36a7d35eb00c8a146c14bf99223907f9a8688e6f84b54fd747a637bb82f02e296203e735e7a6b40059fffffffff02496ff502000000001976a914ac19d3fd17710e6b9a331022fe92c693fdf6659588ac0046c323000000001976a9142de490b09ef14673af2bb4998fcb9f6b8446a84e88ac00000000

但是現在,當我嘗試通過 Web 服務在 testnet 網路上發送簽名的原始交易時,每次都會出錯。sandbox.smartbit.com.au/txs/pushtx 回复我

"PUSH TRANSACTION ERROR: 16: MANDATORY-SCRIPT-VERIFY-FLAG-FAILED (SCRIPT EVALUATED WITHOUT ERROR BUT FINISHED WITH A FALSE/EMPTY TOP STACK ELEMENT)"

live.blockcypher.com/btc-testnet/pushtx/ 還給我

"Error sending transaction: Error running script for input 0 referencing 912a2c3d84c8572b39c173b2bcde950cfe4ae07756bac189ace98f198d5ccb7d at 1: Script was NOT verified successfully.."

與 tbtc.blockr.io/tx/push 相同

我遠未掌握比特幣或 c#,我正在學習(並且想了解它是如何工作的)。有人看到我的錯誤在哪裡嗎?謝謝

您生成的簽名是正確的,但是對於錯誤的“消息”,這是我能找到的唯一錯誤。這是你簽署的:

f64b6480a2888596636d4995153e990ce95582a1308c9c568d2698e6dc1f7893

這是錯誤的(因為您反轉了 has 結果)。相反,您應該對從您SHA256(SHA256(<bytes>))的簽名函式獲得的實際結果進行簽名,這意味著:

93781fdce698268d569c8c30a18255e90c993e1595496d63968588a280644bf6

有幾個地方我們反轉雜湊結果,這不是其中之一。在這裡,您只是對序列化交易進行雜湊處理,以將其大小從任意長度轉換為固定的 32 字節大小,以便您可以使用 ECDSA 方案對其進行簽名。

直接使用 BouncyCastle 或任何為密碼學設計的類似庫通常不是為比特幣設計的,還有一個可能的問題,它們返回的簽名可能具有大於 curve的s值(簽名中的第二個) 。在這種情況下,您必須通過計算將其更改為。BigInteger``N/2``s'``s' = N - s

為什麼不使用NBitcoin庫創建原始交易並將其發佈到 blockr.io 或您正在使用的任何 API 提供商?NBitcoin 是 C# 加密貨幣開發人員的絕佳庫。

引用自:https://bitcoin.stackexchange.com/questions/48131