P2sh

Ledger Nono S (ledgerjs) signP2SHTransaction 正在產生無效簽名

  • July 19, 2018

我在使用由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());

您可以在此處對其進行解碼:https48'/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”?

(無需再次回复,您可以通過編輯附加到您的問題)

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