rust-bitcoin 非規範 DER 簽名
我正在嘗試使用rust-bitcoin創建一個花費 P2PKH 輸出的原始交易,但是每當我將交易推送到測試網時,我都會收到以下錯誤
mandatory-script-verify-flag-failed (Non-canonical DER signature)
我的簽名程式碼如下所示:/// Sign a bitcoin transaction spending P2PKH outputs /// /// # Arguments /// /// * `tx` the transaction to be signed /// * `script_pubkeys` list of script pubkeys of the inputs (has to be indexed in the same order as the inputs in the transaction) /// * `skeys` list of secret keys with which to sign the inputs (has to be indexed in the same order as the inputs in the transaction) /// * `pkeys` list of public keys for the inputs which are spent (has to be indexed in the same order as the inputs in the transaction) /// * `curve` reference to the elliptic curve object used for signing pub fn sign_transaction(tx : Transaction, script_pubkeys : Vec<Script>, skeys : Vec<PrivateKey>, pkeys: Vec<PublicKey>, curve : &Secp256k1<All>) -> Transaction { let mut signed_inp : Vec<TxIn> = Vec::new(); for (i, unsigned_inp) in tx.input.iter().enumerate() { let script_pubkey = script_pubkeys.get(i).unwrap(); let signing_key = skeys.get(i).unwrap().key; let pub_key = pkeys.get(i).unwrap(); let sighash = tx.signature_hash(i, &script_pubkey, SIGHASH_ALL); let msg = Message::from_slice(&sighash.as_ref()).unwrap(); let sig = curve.sign(&msg, &signing_key); // Standard P2PKH redeem script: // <sig> <pubkey> let redeem_script = Builder::new() .push_slice(&sig.serialize_der()) .push_int(1) .push_key(&pub_key) .into_script(); signed_inp.push(TxIn { previous_output : unsigned_inp.previous_output, script_sig: redeem_script, sequence : unsigned_inp.sequence, witness : unsigned_inp.witness.clone() }); } Transaction { version : tx.version, lock_time : tx.lock_time, input : signed_inp, output: tx.output } }
這是一個範例交易
01000000010b41a0a10f36c39b057053281d1d4d9f67410c40a093c351024f57af4e133c21010000006a46304402202d99eb85a14f483f4679b93eb1cf0f67b64d788dc4cd5ad782e75540508922ce0220752a9237e320497ba289a91edd7135dd6c53f9332dc33c71a3020bf0555607fc512103202430a99091407e6c724c5c88504e69ef6917f042a65cb990537922f823d9dfffffffff02e80300000000000017a9141831af16119be20b532668d5995bd05ac955153b872a091e00000000001976a9146b538e889cf0df7b69112b50db8faadb4e457b9288ac00000000
並以解碼形式
{ "result":{ "txid":"b36457604e0ccd491e97c30c06a011fd906bb83d6fe81c676efb9fc60f17c5a5", "hash":"b36457604e0ccd491e97c30c06a011fd906bb83d6fe81c676efb9fc60f17c5a5", "version":1, "size":223, "vsize":223, "weight":892, "locktime":0, "vin":[ { "txid":"213c134eaf574f0251c393a0400c41679f4d1d1d285370059bc3360fa1a0410b", "vout":1, "scriptSig":{ "asm":"304402202d99eb85a14f483f4679b93eb1cf0f67b64d788dc4cd5ad782e75540508922ce0220752a9237e320497ba289a91edd7135dd6c53f9332dc33c71a3020bf0555607fc 1 03202430a99091407e6c724c5c88504e69ef6917f042a65cb990537922f823d9df", "hex":"46304402202d99eb85a14f483f4679b93eb1cf0f67b64d788dc4cd5ad782e75540508922ce0220752a9237e320497ba289a91edd7135dd6c53f9332dc33c71a3020bf0555607fc512103202430a99091407e6c724c5c88504e69ef6917f042a65cb990537922f823d9df" }, "sequence":4294967295 } ], "vout":[ { "value":0.00001000, "n":0, "scriptPubKey":{ "asm":"OP_HASH160 1831af16119be20b532668d5995bd05ac955153b OP_EQUAL", "hex":"a9141831af16119be20b532668d5995bd05ac955153b87", "reqSigs":1, "type":"scripthash", "addresses":[ "2MuT9izFXKft5umHqr1gviyhus6JGLCxGd6" ] } }, { "value":0.01968426, "n":1, "scriptPubKey":{ "asm":"OP_DUP OP_HASH160 6b538e889cf0df7b69112b50db8faadb4e457b92 OP_EQUALVERIFY OP_CHECKSIG", "hex":"76a9146b538e889cf0df7b69112b50db8faadb4e457b9288ac", "reqSigs":1, "type":"pubkeyhash", "addresses":[ "mqJShCuqM7FK5zPa7Z1PNJySMHTVPrK9bb" ] } } ] }, "error":null, "id":"curltest" }
非常感謝任何有關可能出錯的幫助
我相信你的意圖
push_int(1)
是增加SIGHASH_ALL
交易。然而,Script 的許多不必要的不靈活之一是 sighash 標誌實際上需要成為簽名本身的一部分,而不是作為腳本中的單獨堆棧元素。
這意味著您需要獲取
Vec<u8>
from 的返回Signature::serialize_der
值,用 對其進行變異sig.push(1)
,然後將其添加到腳本堆棧中。通過手動編輯您的交易以將51
(OP_1
)更改為01
(1 字節),並增加簽名操作碼中的長度以使用它,我能夠使您的交易通過測試網路上的驗證。(雖然我沒有送出它,以免您處理“輸入已花費”錯誤的煩惱!)我對這個 API 並不感興趣——我想至少
Signature
應該有一個方法serialize_der_with_sighashflag
或其他東西來消除呼叫者使用臨時變數的需要 andmut
,但是手動建構這樣的腳本並不常見估計還沒出現您可能會考慮查看rust-miniscript,它為您做了很多這樣的事情。