@taquito/ledger-signer 17.3.2 → 17.4.0

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.
@@ -17,6 +17,8 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
17
17
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
18
18
  PERFORMANCE OF THIS SOFTWARE.
19
19
  ***************************************************************************** */
20
+ /* global Reflect, Promise, SuppressedError, Symbol */
21
+
20
22
 
21
23
  function __awaiter(thisArg, _arguments, P, generator) {
22
24
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
@@ -33,360 +35,360 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
33
35
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
34
36
  };
35
37
 
36
- /*
37
- * Some code in this file is adapted from sotez
38
- * Copyright (c) 2018 Andrew Kishino
39
- */
40
- const MAX_CHUNK_SIZE = 230;
41
- /**
42
- *
43
- * @description Convert the path to a buffer that will be used as LC and CDATA in the APDU send to the ledger device (https://github.com/obsidiansystems/ledger-app-tezos/blob/master/APDUs.md)
44
- *
45
- * @param path The ledger derivation path (default is "44'/1729'/0'/0'")
46
- * @returns A buffer where the first element is the length of the path (default is 4), then 3 bytes for each number of the path to which is added 0x8000000
47
- */
48
- function transformPathToBuffer(path) {
49
- const result = [];
50
- const components = path.split('/');
51
- components.forEach((element) => {
52
- let toNumber = parseInt(element, 10);
53
- if (Number.isNaN(toNumber)) {
54
- return;
55
- }
56
- if (element.length > 1 && element[element.length - 1] === "'") {
57
- toNumber += 0x80000000;
58
- }
59
- result.push(toNumber);
60
- });
61
- const buffer = Buffer.alloc(1 + result.length * 4);
62
- buffer[0] = result.length;
63
- result.forEach((element, index) => {
64
- buffer.writeUInt32BE(element, 1 + 4 * index);
65
- });
66
- return buffer;
67
- }
68
- /**
69
- *
70
- * @description Converts uncompressed ledger key to standard tezos binary representation
71
- */
72
- function compressPublicKey(publicKey, curve) {
73
- if (curve === 0x00 || curve === 0x03) {
74
- publicKey = publicKey.slice(1);
75
- }
76
- else {
77
- publicKey[0] = 0x02 + (publicKey[64] & 0x01);
78
- publicKey = publicKey.slice(0, 33);
79
- }
80
- return publicKey;
81
- }
82
- function appendWatermark(bytes, watermark) {
83
- let transactionHex = bytes;
84
- if (typeof watermark !== 'undefined') {
85
- const hexWatermark = Buffer.from(watermark).toString('hex');
86
- transactionHex = hexWatermark.concat(bytes);
87
- }
88
- return transactionHex;
89
- }
90
- /**
91
- *
92
- * @description In order not to exceed the data length allowed by the Ledger device, split the operation into buffers of 230 bytes (max) and add them to the message to send to the Ledger
93
- * @param messageToSend The message to send to the Ledger device
94
- * @param operation The operation which will be chunk if its length is over 230 bytes
95
- * @returns The instruction to send to the Ledger device
96
- */
97
- function chunkOperation(messageToSend, operation) {
98
- let offset = 0;
99
- while (offset !== operation.length) {
100
- const chunkSize = offset + MAX_CHUNK_SIZE >= operation.length ? operation.length - offset : MAX_CHUNK_SIZE;
101
- const buff = Buffer.alloc(chunkSize);
102
- operation.copy(buff, 0, offset, offset + chunkSize);
103
- messageToSend.push(buff);
104
- offset += chunkSize;
105
- }
106
- return messageToSend;
107
- }
108
- /**
109
- *
110
- * @description Verify if the signature returned by the ledger for tz2 and tz3 is valid
111
- * @param response The signature returned by the Ledger (return from the signWithLedger function)
112
- * @returns True if valid, false otherwise
113
- */
114
- function validateResponse(response) {
115
- let valid = true;
116
- if (response[0] !== 0x31 && response[0] !== 0x30) {
117
- valid = false;
118
- }
119
- if (response[1] + 4 !== response.length) {
120
- valid = false;
121
- }
122
- if (response[2] !== 0x02) {
123
- valid = false;
124
- }
125
- const rLength = response[3];
126
- if (response[4 + rLength] !== 0x02) {
127
- valid = false;
128
- }
129
- const idxLengthSVal = 5 + rLength;
130
- const sLength = response[idxLengthSVal];
131
- if (idxLengthSVal + 1 + sLength + 2 !== response.length) {
132
- valid = false;
133
- }
134
- return valid;
135
- }
136
- /**
137
- *
138
- * @description Extract a part of the response returned by the Ledger
139
- * @param idxLength The index in the response from the Ledger that corresponds to the length of the part to extract
140
- * @param response The signature returned by the Ledger (return from the signWithLedger function)
141
- * @returns An object that contains the extracted buffer, the index where it starts in the response and the length of the extracted part
142
- */
143
- function extractValue(idxLength, response) {
144
- const buffer = Buffer.alloc(32);
145
- buffer.fill(0);
146
- let length = response[idxLength];
147
- let idxValueStart = idxLength + 1;
148
- if (length > 32) {
149
- idxValueStart += length - 32;
150
- length = 32;
151
- }
152
- response.copy(buffer, 32 - length, idxValueStart, idxValueStart + length);
153
- return { buffer, idxValueStart, length };
38
+ /*
39
+ * Some code in this file is adapted from sotez
40
+ * Copyright (c) 2018 Andrew Kishino
41
+ */
42
+ const MAX_CHUNK_SIZE = 230;
43
+ /**
44
+ *
45
+ * @description Convert the path to a buffer that will be used as LC and CDATA in the APDU send to the ledger device (https://github.com/obsidiansystems/ledger-app-tezos/blob/master/APDUs.md)
46
+ *
47
+ * @param path The ledger derivation path (default is "44'/1729'/0'/0'")
48
+ * @returns A buffer where the first element is the length of the path (default is 4), then 3 bytes for each number of the path to which is added 0x8000000
49
+ */
50
+ function transformPathToBuffer(path) {
51
+ const result = [];
52
+ const components = path.split('/');
53
+ components.forEach((element) => {
54
+ let toNumber = parseInt(element, 10);
55
+ if (Number.isNaN(toNumber)) {
56
+ return;
57
+ }
58
+ if (element.length > 1 && element[element.length - 1] === "'") {
59
+ toNumber += 0x80000000;
60
+ }
61
+ result.push(toNumber);
62
+ });
63
+ const buffer = Buffer.alloc(1 + result.length * 4);
64
+ buffer[0] = result.length;
65
+ result.forEach((element, index) => {
66
+ buffer.writeUInt32BE(element, 1 + 4 * index);
67
+ });
68
+ return buffer;
69
+ }
70
+ /**
71
+ *
72
+ * @description Converts uncompressed ledger key to standard tezos binary representation
73
+ */
74
+ function compressPublicKey(publicKey, curve) {
75
+ if (curve === 0x00 || curve === 0x03) {
76
+ publicKey = publicKey.slice(1);
77
+ }
78
+ else {
79
+ publicKey[0] = 0x02 + (publicKey[64] & 0x01);
80
+ publicKey = publicKey.slice(0, 33);
81
+ }
82
+ return publicKey;
83
+ }
84
+ function appendWatermark(bytes, watermark) {
85
+ let transactionHex = bytes;
86
+ if (typeof watermark !== 'undefined') {
87
+ const hexWatermark = Buffer.from(watermark).toString('hex');
88
+ transactionHex = hexWatermark.concat(bytes);
89
+ }
90
+ return transactionHex;
91
+ }
92
+ /**
93
+ *
94
+ * @description In order not to exceed the data length allowed by the Ledger device, split the operation into buffers of 230 bytes (max) and add them to the message to send to the Ledger
95
+ * @param messageToSend The message to send to the Ledger device
96
+ * @param operation The operation which will be chunk if its length is over 230 bytes
97
+ * @returns The instruction to send to the Ledger device
98
+ */
99
+ function chunkOperation(messageToSend, operation) {
100
+ let offset = 0;
101
+ while (offset !== operation.length) {
102
+ const chunkSize = offset + MAX_CHUNK_SIZE >= operation.length ? operation.length - offset : MAX_CHUNK_SIZE;
103
+ const buff = Buffer.alloc(chunkSize);
104
+ operation.copy(buff, 0, offset, offset + chunkSize);
105
+ messageToSend.push(buff);
106
+ offset += chunkSize;
107
+ }
108
+ return messageToSend;
109
+ }
110
+ /**
111
+ *
112
+ * @description Verify if the signature returned by the ledger for tz2 and tz3 is valid
113
+ * @param response The signature returned by the Ledger (return from the signWithLedger function)
114
+ * @returns True if valid, false otherwise
115
+ */
116
+ function validateResponse(response) {
117
+ let valid = true;
118
+ if (response[0] !== 0x31 && response[0] !== 0x30) {
119
+ valid = false;
120
+ }
121
+ if (response[1] + 4 !== response.length) {
122
+ valid = false;
123
+ }
124
+ if (response[2] !== 0x02) {
125
+ valid = false;
126
+ }
127
+ const rLength = response[3];
128
+ if (response[4 + rLength] !== 0x02) {
129
+ valid = false;
130
+ }
131
+ const idxLengthSVal = 5 + rLength;
132
+ const sLength = response[idxLengthSVal];
133
+ if (idxLengthSVal + 1 + sLength + 2 !== response.length) {
134
+ valid = false;
135
+ }
136
+ return valid;
137
+ }
138
+ /**
139
+ *
140
+ * @description Extract a part of the response returned by the Ledger
141
+ * @param idxLength The index in the response from the Ledger that corresponds to the length of the part to extract
142
+ * @param response The signature returned by the Ledger (return from the signWithLedger function)
143
+ * @returns An object that contains the extracted buffer, the index where it starts in the response and the length of the extracted part
144
+ */
145
+ function extractValue(idxLength, response) {
146
+ const buffer = Buffer.alloc(32);
147
+ buffer.fill(0);
148
+ let length = response[idxLength];
149
+ let idxValueStart = idxLength + 1;
150
+ if (length > 32) {
151
+ idxValueStart += length - 32;
152
+ length = 32;
153
+ }
154
+ response.copy(buffer, 32 - length, idxValueStart, idxValueStart + length);
155
+ return { buffer, idxValueStart, length };
154
156
  }
155
157
 
156
- /**
157
- * @category Error
158
- * @description Error that indicates an invalid or unparseable ledger response
159
- */
160
- class InvalidLedgerResponseError extends TaquitoError {
161
- constructor(message) {
162
- super();
163
- this.message = message;
164
- this.name = 'InvalidLedgerResponseError';
165
- }
166
- }
167
- /**
168
- * @category Error
169
- * @description Error that indicates a failure when trying to retrieve a Public Key from Ledger signer
170
- */
171
- class PublicKeyRetrievalError extends TaquitoError {
172
- constructor(cause) {
173
- super();
174
- this.cause = cause;
175
- this.name = 'PublicKeyRetrievalError';
176
- this.message = `Unable to retrieve Public Key from Ledger`;
177
- }
178
- }
179
- /**
180
- * @category Error
181
- * @description Error that indicates a failure when trying to retrieve a Public Key Hash from Ledger signer
182
- */
183
- class PublicKeyHashRetrievalError extends TaquitoError {
184
- constructor() {
185
- super();
186
- this.name = 'PublicKeyHashRetrievalError';
187
- this.message = 'Unable to retrieve Public Key Hash from Ledger';
188
- }
189
- }
190
- /**
191
- * @category Error
192
- * @description Error that indicates an invalid derivation type being passed or used
193
- */
194
- class InvalidDerivationTypeError extends ParameterValidationError {
195
- constructor(derivationType) {
196
- super();
197
- this.derivationType = derivationType;
198
- this.name = 'InvalidDerivationTypeError';
199
- this.message = `Invalid derivation type ${derivationType} expecting one of the following: DerivationType.ED25519, DerivationType.SECP256K1, DerivationType.P256 or DerivationType.BIP32_ED25519`;
200
- }
158
+ /**
159
+ * @category Error
160
+ * @description Error that indicates an invalid or unparseable ledger response
161
+ */
162
+ class InvalidLedgerResponseError extends TaquitoError {
163
+ constructor(message) {
164
+ super();
165
+ this.message = message;
166
+ this.name = 'InvalidLedgerResponseError';
167
+ }
168
+ }
169
+ /**
170
+ * @category Error
171
+ * @description Error that indicates a failure when trying to retrieve a Public Key from Ledger signer
172
+ */
173
+ class PublicKeyRetrievalError extends TaquitoError {
174
+ constructor(cause) {
175
+ super();
176
+ this.cause = cause;
177
+ this.name = 'PublicKeyRetrievalError';
178
+ this.message = `Unable to retrieve Public Key from Ledger`;
179
+ }
180
+ }
181
+ /**
182
+ * @category Error
183
+ * @description Error that indicates a failure when trying to retrieve a Public Key Hash from Ledger signer
184
+ */
185
+ class PublicKeyHashRetrievalError extends TaquitoError {
186
+ constructor() {
187
+ super();
188
+ this.name = 'PublicKeyHashRetrievalError';
189
+ this.message = 'Unable to retrieve Public Key Hash from Ledger';
190
+ }
191
+ }
192
+ /**
193
+ * @category Error
194
+ * @description Error that indicates an invalid derivation type being passed or used
195
+ */
196
+ class InvalidDerivationTypeError extends ParameterValidationError {
197
+ constructor(derivationType) {
198
+ super();
199
+ this.derivationType = derivationType;
200
+ this.name = 'InvalidDerivationTypeError';
201
+ this.message = `Invalid derivation type ${derivationType} expecting one of the following: DerivationType.ED25519, DerivationType.SECP256K1, DerivationType.P256 or DerivationType.BIP32_ED25519`;
202
+ }
201
203
  }
202
204
 
203
- // IMPORTANT: THIS FILE IS AUTO GENERATED! DO NOT MANUALLY EDIT OR CHECKIN!
204
- const VERSION = {
205
- "commitHash": "a97e506efd61b86e39ae30db588401b8fda46553",
206
- "version": "17.3.2"
205
+ // IMPORTANT: THIS FILE IS AUTO GENERATED! DO NOT MANUALLY EDIT OR CHECKIN!
206
+ const VERSION = {
207
+ "commitHash": "a908ab176a8c52c025fd43e7acd452415396f54e",
208
+ "version": "17.4.0"
207
209
  };
208
210
 
209
- /**
210
- * @packageDocumentation
211
- * @module @taquito/ledger-signer
212
- */
213
- var DerivationType;
214
- (function (DerivationType) {
215
- DerivationType[DerivationType["ED25519"] = 0] = "ED25519";
216
- DerivationType[DerivationType["SECP256K1"] = 1] = "SECP256K1";
217
- DerivationType[DerivationType["P256"] = 2] = "P256";
218
- DerivationType[DerivationType["BIP32_ED25519"] = 3] = "BIP32_ED25519";
219
- })(DerivationType || (DerivationType = {}));
220
- const HDPathTemplate = (account) => {
221
- return `44'/1729'/${account}'/0'`;
222
- };
223
- /**
224
- *
225
- * @description Implementation of the Signer interface that will allow signing operation from a Ledger Nano device
226
- *
227
- * @param transport A transport instance from LedgerJS libraries depending on the platform used (e.g. Web, Node)
228
- * @param path The ledger derivation path (default is "44'/1729'/0'/0'")
229
- * @param prompt Whether to prompt the ledger for public key (default is true)
230
- * @param derivationType The value which defines the curve to use (DerivationType.ED25519(default), DerivationType.SECP256K1, DerivationType.P256, DerivationType.BIP32_ED25519)
231
- *
232
- * @example
233
- * ```
234
- * import TransportNodeHid from "@ledgerhq/hw-transport-node-hid";
235
- * const transport = await TransportNodeHid.create();
236
- * const ledgerSigner = new LedgerSigner(transport, "44'/1729'/0'/0'", false, DerivationType.ED25519);
237
- * ```
238
- *
239
- * @example
240
- * ```
241
- * import TransportU2F from "@ledgerhq/hw-transport-u2f";
242
- * const transport = await TransportU2F.create();
243
- * const ledgerSigner = new LedgerSigner(transport, "44'/1729'/0'/0'", true, DerivationType.SECP256K1);
244
- * ```
245
- *
246
- * @example
247
- * ```
248
- * import TransportU2F from "@ledgerhq/hw-transport-u2f";
249
- * const transport = await TransportU2F.create();
250
- * const ledgerSigner = new LedgerSigner(transport, "44'/1729'/6'/0'", true, DerivationType.BIP32_ED25519);
251
- * ```
252
- */
253
- class LedgerSigner {
254
- constructor(transport, path = "44'/1729'/0'/0'", prompt = true, derivationType = DerivationType.ED25519) {
255
- this.transport = transport;
256
- this.path = path;
257
- this.prompt = prompt;
258
- this.derivationType = derivationType;
259
- // constants for APDU requests (https://github.com/obsidiansystems/ledger-app-tezos/blob/master/APDUs.md)
260
- this.CLA = 0x80; // Instruction class (always 0x80)
261
- this.INS_GET_PUBLIC_KEY = 0x02; // Instruction code to get the ledger’s internal public key without prompt
262
- this.INS_PROMPT_PUBLIC_KEY = 0x03; // Instruction code to get the ledger’s internal public key with prompt
263
- this.INS_SIGN = 0x04; // Sign a message with the ledger’s key
264
- this.FIRST_MESSAGE_SEQUENCE = 0x00;
265
- this.LAST_MESSAGE_SEQUENCE = 0x81;
266
- this.OTHER_MESSAGE_SEQUENCE = 0x01;
267
- this.transport.setScrambleKey('XTZ');
268
- if (!path.startsWith(`44'/1729'`)) {
269
- throw new InvalidDerivationPathError(path, `${invalidDetail(ValidationResult.NO_PREFIX_MATCHED)} expecting prefix "44'/1729'".`);
270
- }
271
- if (!Object.values(DerivationType).includes(derivationType)) {
272
- throw new InvalidDerivationTypeError(derivationType.toString());
273
- }
274
- }
275
- publicKeyHash() {
276
- return __awaiter(this, void 0, void 0, function* () {
277
- if (!this._publicKeyHash) {
278
- yield this.publicKey();
279
- }
280
- if (this._publicKeyHash) {
281
- return this._publicKeyHash;
282
- }
283
- throw new PublicKeyHashRetrievalError();
284
- });
285
- }
286
- publicKey() {
287
- return __awaiter(this, void 0, void 0, function* () {
288
- if (this._publicKey) {
289
- return this._publicKey;
290
- }
291
- const responseLedger = yield this.getLedgerPublicKey();
292
- const publicKeyLength = responseLedger[0];
293
- const rawPublicKey = responseLedger.slice(1, 1 + publicKeyLength);
294
- const compressedPublicKey = compressPublicKey(rawPublicKey, this.derivationType);
295
- const prefixes = this.getPrefixes();
296
- const publicKey = b58cencode(compressedPublicKey, prefixes.prefPk);
297
- const publicKeyHash = b58cencode(hash(compressedPublicKey, 20), prefixes.prefPkh);
298
- this._publicKey = publicKey;
299
- this._publicKeyHash = publicKeyHash;
300
- return publicKey;
301
- });
302
- }
303
- getLedgerPublicKey() {
304
- return __awaiter(this, void 0, void 0, function* () {
305
- try {
306
- let ins = this.INS_PROMPT_PUBLIC_KEY;
307
- if (this.prompt === false) {
308
- ins = this.INS_GET_PUBLIC_KEY;
309
- }
310
- const responseLedger = yield this.transport.send(this.CLA, ins, this.FIRST_MESSAGE_SEQUENCE, this.derivationType, transformPathToBuffer(this.path));
311
- return responseLedger;
312
- }
313
- catch (error) {
314
- throw new PublicKeyRetrievalError(error);
315
- }
316
- });
317
- }
318
- secretKey() {
319
- return __awaiter(this, void 0, void 0, function* () {
320
- throw new ProhibitedActionError('Secret key cannot be exposed');
321
- });
322
- }
323
- sign(bytes, watermark) {
324
- return __awaiter(this, void 0, void 0, function* () {
325
- const watermarkedBytes = appendWatermark(bytes, watermark);
326
- const watermarkedBytes2buff = Buffer.from(watermarkedBytes, 'hex');
327
- let messageToSend = [];
328
- messageToSend.push(transformPathToBuffer(this.path));
329
- messageToSend = chunkOperation(messageToSend, watermarkedBytes2buff);
330
- const ledgerResponse = yield this.signWithLedger(messageToSend);
331
- let signature;
332
- if (this.derivationType === DerivationType.ED25519 ||
333
- this.derivationType === DerivationType.BIP32_ED25519) {
334
- signature = ledgerResponse.slice(0, ledgerResponse.length - 2).toString('hex');
335
- }
336
- else {
337
- if (!validateResponse(ledgerResponse)) {
338
- throw new InvalidLedgerResponseError('Invalid signature return by ledger unable to parse the response');
339
- }
340
- const idxLengthRVal = 3; // Third element of response is length of r value
341
- const rValue = extractValue(idxLengthRVal, ledgerResponse);
342
- const idxLengthSVal = rValue.idxValueStart + rValue.length + 1;
343
- const sValue = extractValue(idxLengthSVal, ledgerResponse);
344
- const signatureBuffer = Buffer.concat([rValue.buffer, sValue.buffer]);
345
- signature = signatureBuffer.toString('hex');
346
- }
347
- return {
348
- bytes,
349
- sig: b58cencode(signature, prefix[Prefix.SIG]),
350
- prefixSig: b58cencode(signature, this.getPrefixes().prefSig),
351
- sbytes: bytes + signature,
352
- };
353
- });
354
- }
355
- signWithLedger(message) {
356
- return __awaiter(this, void 0, void 0, function* () {
357
- // first element of the message represents the path
358
- let ledgerResponse = yield this.transport.send(this.CLA, this.INS_SIGN, this.FIRST_MESSAGE_SEQUENCE, this.derivationType, message[0]);
359
- for (let i = 1; i < message.length; i++) {
360
- const p1 = i === message.length - 1 ? this.LAST_MESSAGE_SEQUENCE : this.OTHER_MESSAGE_SEQUENCE;
361
- ledgerResponse = yield this.transport.send(this.CLA, this.INS_SIGN, p1, this.derivationType, message[i]);
362
- }
363
- return ledgerResponse;
364
- });
365
- }
366
- getPrefixes() {
367
- if (this.derivationType === DerivationType.ED25519 ||
368
- this.derivationType === DerivationType.BIP32_ED25519) {
369
- return {
370
- prefPk: prefix[Prefix.EDPK],
371
- prefPkh: prefix[Prefix.TZ1],
372
- prefSig: prefix[Prefix.EDSIG],
373
- };
374
- }
375
- else if (this.derivationType === DerivationType.SECP256K1) {
376
- return {
377
- prefPk: prefix[Prefix.SPPK],
378
- prefPkh: prefix[Prefix.TZ2],
379
- prefSig: prefix[Prefix.SPSIG],
380
- };
381
- }
382
- else {
383
- return {
384
- prefPk: prefix[Prefix.P2PK],
385
- prefPkh: prefix[Prefix.TZ3],
386
- prefSig: prefix[Prefix.P2SIG],
387
- };
388
- }
389
- }
211
+ /**
212
+ * @packageDocumentation
213
+ * @module @taquito/ledger-signer
214
+ */
215
+ var DerivationType;
216
+ (function (DerivationType) {
217
+ DerivationType[DerivationType["ED25519"] = 0] = "ED25519";
218
+ DerivationType[DerivationType["SECP256K1"] = 1] = "SECP256K1";
219
+ DerivationType[DerivationType["P256"] = 2] = "P256";
220
+ DerivationType[DerivationType["BIP32_ED25519"] = 3] = "BIP32_ED25519";
221
+ })(DerivationType || (DerivationType = {}));
222
+ const HDPathTemplate = (account) => {
223
+ return `44'/1729'/${account}'/0'`;
224
+ };
225
+ /**
226
+ *
227
+ * @description Implementation of the Signer interface that will allow signing operation from a Ledger Nano device
228
+ *
229
+ * @param transport A transport instance from LedgerJS libraries depending on the platform used (e.g. Web, Node)
230
+ * @param path The ledger derivation path (default is "44'/1729'/0'/0'")
231
+ * @param prompt Whether to prompt the ledger for public key (default is true)
232
+ * @param derivationType The value which defines the curve to use (DerivationType.ED25519(default), DerivationType.SECP256K1, DerivationType.P256, DerivationType.BIP32_ED25519)
233
+ *
234
+ * @example
235
+ * ```
236
+ * import TransportNodeHid from "@ledgerhq/hw-transport-node-hid";
237
+ * const transport = await TransportNodeHid.create();
238
+ * const ledgerSigner = new LedgerSigner(transport, "44'/1729'/0'/0'", false, DerivationType.ED25519);
239
+ * ```
240
+ *
241
+ * @example
242
+ * ```
243
+ * import TransportU2F from "@ledgerhq/hw-transport-u2f";
244
+ * const transport = await TransportU2F.create();
245
+ * const ledgerSigner = new LedgerSigner(transport, "44'/1729'/0'/0'", true, DerivationType.SECP256K1);
246
+ * ```
247
+ *
248
+ * @example
249
+ * ```
250
+ * import TransportU2F from "@ledgerhq/hw-transport-u2f";
251
+ * const transport = await TransportU2F.create();
252
+ * const ledgerSigner = new LedgerSigner(transport, "44'/1729'/6'/0'", true, DerivationType.BIP32_ED25519);
253
+ * ```
254
+ */
255
+ class LedgerSigner {
256
+ constructor(transport, path = "44'/1729'/0'/0'", prompt = true, derivationType = DerivationType.ED25519) {
257
+ this.transport = transport;
258
+ this.path = path;
259
+ this.prompt = prompt;
260
+ this.derivationType = derivationType;
261
+ // constants for APDU requests (https://github.com/obsidiansystems/ledger-app-tezos/blob/master/APDUs.md)
262
+ this.CLA = 0x80; // Instruction class (always 0x80)
263
+ this.INS_GET_PUBLIC_KEY = 0x02; // Instruction code to get the ledger’s internal public key without prompt
264
+ this.INS_PROMPT_PUBLIC_KEY = 0x03; // Instruction code to get the ledger’s internal public key with prompt
265
+ this.INS_SIGN = 0x04; // Sign a message with the ledger’s key
266
+ this.FIRST_MESSAGE_SEQUENCE = 0x00;
267
+ this.LAST_MESSAGE_SEQUENCE = 0x81;
268
+ this.OTHER_MESSAGE_SEQUENCE = 0x01;
269
+ this.transport.setScrambleKey('XTZ');
270
+ if (!path.startsWith(`44'/1729'`)) {
271
+ throw new InvalidDerivationPathError(path, `${invalidDetail(ValidationResult.NO_PREFIX_MATCHED)} expecting prefix "44'/1729'".`);
272
+ }
273
+ if (!Object.values(DerivationType).includes(derivationType)) {
274
+ throw new InvalidDerivationTypeError(derivationType.toString());
275
+ }
276
+ }
277
+ publicKeyHash() {
278
+ return __awaiter(this, void 0, void 0, function* () {
279
+ if (!this._publicKeyHash) {
280
+ yield this.publicKey();
281
+ }
282
+ if (this._publicKeyHash) {
283
+ return this._publicKeyHash;
284
+ }
285
+ throw new PublicKeyHashRetrievalError();
286
+ });
287
+ }
288
+ publicKey() {
289
+ return __awaiter(this, void 0, void 0, function* () {
290
+ if (this._publicKey) {
291
+ return this._publicKey;
292
+ }
293
+ const responseLedger = yield this.getLedgerPublicKey();
294
+ const publicKeyLength = responseLedger[0];
295
+ const rawPublicKey = responseLedger.slice(1, 1 + publicKeyLength);
296
+ const compressedPublicKey = compressPublicKey(rawPublicKey, this.derivationType);
297
+ const prefixes = this.getPrefixes();
298
+ const publicKey = b58cencode(compressedPublicKey, prefixes.prefPk);
299
+ const publicKeyHash = b58cencode(hash(compressedPublicKey, 20), prefixes.prefPkh);
300
+ this._publicKey = publicKey;
301
+ this._publicKeyHash = publicKeyHash;
302
+ return publicKey;
303
+ });
304
+ }
305
+ getLedgerPublicKey() {
306
+ return __awaiter(this, void 0, void 0, function* () {
307
+ try {
308
+ let ins = this.INS_PROMPT_PUBLIC_KEY;
309
+ if (this.prompt === false) {
310
+ ins = this.INS_GET_PUBLIC_KEY;
311
+ }
312
+ const responseLedger = yield this.transport.send(this.CLA, ins, this.FIRST_MESSAGE_SEQUENCE, this.derivationType, transformPathToBuffer(this.path));
313
+ return responseLedger;
314
+ }
315
+ catch (error) {
316
+ throw new PublicKeyRetrievalError(error);
317
+ }
318
+ });
319
+ }
320
+ secretKey() {
321
+ return __awaiter(this, void 0, void 0, function* () {
322
+ throw new ProhibitedActionError('Secret key cannot be exposed');
323
+ });
324
+ }
325
+ sign(bytes, watermark) {
326
+ return __awaiter(this, void 0, void 0, function* () {
327
+ const watermarkedBytes = appendWatermark(bytes, watermark);
328
+ const watermarkedBytes2buff = Buffer.from(watermarkedBytes, 'hex');
329
+ let messageToSend = [];
330
+ messageToSend.push(transformPathToBuffer(this.path));
331
+ messageToSend = chunkOperation(messageToSend, watermarkedBytes2buff);
332
+ const ledgerResponse = yield this.signWithLedger(messageToSend);
333
+ let signature;
334
+ if (this.derivationType === DerivationType.ED25519 ||
335
+ this.derivationType === DerivationType.BIP32_ED25519) {
336
+ signature = ledgerResponse.slice(0, ledgerResponse.length - 2).toString('hex');
337
+ }
338
+ else {
339
+ if (!validateResponse(ledgerResponse)) {
340
+ throw new InvalidLedgerResponseError('Invalid signature return by ledger unable to parse the response');
341
+ }
342
+ const idxLengthRVal = 3; // Third element of response is length of r value
343
+ const rValue = extractValue(idxLengthRVal, ledgerResponse);
344
+ const idxLengthSVal = rValue.idxValueStart + rValue.length + 1;
345
+ const sValue = extractValue(idxLengthSVal, ledgerResponse);
346
+ const signatureBuffer = Buffer.concat([rValue.buffer, sValue.buffer]);
347
+ signature = signatureBuffer.toString('hex');
348
+ }
349
+ return {
350
+ bytes,
351
+ sig: b58cencode(signature, prefix[Prefix.SIG]),
352
+ prefixSig: b58cencode(signature, this.getPrefixes().prefSig),
353
+ sbytes: bytes + signature,
354
+ };
355
+ });
356
+ }
357
+ signWithLedger(message) {
358
+ return __awaiter(this, void 0, void 0, function* () {
359
+ // first element of the message represents the path
360
+ let ledgerResponse = yield this.transport.send(this.CLA, this.INS_SIGN, this.FIRST_MESSAGE_SEQUENCE, this.derivationType, message[0]);
361
+ for (let i = 1; i < message.length; i++) {
362
+ const p1 = i === message.length - 1 ? this.LAST_MESSAGE_SEQUENCE : this.OTHER_MESSAGE_SEQUENCE;
363
+ ledgerResponse = yield this.transport.send(this.CLA, this.INS_SIGN, p1, this.derivationType, message[i]);
364
+ }
365
+ return ledgerResponse;
366
+ });
367
+ }
368
+ getPrefixes() {
369
+ if (this.derivationType === DerivationType.ED25519 ||
370
+ this.derivationType === DerivationType.BIP32_ED25519) {
371
+ return {
372
+ prefPk: prefix[Prefix.EDPK],
373
+ prefPkh: prefix[Prefix.TZ1],
374
+ prefSig: prefix[Prefix.EDSIG],
375
+ };
376
+ }
377
+ else if (this.derivationType === DerivationType.SECP256K1) {
378
+ return {
379
+ prefPk: prefix[Prefix.SPPK],
380
+ prefPkh: prefix[Prefix.TZ2],
381
+ prefSig: prefix[Prefix.SPSIG],
382
+ };
383
+ }
384
+ else {
385
+ return {
386
+ prefPk: prefix[Prefix.P2PK],
387
+ prefPkh: prefix[Prefix.TZ3],
388
+ prefSig: prefix[Prefix.P2SIG],
389
+ };
390
+ }
391
+ }
390
392
  }
391
393
 
392
394
  export { DerivationType, HDPathTemplate, InvalidDerivationTypeError, LedgerSigner, VERSION };