@ledgerhq/hw-app-btc 6.11.1 → 6.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
1
  import { crypto } from "bitcoinjs-lib";
2
+ import { BufferReader } from "../buffertools";
2
3
  import { createVarint } from "../varint";
3
4
  import { hashLeaf, Merkle } from "./merkle";
4
5
  import { MerkleMap } from "./merkleMap";
@@ -106,19 +107,24 @@ export class GetMerkleLeafProofCommand extends ClientCommand {
106
107
  execute(request: Buffer): Buffer {
107
108
  const req = request.subarray(1);
108
109
 
109
- if (req.length != 32 + 4 + 4) {
110
- throw new Error("Invalid request, unexpected trailing data");
110
+ if (req.length < 32 + 1 + 1) {
111
+ throw new Error("Invalid request, expected at least 34 bytes");
111
112
  }
112
113
 
113
- // read the hash
114
- const hash = Buffer.alloc(32);
115
- for (let i = 0; i < 32; i++) {
116
- hash[i] = req.readUInt8(i);
117
- }
114
+ const reqBuf = new BufferReader(req);
115
+ const hash = reqBuf.readSlice(32);
118
116
  const hash_hex = hash.toString("hex");
119
117
 
120
- const tree_size = req.readUInt32BE(32);
121
- const leaf_index = req.readUInt32BE(32 + 4);
118
+ let tree_size;
119
+ let leaf_index;
120
+ try {
121
+ tree_size = reqBuf.readVarInt();
122
+ leaf_index = reqBuf.readVarInt();
123
+ } catch (e: any) {
124
+ throw new Error(
125
+ "Invalid request, couldn't parse tree_size or leaf_index"
126
+ );
127
+ }
122
128
 
123
129
  const mt = this.known_trees.get(hash_hex);
124
130
  if (!mt) {
package/tests/Btc.test.ts CHANGED
@@ -469,6 +469,11 @@ ${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'"} | ${"bech32m"} | ${false} | ${"
469
469
  ${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'"} | ${"bech32"} | ${false} | ${"new"}
470
470
  ${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'"} | ${"bech32"} | ${undefined} | ${"old"}
471
471
  ${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'"} | ${"bech32"} | ${true} | ${"new"}
472
+ ${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/0/0"} | ${"bech32"} | ${false} | ${"new"}
473
+ ${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/1/0"} | ${"bech32"} | ${false} | ${"new"}
474
+ ${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/1/0"} | ${"legacy"} | ${false} | ${"new"}
475
+ ${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/1/0"} | ${"p2sh"} | ${false} | ${"new"}
476
+ ${"Bitcoin"} | ${"2.0.0-alpha1"} | ${"m/44'/0'/1'/2/0"} | ${"bech32"} | ${false} | ${"old"}
472
477
  `("dispatch $app $ver $path $format $display to $exp", async ({ app, ver, path, format, display, exp }) => {
473
478
  const appName = Buffer.of(app.length)
474
479
  .toString("hex")
@@ -9,7 +9,7 @@ import {
9
9
  WalletPolicy
10
10
  } from "../../src/newops/policy";
11
11
  import { PsbtV2 } from "../../src/newops/psbtv2";
12
- import { AccountType, addressFormatFromDescriptorTemplate, creatDummyXpub, masterFingerprint, runSignTransaction, TestingClient } from "./integrationtools";
12
+ import { StandardPurpose, addressFormatFromDescriptorTemplate, creatDummyXpub, masterFingerprint, runSignTransaction, TestingClient } from "./integrationtools";
13
13
  import { CoreInput, CoreTx, p2pkh, p2tr, p2wpkh, wrappedP2wpkh, wrappedP2wpkhTwoInputs } from "./testtx";
14
14
 
15
15
  test("getWalletPublicKey p2pkh", async () => {
@@ -40,7 +40,7 @@ test("getWalletXpub normal path", async () => {
40
40
  await testGetWalletXpub("m/44'/0'/0'");
41
41
  });
42
42
 
43
- function testPaths(type: AccountType): { ins: string[], out?: string } {
43
+ function testPaths(type: StandardPurpose): { ins: string[], out?: string } {
44
44
  const basePath = `m/${type}/1'/0'/`;
45
45
  const ins = [
46
46
  basePath + "0/0",
@@ -55,21 +55,21 @@ function testPaths(type: AccountType): { ins: string[], out?: string } {
55
55
 
56
56
  test("Sign p2pkh", async () => {
57
57
  const changePubkey = "037ed58c914720772c59f7a1e7e76fba0ef95d7c5667119798586301519b9ad2cf";
58
- await runSignTransactionTest(p2pkh, AccountType.p2pkh, changePubkey);
58
+ await runSignTransactionTest(p2pkh, StandardPurpose.p2pkh, changePubkey);
59
59
  });
60
60
  test("Sign p2wpkh wrapped", async () => {
61
61
  let changePubkey = "03efc6b990c1626d08bd176aab0e545a4f55c627c7ddee878d12bbbc46a126177a";
62
- await runSignTransactionTest(wrappedP2wpkh, AccountType.p2wpkhInP2sh, changePubkey);
62
+ await runSignTransactionTest(wrappedP2wpkh, StandardPurpose.p2wpkhInP2sh, changePubkey);
63
63
  changePubkey = "031175a985c56e310ce3496a819229b427a2172920fd20b5972dda62758c6def09";
64
- await runSignTransactionTest(wrappedP2wpkhTwoInputs, AccountType.p2wpkhInP2sh, changePubkey);
64
+ await runSignTransactionTest(wrappedP2wpkhTwoInputs, StandardPurpose.p2wpkhInP2sh, changePubkey);
65
65
  });
66
66
  test("Sign p2wpkh", async () => {
67
- await runSignTransactionTest(p2wpkh, AccountType.p2wpkh);
67
+ await runSignTransactionTest(p2wpkh, StandardPurpose.p2wpkh);
68
68
  });
69
69
  test("Sign p2tr", async () => {
70
70
  // This tx uses locktime, so this test verifies that locktime is propagated to/from
71
71
  // the psbt correctly.
72
- await runSignTransactionTest(p2tr, AccountType.p2tr);
72
+ await runSignTransactionTest(p2tr, StandardPurpose.p2tr);
73
73
  });
74
74
 
75
75
  test("Sign p2tr with sigHashType", async () => {
@@ -79,16 +79,16 @@ test("Sign p2tr with sigHashType", async () => {
79
79
  const sig = input.txinwitness![0] + "83";
80
80
  input.txinwitness = [sig];
81
81
  })
82
- const tx = await runSignTransactionNoVerification(testTx, AccountType.p2tr);
82
+ const tx = await runSignTransactionNoVerification(testTx, StandardPurpose.p2tr);
83
83
  // The verification of the sighashtype is done in MockClient.signPsbt
84
84
  })
85
85
 
86
- async function runSignTransactionTest(testTx: CoreTx, accountType: AccountType, changePubkey?: string) {
86
+ async function runSignTransactionTest(testTx: CoreTx, accountType: StandardPurpose, changePubkey?: string) {
87
87
  const tx = await runSignTransactionNoVerification(testTx, accountType, changePubkey);
88
88
  expect(tx).toEqual(testTx.hex);
89
89
  }
90
90
 
91
- async function runSignTransactionNoVerification(testTx: CoreTx, accountType: AccountType, changePubkey?: string): Promise<string> {
91
+ async function runSignTransactionNoVerification(testTx: CoreTx, accountType: StandardPurpose, changePubkey?: string): Promise<string> {
92
92
  const [client, transport] = await createClient();
93
93
  const accountXpub = "tpubDCwYjpDhUdPGP5rS3wgNg13mTrrjBuG8V9VpWbyptX6TRPbNoZVXsoVUSkCjmQ8jJycjuDKBb9eataSymXakTTaGifxR6kmVsfFehH1ZgJT";
94
94
  client.mockGetPubkeyResponse(`m/${accountType}/1'/0'`, accountXpub);
@@ -25,10 +25,10 @@ export async function runSignTransaction(
25
25
  const btc = new Btc(transport);
26
26
  const accountType = getAccountType(testTx.vin[0], btc);
27
27
  const additionals: string[] = [];
28
- if (accountType == AccountType.p2wpkh) {
28
+ if (accountType == StandardPurpose.p2wpkh) {
29
29
  additionals.push("bech32");
30
30
  }
31
- if (accountType == AccountType.p2tr) {
31
+ if (accountType == StandardPurpose.p2tr) {
32
32
  additionals.push("bech32m");
33
33
  }
34
34
  const associatedKeysets: string[] = [];
@@ -68,7 +68,7 @@ export async function runSignTransaction(
68
68
  outputScriptHex,
69
69
  lockTime: testTx.locktime,
70
70
  sigHashType,
71
- segwit: accountType != AccountType.p2pkh,
71
+ segwit: accountType != StandardPurpose.p2pkh,
72
72
  onDeviceSignatureGranted: () => logCallback("CALLBACK: signature granted"),
73
73
  onDeviceSignatureRequested: () => logCallback("CALLBACK: signature requested"),
74
74
  onDeviceStreaming: (arg) => logCallback("CALLBACK: " + JSON.stringify(arg))
@@ -90,42 +90,42 @@ export function addressFormatFromDescriptorTemplate(descTemp: DefaultDescriptorT
90
90
  throw new Error();
91
91
  }
92
92
 
93
- export enum AccountType {
93
+ export enum StandardPurpose {
94
94
  p2tr = "86'",
95
95
  p2wpkh = "84'",
96
96
  p2wpkhInP2sh = "49'",
97
97
  p2pkh = "44'"
98
98
  }
99
99
 
100
- function getPubkey(inputIndex: number, accountType: AccountType, testTx: CoreTx, spentTx: Transaction, spentOutputIndex: number): Buffer {
100
+ function getPubkey(inputIndex: number, accountType: StandardPurpose, testTx: CoreTx, spentTx: Transaction, spentOutputIndex: number): Buffer {
101
101
  const scriptSig = Buffer.from(testTx.vin[inputIndex].scriptSig.hex, "hex");
102
- if (accountType == AccountType.p2pkh) {
102
+ if (accountType == StandardPurpose.p2pkh) {
103
103
  return scriptSig.slice(scriptSig.length - 33);
104
104
  }
105
- if (accountType == AccountType.p2tr) {
105
+ if (accountType == StandardPurpose.p2tr) {
106
106
  return spentTx.outputs![spentOutputIndex].script.slice(2, 34); // 32 bytes x-only pubkey
107
107
  }
108
- if (accountType == AccountType.p2wpkh || accountType == AccountType.p2wpkhInP2sh) {
108
+ if (accountType == StandardPurpose.p2wpkh || accountType == StandardPurpose.p2wpkhInP2sh) {
109
109
  return Buffer.from(testTx.vin[inputIndex].txinwitness![1], "hex");
110
110
  }
111
111
  throw new Error();
112
112
  }
113
113
 
114
- function getSignature(testTxInput: CoreInput, accountType: AccountType): Buffer {
114
+ function getSignature(testTxInput: CoreInput, accountType: StandardPurpose): Buffer {
115
115
  const scriptSig = Buffer.from(testTxInput.scriptSig.hex, "hex");
116
- if (accountType == AccountType.p2pkh) {
116
+ if (accountType == StandardPurpose.p2pkh) {
117
117
  return scriptSig.slice(1, scriptSig.length - 34);
118
118
  }
119
- if (accountType == AccountType.p2tr) {
119
+ if (accountType == StandardPurpose.p2tr) {
120
120
  return Buffer.from(testTxInput.txinwitness![0], "hex");
121
121
  }
122
- if (accountType == AccountType.p2wpkh || accountType == AccountType.p2wpkhInP2sh) {
122
+ if (accountType == StandardPurpose.p2wpkh || accountType == StandardPurpose.p2wpkhInP2sh) {
123
123
  return Buffer.from(testTxInput.txinwitness![0], "hex");
124
124
  }
125
125
  throw new Error();
126
126
  }
127
127
 
128
- function getAccountType(coreInput: CoreInput, btc: Btc): AccountType {
128
+ function getAccountType(coreInput: CoreInput, btc: Btc): StandardPurpose {
129
129
  const spentTx = spentTxs[coreInput.txid];
130
130
  if (!spentTx) {
131
131
  throw new Error("Spent tx " + coreInput.txid + " unavailable.");
@@ -134,15 +134,15 @@ function getAccountType(coreInput: CoreInput, btc: Btc): AccountType {
134
134
  const spentOutput = splitSpentTx.outputs![coreInput.vout];
135
135
  const script = spentOutput.script;
136
136
  if (script.length == 34 && script[0] == 0x51) {
137
- return AccountType.p2tr;
137
+ return StandardPurpose.p2tr;
138
138
  }
139
139
  if (script.length == 22 && script[0] == 0x00) {
140
- return AccountType.p2wpkh;
140
+ return StandardPurpose.p2wpkh;
141
141
  }
142
142
  if (script.length == 23) {
143
- return AccountType.p2wpkhInP2sh;
143
+ return StandardPurpose.p2wpkhInP2sh;
144
144
  }
145
- return AccountType.p2pkh;
145
+ return StandardPurpose.p2pkh;
146
146
  }
147
147
 
148
148
  export function creatDummyXpub(pubkey: Buffer): string {