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.
- package/dist/src/signers/ecdsa.d.ts +19 -0
- package/dist/src/signers/ecdsa.d.ts.map +1 -1
- package/dist/src/signers/eddsa.d.ts +1 -1
- package/dist/src/signers/eddsa.d.ts.map +1 -1
- package/dist/src/signers/eip191.d.ts +7 -1
- package/dist/src/signers/eip191.d.ts.map +1 -1
- package/dist/src/signers/es256k.d.ts +1 -1
- package/dist/src/signers/es256k.d.ts.map +1 -1
- package/dist/src/types.d.ts +20 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/verifiers/ecdsa.d.ts +2 -2
- package/dist/src/verifiers/ecdsa.d.ts.map +1 -1
- package/dist/src/verifiers/eip191.d.ts.map +1 -1
- package/dist/src/verifiers/resolver.d.ts +1 -0
- package/dist/src/verifiers/resolver.d.ts.map +1 -1
- package/package.json +11 -11
- package/readme.md +25 -0
- package/src/signers/ecdsa.js +62 -1
- package/src/types.ts +20 -0
- package/src/verifiers/ecdsa.js +9 -5
- package/src/verifiers/eip191.js +15 -5
- package/src/verifiers/resolver.js +3 -2
|
@@ -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":"
|
|
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<
|
|
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,
|
|
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("
|
|
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
|
|
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<
|
|
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,
|
|
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"}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -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
|
package/dist/src/types.d.ts.map
CHANGED
|
@@ -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;
|
|
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}
|
|
4
|
+
* @param {import('../types.js').VerifyInput} input
|
|
5
5
|
* @returns
|
|
6
6
|
*/
|
|
7
|
-
export function verify(type: "ES256" | "ES384" | "ES512" | "ES256K",
|
|
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":"
|
|
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":"
|
|
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,
|
|
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.
|
|
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
|
|
85
|
-
"@noble/hashes": "^2.
|
|
86
|
-
"@noble/secp256k1": "^3.
|
|
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": "^
|
|
90
|
-
"ox": "^0.14.
|
|
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.
|
|
95
|
+
"@types/node": "^26.6.2",
|
|
96
96
|
"assert": "^2.1.0",
|
|
97
|
-
"mocha": "^
|
|
98
|
-
"playwright-test": "^
|
|
99
|
-
"type-fest": "^5.
|
|
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": "
|
|
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>
|
package/src/signers/ecdsa.js
CHANGED
|
@@ -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
|
}
|
package/src/verifiers/ecdsa.js
CHANGED
|
@@ -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}
|
|
65
|
+
* @param {import('../types.js').VerifyInput} input
|
|
62
66
|
* @returns
|
|
63
67
|
*/
|
|
64
|
-
export async function verify(type,
|
|
65
|
-
return await verifier[type](
|
|
68
|
+
export async function verify(type, input) {
|
|
69
|
+
return await verifier[type](input)
|
|
66
70
|
}
|
package/src/verifiers/eip191.js
CHANGED
|
@@ -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
|
|
38
|
-
|
|
39
|
-
|
|
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
|
}
|