@@ -22,7 +22,6 @@ import {
22
22
ECDSA_PUBKEY_LEN ,
23
23
ED25519_PUBKEY_LEN ,
24
24
GenericResponseSign ,
25
- GenericResponseSignEcdsa ,
26
25
GenericeResponseAddress ,
27
26
P1_VALUES ,
28
27
SCHEME ,
@@ -265,14 +264,18 @@ export class PolkadotGenericApp extends BaseApp {
265
264
* @param blob - The transaction blob.
266
265
* @param metadata - The optional metadata.
267
266
* @throws {ResponseError } If the response from the device indicates an error.
268
- * @returns The response containing the signature and status.
267
+ * @returns The response containing the signature and status. For ECDSA, the signature is in RSV format:
268
+ * - R: First 32 bytes (signature.slice(0, 32))
269
+ * - S: Next 32 bytes (signature.slice(32, 64))
270
+ * - V: Last byte (signature.slice(64, 65))
271
+ * @see parseEcdsaSignature - Use this utility function to easily parse the signature into R, S, V components
269
272
*/
270
273
private async signImplEcdsa (
271
274
path : BIP32Path ,
272
275
ins : number ,
273
276
blob : TransactionBlob ,
274
277
metadata ?: TransactionMetadataBlob
275
- ) : Promise < GenericResponseSignEcdsa > {
278
+ ) : Promise < GenericResponseSign > {
276
279
const chunks = this . getSignReqChunks ( path , blob , metadata )
277
280
278
281
try {
@@ -283,9 +286,7 @@ export class PolkadotGenericApp extends BaseApp {
283
286
}
284
287
285
288
return {
286
- r : result . readBytes ( 32 ) ,
287
- s : result . readBytes ( 32 ) ,
288
- v : result . readBytes ( 1 ) ,
289
+ signature : result . readBytes ( result . length ( ) ) ,
289
290
}
290
291
} catch ( e ) {
291
292
throw processErrorResponse ( e )
@@ -342,7 +343,11 @@ export class PolkadotGenericApp extends BaseApp {
342
343
* @param path - The BIP44 path.
343
344
* @param txBlob - The transaction blob.
344
345
* @throws {ResponseError } If the response from the device indicates an error.
345
- * @returns The response containing the signature and status.
346
+ * @returns The response containing the signature and status. For ECDSA, the signature is in RSV format:
347
+ * - R: First 32 bytes (signature.slice(0, 32))
348
+ * - S: Next 32 bytes (signature.slice(32, 64))
349
+ * - V: Last byte (signature.slice(64, 65))
350
+ * @see parseEcdsaSignature - Use this utility function to easily parse the signature into R, S, V components
346
351
*/
347
352
async signEcdsa ( path : BIP32Path , txBlob : TransactionBlob ) {
348
353
if ( ! this . txMetadataSrvUrl ) {
@@ -425,7 +430,11 @@ export class PolkadotGenericApp extends BaseApp {
425
430
* @param path - The BIP44 path.
426
431
* @param txBlob - The transaction blob.
427
432
* @throws {ResponseError } If the response from the device indicates an error.
428
- * @returns The response containing the signature and status.
433
+ * @returns The response containing the signature and status. For ECDSA, the signature is in RSV format:
434
+ * - R: First 32 bytes (signature.slice(0, 32))
435
+ * - S: Next 32 bytes (signature.slice(32, 64))
436
+ * - V: Last byte (signature.slice(64, 65))
437
+ * @see parseEcdsaSignature - Use this utility function to easily parse the signature into R, S, V components
429
438
*/
430
439
async signRawEcdsa ( path : BIP32Path , txBlob : TransactionBlob ) {
431
440
return await this . signImplEcdsa ( path , this . INS . SIGN_RAW , txBlob )
@@ -440,7 +449,7 @@ export class PolkadotGenericApp extends BaseApp {
440
449
* @throws {ResponseError } If the response from the device indicates an error.
441
450
* @returns The response containing the signature and status.
442
451
*/
443
- async signWithMetadata ( path : BIP32Path , txBlob : TransactionBlob , txMetadata : TransactionMetadataBlob , scheme : SCHEME ) {
452
+ async signWithMetadata ( path : BIP32Path , txBlob : TransactionBlob , txMetadata : TransactionMetadataBlob , scheme = SCHEME . ED25519 ) {
444
453
if ( scheme != SCHEME . ECDSA && scheme != SCHEME . ED25519 ) {
445
454
throw new ResponseError ( LedgerError . ConditionsOfUseNotSatisfied , `Unexpected scheme ${ scheme } . Needs to be ECDSA (2) or ED25519 (0)` )
446
455
}
@@ -456,7 +465,11 @@ export class PolkadotGenericApp extends BaseApp {
456
465
* @param txBlob - The transaction blob.
457
466
* @param txMetadata - The transaction metadata.
458
467
* @throws {ResponseError } If the response from the device indicates an error.
459
- * @returns The response containing the signature and status.
468
+ * @returns The response containing the signature and status. For ECDSA, the signature is in RSV format:
469
+ * - R: First 32 bytes (signature.slice(0, 32))
470
+ * - S: Next 32 bytes (signature.slice(32, 64))
471
+ * - V: Last byte (signature.slice(64, 65))
472
+ * @see parseEcdsaSignature - Use this utility function to easily parse the signature into R, S, V components
460
473
*/
461
474
async signWithMetadataEcdsa ( path : BIP32Path , txBlob : TransactionBlob , txMetadata : TransactionMetadataBlob ) {
462
475
return await this . signImplEcdsa ( path , this . INS . SIGN , txBlob , txMetadata )
@@ -473,4 +486,22 @@ export class PolkadotGenericApp extends BaseApp {
473
486
async signWithMetadataEd25519 ( path : BIP32Path , txBlob : TransactionBlob , txMetadata : TransactionMetadataBlob ) {
474
487
return await this . signImplEd25519 ( path , this . INS . SIGN , txBlob , txMetadata )
475
488
}
489
+
490
+ /**
491
+ * Utility function to convert ECDSA signature response into RSV structure
492
+ * @param signature - The ECDSA signature buffer from the device response
493
+ * @returns Object containing R, S, and V components of the ECDSA signature
494
+ * @throws {Error } If signature length is not 65 bytes (expected for ECDSA RSV format)
495
+ */
496
+ static parseEcdsaSignature ( signature : Buffer ) : { r : string ; s : string ; v : string } {
497
+ if ( signature . length !== 65 ) {
498
+ throw new Error ( 'Invalid ECDSA signature length. Expected 65 bytes for RSV format' )
499
+ }
500
+
501
+ return {
502
+ r : signature . slice ( 0 , 32 ) . toString ( 'hex' ) ,
503
+ s : signature . slice ( 32 , 64 ) . toString ( 'hex' ) ,
504
+ v : signature . slice ( 64 , 65 ) . toString ( 'hex' ) ,
505
+ }
506
+ }
476
507
}
0 commit comments