@noble/curves 1.9.5 → 2.0.0-beta.1
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/README.md +267 -421
- package/abstract/bls.d.ts +49 -111
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +108 -152
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +7 -48
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +22 -47
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +17 -68
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +98 -175
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.js +14 -27
- package/abstract/fft.js.map +1 -1
- package/abstract/hash-to-curve.d.ts +11 -24
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +30 -35
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +5 -17
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +166 -167
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +4 -9
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +17 -20
- package/abstract/montgomery.js.map +1 -1
- package/abstract/oprf.d.ts +282 -0
- package/abstract/oprf.d.ts.map +1 -0
- package/abstract/oprf.js +297 -0
- package/abstract/oprf.js.map +1 -0
- package/abstract/poseidon.js +20 -24
- package/abstract/poseidon.js.map +1 -1
- package/abstract/tower.d.ts +9 -7
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +600 -364
- package/abstract/tower.js.map +1 -1
- package/abstract/weierstrass.d.ts +12 -145
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +153 -377
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts +2 -2
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +174 -216
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +58 -10
- package/bn254.d.ts.map +1 -1
- package/bn254.js +70 -130
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +12 -31
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +104 -146
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +14 -33
- package/ed448.d.ts.map +1 -1
- package/ed448.js +105 -132
- package/ed448.js.map +1 -1
- package/index.js +1 -1
- package/misc.d.ts +10 -14
- package/misc.d.ts.map +1 -1
- package/misc.js +51 -60
- package/misc.js.map +1 -1
- package/nist.d.ts +11 -14
- package/nist.d.ts.map +1 -1
- package/nist.js +46 -55
- package/nist.js.map +1 -1
- package/package.json +9 -224
- package/secp256k1.d.ts +7 -23
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +72 -83
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +197 -344
- package/src/abstract/curve.ts +10 -83
- package/src/abstract/edwards.ts +96 -223
- package/src/abstract/hash-to-curve.ts +32 -45
- package/src/abstract/modular.ts +144 -130
- package/src/abstract/montgomery.ts +21 -22
- package/src/abstract/oprf.ts +600 -0
- package/src/abstract/tower.ts +627 -382
- package/src/abstract/weierstrass.ts +101 -482
- package/src/bls12-381.ts +148 -176
- package/src/bn254.ts +67 -122
- package/src/ed25519.ts +65 -118
- package/src/ed448.ts +63 -113
- package/src/index.ts +1 -1
- package/src/misc.ts +66 -49
- package/src/nist.ts +48 -57
- package/src/secp256k1.ts +56 -88
- package/src/utils.ts +41 -61
- package/src/webcrypto.ts +362 -0
- package/utils.d.ts +28 -19
- package/utils.d.ts.map +1 -1
- package/utils.js +45 -121
- package/utils.js.map +1 -1
- package/webcrypto.d.ts +47 -0
- package/webcrypto.d.ts.map +1 -0
- package/webcrypto.js +231 -0
- package/webcrypto.js.map +1 -0
- package/esm/_shortw_utils.d.ts +0 -19
- package/esm/_shortw_utils.d.ts.map +0 -1
- package/esm/_shortw_utils.js +0 -16
- package/esm/_shortw_utils.js.map +0 -1
- package/esm/abstract/bls.d.ts +0 -190
- package/esm/abstract/bls.d.ts.map +0 -1
- package/esm/abstract/bls.js +0 -408
- package/esm/abstract/bls.js.map +0 -1
- package/esm/abstract/curve.d.ts +0 -231
- package/esm/abstract/curve.d.ts.map +0 -1
- package/esm/abstract/curve.js +0 -465
- package/esm/abstract/curve.js.map +0 -1
- package/esm/abstract/edwards.d.ts +0 -237
- package/esm/abstract/edwards.d.ts.map +0 -1
- package/esm/abstract/edwards.js +0 -632
- package/esm/abstract/edwards.js.map +0 -1
- package/esm/abstract/fft.d.ts +0 -122
- package/esm/abstract/fft.d.ts.map +0 -1
- package/esm/abstract/fft.js +0 -425
- package/esm/abstract/fft.js.map +0 -1
- package/esm/abstract/hash-to-curve.d.ts +0 -102
- package/esm/abstract/hash-to-curve.d.ts.map +0 -1
- package/esm/abstract/hash-to-curve.js +0 -203
- package/esm/abstract/hash-to-curve.js.map +0 -1
- package/esm/abstract/modular.d.ts +0 -171
- package/esm/abstract/modular.d.ts.map +0 -1
- package/esm/abstract/modular.js +0 -530
- package/esm/abstract/modular.js.map +0 -1
- package/esm/abstract/montgomery.d.ts +0 -30
- package/esm/abstract/montgomery.d.ts.map +0 -1
- package/esm/abstract/montgomery.js +0 -157
- package/esm/abstract/montgomery.js.map +0 -1
- package/esm/abstract/poseidon.d.ts +0 -68
- package/esm/abstract/poseidon.d.ts.map +0 -1
- package/esm/abstract/poseidon.js +0 -296
- package/esm/abstract/poseidon.js.map +0 -1
- package/esm/abstract/tower.d.ts +0 -93
- package/esm/abstract/tower.d.ts.map +0 -1
- package/esm/abstract/tower.js +0 -502
- package/esm/abstract/tower.js.map +0 -1
- package/esm/abstract/utils.d.ts +0 -5
- package/esm/abstract/utils.d.ts.map +0 -1
- package/esm/abstract/utils.js +0 -7
- package/esm/abstract/utils.js.map +0 -1
- package/esm/abstract/weierstrass.d.ts +0 -412
- package/esm/abstract/weierstrass.d.ts.map +0 -1
- package/esm/abstract/weierstrass.js +0 -1428
- package/esm/abstract/weierstrass.js.map +0 -1
- package/esm/bls12-381.d.ts +0 -16
- package/esm/bls12-381.d.ts.map +0 -1
- package/esm/bls12-381.js +0 -738
- package/esm/bls12-381.js.map +0 -1
- package/esm/bn254.d.ts +0 -18
- package/esm/bn254.d.ts.map +0 -1
- package/esm/bn254.js +0 -246
- package/esm/bn254.js.map +0 -1
- package/esm/ed25519.d.ts +0 -106
- package/esm/ed25519.d.ts.map +0 -1
- package/esm/ed25519.js +0 -467
- package/esm/ed25519.js.map +0 -1
- package/esm/ed448.d.ts +0 -101
- package/esm/ed448.d.ts.map +0 -1
- package/esm/ed448.js +0 -448
- package/esm/ed448.js.map +0 -1
- package/esm/index.d.ts +0 -2
- package/esm/index.d.ts.map +0 -1
- package/esm/index.js +0 -17
- package/esm/index.js.map +0 -1
- package/esm/jubjub.d.ts +0 -12
- package/esm/jubjub.d.ts.map +0 -1
- package/esm/jubjub.js +0 -12
- package/esm/jubjub.js.map +0 -1
- package/esm/misc.d.ts +0 -19
- package/esm/misc.d.ts.map +0 -1
- package/esm/misc.js +0 -109
- package/esm/misc.js.map +0 -1
- package/esm/nist.d.ts +0 -21
- package/esm/nist.d.ts.map +0 -1
- package/esm/nist.js +0 -132
- package/esm/nist.js.map +0 -1
- package/esm/p256.d.ts +0 -16
- package/esm/p256.d.ts.map +0 -1
- package/esm/p256.js +0 -16
- package/esm/p256.js.map +0 -1
- package/esm/p384.d.ts +0 -16
- package/esm/p384.d.ts.map +0 -1
- package/esm/p384.js +0 -16
- package/esm/p384.js.map +0 -1
- package/esm/p521.d.ts +0 -16
- package/esm/p521.d.ts.map +0 -1
- package/esm/p521.js +0 -16
- package/esm/p521.js.map +0 -1
- package/esm/package.json +0 -4
- package/esm/pasta.d.ts +0 -10
- package/esm/pasta.d.ts.map +0 -1
- package/esm/pasta.js +0 -10
- package/esm/pasta.js.map +0 -1
- package/esm/secp256k1.d.ts +0 -89
- package/esm/secp256k1.d.ts.map +0 -1
- package/esm/secp256k1.js +0 -292
- package/esm/secp256k1.js.map +0 -1
- package/esm/utils.d.ts +0 -110
- package/esm/utils.d.ts.map +0 -1
- package/esm/utils.js +0 -322
- package/esm/utils.js.map +0 -1
- package/src/_shortw_utils.ts +0 -21
- package/src/abstract/utils.ts +0 -7
- package/src/jubjub.ts +0 -12
- package/src/p256.ts +0 -15
- package/src/p384.ts +0 -15
- package/src/p521.ts +0 -15
- package/src/package.json +0 -3
- package/src/pasta.ts +0 -9
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
*/
|
|
27
27
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
28
28
|
import { hmac as nobleHmac } from '@noble/hashes/hmac.js';
|
|
29
|
-
import { ahash } from '@noble/hashes/utils';
|
|
29
|
+
import { ahash } from '@noble/hashes/utils.js';
|
|
30
30
|
import {
|
|
31
31
|
_validateObject,
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
abool,
|
|
33
|
+
abytes,
|
|
34
34
|
aInRange,
|
|
35
35
|
bitLen,
|
|
36
36
|
bitMask,
|
|
@@ -38,39 +38,31 @@ import {
|
|
|
38
38
|
bytesToNumberBE,
|
|
39
39
|
concatBytes,
|
|
40
40
|
createHmacDrbg,
|
|
41
|
-
ensureBytes,
|
|
42
41
|
hexToBytes,
|
|
43
|
-
inRange,
|
|
44
42
|
isBytes,
|
|
45
43
|
memoized,
|
|
46
44
|
numberToHexUnpadded,
|
|
47
45
|
randomBytes as wcRandomBytes,
|
|
48
46
|
type CHash,
|
|
49
|
-
type
|
|
50
|
-
type PrivKey,
|
|
47
|
+
type Signer,
|
|
51
48
|
} from '../utils.ts';
|
|
52
49
|
import {
|
|
53
50
|
_createCurveFields,
|
|
54
51
|
mulEndoUnsafe,
|
|
55
52
|
negateCt,
|
|
56
53
|
normalizeZ,
|
|
57
|
-
pippenger,
|
|
58
54
|
wNAF,
|
|
59
55
|
type AffinePoint,
|
|
60
|
-
type BasicCurve,
|
|
61
56
|
type CurveLengths,
|
|
62
57
|
type CurvePoint,
|
|
63
58
|
type CurvePointCons,
|
|
64
59
|
} from './curve.ts';
|
|
65
60
|
import {
|
|
66
|
-
Field,
|
|
67
61
|
FpInvertBatch,
|
|
68
62
|
getMinHashLength,
|
|
69
63
|
mapHashToField,
|
|
70
|
-
nLength,
|
|
71
64
|
validateField,
|
|
72
65
|
type IField,
|
|
73
|
-
type NLength,
|
|
74
66
|
} from './modular.ts';
|
|
75
67
|
|
|
76
68
|
export type { AffinePoint };
|
|
@@ -105,7 +97,6 @@ export type EndomorphismOpts = {
|
|
|
105
97
|
basises?: EndoBasis;
|
|
106
98
|
splitScalar?: (k: bigint) => { k1neg: boolean; k1: bigint; k2neg: boolean; k2: bigint };
|
|
107
99
|
};
|
|
108
|
-
|
|
109
100
|
// We construct basis in such way that den is always positive and equals n, but num sign depends on basis (not on secret value)
|
|
110
101
|
const divNearest = (num: bigint, den: bigint) => (num + (num >= 0 ? den : -den) / _2n) / den;
|
|
111
102
|
|
|
@@ -190,25 +181,6 @@ export interface WeierstrassPoint<T> extends CurvePoint<T, WeierstrassPoint<T>>
|
|
|
190
181
|
/** Encodes point using IEEE P1363 (DER) encoding. First byte is 2/3/4. Default = isCompressed. */
|
|
191
182
|
toBytes(isCompressed?: boolean): Uint8Array;
|
|
192
183
|
toHex(isCompressed?: boolean): string;
|
|
193
|
-
|
|
194
|
-
/** @deprecated use `.X` */
|
|
195
|
-
readonly px: T;
|
|
196
|
-
/** @deprecated use `.Y` */
|
|
197
|
-
readonly py: T;
|
|
198
|
-
/** @deprecated use `.Z` */
|
|
199
|
-
readonly pz: T;
|
|
200
|
-
/** @deprecated use `toBytes` */
|
|
201
|
-
toRawBytes(isCompressed?: boolean): Uint8Array;
|
|
202
|
-
/** @deprecated use `multiplyUnsafe` */
|
|
203
|
-
multiplyAndAddUnsafe(
|
|
204
|
-
Q: WeierstrassPoint<T>,
|
|
205
|
-
a: bigint,
|
|
206
|
-
b: bigint
|
|
207
|
-
): WeierstrassPoint<T> | undefined;
|
|
208
|
-
/** @deprecated use `p.y % 2n === 0n` */
|
|
209
|
-
hasEvenY(): boolean;
|
|
210
|
-
/** @deprecated use `p.precompute(windowSize)` */
|
|
211
|
-
_setWindowSize(windowSize: number): void;
|
|
212
184
|
}
|
|
213
185
|
|
|
214
186
|
/** Static methods for 3D XYZ projective points. */
|
|
@@ -216,12 +188,6 @@ export interface WeierstrassPointCons<T> extends CurvePointCons<WeierstrassPoint
|
|
|
216
188
|
/** Does NOT validate if the point is valid. Use `.assertValidity()`. */
|
|
217
189
|
new (X: T, Y: T, Z: T): WeierstrassPoint<T>;
|
|
218
190
|
CURVE(): WeierstrassOpts<T>;
|
|
219
|
-
/** @deprecated use `Point.BASE.multiply(Point.Fn.fromBytes(privateKey))` */
|
|
220
|
-
fromPrivateKey(privateKey: PrivKey): WeierstrassPoint<T>;
|
|
221
|
-
/** @deprecated use `import { normalizeZ } from '@noble/curves/abstract/curve.js';` */
|
|
222
|
-
normalizeZ(points: WeierstrassPoint<T>[]): WeierstrassPoint<T>[];
|
|
223
|
-
/** @deprecated use `import { pippenger } from '@noble/curves/abstract/curve.js';` */
|
|
224
|
-
msm(points: WeierstrassPoint<T>[], scalars: bigint[]): WeierstrassPoint<T>;
|
|
225
191
|
}
|
|
226
192
|
|
|
227
193
|
/**
|
|
@@ -286,21 +252,17 @@ export type ECDSAOpts = Partial<{
|
|
|
286
252
|
*/
|
|
287
253
|
export interface ECDH {
|
|
288
254
|
keygen: (seed?: Uint8Array) => { secretKey: Uint8Array; publicKey: Uint8Array };
|
|
289
|
-
getPublicKey: (secretKey:
|
|
290
|
-
getSharedSecret: (
|
|
255
|
+
getPublicKey: (secretKey: Uint8Array, isCompressed?: boolean) => Uint8Array;
|
|
256
|
+
getSharedSecret: (
|
|
257
|
+
secretKeyA: Uint8Array,
|
|
258
|
+
publicKeyB: Uint8Array,
|
|
259
|
+
isCompressed?: boolean
|
|
260
|
+
) => Uint8Array;
|
|
291
261
|
Point: WeierstrassPointCons<bigint>;
|
|
292
262
|
utils: {
|
|
293
|
-
isValidSecretKey: (secretKey:
|
|
263
|
+
isValidSecretKey: (secretKey: Uint8Array) => boolean;
|
|
294
264
|
isValidPublicKey: (publicKey: Uint8Array, isCompressed?: boolean) => boolean;
|
|
295
265
|
randomSecretKey: (seed?: Uint8Array) => Uint8Array;
|
|
296
|
-
/** @deprecated use `randomSecretKey` */
|
|
297
|
-
randomPrivateKey: (seed?: Uint8Array) => Uint8Array;
|
|
298
|
-
/** @deprecated use `isValidSecretKey` */
|
|
299
|
-
isValidPrivateKey: (secretKey: PrivKey) => boolean;
|
|
300
|
-
/** @deprecated use `Point.Fn.fromBytes()` */
|
|
301
|
-
normPrivateKeyToScalar: (key: PrivKey) => bigint;
|
|
302
|
-
/** @deprecated use `point.precompute()` */
|
|
303
|
-
precompute: (windowSize?: number, point?: WeierstrassPoint<bigint>) => WeierstrassPoint<bigint>;
|
|
304
266
|
};
|
|
305
267
|
lengths: CurveLengths;
|
|
306
268
|
}
|
|
@@ -310,7 +272,7 @@ export interface ECDH {
|
|
|
310
272
|
* Only supported for prime fields, not Fp2 (extension fields).
|
|
311
273
|
*/
|
|
312
274
|
export interface ECDSA extends ECDH {
|
|
313
|
-
sign: (message:
|
|
275
|
+
sign: (message: Uint8Array, secretKey: Uint8Array, opts?: ECDSASignOpts) => Uint8Array;
|
|
314
276
|
verify: (
|
|
315
277
|
signature: Uint8Array,
|
|
316
278
|
message: Uint8Array,
|
|
@@ -418,10 +380,10 @@ export const DER: IDER = {
|
|
|
418
380
|
return bytesToNumberBE(data);
|
|
419
381
|
},
|
|
420
382
|
},
|
|
421
|
-
toSig(
|
|
383
|
+
toSig(bytes: Uint8Array): { r: bigint; s: bigint } {
|
|
422
384
|
// parse DER signature
|
|
423
385
|
const { Err: E, _int: int, _tlv: tlv } = DER;
|
|
424
|
-
const data =
|
|
386
|
+
const data = abytes(bytes, undefined, 'signature');
|
|
425
387
|
const { v: seqBytes, l: seqLeftBytes } = tlv.decode(0x30, data);
|
|
426
388
|
if (seqLeftBytes.length) throw new E('invalid signature: left bytes after parsing');
|
|
427
389
|
const { v: rBytes, l: rLeftBytes } = tlv.decode(0x02, seqBytes);
|
|
@@ -442,23 +404,6 @@ export const DER: IDER = {
|
|
|
442
404
|
// prettier-ignore
|
|
443
405
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
|
|
444
406
|
|
|
445
|
-
export function _normFnElement(Fn: IField<bigint>, key: PrivKey): bigint {
|
|
446
|
-
const { BYTES: expected } = Fn;
|
|
447
|
-
let num: bigint;
|
|
448
|
-
if (typeof key === 'bigint') {
|
|
449
|
-
num = key;
|
|
450
|
-
} else {
|
|
451
|
-
let bytes = ensureBytes('private key', key);
|
|
452
|
-
try {
|
|
453
|
-
num = Fn.fromBytes(bytes);
|
|
454
|
-
} catch (error) {
|
|
455
|
-
throw new Error(`invalid private key: expected ui8a of size ${expected}, got ${typeof key}`);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
if (!Fn.isValidNot0(num)) throw new Error('invalid private key: out of range [1..N-1]');
|
|
459
|
-
return num;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
407
|
/**
|
|
463
408
|
* Creates weierstrass Point constructor, based on specified curve options.
|
|
464
409
|
*
|
|
@@ -476,7 +421,7 @@ const opts = {
|
|
|
476
421
|
const p256_Point = weierstrass(opts);
|
|
477
422
|
```
|
|
478
423
|
*/
|
|
479
|
-
export function
|
|
424
|
+
export function weierstrass<T>(
|
|
480
425
|
params: WeierstrassOpts<T>,
|
|
481
426
|
extraOpts: WeierstrassExtraOpts<T> = {}
|
|
482
427
|
): WeierstrassPointCons<T> {
|
|
@@ -531,7 +476,7 @@ export function weierstrassN<T>(
|
|
|
531
476
|
}
|
|
532
477
|
function pointFromBytes(bytes: Uint8Array) {
|
|
533
478
|
abytes(bytes, undefined, 'Point');
|
|
534
|
-
const {
|
|
479
|
+
const { publicKey: comp, publicKeyUncompressed: uncomp } = lengths; // e.g. for 32-byte: 33, 65
|
|
535
480
|
const length = bytes.length;
|
|
536
481
|
const head = bytes[0];
|
|
537
482
|
const tail = bytes.subarray(1);
|
|
@@ -704,8 +649,9 @@ export function weierstrassN<T>(
|
|
|
704
649
|
P.assertValidity();
|
|
705
650
|
return P;
|
|
706
651
|
}
|
|
707
|
-
|
|
708
|
-
|
|
652
|
+
|
|
653
|
+
static fromHex(hex: string): Point {
|
|
654
|
+
return Point.fromBytes(hexToBytes(hex));
|
|
709
655
|
}
|
|
710
656
|
|
|
711
657
|
get x(): T {
|
|
@@ -959,35 +905,10 @@ export function weierstrassN<T>(
|
|
|
959
905
|
toString() {
|
|
960
906
|
return `<Point ${this.is0() ? 'ZERO' : this.toHex()}>`;
|
|
961
907
|
}
|
|
962
|
-
|
|
963
|
-
// TODO: remove
|
|
964
|
-
get px(): T {
|
|
965
|
-
return this.X;
|
|
966
|
-
}
|
|
967
|
-
get py(): T {
|
|
968
|
-
return this.X;
|
|
969
|
-
}
|
|
970
|
-
get pz(): T {
|
|
971
|
-
return this.Z;
|
|
972
|
-
}
|
|
973
|
-
toRawBytes(isCompressed = true): Uint8Array {
|
|
974
|
-
return this.toBytes(isCompressed);
|
|
975
|
-
}
|
|
976
|
-
_setWindowSize(windowSize: number) {
|
|
977
|
-
this.precompute(windowSize);
|
|
978
|
-
}
|
|
979
|
-
static normalizeZ(points: Point[]): Point[] {
|
|
980
|
-
return normalizeZ(Point, points);
|
|
981
|
-
}
|
|
982
|
-
static msm(points: Point[], scalars: bigint[]): Point {
|
|
983
|
-
return pippenger(Point, Fn, points, scalars);
|
|
984
|
-
}
|
|
985
|
-
static fromPrivateKey(privateKey: PrivKey) {
|
|
986
|
-
return Point.BASE.multiply(_normFnElement(Fn, privateKey));
|
|
987
|
-
}
|
|
988
908
|
}
|
|
989
909
|
const bits = Fn.BITS;
|
|
990
910
|
const wnaf = new wNAF(Point, extraOpts.endo ? Math.ceil(bits / 2) : bits);
|
|
911
|
+
Point.BASE.precompute(8); // Enable precomputes. Slows down first publicKey computation by 20ms.
|
|
991
912
|
return Point;
|
|
992
913
|
}
|
|
993
914
|
|
|
@@ -996,39 +917,16 @@ export interface ECDSASignature {
|
|
|
996
917
|
readonly r: bigint;
|
|
997
918
|
readonly s: bigint;
|
|
998
919
|
readonly recovery?: number;
|
|
999
|
-
addRecoveryBit(recovery: number):
|
|
920
|
+
addRecoveryBit(recovery: number): ECDSASignature & { readonly recovery: number };
|
|
1000
921
|
hasHighS(): boolean;
|
|
1001
922
|
toBytes(format?: string): Uint8Array;
|
|
1002
923
|
toHex(format?: string): string;
|
|
1003
|
-
|
|
1004
|
-
/** @deprecated */
|
|
1005
|
-
assertValidity(): void;
|
|
1006
|
-
/** @deprecated */
|
|
1007
|
-
normalizeS(): ECDSASignature;
|
|
1008
|
-
/** @deprecated use standalone method `curve.recoverPublicKey(sig.toBytes('recovered'), msg)` */
|
|
1009
|
-
recoverPublicKey(msgHash: Hex): WeierstrassPoint<bigint>;
|
|
1010
|
-
/** @deprecated use `.toBytes('compact')` */
|
|
1011
|
-
toCompactRawBytes(): Uint8Array;
|
|
1012
|
-
/** @deprecated use `.toBytes('compact')` */
|
|
1013
|
-
toCompactHex(): string;
|
|
1014
|
-
/** @deprecated use `.toBytes('der')` */
|
|
1015
|
-
toDERRawBytes(): Uint8Array;
|
|
1016
|
-
/** @deprecated use `.toBytes('der')` */
|
|
1017
|
-
toDERHex(): string;
|
|
1018
924
|
}
|
|
1019
|
-
export type ECDSASigRecovered = ECDSASignature & {
|
|
1020
|
-
readonly recovery: number;
|
|
1021
|
-
};
|
|
1022
925
|
/** Methods of ECDSA signature constructor. */
|
|
1023
926
|
export type ECDSASignatureCons = {
|
|
1024
927
|
new (r: bigint, s: bigint, recovery?: number): ECDSASignature;
|
|
1025
928
|
fromBytes(bytes: Uint8Array, format?: ECDSASigFormat): ECDSASignature;
|
|
1026
929
|
fromHex(hex: string, format?: ECDSASigFormat): ECDSASignature;
|
|
1027
|
-
|
|
1028
|
-
/** @deprecated use `.fromBytes(bytes, 'compact')` */
|
|
1029
|
-
fromCompact(hex: Hex): ECDSASignature;
|
|
1030
|
-
/** @deprecated use `.fromBytes(bytes, 'der')` */
|
|
1031
|
-
fromDER(hex: Hex): ECDSASignature;
|
|
1032
930
|
};
|
|
1033
931
|
|
|
1034
932
|
// Points start with byte 0x02 when y is even; otherwise 0x03
|
|
@@ -1171,9 +1069,9 @@ export function mapToCurveSimpleSWU<T>(
|
|
|
1171
1069
|
|
|
1172
1070
|
function getWLengths<T>(Fp: IField<T>, Fn: IField<bigint>) {
|
|
1173
1071
|
return {
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1072
|
+
secretKey: Fn.BYTES,
|
|
1073
|
+
publicKey: 1 + Fp.BYTES,
|
|
1074
|
+
publicKeyUncompressed: 1 + 2 * Fp.BYTES,
|
|
1177
1075
|
publicKeyHasPrefix: true,
|
|
1178
1076
|
signature: 2 * Fn.BYTES,
|
|
1179
1077
|
};
|
|
@@ -1191,20 +1089,21 @@ export function ecdh(
|
|
|
1191
1089
|
const randomBytes_ = ecdhOpts.randomBytes || wcRandomBytes;
|
|
1192
1090
|
const lengths = Object.assign(getWLengths(Point.Fp, Fn), { seed: getMinHashLength(Fn.ORDER) });
|
|
1193
1091
|
|
|
1194
|
-
function isValidSecretKey(secretKey:
|
|
1092
|
+
function isValidSecretKey(secretKey: Uint8Array) {
|
|
1195
1093
|
try {
|
|
1196
|
-
|
|
1094
|
+
const num = Fn.fromBytes(secretKey);
|
|
1095
|
+
return Fn.isValidNot0(num);
|
|
1197
1096
|
} catch (error) {
|
|
1198
1097
|
return false;
|
|
1199
1098
|
}
|
|
1200
1099
|
}
|
|
1201
1100
|
|
|
1202
1101
|
function isValidPublicKey(publicKey: Uint8Array, isCompressed?: boolean): boolean {
|
|
1203
|
-
const {
|
|
1102
|
+
const { publicKey: comp, publicKeyUncompressed } = lengths;
|
|
1204
1103
|
try {
|
|
1205
1104
|
const l = publicKey.length;
|
|
1206
1105
|
if (isCompressed === true && l !== comp) return false;
|
|
1207
|
-
if (isCompressed === false && l !==
|
|
1106
|
+
if (isCompressed === false && l !== publicKeyUncompressed) return false;
|
|
1208
1107
|
return !!Point.fromBytes(publicKey);
|
|
1209
1108
|
} catch (error) {
|
|
1210
1109
|
return false;
|
|
@@ -1224,8 +1123,8 @@ export function ecdh(
|
|
|
1224
1123
|
* @param isCompressed whether to return compact (default), or full key
|
|
1225
1124
|
* @returns Public key, full when isCompressed=false; short when isCompressed=true
|
|
1226
1125
|
*/
|
|
1227
|
-
function getPublicKey(secretKey:
|
|
1228
|
-
return Point.BASE.multiply(
|
|
1126
|
+
function getPublicKey(secretKey: Uint8Array, isCompressed = true): Uint8Array {
|
|
1127
|
+
return Point.BASE.multiply(Fn.fromBytes(secretKey)).toBytes(isCompressed);
|
|
1229
1128
|
}
|
|
1230
1129
|
|
|
1231
1130
|
function keygen(seed?: Uint8Array) {
|
|
@@ -1236,12 +1135,12 @@ export function ecdh(
|
|
|
1236
1135
|
/**
|
|
1237
1136
|
* Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
|
|
1238
1137
|
*/
|
|
1239
|
-
function isProbPub(item:
|
|
1240
|
-
|
|
1241
|
-
if (item
|
|
1242
|
-
if (Fn.
|
|
1243
|
-
const l =
|
|
1244
|
-
return l ===
|
|
1138
|
+
function isProbPub(item: Uint8Array): boolean | undefined {
|
|
1139
|
+
const { secretKey, publicKey, publicKeyUncompressed } = lengths;
|
|
1140
|
+
if (!isBytes(item)) return undefined;
|
|
1141
|
+
if (('_lengths' in Fn && Fn._lengths) || secretKey === publicKey) return undefined;
|
|
1142
|
+
const l = abytes(item, undefined, 'key').length;
|
|
1143
|
+
return l === publicKey || l === publicKeyUncompressed;
|
|
1245
1144
|
}
|
|
1246
1145
|
|
|
1247
1146
|
/**
|
|
@@ -1252,11 +1151,15 @@ export function ecdh(
|
|
|
1252
1151
|
* @param isCompressed whether to return compact (default), or full key
|
|
1253
1152
|
* @returns shared public key
|
|
1254
1153
|
*/
|
|
1255
|
-
function getSharedSecret(
|
|
1154
|
+
function getSharedSecret(
|
|
1155
|
+
secretKeyA: Uint8Array,
|
|
1156
|
+
publicKeyB: Uint8Array,
|
|
1157
|
+
isCompressed = true
|
|
1158
|
+
): Uint8Array {
|
|
1256
1159
|
if (isProbPub(secretKeyA) === true) throw new Error('first arg must be private key');
|
|
1257
1160
|
if (isProbPub(publicKeyB) === false) throw new Error('second arg must be public key');
|
|
1258
|
-
const s =
|
|
1259
|
-
const b = Point.
|
|
1161
|
+
const s = Fn.fromBytes(secretKeyA);
|
|
1162
|
+
const b = Point.fromBytes(publicKeyB); // checks for being on-curve
|
|
1260
1163
|
return b.multiply(s).toBytes(isCompressed);
|
|
1261
1164
|
}
|
|
1262
1165
|
|
|
@@ -1264,14 +1167,6 @@ export function ecdh(
|
|
|
1264
1167
|
isValidSecretKey,
|
|
1265
1168
|
isValidPublicKey,
|
|
1266
1169
|
randomSecretKey,
|
|
1267
|
-
|
|
1268
|
-
// TODO: remove
|
|
1269
|
-
isValidPrivateKey: isValidSecretKey,
|
|
1270
|
-
randomPrivateKey: randomSecretKey,
|
|
1271
|
-
normPrivateKeyToScalar: (key: PrivKey) => _normFnElement(Fn, key),
|
|
1272
|
-
precompute(windowSize = 8, point = Point.BASE): WeierstrassPoint<bigint> {
|
|
1273
|
-
return point.precompute(windowSize, false);
|
|
1274
|
-
},
|
|
1275
1170
|
};
|
|
1276
1171
|
|
|
1277
1172
|
return Object.freeze({ getPublicKey, getSharedSecret, keygen, Point, utils, lengths });
|
|
@@ -1290,6 +1185,7 @@ export function ecdh(
|
|
|
1290
1185
|
* const p256_Point = weierstrass(...);
|
|
1291
1186
|
* const p256_sha256 = ecdsa(p256_Point, sha256);
|
|
1292
1187
|
* const p256_sha224 = ecdsa(p256_Point, sha224);
|
|
1188
|
+
* const p256_sha224_r = ecdsa(p256_Point, sha224, { randomBytes: (length) => { ... } });
|
|
1293
1189
|
* ```
|
|
1294
1190
|
*/
|
|
1295
1191
|
export function ecdsa(
|
|
@@ -1309,9 +1205,9 @@ export function ecdsa(
|
|
|
1309
1205
|
bits2int_modN: 'function',
|
|
1310
1206
|
}
|
|
1311
1207
|
);
|
|
1312
|
-
|
|
1313
|
-
const
|
|
1314
|
-
const
|
|
1208
|
+
ecdsaOpts = Object.assign({}, ecdsaOpts);
|
|
1209
|
+
const randomBytes = ecdsaOpts.randomBytes || wcRandomBytes;
|
|
1210
|
+
const hmac: HmacFnSync =
|
|
1315
1211
|
ecdsaOpts.hmac ||
|
|
1316
1212
|
(((key, ...msgs) => nobleHmac(hash, key, concatBytes(...msgs))) satisfies HmacFnSync);
|
|
1317
1213
|
|
|
@@ -1319,25 +1215,27 @@ export function ecdsa(
|
|
|
1319
1215
|
const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
|
|
1320
1216
|
const { keygen, getPublicKey, getSharedSecret, utils, lengths } = ecdh(Point, ecdsaOpts);
|
|
1321
1217
|
const defaultSigOpts: Required<ECDSASignOpts> = {
|
|
1322
|
-
prehash:
|
|
1323
|
-
lowS: typeof ecdsaOpts.lowS === 'boolean' ? ecdsaOpts.lowS :
|
|
1324
|
-
format:
|
|
1218
|
+
prehash: true,
|
|
1219
|
+
lowS: typeof ecdsaOpts.lowS === 'boolean' ? ecdsaOpts.lowS : true,
|
|
1220
|
+
format: 'compact' as ECDSASigFormat,
|
|
1325
1221
|
extraEntropy: false,
|
|
1326
1222
|
};
|
|
1327
|
-
const defaultSigOpts_format = 'compact';
|
|
1328
1223
|
|
|
1329
1224
|
function isBiggerThanHalfOrder(number: bigint) {
|
|
1330
1225
|
const HALF = CURVE_ORDER >> _1n;
|
|
1331
1226
|
return number > HALF;
|
|
1332
1227
|
}
|
|
1333
|
-
function normalizeS(s: bigint) {
|
|
1334
|
-
return isBiggerThanHalfOrder(s) ? Fn.neg(s) : s;
|
|
1335
|
-
}
|
|
1336
1228
|
function validateRS(title: string, num: bigint): bigint {
|
|
1337
1229
|
if (!Fn.isValidNot0(num))
|
|
1338
1230
|
throw new Error(`invalid signature ${title}: out of range 1..Point.Fn.ORDER`);
|
|
1339
1231
|
return num;
|
|
1340
1232
|
}
|
|
1233
|
+
function validateSigLength(bytes: Uint8Array, format: ECDSASigFormat) {
|
|
1234
|
+
validateSigFormat(format);
|
|
1235
|
+
const size = lengths.signature!;
|
|
1236
|
+
const sizer = format === 'compact' ? size : format === 'recovered' ? size + 1 : undefined;
|
|
1237
|
+
return abytes(bytes, sizer);
|
|
1238
|
+
}
|
|
1341
1239
|
|
|
1342
1240
|
/**
|
|
1343
1241
|
* ECDSA signature with its (r, s) properties. Supports compact, recovered & DER representations.
|
|
@@ -1346,6 +1244,7 @@ export function ecdsa(
|
|
|
1346
1244
|
readonly r: bigint;
|
|
1347
1245
|
readonly s: bigint;
|
|
1348
1246
|
readonly recovery?: number;
|
|
1247
|
+
|
|
1349
1248
|
constructor(r: bigint, s: bigint, recovery?: number) {
|
|
1350
1249
|
this.r = validateRS('r', r); // r in [1..N-1];
|
|
1351
1250
|
this.s = validateRS('s', s); // s in [1..N-1];
|
|
@@ -1353,22 +1252,19 @@ export function ecdsa(
|
|
|
1353
1252
|
Object.freeze(this);
|
|
1354
1253
|
}
|
|
1355
1254
|
|
|
1356
|
-
static fromBytes(bytes: Uint8Array, format: ECDSASigFormat =
|
|
1357
|
-
|
|
1358
|
-
const size = lengths.signature!;
|
|
1255
|
+
static fromBytes(bytes: Uint8Array, format: ECDSASigFormat = defaultSigOpts.format): Signature {
|
|
1256
|
+
validateSigLength(bytes, format);
|
|
1359
1257
|
let recid: number | undefined;
|
|
1360
1258
|
if (format === 'der') {
|
|
1361
1259
|
const { r, s } = DER.toSig(abytes(bytes));
|
|
1362
1260
|
return new Signature(r, s);
|
|
1363
1261
|
}
|
|
1364
1262
|
if (format === 'recovered') {
|
|
1365
|
-
abytes(bytes, size + 1);
|
|
1366
1263
|
recid = bytes[0];
|
|
1367
1264
|
format = 'compact';
|
|
1368
1265
|
bytes = bytes.subarray(1);
|
|
1369
1266
|
}
|
|
1370
|
-
|
|
1371
|
-
const L = size / 2;
|
|
1267
|
+
const L = lengths.signature! / 2;
|
|
1372
1268
|
const r = bytes.subarray(0, L);
|
|
1373
1269
|
const s = bytes.subarray(L, L * 2);
|
|
1374
1270
|
return new Signature(Fn.fromBytes(r), Fn.fromBytes(s), recid);
|
|
@@ -1382,7 +1278,7 @@ export function ecdsa(
|
|
|
1382
1278
|
return new Signature(this.r, this.s, recovery) as RecoveredSignature;
|
|
1383
1279
|
}
|
|
1384
1280
|
|
|
1385
|
-
recoverPublicKey(
|
|
1281
|
+
recoverPublicKey(messageHash: Uint8Array): WeierstrassPoint<bigint> {
|
|
1386
1282
|
const FIELD_ORDER = Fp.ORDER;
|
|
1387
1283
|
const { r, s, recovery: rec } = this;
|
|
1388
1284
|
if (rec == null || ![0, 1, 2, 3].includes(rec)) throw new Error('recovery id invalid');
|
|
@@ -1403,7 +1299,7 @@ export function ecdsa(
|
|
|
1403
1299
|
const x = Fp.toBytes(radj);
|
|
1404
1300
|
const R = Point.fromBytes(concatBytes(pprefix((rec & 1) === 0), x));
|
|
1405
1301
|
const ir = Fn.inv(radj); // r^-1
|
|
1406
|
-
const h = bits2int_modN(
|
|
1302
|
+
const h = bits2int_modN(abytes(messageHash, undefined, 'msgHash')); // Truncate hash
|
|
1407
1303
|
const u1 = Fn.create(-h * ir); // -hr^-1
|
|
1408
1304
|
const u2 = Fn.create(s * ir); // sr^-1
|
|
1409
1305
|
// (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1). unsafe is fine: there is no private data.
|
|
@@ -1418,7 +1314,7 @@ export function ecdsa(
|
|
|
1418
1314
|
return isBiggerThanHalfOrder(this.s);
|
|
1419
1315
|
}
|
|
1420
1316
|
|
|
1421
|
-
toBytes(format: ECDSASigFormat =
|
|
1317
|
+
toBytes(format: ECDSASigFormat = defaultSigOpts.format) {
|
|
1422
1318
|
validateSigFormat(format);
|
|
1423
1319
|
if (format === 'der') return hexToBytes(DER.hexFromSig(this));
|
|
1424
1320
|
const r = Fn.toBytes(this.r);
|
|
@@ -1433,30 +1329,6 @@ export function ecdsa(
|
|
|
1433
1329
|
toHex(format?: ECDSASigFormat) {
|
|
1434
1330
|
return bytesToHex(this.toBytes(format));
|
|
1435
1331
|
}
|
|
1436
|
-
|
|
1437
|
-
// TODO: remove
|
|
1438
|
-
assertValidity(): void {}
|
|
1439
|
-
static fromCompact(hex: Hex) {
|
|
1440
|
-
return Signature.fromBytes(ensureBytes('sig', hex), 'compact');
|
|
1441
|
-
}
|
|
1442
|
-
static fromDER(hex: Hex) {
|
|
1443
|
-
return Signature.fromBytes(ensureBytes('sig', hex), 'der');
|
|
1444
|
-
}
|
|
1445
|
-
normalizeS() {
|
|
1446
|
-
return this.hasHighS() ? new Signature(this.r, Fn.neg(this.s), this.recovery) : this;
|
|
1447
|
-
}
|
|
1448
|
-
toDERRawBytes() {
|
|
1449
|
-
return this.toBytes('der');
|
|
1450
|
-
}
|
|
1451
|
-
toDERHex() {
|
|
1452
|
-
return bytesToHex(this.toBytes('der'));
|
|
1453
|
-
}
|
|
1454
|
-
toCompactRawBytes() {
|
|
1455
|
-
return this.toBytes('compact');
|
|
1456
|
-
}
|
|
1457
|
-
toCompactHex() {
|
|
1458
|
-
return bytesToHex(this.toBytes('compact'));
|
|
1459
|
-
}
|
|
1460
1332
|
}
|
|
1461
1333
|
type RecoveredSignature = Signature & { recovery: number };
|
|
1462
1334
|
|
|
@@ -1466,7 +1338,7 @@ export function ecdsa(
|
|
|
1466
1338
|
// int2octets can't be used; pads small msgs with 0: unacceptatble for trunc as per RFC vectors
|
|
1467
1339
|
const bits2int =
|
|
1468
1340
|
ecdsaOpts.bits2int ||
|
|
1469
|
-
function (bytes: Uint8Array): bigint {
|
|
1341
|
+
function bits2int_def(bytes: Uint8Array): bigint {
|
|
1470
1342
|
// Our custom check "just in case", for protection against DoS
|
|
1471
1343
|
if (bytes.length > 8192) throw new Error('input is too large');
|
|
1472
1344
|
// For curves with nBitLength % 8 !== 0: bits2octets(bits2octets(m)) !== bits2octets(m)
|
|
@@ -1477,20 +1349,23 @@ export function ecdsa(
|
|
|
1477
1349
|
};
|
|
1478
1350
|
const bits2int_modN =
|
|
1479
1351
|
ecdsaOpts.bits2int_modN ||
|
|
1480
|
-
function (bytes: Uint8Array): bigint {
|
|
1352
|
+
function bits2int_modN_def(bytes: Uint8Array): bigint {
|
|
1481
1353
|
return Fn.create(bits2int(bytes)); // can't use bytesToNumberBE here
|
|
1482
1354
|
};
|
|
1483
|
-
//
|
|
1355
|
+
// Pads output with zero as per spec
|
|
1484
1356
|
const ORDER_MASK = bitMask(fnBits);
|
|
1485
|
-
/**
|
|
1486
|
-
* Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`.
|
|
1487
|
-
*/
|
|
1357
|
+
/** Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`. */
|
|
1488
1358
|
function int2octets(num: bigint): Uint8Array {
|
|
1489
1359
|
// IMPORTANT: the check ensures working for case `Fn.BYTES != Fn.BITS * 8`
|
|
1490
1360
|
aInRange('num < 2^' + fnBits, num, _0n, ORDER_MASK);
|
|
1491
1361
|
return Fn.toBytes(num);
|
|
1492
1362
|
}
|
|
1493
1363
|
|
|
1364
|
+
function validateMsgAndHash(message: Uint8Array, prehash: boolean) {
|
|
1365
|
+
abytes(message, undefined, 'message');
|
|
1366
|
+
return prehash ? abytes(hash(message), undefined, 'prehashed message') : message;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1494
1369
|
/**
|
|
1495
1370
|
* Steps A, D of RFC6979 3.2.
|
|
1496
1371
|
* Creates RFC6979 seed; converts msg/privKey to numbers.
|
|
@@ -1499,29 +1374,25 @@ export function ecdsa(
|
|
|
1499
1374
|
* Warning: we cannot assume here that message has same amount of bytes as curve order,
|
|
1500
1375
|
* this will be invalid at least for P521. Also it can be bigger for P224 + SHA256.
|
|
1501
1376
|
*/
|
|
1502
|
-
function prepSig(message: Uint8Array, privateKey:
|
|
1503
|
-
if (['recovered', 'canonical'].some((k) => k in opts))
|
|
1504
|
-
throw new Error('sign() legacy options not supported');
|
|
1377
|
+
function prepSig(message: Uint8Array, privateKey: Uint8Array, opts: ECDSASignOpts) {
|
|
1505
1378
|
const { lowS, prehash, extraEntropy } = validateSigOpts(opts, defaultSigOpts);
|
|
1506
|
-
// RFC6979 3.2
|
|
1507
|
-
message = abytes(message, undefined, 'message');
|
|
1508
|
-
if (prehash) message = abytes(hash(message), undefined, 'prehashed message');
|
|
1509
|
-
|
|
1379
|
+
message = validateMsgAndHash(message, prehash); // RFC6979 3.2 A: h1 = H(m)
|
|
1510
1380
|
// We can't later call bits2octets, since nested bits2int is broken for curves
|
|
1511
1381
|
// with fnBits % 8 !== 0. Because of that, we unwrap it here as int2octets call.
|
|
1512
1382
|
// const bits2octets = (bits) => int2octets(bits2int_modN(bits))
|
|
1513
1383
|
const h1int = bits2int_modN(message);
|
|
1514
|
-
const d =
|
|
1384
|
+
const d = Fn.fromBytes(privateKey); // validate secret key, convert to bigint
|
|
1385
|
+
if (!Fn.isValidNot0(d)) throw new Error('invalid private key');
|
|
1515
1386
|
const seedArgs = [int2octets(d), int2octets(h1int)];
|
|
1516
1387
|
// extraEntropy. RFC6979 3.6: additional k' (optional).
|
|
1517
1388
|
if (extraEntropy != null && extraEntropy !== false) {
|
|
1518
1389
|
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
|
|
1519
1390
|
// gen random bytes OR pass as-is
|
|
1520
|
-
const e = extraEntropy === true ?
|
|
1521
|
-
seedArgs.push(
|
|
1391
|
+
const e = extraEntropy === true ? randomBytes(lengths.secretKey) : extraEntropy;
|
|
1392
|
+
seedArgs.push(abytes(e, undefined, 'extraEntropy')); // check for being bytes
|
|
1522
1393
|
}
|
|
1523
1394
|
const seed = concatBytes(...seedArgs); // Step D of RFC6979 3.2
|
|
1524
|
-
const m = h1int; //
|
|
1395
|
+
const m = h1int; // no need to call bits2int second time here, it is inside truncateHash!
|
|
1525
1396
|
// Converts signature params into point w r/s, checks result for validity.
|
|
1526
1397
|
// To transform k => Signature:
|
|
1527
1398
|
// q = k⋅G
|
|
@@ -1533,7 +1404,7 @@ export function ecdsa(
|
|
|
1533
1404
|
function k2sig(kBytes: Uint8Array): RecoveredSignature | undefined {
|
|
1534
1405
|
// RFC 6979 Section 3.2, step 3: k = bits2int(T)
|
|
1535
1406
|
// Important: all mod() calls here must be done over N
|
|
1536
|
-
const k = bits2int(kBytes); //
|
|
1407
|
+
const k = bits2int(kBytes); // Cannot use fields methods, since it is group element
|
|
1537
1408
|
if (!Fn.isValidNot0(k)) return; // Valid scalars (including k) must be in 1..N-1
|
|
1538
1409
|
const ik = Fn.inv(k); // k^-1 mod n
|
|
1539
1410
|
const q = Point.BASE.multiply(k).toAffine(); // q = k⋅G
|
|
@@ -1544,7 +1415,7 @@ export function ecdsa(
|
|
|
1544
1415
|
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n); // recovery bit (2 or 3, when q.x > n)
|
|
1545
1416
|
let normS = s;
|
|
1546
1417
|
if (lowS && isBiggerThanHalfOrder(s)) {
|
|
1547
|
-
normS =
|
|
1418
|
+
normS = Fn.neg(s); // if lowS was passed, ensure s is always
|
|
1548
1419
|
recovery ^= 1; // // in the bottom half of N
|
|
1549
1420
|
}
|
|
1550
1421
|
return new Signature(r, normS, recovery) as RecoveredSignature; // use normS, not s
|
|
@@ -1563,17 +1434,13 @@ export function ecdsa(
|
|
|
1563
1434
|
* s = (m + dr) / k mod n
|
|
1564
1435
|
* ```
|
|
1565
1436
|
*/
|
|
1566
|
-
function sign(message:
|
|
1567
|
-
message = ensureBytes('message', message);
|
|
1437
|
+
function sign(message: Uint8Array, secretKey: Uint8Array, opts: ECDSASignOpts = {}): Uint8Array {
|
|
1568
1438
|
const { seed, k2sig } = prepSig(message, secretKey, opts); // Steps A, D of RFC6979 3.2.
|
|
1569
|
-
const drbg = createHmacDrbg<RecoveredSignature>(hash.outputLen, Fn.BYTES,
|
|
1439
|
+
const drbg = createHmacDrbg<RecoveredSignature>(hash.outputLen, Fn.BYTES, hmac);
|
|
1570
1440
|
const sig = drbg(seed, k2sig); // Steps B, C, D, E, F, G
|
|
1571
|
-
return sig;
|
|
1441
|
+
return sig.toBytes(opts.format);
|
|
1572
1442
|
}
|
|
1573
1443
|
|
|
1574
|
-
// Enable precomputes. Slows down first publicKey computation by 20ms.
|
|
1575
|
-
Point.BASE.precompute(8);
|
|
1576
|
-
|
|
1577
1444
|
/**
|
|
1578
1445
|
* Verifies a signature against message and public key.
|
|
1579
1446
|
* Rejects lowS signatures by default: see {@link ECDSAVerifyOpts}.
|
|
@@ -1588,66 +1455,24 @@ export function ecdsa(
|
|
|
1588
1455
|
* ```
|
|
1589
1456
|
*/
|
|
1590
1457
|
function verify(
|
|
1591
|
-
signature:
|
|
1592
|
-
message:
|
|
1593
|
-
publicKey:
|
|
1458
|
+
signature: Uint8Array,
|
|
1459
|
+
message: Uint8Array,
|
|
1460
|
+
publicKey: Uint8Array,
|
|
1594
1461
|
opts: ECDSAVerifyOpts = {}
|
|
1595
1462
|
): boolean {
|
|
1596
|
-
const sg = signature;
|
|
1597
|
-
message = ensureBytes('msgHash', message);
|
|
1598
|
-
publicKey = ensureBytes('publicKey', publicKey);
|
|
1599
1463
|
const { lowS, prehash, format } = validateSigOpts(opts, defaultSigOpts);
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
// Try to deduce format
|
|
1606
|
-
const isHex = typeof sg === 'string' || isBytes(sg);
|
|
1607
|
-
const isObj =
|
|
1608
|
-
!isHex &&
|
|
1609
|
-
sg !== null &&
|
|
1610
|
-
typeof sg === 'object' &&
|
|
1611
|
-
typeof sg.r === 'bigint' &&
|
|
1612
|
-
typeof sg.s === 'bigint';
|
|
1613
|
-
if (!isHex && !isObj)
|
|
1614
|
-
throw new Error('invalid signature, expected Uint8Array, hex string or Signature instance');
|
|
1615
|
-
if (isObj) {
|
|
1616
|
-
_sig = new Signature(sg.r, sg.s);
|
|
1617
|
-
} else if (isHex) {
|
|
1618
|
-
// TODO: remove this malleable check
|
|
1619
|
-
// Signature can be represented in 2 ways: compact (2*Fn.BYTES) & DER (variable-length).
|
|
1620
|
-
// Since DER can also be 2*Fn.BYTES bytes, we check for it first.
|
|
1621
|
-
try {
|
|
1622
|
-
_sig = Signature.fromDER(sg);
|
|
1623
|
-
} catch (derError) {
|
|
1624
|
-
if (!(derError instanceof DER.Err)) throw derError;
|
|
1625
|
-
}
|
|
1626
|
-
if (!_sig) {
|
|
1627
|
-
try {
|
|
1628
|
-
_sig = Signature.fromCompact(sg);
|
|
1629
|
-
} catch (error) {
|
|
1630
|
-
return false;
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
}
|
|
1634
|
-
} else {
|
|
1635
|
-
if (format === 'compact' || format === 'der') {
|
|
1636
|
-
if (typeof sg !== 'string' && !isBytes(sg))
|
|
1637
|
-
throw new Error('"der" / "compact" format expects Uint8Array signature');
|
|
1638
|
-
_sig = Signature.fromBytes(ensureBytes('sig', sg), format);
|
|
1639
|
-
} else {
|
|
1640
|
-
throw new Error('format must be "compact", "der" or "js"');
|
|
1641
|
-
}
|
|
1464
|
+
publicKey = abytes(publicKey, undefined, 'publicKey');
|
|
1465
|
+
message = validateMsgAndHash(message, prehash);
|
|
1466
|
+
if (!isBytes(signature as any)) {
|
|
1467
|
+
const end = signature instanceof Signature ? ', use sig.toBytes()' : '';
|
|
1468
|
+
throw new Error('verify expects Uint8Array signature' + end);
|
|
1642
1469
|
}
|
|
1643
|
-
|
|
1644
|
-
if (!_sig) return false;
|
|
1470
|
+
validateSigLength(signature, format); // execute this twice because we want loud error
|
|
1645
1471
|
try {
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
const { r, s } = _sig;
|
|
1472
|
+
const sig = Signature.fromBytes(signature, format);
|
|
1473
|
+
const P = Point.fromBytes(publicKey);
|
|
1474
|
+
if (lowS && sig.hasHighS()) return false;
|
|
1475
|
+
const { r, s } = sig;
|
|
1651
1476
|
const h = bits2int_modN(message); // mod n, not mod p
|
|
1652
1477
|
const is = Fn.inv(s); // s^-1 mod n
|
|
1653
1478
|
const u1 = Fn.create(h * is); // u1 = hs^-1 mod n
|
|
@@ -1666,10 +1491,8 @@ export function ecdsa(
|
|
|
1666
1491
|
message: Uint8Array,
|
|
1667
1492
|
opts: ECDSARecoverOpts = {}
|
|
1668
1493
|
): Uint8Array {
|
|
1669
|
-
const
|
|
1670
|
-
|
|
1671
|
-
message = abytes(message, undefined, 'message');
|
|
1672
|
-
if (prehash) message = abytes(hash(message), undefined, 'prehashed message');
|
|
1494
|
+
const { prehash } = validateSigOpts(opts, defaultSigOpts);
|
|
1495
|
+
message = validateMsgAndHash(message, prehash);
|
|
1673
1496
|
return Signature.fromBytes(signature, 'recovered').recoverPublicKey(message).toBytes();
|
|
1674
1497
|
}
|
|
1675
1498
|
|
|
@@ -1685,209 +1508,5 @@ export function ecdsa(
|
|
|
1685
1508
|
recoverPublicKey,
|
|
1686
1509
|
Signature,
|
|
1687
1510
|
hash,
|
|
1688
|
-
});
|
|
1689
|
-
}
|
|
1690
|
-
|
|
1691
|
-
// TODO: remove everything below
|
|
1692
|
-
/** @deprecated */
|
|
1693
|
-
export type SignatureType = ECDSASignature;
|
|
1694
|
-
/** @deprecated */
|
|
1695
|
-
export type RecoveredSignatureType = ECDSASigRecovered;
|
|
1696
|
-
/** @deprecated */
|
|
1697
|
-
export type SignatureLike = { r: bigint; s: bigint };
|
|
1698
|
-
/** @deprecated use `Uint8Array | boolean` */
|
|
1699
|
-
export type Entropy = Hex | boolean;
|
|
1700
|
-
export type BasicWCurve<T> = BasicCurve<T> & {
|
|
1701
|
-
// Params: a, b
|
|
1702
|
-
a: T;
|
|
1703
|
-
b: T;
|
|
1704
|
-
|
|
1705
|
-
// Optional params
|
|
1706
|
-
allowedPrivateKeyLengths?: readonly number[]; // for P521
|
|
1707
|
-
wrapPrivateKey?: boolean; // bls12-381 requires mod(n) instead of rejecting keys >= n
|
|
1708
|
-
endo?: EndomorphismOpts;
|
|
1709
|
-
// When a cofactor != 1, there can be an effective methods to:
|
|
1710
|
-
// 1. Determine whether a point is torsion-free
|
|
1711
|
-
isTorsionFree?: (c: WeierstrassPointCons<T>, point: WeierstrassPoint<T>) => boolean;
|
|
1712
|
-
// 2. Clear torsion component
|
|
1713
|
-
clearCofactor?: (c: WeierstrassPointCons<T>, point: WeierstrassPoint<T>) => WeierstrassPoint<T>;
|
|
1714
|
-
};
|
|
1715
|
-
/** @deprecated use ECDSASignOpts */
|
|
1716
|
-
export type SignOpts = ECDSASignOpts;
|
|
1717
|
-
/** @deprecated use ECDSASignOpts */
|
|
1718
|
-
export type VerOpts = ECDSAVerifyOpts;
|
|
1719
|
-
|
|
1720
|
-
/** @deprecated use WeierstrassPoint */
|
|
1721
|
-
export type ProjPointType<T> = WeierstrassPoint<T>;
|
|
1722
|
-
/** @deprecated use WeierstrassPointCons */
|
|
1723
|
-
export type ProjConstructor<T> = WeierstrassPointCons<T>;
|
|
1724
|
-
|
|
1725
|
-
// TODO: remove
|
|
1726
|
-
export type CurvePointsType<T> = BasicWCurve<T> & {
|
|
1727
|
-
fromBytes?: (bytes: Uint8Array) => AffinePoint<T>;
|
|
1728
|
-
toBytes?: (
|
|
1729
|
-
c: WeierstrassPointCons<T>,
|
|
1730
|
-
point: WeierstrassPoint<T>,
|
|
1731
|
-
isCompressed: boolean
|
|
1732
|
-
) => Uint8Array;
|
|
1733
|
-
};
|
|
1734
|
-
|
|
1735
|
-
// LegacyWeierstrassOpts
|
|
1736
|
-
export type CurvePointsTypeWithLength<T> = Readonly<CurvePointsType<T> & Partial<NLength>>;
|
|
1737
|
-
|
|
1738
|
-
// LegacyWeierstrass
|
|
1739
|
-
export type CurvePointsRes<T> = {
|
|
1740
|
-
Point: WeierstrassPointCons<T>;
|
|
1741
|
-
|
|
1742
|
-
/** @deprecated use `Point.CURVE()` */
|
|
1743
|
-
CURVE: CurvePointsType<T>;
|
|
1744
|
-
/** @deprecated use `Point` */
|
|
1745
|
-
ProjectivePoint: WeierstrassPointCons<T>;
|
|
1746
|
-
/** @deprecated use `Point.Fn.fromBytes(privateKey)` */
|
|
1747
|
-
normPrivateKeyToScalar: (key: PrivKey) => bigint;
|
|
1748
|
-
/** @deprecated */
|
|
1749
|
-
weierstrassEquation: (x: T) => T;
|
|
1750
|
-
/** @deprecated use `Point.Fn.isValidNot0(num)` */
|
|
1751
|
-
isWithinCurveOrder: (num: bigint) => boolean;
|
|
1752
|
-
};
|
|
1753
|
-
|
|
1754
|
-
// Aliases to legacy types
|
|
1755
|
-
// export type CurveType = LegacyECDSAOpts;
|
|
1756
|
-
// export type CurveFn = LegacyECDSA;
|
|
1757
|
-
// export type CurvePointsRes<T> = LegacyWeierstrass<T>;
|
|
1758
|
-
// export type CurvePointsType<T> = LegacyWeierstrassOpts<T>;
|
|
1759
|
-
// export type CurvePointsTypeWithLength<T> = LegacyWeierstrassOpts<T>;
|
|
1760
|
-
// export type BasicWCurve<T> = LegacyWeierstrassOpts<T>;
|
|
1761
|
-
|
|
1762
|
-
/** @deprecated use `Uint8Array` */
|
|
1763
|
-
export type PubKey = Hex | WeierstrassPoint<bigint>;
|
|
1764
|
-
export type CurveType = BasicWCurve<bigint> & {
|
|
1765
|
-
hash: CHash; // CHash not FHash because we need outputLen for DRBG
|
|
1766
|
-
hmac?: HmacFnSync;
|
|
1767
|
-
randomBytes?: (bytesLength?: number) => Uint8Array;
|
|
1768
|
-
lowS?: boolean;
|
|
1769
|
-
bits2int?: (bytes: Uint8Array) => bigint;
|
|
1770
|
-
bits2int_modN?: (bytes: Uint8Array) => bigint;
|
|
1771
|
-
};
|
|
1772
|
-
export type CurveFn = {
|
|
1773
|
-
/** @deprecated use `Point.CURVE()` */
|
|
1774
|
-
CURVE: CurvePointsType<bigint>;
|
|
1775
|
-
keygen: ECDSA['keygen'];
|
|
1776
|
-
getPublicKey: ECDSA['getPublicKey'];
|
|
1777
|
-
getSharedSecret: ECDSA['getSharedSecret'];
|
|
1778
|
-
sign: ECDSA['sign'];
|
|
1779
|
-
verify: ECDSA['verify'];
|
|
1780
|
-
Point: WeierstrassPointCons<bigint>;
|
|
1781
|
-
/** @deprecated use `Point` */
|
|
1782
|
-
ProjectivePoint: WeierstrassPointCons<bigint>;
|
|
1783
|
-
Signature: ECDSASignatureCons;
|
|
1784
|
-
utils: ECDSA['utils'];
|
|
1785
|
-
lengths: ECDSA['lengths'];
|
|
1786
|
-
};
|
|
1787
|
-
/** @deprecated use `weierstrass` in newer releases */
|
|
1788
|
-
export function weierstrassPoints<T>(c: CurvePointsTypeWithLength<T>): CurvePointsRes<T> {
|
|
1789
|
-
const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
|
|
1790
|
-
const Point = weierstrassN(CURVE, curveOpts);
|
|
1791
|
-
return _weierstrass_new_output_to_legacy(c, Point);
|
|
1792
|
-
}
|
|
1793
|
-
export type WsPointComposed<T> = {
|
|
1794
|
-
CURVE: WeierstrassOpts<T>;
|
|
1795
|
-
curveOpts: WeierstrassExtraOpts<T>;
|
|
1796
|
-
};
|
|
1797
|
-
export type WsComposed = {
|
|
1798
|
-
/** @deprecated use `Point.CURVE()` */
|
|
1799
|
-
CURVE: WeierstrassOpts<bigint>;
|
|
1800
|
-
hash: CHash;
|
|
1801
|
-
curveOpts: WeierstrassExtraOpts<bigint>;
|
|
1802
|
-
ecdsaOpts: ECDSAOpts;
|
|
1803
|
-
};
|
|
1804
|
-
function _weierstrass_legacy_opts_to_new<T>(c: CurvePointsType<T>): WsPointComposed<T> {
|
|
1805
|
-
const CURVE: WeierstrassOpts<T> = {
|
|
1806
|
-
a: c.a,
|
|
1807
|
-
b: c.b,
|
|
1808
|
-
p: c.Fp.ORDER,
|
|
1809
|
-
n: c.n,
|
|
1810
|
-
h: c.h,
|
|
1811
|
-
Gx: c.Gx,
|
|
1812
|
-
Gy: c.Gy,
|
|
1813
|
-
};
|
|
1814
|
-
const Fp = c.Fp;
|
|
1815
|
-
let allowedLengths = c.allowedPrivateKeyLengths
|
|
1816
|
-
? Array.from(new Set(c.allowedPrivateKeyLengths.map((l) => Math.ceil(l / 2))))
|
|
1817
|
-
: undefined;
|
|
1818
|
-
const Fn = Field(CURVE.n, {
|
|
1819
|
-
BITS: c.nBitLength,
|
|
1820
|
-
allowedLengths: allowedLengths,
|
|
1821
|
-
modFromBytes: c.wrapPrivateKey,
|
|
1822
|
-
});
|
|
1823
|
-
const curveOpts: WeierstrassExtraOpts<T> = {
|
|
1824
|
-
Fp,
|
|
1825
|
-
Fn,
|
|
1826
|
-
allowInfinityPoint: c.allowInfinityPoint,
|
|
1827
|
-
endo: c.endo,
|
|
1828
|
-
isTorsionFree: c.isTorsionFree,
|
|
1829
|
-
clearCofactor: c.clearCofactor,
|
|
1830
|
-
fromBytes: c.fromBytes,
|
|
1831
|
-
toBytes: c.toBytes,
|
|
1832
|
-
};
|
|
1833
|
-
return { CURVE, curveOpts };
|
|
1834
|
-
}
|
|
1835
|
-
function _ecdsa_legacy_opts_to_new(c: CurveType): WsComposed {
|
|
1836
|
-
const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
|
|
1837
|
-
const ecdsaOpts: ECDSAOpts = {
|
|
1838
|
-
hmac: c.hmac,
|
|
1839
|
-
randomBytes: c.randomBytes,
|
|
1840
|
-
lowS: c.lowS,
|
|
1841
|
-
bits2int: c.bits2int,
|
|
1842
|
-
bits2int_modN: c.bits2int_modN,
|
|
1843
|
-
};
|
|
1844
|
-
return { CURVE, curveOpts, hash: c.hash, ecdsaOpts };
|
|
1845
|
-
}
|
|
1846
|
-
export function _legacyHelperEquat<T>(Fp: IField<T>, a: T, b: T): (x: T) => T {
|
|
1847
|
-
/**
|
|
1848
|
-
* y² = x³ + ax + b: Short weierstrass curve formula. Takes x, returns y².
|
|
1849
|
-
* @returns y²
|
|
1850
|
-
*/
|
|
1851
|
-
function weierstrassEquation(x: T): T {
|
|
1852
|
-
const x2 = Fp.sqr(x); // x * x
|
|
1853
|
-
const x3 = Fp.mul(x2, x); // x² * x
|
|
1854
|
-
return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x³ + a * x + b
|
|
1855
|
-
}
|
|
1856
|
-
return weierstrassEquation;
|
|
1857
|
-
}
|
|
1858
|
-
function _weierstrass_new_output_to_legacy<T>(
|
|
1859
|
-
c: CurvePointsType<T>,
|
|
1860
|
-
Point: WeierstrassPointCons<T>
|
|
1861
|
-
): CurvePointsRes<T> {
|
|
1862
|
-
const { Fp, Fn } = Point;
|
|
1863
|
-
function isWithinCurveOrder(num: bigint): boolean {
|
|
1864
|
-
return inRange(num, _1n, Fn.ORDER);
|
|
1865
|
-
}
|
|
1866
|
-
const weierstrassEquation = _legacyHelperEquat(Fp, c.a, c.b);
|
|
1867
|
-
return Object.assign(
|
|
1868
|
-
{},
|
|
1869
|
-
{
|
|
1870
|
-
CURVE: c,
|
|
1871
|
-
Point: Point,
|
|
1872
|
-
ProjectivePoint: Point,
|
|
1873
|
-
normPrivateKeyToScalar: (key: PrivKey) => _normFnElement(Fn, key),
|
|
1874
|
-
weierstrassEquation,
|
|
1875
|
-
isWithinCurveOrder,
|
|
1876
|
-
}
|
|
1877
|
-
);
|
|
1878
|
-
}
|
|
1879
|
-
function _ecdsa_new_output_to_legacy(c: CurveType, _ecdsa: ECDSA): CurveFn {
|
|
1880
|
-
const Point = _ecdsa.Point;
|
|
1881
|
-
return Object.assign({}, _ecdsa, {
|
|
1882
|
-
ProjectivePoint: Point,
|
|
1883
|
-
CURVE: Object.assign({}, c, nLength(Point.Fn.ORDER, Point.Fn.BITS)),
|
|
1884
|
-
});
|
|
1885
|
-
}
|
|
1886
|
-
|
|
1887
|
-
// _ecdsa_legacy
|
|
1888
|
-
export function weierstrass(c: CurveType): CurveFn {
|
|
1889
|
-
const { CURVE, curveOpts, hash, ecdsaOpts } = _ecdsa_legacy_opts_to_new(c);
|
|
1890
|
-
const Point = weierstrassN(CURVE, curveOpts);
|
|
1891
|
-
const signs = ecdsa(Point, hash, ecdsaOpts);
|
|
1892
|
-
return _ecdsa_new_output_to_legacy(c, signs);
|
|
1511
|
+
}) satisfies Signer;
|
|
1893
1512
|
}
|