iso-signatures 0.5.2 → 0.6.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.
@@ -1,3 +1,19 @@
1
+ /**
2
+ * Check if a raw `r‖s` ECDSA signature has a high S value (`s > n/2`)
3
+ *
4
+ * Signatures with the wrong length for the curve are reported as high S.
5
+ *
6
+ * @param {Curves} curve
7
+ * @param {Uint8Array} signature
8
+ */
9
+ export function isHighS(curve: Curves, signature: Uint8Array): boolean;
10
+ /**
11
+ * Normalize a raw `r‖s` ECDSA signature to low S (`s <= n/2`)
12
+ *
13
+ * @param {Curves} curve
14
+ * @param {Uint8Array} signature
15
+ */
16
+ export function normalizeS(curve: Curves, signature: Uint8Array): Uint8Array<ArrayBufferLike>;
1
17
  /**
2
18
  * Create web crypto params for ECDSA.
3
19
  *
@@ -46,6 +62,9 @@ export class ECDSASigner extends DID implements ISigner {
46
62
  /**
47
63
  * Sign a message
48
64
  *
65
+ * Signatures are normalized to low S (`s <= n/2`) so each message has a
66
+ * single signature encoding per signing operation.
67
+ *
49
68
  * @param {Uint8Array} message
50
69
  */
51
70
  sign(message: Uint8Array): Promise<Uint8Array<ArrayBufferLike>>;
@@ -1 +1 @@
1
- {"version":3,"file":"ecdsa.d.ts","sourceRoot":"","sources":["../../../src/signers/ecdsa.js"],"names":[],"mappings":"AAwCA;;;;;GAKG;AACH,yCAHW,MAAM,GACJ;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IAAC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAA;CAAC,CA8B7G;AAED;;;;GAIG;AACH,gDAFgB,OAAO;IAuBrB;;;;OAIG;IACH,uBAFW,MAAM,wBAkBhB;IAED;;;;;OAKG;IACH,sBAHW,OAAO,eAAe,EAAE,YAAY,QACpC,OAAO,eAAe,EAAE,aAAa,wBA2B/C;IAED;;;;;OAKG;IACH,mBAHW,aAAa,QACb,OAAO,eAAe,EAAE,aAAa,wBA8B/C;IAtGD;;;OAGG;IACH,iBAHW,OAAO,eAAe,EAAE,aAAa,WACrC,aAAa,EAQvB;IAZD,kDAAkD;IAClD,eADW,OAAO,aAAa,EAAE,aAAa,CACjC;IAOX,mCAA+C;IAkGjD;;;;OAIG;IACH,cAFW,UAAU,wCAUpB;IAED;;;;OAIG;IACH,UAFa,aAAa,CAIzB;;CAKF;sBAtNY,OAAO,aAAa,EAAE,OAAO,CAAC,aAAa,CAAC;qBAC5C,OAAO,CAAC,OAAO,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;6BACrE,OAAO,CAAC,OAAO,aAAa,EAAE,aAAa,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;oBAPlE,SAAS"}
1
+ {"version":3,"file":"ecdsa.d.ts","sourceRoot":"","sources":["../../../src/signers/ecdsa.js"],"names":[],"mappings":"AA6DA;;;;;;;GAOG;AACH,+BAHW,MAAM,aACN,UAAU,WASpB;AAED;;;;;GAKG;AACH,kCAHW,MAAM,aACN,UAAU,+BAcpB;AAED;;;;;GAKG;AACH,yCAHW,MAAM,GACJ;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IAAC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAA;CAAC,CA8B7G;AAED;;;;GAIG;AACH,gDAFgB,OAAO;IAuBrB;;;;OAIG;IACH,uBAFW,MAAM,wBAkBhB;IAED;;;;;OAKG;IACH,sBAHW,OAAO,eAAe,EAAE,YAAY,QACpC,OAAO,eAAe,EAAE,aAAa,wBA2B/C;IAED;;;;;OAKG;IACH,mBAHW,aAAa,QACb,OAAO,eAAe,EAAE,aAAa,wBA8B/C;IAtGD;;;OAGG;IACH,iBAHW,OAAO,eAAe,EAAE,aAAa,WACrC,aAAa,EAQvB;IAZD,kDAAkD;IAClD,eADW,OAAO,aAAa,EAAE,aAAa,CACjC;IAOX,mCAA+C;IAkGjD;;;;;;;OAOG;IACH,cAFW,UAAU,wCAUpB;IAED;;;;OAIG;IACH,UAFa,aAAa,CAIzB;;CAKF;sBAlRY,OAAO,aAAa,EAAE,OAAO,CAAC,aAAa,CAAC;qBAC5C,OAAO,CAAC,OAAO,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;6BACrE,OAAO,CAAC,OAAO,aAAa,EAAE,aAAa,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;oBAPlE,SAAS"}
@@ -42,7 +42,7 @@ export class EdDSASigner extends DID implements ISigner {
42
42
  *
43
43
  * @param {Uint8Array} message
44
44
  */
45
- sign(message: Uint8Array): Promise<import("@noble/ed25519").Bytes & Uint8Array<ArrayBuffer>>;
45
+ sign(message: Uint8Array): Promise<Uint8Array<ArrayBufferLike> & Uint8Array<ArrayBuffer>>;
46
46
  /**
47
47
  * Export the signer as a encoded string
48
48
  */
@@ -1 +1 @@
1
- {"version":3,"file":"eddsa.d.ts","sourceRoot":"","sources":["../../../src/signers/eddsa.js"],"names":[],"mappings":"AAyBA;;;;GAIG;AACH,gDAFgB,OAAO;IAGrB;;;;OAIG;IACH,aAFU,MAAM,CAEI;IAmBpB;;;;OAIG;IACH,wBAFW,UAAU,wBAiBpB;IAED;;;;;OAKG;IACH,uBAHW,MAAM,QACN,OAAO,eAAe,EAAE,aAAa,wBAU/C;IAED;;;;;OAKG;IACH,sBAHW,OAAO,eAAe,EAAE,aAAa,QACrC,OAAO,eAAe,EAAE,aAAa,eAU/C;IA/DD;;;OAGG;IACH,iBAHW,OAAO,eAAe,EAAE,aAAa,cACrC,UAAU,EAOpB;IAZD,kDAAkD;IAClD,eADW,OAAO,aAAa,EAAE,aAAa,CACjC;IAmEb;;;;OAIG;IACH,cAFW,UAAU,qEAIpB;IAED;;OAEG;IACH,iBAEC;;CAKF;sBApHY,OAAO,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC;oBAP9B,SAAS"}
1
+ {"version":3,"file":"eddsa.d.ts","sourceRoot":"","sources":["../../../src/signers/eddsa.js"],"names":[],"mappings":"AAyBA;;;;GAIG;AACH,gDAFgB,OAAO;IAGrB;;;;OAIG;IACH,aAFU,MAAM,CAEI;IAmBpB;;;;OAIG;IACH,wBAFW,UAAU,wBAiBpB;IAED;;;;;OAKG;IACH,uBAHW,MAAM,QACN,OAAO,eAAe,EAAE,aAAa,wBAU/C;IAED;;;;;OAKG;IACH,sBAHW,OAAO,eAAe,EAAE,aAAa,QACrC,OAAO,eAAe,EAAE,aAAa,eAU/C;IA/DD;;;OAGG;IACH,iBAHW,OAAO,eAAe,EAAE,aAAa,cACrC,UAAU,EAOpB;IAZD,kDAAkD;IAClD,eADW,OAAO,aAAa,EAAE,aAAa,CACjC;IAmEb;;;;OAIG;IACH,cAFW,UAAU,kEAIpB;IAED;;OAEG;IACH,iBAEC;;CAKF;sBApHY,OAAO,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC;oBAP9B,SAAS"}
@@ -159,6 +159,12 @@ export class EIP191Signer extends DID implements ISigner {
159
159
  params: [address: import("ox/Address").Address, storageKeys: import("ox/Hex").Hex[], block: import("ox/Block").Number<import("ox/Hex").Hex> | import("ox/Block").Tag | import("ox/Block").Hash | import("ox/Block").Identifier];
160
160
  };
161
161
  ReturnType: import("ox/AccountProof").Rpc;
162
+ } | {
163
+ Request: {
164
+ method: "eth_getRawTransactionByHash";
165
+ params: [hash: import("ox/Hex").Hex];
166
+ };
167
+ ReturnType: import("ox/Hex").Hex | null;
162
168
  } | {
163
169
  Request: {
164
170
  method: "eth_getStorageAt";
@@ -266,7 +272,7 @@ export class EIP191Signer extends DID implements ISigner {
266
272
  method: "eth_simulateV1";
267
273
  params: [{
268
274
  blockStateCalls: readonly {
269
- blockOverrides?: import("viem").RpcBlockOverrides | undefined;
275
+ blockOverrides?: import("ox/BlockOverrides").Rpc | undefined;
270
276
  calls?: readonly import("ox/TransactionRequest").Rpc[] | undefined;
271
277
  stateOverrides?: import("ox/StateOverrides").Rpc | undefined;
272
278
  }[];
@@ -1 +1 @@
1
- {"version":3,"file":"eip191.d.ts","sourceRoot":"","sources":["../../../src/signers/eip191.js"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH;;;;GAIG;AACH,iDAFgB,OAAO;IAuBrB;;;;;;;;;;;;;;;;;OAiBG;IACH,qBAdG;QAA0B,QAAQ,EAA1B,QAAQ;QACgB,OAAO;QACE,OAAO;QACvB,SAAS;KAElC,yBAwBF;IAlDD;;;;;;;OAOG;IACH,sBALW,QAAQ,WACR,KAAK,MAAM,EAAE,YACb,MAAM,GAAG,KAAK,MAAM,EAAE,cACtB,MAAM,EAShB;IAlBD,kDAAkD;IAClD,eADW,OAAO,aAAa,EAAE,aAAa,CACjC;IAaX;;;;sBAW0B,CAAC;;;;;;sBAOJ,CAAC;;;;;;sBAUpB,CAAL;;;;;;;;;;;;sBAqCwQ,CAAC;;;;;;sBAAmP,CAAC;;;;;;;;;;;;;;;;;;sBAA6jE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAAqxP,CAAC;;;;;;sBAAkT,CAAC;;;;;;;;;;;;sBAAovB,CAAC;;;;;;sBAAuQ,CAAC;;;;;;sBAAwW,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;sCAAs0C,CAAC;6BAA2D,CAAC;sCAAmF,CAAC;;0CAA6F,CAAC;kCAAqD,CAAC;8BAAiD,CAAC;;;;qBAAkM,CAAC;yBAA8B,CAAC;4BAAwB,CAAC;;;;wBAAiI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAnE9+b,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAmE4gD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAA0Q,CAAC;;;;;;;;;;sBAA+Z,CAAC;;;;;;;;;;;;;;;sBAAmQ,CAAC;;;4BAAguI,CAAC;;;;;;;;gCAA4M,CAAC;;;;;;;;;;;;;;;;4BAA2f,CAAC;;;;;iCAA8H,CAAC;mCAAoD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCAA+R,CAAC;;;0BAAgD,CAAC;4BAA+C,CAAC;6BAAwC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAA68B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAjEh5R;IACxB,uBAAsB;IACtB,gCAAsB;IACtB,kBAA0B;IAsC5B;;;;OAIG;IACH,cAFW,UAAU,wCAQpB;IAED;;OAEG;IACH,iBAEC;CAKF;sBAzFY,OAAO,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC;uBACrC,OAAO,IAAI,EAAE,QAAQ,CAAC,QAAQ;2BAC9B,OAAO,eAAe,EAAE,YAAY;oBAN7B,SAAS"}
1
+ {"version":3,"file":"eip191.d.ts","sourceRoot":"","sources":["../../../src/signers/eip191.js"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH;;;;GAIG;AACH,iDAFgB,OAAO;IAuBrB;;;;;;;;;;;;;;;;;OAiBG;IACH,qBAdG;QAA0B,QAAQ,EAA1B,QAAQ;QACgB,OAAO;QACE,OAAO;QACvB,SAAS;KAElC,yBAwBF;IAlDD;;;;;;;OAOG;IACH,sBALW,QAAQ,WACR,KAAK,MAAM,EAAE,YACb,MAAM,GAAG,KAAK,MAAM,EAAE,cACtB,MAAM,EAShB;IAlBD,kDAAkD;IAClD,eADW,OAAO,aAAa,EAAE,aAAa,CACjC;IAaX;;;;sBAW0B,CAAC;;;;;;sBAOJ,CAAC;;;;;;sBAUpB,CAAL;;;;;;;;;;;;sBAqCwQ,CAAC;;;;;;sBAAmP,CAAC;;;;;;;;;;;;;;;;;;sBAA6jE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAA2lQ,CAAC;;;;;;sBAAkT,CAAC;;;;;;;;;;;;sBAAovB,CAAC;;;;;;sBAAuQ,CAAC;;;;;;sBAAwW,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;sCAAs0C,CAAC;6BAA2D,CAAC;sCAAmF,CAAC;;0CAA6F,CAAC;kCAAqD,CAAC;8BAAiD,CAAC;;;;qBAAkM,CAAC;yBAA8B,CAAC;4BAAwB,CAAC;;;;wBAAiI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAnEpzc,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAmE4gD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAA0Q,CAAC;;;;;;;;;;sBAA+Z,CAAC;;;;;;;;;;;;;;;sBAAmQ,CAAC;;;4BAAguI,CAAC;;;;;;;;gCAA4M,CAAC;;;;;;;;;;;;;;;;4BAA2f,CAAC;;;;;iCAA8H,CAAC;mCAAoD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oCAA+R,CAAC;;;0BAAgD,CAAC;4BAA+C,CAAC;6BAAwC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAA68B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAjEh5R;IACxB,uBAAsB;IACtB,gCAAsB;IACtB,kBAA0B;IAsC5B;;;;OAIG;IACH,cAFW,UAAU,wCAQpB;IAED;;OAEG;IACH,iBAEC;CAKF;sBAzFY,OAAO,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC;uBACrC,OAAO,IAAI,EAAE,QAAQ,CAAC,QAAQ;2BAC9B,OAAO,eAAe,EAAE,YAAY;oBAN7B,SAAS"}
@@ -43,7 +43,7 @@ export class ES256KSigner extends DID implements ISigner {
43
43
  *
44
44
  * @param {Uint8Array} message
45
45
  */
46
- sign(message: Uint8Array): Promise<import("@noble/secp256k1").Bytes & Uint8Array<ArrayBuffer>>;
46
+ sign(message: Uint8Array): Promise<Uint8Array<ArrayBufferLike> & Uint8Array<ArrayBuffer>>;
47
47
  /**
48
48
  * Export the signer as a encoded string
49
49
  */
@@ -1 +1 @@
1
- {"version":3,"file":"es256k.d.ts","sourceRoot":"","sources":["../../../src/signers/es256k.js"],"names":[],"mappings":"AAoBA;;;;GAIG;AACH,iDAFgB,OAAO;IAGrB;;;;OAIG;IACH,aAFU,MAAM,CAEI;IAoBpB;;;;OAIG;IACH,wBAFW,UAAU,gBAUpB;IAED;;;;;OAKG;IACH,sBAHW,OAAO,eAAe,EAAE,YAAY,QACpC,OAAO,eAAe,EAAE,aAAa,gBAU/C;IAED;;;;;OAKG;IACH,uBAHW,MAAM,QACN,OAAO,eAAe,EAAE,aAAa,gBAU/C;IAzDD;;;;OAIG;IACH,iBAHW,OAAO,eAAe,EAAE,aAAa,cACrC,UAAU,EAOpB;IAhBD,kDAAkD;IAClD,eADW,OAAO,aAAa,EAAE,aAAa,CACjC;IAgEb;;;;OAIG;IACH,cAFW,UAAU,uEAKpB;IAED;;OAEG;IACH,iBAEC;;CAKF;sBA9GY,OAAO,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC;oBAL9B,SAAS"}
1
+ {"version":3,"file":"es256k.d.ts","sourceRoot":"","sources":["../../../src/signers/es256k.js"],"names":[],"mappings":"AAoBA;;;;GAIG;AACH,iDAFgB,OAAO;IAGrB;;;;OAIG;IACH,aAFU,MAAM,CAEI;IAoBpB;;;;OAIG;IACH,wBAFW,UAAU,gBAUpB;IAED;;;;;OAKG;IACH,sBAHW,OAAO,eAAe,EAAE,YAAY,QACpC,OAAO,eAAe,EAAE,aAAa,gBAU/C;IAED;;;;;OAKG;IACH,uBAHW,MAAM,QACN,OAAO,eAAe,EAAE,aAAa,gBAU/C;IAzDD;;;;OAIG;IACH,iBAHW,OAAO,eAAe,EAAE,aAAa,cACrC,UAAU,EAOpB;IAhBD,kDAAkD;IAClD,eADW,OAAO,aAAa,EAAE,aAAa,CACjC;IAgEb;;;;OAIG;IACH,cAFW,UAAU,kEAKpB;IAED;;OAEG;IACH,iBAEC;;CAKF;sBA9GY,OAAO,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC;oBAL9B,SAAS"}
@@ -11,6 +11,16 @@ export interface VerifyInput {
11
11
  signature: Uint8Array;
12
12
  message: Uint8Array;
13
13
  did: VerifiableDID;
14
+ /**
15
+ * Only accept the canonical signature encoding. ECDSA (P-256/384/521) and
16
+ * EIP-191 signatures with a high S value (`s > n/2`) are rejected, and
17
+ * EIP-191 signatures must use 27/28 as the recovery byte.
18
+ *
19
+ * Other signature types ignore this option.
20
+ *
21
+ * @default false
22
+ */
23
+ strict?: boolean;
14
24
  }
15
25
  export type Verify = (input: VerifyInput) => Promise<boolean>;
16
26
  export type Verifier<T extends SignatureType> = Record<T, Verify>;
@@ -27,5 +37,15 @@ export interface IResolver {
27
37
  }
28
38
  export interface ResolverOptions {
29
39
  cache?: Cache | boolean | undefined;
40
+ /**
41
+ * Default `strict` value for verify calls that don't set it.
42
+ *
43
+ * Only enable this when you control all signers: other implementations
44
+ * produce high S ECDSA signatures and 0/1 EIP-191 recovery bytes.
45
+ *
46
+ * @see {@link VerifyInput.strict}
47
+ * @default false
48
+ */
49
+ strict?: boolean;
30
50
  }
31
51
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAElD,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,OAAO,GACP,OAAO,GACP,OAAO,GACP,QAAQ,GACR,OAAO,GACP,QAAQ,CAAA;AAEZ,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,CAAA;CACnD;AAED,MAAM,WAAW,OAAO,CAAC,MAAM,SAAS,aAAa,GAAG,MAAM,GAAG,MAAM,CACrE,SAAQ,aAAa,EACnB,IAAI;IACN,MAAM,EAAE,MAAM,MAAM,CAAA;IACpB,aAAa,EAAE,aAAa,CAAA;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,UAAU,CAAA;IACrB,OAAO,EAAE,UAAU,CAAA;IACnB,GAAG,EAAE,aAAa,CAAA;CACnB;AACD,MAAM,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAE7D,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,aAAa,IAAI,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;AAEjE,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,aAAa,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;AAE5E,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD;;OAEG;IACH,IAAI,EAAE,aAAa,CAAA;CACpB;AACD,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAE7E,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CACzD;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,SAAS,CAAA;CACpC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAElD,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,OAAO,GACP,OAAO,GACP,OAAO,GACP,QAAQ,GACR,OAAO,GACP,QAAQ,CAAA;AAEZ,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,CAAA;CACnD;AAED,MAAM,WAAW,OAAO,CAAC,MAAM,SAAS,aAAa,GAAG,MAAM,GAAG,MAAM,CACrE,SAAQ,aAAa,EACnB,IAAI;IACN,MAAM,EAAE,MAAM,MAAM,CAAA;IACpB,aAAa,EAAE,aAAa,CAAA;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,UAAU,CAAA;IACrB,OAAO,EAAE,UAAU,CAAA;IACnB,GAAG,EAAE,aAAa,CAAA;IAClB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AACD,MAAM,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAE7D,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,aAAa,IAAI,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;AAEjE,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,aAAa,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;AAE5E,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD;;OAEG;IACH,IAAI,EAAE,aAAa,CAAA;CACpB;AACD,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAE7E,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CACzD;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,SAAS,CAAA;IACnC;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB"}
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  *
3
3
  * @param {'ES256' | 'ES384' | 'ES512' | 'ES256K'} type
4
- * @param {import('../types.js').VerifyInput} param1
4
+ * @param {import('../types.js').VerifyInput} input
5
5
  * @returns
6
6
  */
7
- export function verify(type: "ES256" | "ES384" | "ES512" | "ES256K", { signature, message, did }: import("../types.js").VerifyInput): Promise<boolean>;
7
+ export function verify(type: "ES256" | "ES384" | "ES512" | "ES256K", input: import("../types.js").VerifyInput): Promise<boolean>;
8
8
  /** @type {import('../types.js').Verifier<'ES256' | 'ES384' | 'ES512' | 'ES256K'>} */
9
9
  export const verifier: import("../types.js").Verifier<"ES256" | "ES384" | "ES512" | "ES256K">;
10
10
  //# sourceMappingURL=ecdsa.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ecdsa.d.ts","sourceRoot":"","sources":["../../../src/verifiers/ecdsa.js"],"names":[],"mappings":"AAyDA;;;;;GAKG;AACH,6BAJW,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,+BACtC,OAAO,aAAa,EAAE,WAAW,oBAK3C;AAhBD,qFAAqF;AACrF,uBADW,OAAO,aAAa,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC,CAMhF"}
1
+ {"version":3,"file":"ecdsa.d.ts","sourceRoot":"","sources":["../../../src/verifiers/ecdsa.js"],"names":[],"mappings":"AA6DA;;;;;GAKG;AACH,6BAJW,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,SACtC,OAAO,aAAa,EAAE,WAAW,oBAK3C;AAhBD,qFAAqF;AACrF,uBADW,OAAO,aAAa,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC,CAMhF"}
@@ -1 +1 @@
1
- {"version":3,"file":"eip191.d.ts","sourceRoot":"","sources":["../../../src/verifiers/eip191.js"],"names":[],"mappings":"AAYA;;;;GAIG;AACH,sCAFW,KAAK,MAAM,EAAE,+BAIvB;AAED;;GAEG;AACH,qCAFW,UAAU,yDAKpB;;AAyBD,oDAAoD;AACpD,uBADW,OAAO,UAAU,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAG/C"}
1
+ {"version":3,"file":"eip191.d.ts","sourceRoot":"","sources":["../../../src/verifiers/eip191.js"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,sCAFW,KAAK,MAAM,EAAE,+BAIvB;AAED;;GAEG;AACH,qCAFW,UAAU,yDAKpB;;AAoCD,oDAAoD;AACpD,uBADW,OAAO,UAAU,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAG/C"}
@@ -12,6 +12,7 @@ export class Resolver implements IResolver {
12
12
  constructor(registry?: import("../types").VerifierRegistry<import("../types").SignatureType>, options?: import("../types").ResolverOptions);
13
13
  registry: Partial<import("../types").Verifier<import("../types").SignatureType>>;
14
14
  cache: import("../types").Cache;
15
+ strict: boolean;
15
16
  verify(input: import("../types").ResolverVerifyInput): Promise<boolean>;
16
17
  }
17
18
  export type IResolver = import("../types").IResolver;
@@ -1 +1 @@
1
- {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../../src/verifiers/resolver.js"],"names":[],"mappings":"AAsCA;;;;GAIG;AACH,iCAFgB,SAAS;IAGvB;;;;OAIG;IACH,uBAHW,OAAO,UAAU,EAAE,gBAAgB,CAAC,OAAO,UAAU,EAAE,aAAa,CAAC,YACrE,OAAO,UAAU,EAAE,eAAe,EAM5C;IAHC,iFAAwB;IACxB,gCACmE;;CAYtE;wBA/DY,OAAO,UAAU,EAAE,SAAS"}
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../../src/verifiers/resolver.js"],"names":[],"mappings":"AAsCA;;;;GAIG;AACH,iCAFgB,SAAS;IAGvB;;;;OAIG;IACH,uBAHW,OAAO,UAAU,EAAE,gBAAgB,CAAC,OAAO,UAAU,EAAE,aAAa,CAAC,YACrE,OAAO,UAAU,EAAE,eAAe,EAO5C;IAJC,iFAAwB;IACxB,gCACmE;IACnE,gBAAqC;;CAYxC;wBAhEY,OAAO,UAAU,EAAE,SAAS"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "iso-signatures",
3
3
  "type": "module",
4
- "version": "0.5.2",
4
+ "version": "0.6.0",
5
5
  "description": "Signatures tooling.",
6
6
  "author": "Hugo Dias <hugomrdias@gmail.com> (hugodias.me)",
7
7
  "license": "MIT",
@@ -81,24 +81,24 @@
81
81
  "dist/src/**/*.d.ts.map"
82
82
  ],
83
83
  "dependencies": {
84
- "@noble/ed25519": "^3.0.1",
85
- "@noble/hashes": "^2.0.0",
86
- "@noble/secp256k1": "^3.0.0",
84
+ "@noble/ed25519": "^3.2.0",
85
+ "@noble/hashes": "^2.4.0",
86
+ "@noble/secp256k1": "^3.2.0",
87
87
  "eventemitter3": "5.0.1",
88
88
  "iso-base": "^4.4.0",
89
- "iso-did": "^2.1.1",
90
- "ox": "^0.14.30"
89
+ "iso-did": "^3.0.0",
90
+ "ox": "^0.14.49"
91
91
  },
92
92
  "devDependencies": {
93
93
  "@types/assert": "^1.5.11",
94
94
  "@types/mocha": "^10.0.10",
95
- "@types/node": "^26.1.1",
95
+ "@types/node": "^26.6.2",
96
96
  "assert": "^2.1.0",
97
- "mocha": "^11.7.5",
98
- "playwright-test": "^14.1.13",
99
- "type-fest": "^5.8.0",
97
+ "mocha": "^12.0.2",
98
+ "playwright-test": "^15.0.1",
99
+ "type-fest": "^5.10.0",
100
100
  "typescript": "^6.0.3",
101
- "viem": "^2.54.6"
101
+ "viem": "~2.56.9"
102
102
  },
103
103
  "publishConfig": {
104
104
  "provenance": true
package/readme.md CHANGED
@@ -52,6 +52,31 @@ const verified = await resolver.verify({
52
52
  })
53
53
  ```
54
54
 
55
+ ### Strict verification
56
+
57
+ `ECDSASigner` always emits low S signatures (`s <= n/2`). Verifiers accept both
58
+ low and high S by default, since other implementations produce high S
59
+ signatures. If you control all your signers, enable `strict` to only accept the
60
+ canonical encoding: ECDSA (P-256/384/521) and EIP-191 signatures with high S are
61
+ rejected, and EIP-191 signatures must use 27/28 as the recovery byte.
62
+
63
+ ```js
64
+ import * as ECDSA from 'iso-signatures/verifiers/ecdsa'
65
+ import * as EIP191 from 'iso-signatures/verifiers/eip191'
66
+ import { Resolver } from 'iso-signatures/verifiers/resolver'
67
+
68
+ const resolver = new Resolver(
69
+ {
70
+ ...ECDSA.verifier,
71
+ ...EIP191.verifier,
72
+ },
73
+ { strict: true }
74
+ )
75
+
76
+ // or per call
77
+ await ECDSA.verify('ES256', { signature, message, did, strict: true })
78
+ ```
79
+
55
80
  ## Docs
56
81
 
57
82
  Check <https://hugomrdias.github.io/iso-repo/modules/iso_signatures.html>
@@ -1,4 +1,5 @@
1
1
  import { webcrypto } from 'iso-base/crypto'
2
+ import { hex } from 'iso-base/rfc4648'
2
3
  import { u8 } from 'iso-base/utils'
3
4
  import { DID } from 'iso-did'
4
5
  import { DIDKey } from 'iso-did/key'
@@ -38,6 +39,63 @@ function curveToSignatureType(type) {
38
39
  }
39
40
  }
40
41
 
42
+ /**
43
+ * Curve orders (n) and signature component sizes in bytes
44
+ *
45
+ * @type {Record<Curves, {n: bigint, size: number}>}
46
+ */
47
+ const CURVES = {
48
+ 'P-256': {
49
+ n: 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551n,
50
+ size: 32,
51
+ },
52
+ 'P-384': {
53
+ n: 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973n,
54
+ size: 48,
55
+ },
56
+ 'P-521': {
57
+ n: 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409n,
58
+ size: 66,
59
+ },
60
+ }
61
+
62
+ /**
63
+ * Check if a raw `r‖s` ECDSA signature has a high S value (`s > n/2`)
64
+ *
65
+ * Signatures with the wrong length for the curve are reported as high S.
66
+ *
67
+ * @param {Curves} curve
68
+ * @param {Uint8Array} signature
69
+ */
70
+ export function isHighS(curve, signature) {
71
+ const { n, size } = CURVES[curve]
72
+ if (signature.length !== size * 2) {
73
+ return true
74
+ }
75
+ const s = BigInt(`0x${hex.encode(signature.subarray(size))}`)
76
+ return s > n >> 1n
77
+ }
78
+
79
+ /**
80
+ * Normalize a raw `r‖s` ECDSA signature to low S (`s <= n/2`)
81
+ *
82
+ * @param {Curves} curve
83
+ * @param {Uint8Array} signature
84
+ */
85
+ export function normalizeS(curve, signature) {
86
+ const { n, size } = CURVES[curve]
87
+ if (signature.length !== size * 2) {
88
+ throw new Error('Invalid signature length')
89
+ }
90
+ const s = BigInt(`0x${hex.encode(signature.subarray(size))}`)
91
+ if (s <= n >> 1n) {
92
+ return signature
93
+ }
94
+ const out = new Uint8Array(signature)
95
+ out.set(hex.decode((n - s).toString(16).padStart(size * 2, '0')), size)
96
+ return out
97
+ }
98
+
41
99
  /**
42
100
  * Create web crypto params for ECDSA.
43
101
  *
@@ -195,6 +253,9 @@ export class ECDSASigner extends DID {
195
253
  /**
196
254
  * Sign a message
197
255
  *
256
+ * Signatures are normalized to low S (`s <= n/2`) so each message has a
257
+ * single signature encoding per signing operation.
258
+ *
198
259
  * @param {Uint8Array} message
199
260
  */
200
261
  async sign(message) {
@@ -204,7 +265,7 @@ export class ECDSASigner extends DID {
204
265
  /** @type {BufferSource} */ (message)
205
266
  )
206
267
 
207
- return u8(buf)
268
+ return normalizeS(this.curve, u8(buf))
208
269
  }
209
270
 
210
271
  /**
package/src/types.ts CHANGED
@@ -24,6 +24,16 @@ export interface VerifyInput {
24
24
  signature: Uint8Array
25
25
  message: Uint8Array
26
26
  did: VerifiableDID
27
+ /**
28
+ * Only accept the canonical signature encoding. ECDSA (P-256/384/521) and
29
+ * EIP-191 signatures with a high S value (`s > n/2`) are rejected, and
30
+ * EIP-191 signatures must use 27/28 as the recovery byte.
31
+ *
32
+ * Other signature types ignore this option.
33
+ *
34
+ * @default false
35
+ */
36
+ strict?: boolean
27
37
  }
28
38
  export type Verify = (input: VerifyInput) => Promise<boolean>
29
39
 
@@ -45,4 +55,14 @@ export interface IResolver {
45
55
 
46
56
  export interface ResolverOptions {
47
57
  cache?: Cache | boolean | undefined
58
+ /**
59
+ * Default `strict` value for verify calls that don't set it.
60
+ *
61
+ * Only enable this when you control all signers: other implementations
62
+ * produce high S ECDSA signatures and 0/1 EIP-191 recovery bytes.
63
+ *
64
+ * @see {@link VerifyInput.strict}
65
+ * @default false
66
+ */
67
+ strict?: boolean
48
68
  }
@@ -1,7 +1,7 @@
1
1
  import { verifyAsync as secpVerify } from '@noble/secp256k1'
2
2
  import { webcrypto } from 'iso-base/crypto'
3
3
  import { decompress, isCompressed } from 'iso-base/ec-compression'
4
- import { createEcdsaParams } from '../signers/ecdsa.js'
4
+ import { createEcdsaParams, isHighS } from '../signers/ecdsa.js'
5
5
 
6
6
  /**
7
7
  *
@@ -11,7 +11,11 @@ function createVerifier(curve) {
11
11
  const params = createEcdsaParams(curve)
12
12
 
13
13
  /** @type {import('../types.js').Verify} */
14
- async function fn({ signature, message, did }) {
14
+ async function fn({ signature, message, did, strict }) {
15
+ if (strict && isHighS(curve, signature)) {
16
+ return false
17
+ }
18
+
15
19
  let publicKey = did.verifiableDid.publicKey
16
20
  if (isCompressed(publicKey)) {
17
21
  publicKey = decompress(publicKey, params.namedCurve)
@@ -58,9 +62,9 @@ export const verifier = {
58
62
  /**
59
63
  *
60
64
  * @param {'ES256' | 'ES384' | 'ES512' | 'ES256K'} type
61
- * @param {import('../types.js').VerifyInput} param1
65
+ * @param {import('../types.js').VerifyInput} input
62
66
  * @returns
63
67
  */
64
- export async function verify(type, { signature, message, did }) {
65
- return await verifier[type]({ signature, message, did })
68
+ export async function verify(type, input) {
69
+ return await verifier[type](input)
66
70
  }
@@ -6,7 +6,6 @@ import { concat } from 'iso-base/utils'
6
6
  import { DIDPkh } from 'iso-did/pkh'
7
7
  import * as Address from 'ox/Address'
8
8
  import * as PublicKey from 'ox/PublicKey'
9
- import * as SignatureOx from 'ox/Signature'
10
9
 
11
10
  const PREFIX = '\x19Ethereum Signed Message:\n'
12
11
 
@@ -28,15 +27,26 @@ export function getSignPayload(data) {
28
27
  }
29
28
 
30
29
  /** @type {import('../types.js').Verify} */
31
- export async function verify({ signature, message, did }) {
30
+ export async function verify({ signature, message, did, strict }) {
32
31
  if (signature.length !== 65) {
33
32
  throw new Error('Invalid signature length')
34
33
  }
35
34
 
35
+ // personal_sign signatures carry v as 27/28, or 0/1 from some signers.
36
+ // EIP-155 values (v >= 35) only apply to transactions.
37
+ const v = signature[64]
38
+ if (v !== 0 && v !== 1 && v !== 27 && v !== 28) {
39
+ throw new Error('Invalid signature recovery byte')
40
+ }
41
+
36
42
  const didPkh = DIDPkh.fromString(did.did)
37
- const sigRecovered = Signature.fromBytes(signature.slice(0, 64))
38
- .addRecoveryBit(SignatureOx.vToYParity(signature[64]))
39
- .toBytes('recovered')
43
+ const sig = Signature.fromBytes(signature.slice(0, 64))
44
+ // strict mode only accepts the canonical encoding: low S and v as 27/28
45
+ if (strict && (sig.hasHighS() || (v !== 27 && v !== 28))) {
46
+ return false
47
+ }
48
+
49
+ const sigRecovered = sig.addRecoveryBit(v % 27).toBytes('recovered')
40
50
  const pubKey = await recoverPublicKeyAsync(
41
51
  sigRecovered,
42
52
  getSignPayload(message),
@@ -23,7 +23,7 @@ function memoryCache() {
23
23
 
24
24
  /** @type {import('../types').Cache} */
25
25
  async function fn(input, verify) {
26
- const key = `${input.did.verifiableDid.toString()}:${hex.encode(input.signature)}:${hex.encode(input.message)}`
26
+ const key = `${input.did.verifiableDid.toString()}:${hex.encode(input.signature)}:${hex.encode(input.message)}:${input.strict === true}`
27
27
  if (cache.has(key)) {
28
28
  return cache.get(key)
29
29
  }
@@ -51,6 +51,7 @@ export class Resolver {
51
51
  this.registry = registry
52
52
  this.cache =
53
53
  options.cache === true ? memoryCache() : options.cache || noCache
54
+ this.strict = options.strict === true
54
55
  }
55
56
 
56
57
  /** @type {IResolver['verify']} */
@@ -60,6 +61,6 @@ export class Resolver {
60
61
  throw new TypeError(`Unsupported signature type "${input.type}"`)
61
62
  }
62
63
 
63
- return this.cache(input, verify)
64
+ return this.cache({ ...input, strict: input.strict ?? this.strict }, verify)
64
65
  }
65
66
  }