Ledger Nono S (ledgerjs) signP2SHTransaction 正在產生無效簽名
我在使用由
signP2SHTransaction
.@ledgerhq/hw-app-btc
因此,我使用 bitcore-lib 創建了一個腳本,將其與 Ledger 生成的簽名進行交叉檢查,並查明導致錯誤的更改。我還驗證了我所有的輸入參數,發現它們是正確的。我將在這裡詳細介紹這兩個腳本,儘管我認為這是 ledger 的 signP2SHTransaction 函式的問題。
我正在使用以下依賴項和節點
v8.9.3
:"@ledgerhq/hw-app-btc": "^4.17.0", "@ledgerhq/hw-app-eth": "^4.19.0", "@ledgerhq/hw-transport-node-hid": "^4.18.0", "babel-runtime": "^6.26.0", "bip32": "^0.1.0", "bitcoinjs-lib": "^3.3.2", "bitcore-lib": "^0.15.0"
我使用我的賬本的以下 2 條路徑創建了 2 of 2 Multisig 地址
48'/0'/0'/69/0/0
-48'/0'/0'/96/0/0
. 我使用了以下 rawTx:01000000016f4fbe65fe5fcb98028d67172f72bdeadc1f45cb49c50f2eb7aca4668e94d50a01000000490047522102a9d50f9817a9cf20f3feb7ad4038e88c8bd471e90dfba3a80c2e0bfd79c893122102faf805ea3652cec322dda6f7571d926f359d8abbd73af1512924151edbec90e752aeffffffff0220d613000000000017a9148eaba4fd80f515c78ddbc2509538e37c40ffcf1287904a96070000000017a914c45f1d5dde5c0f7008dd6c228c1702cfdafdf1a98700000000
我使用了以下兌換腳本:
522102a9d50f9817a9cf20f3feb7ad4038e88c8bd471e90dfba3a80c2e0bfd79c893122102faf805ea3652cec322dda6f7571d926f359d8abbd73af1512924151edbec90e752ae
這是我用來生成它的程式碼:
const bitcore = require("bitcore-lib"); const PublicKey = bitcore.PublicKey; const Script = bitcore.Script; var publicKey1 = new PublicKey( "02a9d50f9817a9cf20f3feb7ad4038e88c8bd471e90dfba3a80c2e0bfd79c89312" ); // public key for path- 48'/0'/0'/69/0/0 var publicKey = new PublicKey( "02faf805ea3652cec322dda6f7571d926f359d8abbd73af1512924151edbec90e7" ); // public key for path- 48'/0'/0'/96/0/0 var pubkeys = [publicKey, publicKey1]; var redeemScript = Script.buildMultisigOut(pubkeys, 2); console.log(redeemScript.toHex());
您可以在此處對其進行解碼:https
48'/0'/0'/69/0/0
://live.blockcypher.com/btc/decodetx/ 這是我的分類帳程式碼,它正在為路徑 創建簽名:const TransportHid = require("@ledgerhq/hw-transport-node-hid").default; const AppBtc = require("@ledgerhq/hw-app-btc").default; TransportHid.create() .then(async transport => { if (!transport) return console.log("err: Unable to establish connection"); var btc = new AppBtc(transport); const rawTx = "01000000016f4fbe65fe5fcb98028d67172f72bdeadc1f45cb49c50f2eb7aca4668e94d50a01000000490047522102a9d50f9817a9cf20f3feb7ad4038e88c8bd471e90dfba3a80c2e0bfd79c893122102faf805ea3652cec322dda6f7571d926f359d8abbd73af1512924151edbec90e752aeffffffff0220d613000000000017a9148eaba4fd80f515c78ddbc2509538e37c40ffcf1287904a96070000000017a914c45f1d5dde5c0f7008dd6c228c1702cfdafdf1a98700000000"; const redeemHex = "522102a9d50f9817a9cf20f3feb7ad4038e88c8bd471e90dfba3a80c2e0bfd79c893122102faf805ea3652cec322dda6f7571d926f359d8abbd73af1512924151edbec90e752ae"; const bufferedData = await btc.splitTransaction(rawTx); let input = []; input.push(bufferedData); input.push(1); input.push(redeemHex); const outputScript = btc .serializeTransactionOutputs(bufferedData) .toString("hex"); console.log("\nOutput script hex:", outputScript); const accountIndex = 69; console.log("\npath:", `48'/0'/0'/${accountIndex}/0/0`); await btc .signP2SHTransaction( [input], [`48'/0'/0'/${accountIndex}/0/0`], outputScript ) .then(sig => console.log("\n\nSig hash:", sig)) .catch(err => console.log("\n\nErr:", err)); }) .catch(err => console.log(err));
當我通過 tx 傳遞 RedeemScript 時,它返回以下簽名:
Sig hash: [ '304402203e24b5ad68c1fe3bf55a11afb6a61e3525c6f0a2780a0ee4bf37401bfd1445ff02207b18b7277b4f2625d04d0fcfd796300a9f6923c1df11a96876ab094138ea2a94' ]
而且我覺得奇怪的是,當我刪除
signP2SHTransaction
函式的兌換腳本參數(標記為可選)時,我得到了一個不同的簽名:Sig hash: [ '3045022100f40f8fa2b75196a50b2f2543a06a3ed3ed79814cd29510f1225a359620b1c19102201af093addc93fce4fe8c59ad127c42064c2840ec7c71fbf5d0bae7ee5cb4cd39' ]
但是兩者都無法以正確的方式簽署交易,並且在我針對交易進行驗證時出錯。
我使用以下腳本使用 bitcore-lib 查找有效簽名:
const bitcoin = require("bitcoinjs-lib"); const bitcore = require("bitcore-lib"); // These are the private keys of paths- 48'/0'/0'/69/0/0 and 48'/0'/0'/96/0/0 of my ledger // I retrieved them using https://iancoleman.io/bip39/ and my ledger's mnemonic const privateKeys = [ new bitcore.PrivateKey( "cNKAjjSL5buaP6q7fE375jkt72JAvvoe8RVh2v5TXv6gdjzXwPVX", "testnet" ), new bitcore.PrivateKey( "cMmNVwdfid1FnT4LjH4SJ1mZvTEGnMfUxdasGKTrHvD5nCY1UCvR", "testnet" ) ]; const publicKeys = privateKeys.map(bitcore.PublicKey, bitcoin.networks.testnet); const address = new bitcore.Address(publicKeys, 2); // 2 of 2 console.log("\n\nCreated this Address:", address); console.log("\n\nPublic keys:", publicKeys); // This utxo will create the same rawTx as I have used in my code with Ledger const utxo = { address: "2NB9YNZwwKXannuZryo2KfvMNe4jeSNcSp5", txid: "0ad5948e66a4acb72e0fc549cb451fdceabd722f17678d0298cb5ffe65be4f6f", vout: 1, scriptPubKey: "a914c45f1d5dde5c0f7008dd6c228c1702cfdafdf1a987", // "script" : new bitcore.Script(address).toHex(), satoshis: 128600000 }; const fee = 10000; const tx = new bitcore.Transaction() .from(utxo, publicKeys, 2) .fee(fee) .to("2N6FbZbJsGHWRpnbu8vrowCfGATKsYxuDf9", 1300000) .change("2NB9YNZwwKXannuZryo2KfvMNe4jeSNcSp5"); const txObj = tx.toObject(); console.log("\n\nTransaction object:", txObj); console.log("\n\nTransaction hash:", tx); const signature1 = tx.getSignatures(privateKeys[0])[0]; console.log("\n\nSignature1 object:", signature1.toObject()); console.log("\n\nSignature1 hash:", signature1.signature.toString()); // Outputs a DER signature1 console.log("\n\nSignature1 type:", signature1.sigtype); console.log("\n\nIs valid tx 1:", tx.isValidSignature(signature1)); if (!tx.isValidSignature(signature1)) throw "Not a valid Signature";
它產生以下有效簽名:
Signature1 hash: 304402203fb366ffd2840a900abc7ed25e945e4fdcf37679870a6ee45ce0030dd725856e02202d3b1c86458121cf4b79382281eca074a56d8b67a86dc754e2f7c65501f75b0b
我認為目前版本的 Ledger 存在錯誤,請您幫幫我。
解決方案:我為我的 Ledger 創建了一個錯誤的輸入,我不得不使用 utxos 來創建輸入 tx,但我使用了最終的 rawtx(我是使用文本創建的)。那些被這個問題困擾的人,請記住以下幾點:
在 Ledger 的 signP2SHTransaction 函式文件中
- <http://ledgerhq.github.io/ledgerjs/docs/#btc>
- 輸入:參考您用於形成 tx 的 utxos - outputScriptHex:可用於指定所有所需的輸出參數如費用,更改地址等。
(這對於評論來說太長了,所以在答案部分):
我的觀察:我試圖在命令行(使用 OpenSSL)驗證三個信號。我可以從您的第一個程式碼片段中看到兩個 pubkey,以及 tx. 我創建了原始的、未簽名的 tx,只有第三個簽名是可以的(使用 pubkey 02a9d50f9817a9…) - 我假設您的第一個程式碼範例中的原始 tx 不正確。我使用了這個未簽名的原始 tx(以兌換腳本和 0x47 作為長度):
01000000016f4fbe65fe5fcb98028d67172f72bdeadc1f45cb49c50f2eb7aca4668e94d50a0100000047522102a9d50f9817a9cf20f3feb7ad4038e88c8bd471e90dfba3a80c2e0bfd79c893122102faf805ea3652cec322dda6f7571d926f359d8abbd73af1512924151edbec90e752aeffffffff0220d613000000000017a9148eaba4fd80f515c78ddbc2509538e37c40ffcf1287904a96070000000017a914c45f1d5dde5c0f7008dd6c228c1702cfdafdf1a9870000000001000000
這是雙重sha256的:
bad8b7f175a67e1ecfd857119609646993eb026b2bb507a49ce47b9ba5d321f7
您使用什麼未簽名的原始 tx 來登錄您的程式碼片段?他們有相同的雙 sha256’d 雜湊嗎?我看到你的原始 tx 有“[version][tx_in count][prev tx id][prev outpoint]490047[redeem script]…”,為什麼是“4900”?
(無需再次回复,您可以通過編輯附加到您的問題)