@noble/curves 0.6.0 → 0.6.2

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 CHANGED
@@ -7,12 +7,11 @@ Minimal, auditable JS implementation of elliptic curve cryptography.
7
7
  - [hash to curve](https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/)
8
8
  for encoding or hashing an arbitrary string to a point on an elliptic curve
9
9
  - [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash
10
- - Auditable
11
10
  - 🏎 [Ultra-fast](#speed), hand-optimized for caveats of JS engines
12
11
  - 🔍 Unique tests ensure correctness. Wycheproof vectors included
13
12
  - 🔻 Tree-shaking-friendly: there is no entry point, which ensures small size of your app
14
13
 
15
- There are two parts of the package:
14
+ Package consists of two parts:
16
15
 
17
16
  1. `abstract/` directory specifies zero-dependency EC algorithms
18
17
  2. root directory utilizes one dependency `@noble/hashes` and provides ready-to-use:
@@ -26,6 +25,7 @@ Curves incorporate work from previous noble packages
26
25
  [ed25519](https://github.com/paulmillr/noble-ed25519),
27
26
  [bls12-381](https://github.com/paulmillr/noble-bls12-381)),
28
27
  which had security audits and were developed from 2019 to 2022.
28
+ Check out [Upgrading](#upgrading) section if you've used them before.
29
29
 
30
30
  ### This library belongs to _noble_ crypto
31
31
 
@@ -329,47 +329,54 @@ The module allows to hash arbitrary strings to elliptic curve points.
329
329
 
330
330
  - `expand_message_xmd` [(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.4.1) produces a uniformly random byte string using a cryptographic hash function H that outputs b bits..
331
331
 
332
- ```ts
333
- function expand_message_xmd(
334
- msg: Uint8Array, DST: Uint8Array, lenInBytes: number, H: CHash
335
- ): Uint8Array;
336
- function expand_message_xof(
337
- msg: Uint8Array, DST: Uint8Array, lenInBytes: number, k: number, H: CHash
338
- ): Uint8Array;
339
- ```
332
+ ```ts
333
+ function expand_message_xmd(
334
+ msg: Uint8Array,
335
+ DST: Uint8Array,
336
+ lenInBytes: number,
337
+ H: CHash
338
+ ): Uint8Array;
339
+ function expand_message_xof(
340
+ msg: Uint8Array,
341
+ DST: Uint8Array,
342
+ lenInBytes: number,
343
+ k: number,
344
+ H: CHash
345
+ ): Uint8Array;
346
+ ```
340
347
 
341
348
  - `hash_to_field(msg, count, options)` [(spec)](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3)
342
- hashes arbitrary-length byte strings to a list of one or more elements of a finite field F.
343
- * `msg` a byte string containing the message to hash
344
- * `count` the number of elements of F to output
345
- * `options` `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`
346
- * Returns `[u_0, ..., u_(count - 1)]`, a list of field elements.
347
-
348
- ```ts
349
- function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][];
350
- type htfOpts = {
351
- // DST: a domain separation tag
352
- // defined in section 2.2.5
353
- DST: string;
354
- // p: the characteristic of F
355
- // where F is a finite field of characteristic p and order q = p^m
356
- p: bigint;
357
- // m: the extension degree of F, m >= 1
358
- // where F is a finite field of characteristic p and order q = p^m
359
- m: number;
360
- // k: the target security level for the suite in bits
361
- // defined in section 5.1
362
- k: number;
363
- // option to use a message that has already been processed by
364
- // expand_message_xmd
365
- expand?: 'xmd' | 'xof';
366
- // Hash functions for: expand_message_xmd is appropriate for use with a
367
- // wide range of hash functions, including SHA-2, SHA-3, BLAKE2, and others.
368
- // BBS+ uses blake2: https://github.com/hyperledger/aries-framework-go/issues/2247
369
- // TODO: verify that hash is shake if expand==='xof' via types
370
- hash: CHash;
371
- };
372
- ```
349
+ hashes arbitrary-length byte strings to a list of one or more elements of a finite field F.
350
+ _ `msg` a byte string containing the message to hash
351
+ _ `count` the number of elements of F to output
352
+ _ `options` `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`
353
+ _ Returns `[u_0, ..., u_(count - 1)]`, a list of field elements.
354
+
355
+ ```ts
356
+ function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][];
357
+ type htfOpts = {
358
+ // DST: a domain separation tag
359
+ // defined in section 2.2.5
360
+ DST: string;
361
+ // p: the characteristic of F
362
+ // where F is a finite field of characteristic p and order q = p^m
363
+ p: bigint;
364
+ // m: the extension degree of F, m >= 1
365
+ // where F is a finite field of characteristic p and order q = p^m
366
+ m: number;
367
+ // k: the target security level for the suite in bits
368
+ // defined in section 5.1
369
+ k: number;
370
+ // option to use a message that has already been processed by
371
+ // expand_message_xmd
372
+ expand?: 'xmd' | 'xof';
373
+ // Hash functions for: expand_message_xmd is appropriate for use with a
374
+ // wide range of hash functions, including SHA-2, SHA-3, BLAKE2, and others.
375
+ // BBS+ uses blake2: https://github.com/hyperledger/aries-framework-go/issues/2247
376
+ // TODO: verify that hash is shake if expand==='xof' via types
377
+ hash: CHash;
378
+ };
379
+ ```
373
380
 
374
381
  ### abstract/poseidon: Poseidon hash
375
382
 
@@ -445,63 +452,94 @@ We consider infrastructure attacks like rogue NPM modules very important; that's
445
452
  Benchmark results on Apple M2 with node v18.10:
446
453
 
447
454
  ```
448
- getPublicKey
449
- secp256k1 x 5,241 ops/sec @ 190μs/op
450
- P256 x 7,993 ops/sec @ 125μs/op
451
- P384 x 3,819 ops/sec @ 261μs/op
452
- P521 x 2,074 ops/sec @ 481μs/op
453
- ed25519 x 8,390 ops/sec @ 119μs/op
454
- ed448 x 3,224 ops/sec @ 310μs/op
455
- sign
456
- secp256k1 x 3,934 ops/sec @ 254μs/op
457
- P256 x 5,327 ops/sec @ 187μs/op
458
- P384 x 2,728 ops/sec @ 366μs/op
459
- P521 x 1,594 ops/sec @ 626μs/op
460
- ed25519 x 4,233 ops/sec @ 236μs/op
461
- ed448 x 1,561 ops/sec @ 640μs/op
462
- verify
463
- secp256k1 x 731 ops/sec @ 1ms/op
464
- P256 x 806 ops/sec @ 1ms/op
465
- P384 x 353 ops/sec @ 2ms/op
466
- P521 x 171 ops/sec @ 5ms/op
467
- ed25519 x 860 ops/sec @ 1ms/op
468
- ed448 x 313 ops/sec @ 3ms/op
469
- getSharedSecret
470
- secp256k1 x 445 ops/sec @ 2ms/op
471
- recoverPublicKey
472
- secp256k1 x 732 ops/sec @ 1ms/op
473
- ==== bls12-381 ====
474
- getPublicKey x 817 ops/sec @ 1ms/op
475
- sign x 50 ops/sec @ 19ms/op
476
- verify x 34 ops/sec @ 28ms/op
477
- pairing x 89 ops/sec @ 11ms/op
478
- ==== stark ====
455
+ secp256k1
456
+ init x 57 ops/sec @ 17ms/op
457
+ getPublicKey x 4,946 ops/sec @ 202μs/op
458
+ sign x 3,914 ops/sec @ 255μs/op
459
+ verify x 682 ops/sec @ 1ms/op
460
+ getSharedSecret x 427 ops/sec @ 2ms/op
461
+ recoverPublicKey x 683 ops/sec @ 1ms/op
462
+ schnorr.sign x 539 ops/sec @ 1ms/op
463
+ schnorr.verify x 716 ops/sec @ 1ms/op
464
+
465
+ P256
466
+ init x 30 ops/sec @ 32ms/op
467
+ getPublicKey x 5,008 ops/sec @ 199μs/op
468
+ sign x 3,970 ops/sec @ 251μs/op
469
+ verify x 515 ops/sec @ 1ms/op
470
+
471
+ P384
472
+ init x 14 ops/sec @ 66ms/op
473
+ getPublicKey x 2,434 ops/sec @ 410μs/op
474
+ sign x 1,942 ops/sec @ 514μs/op
475
+ verify x 206 ops/sec @ 4ms/op
476
+
477
+ P521
478
+ init x 7 ops/sec @ 126ms/op
479
+ getPublicKey x 1,282 ops/sec @ 779μs/op
480
+ sign x 1,077 ops/sec @ 928μs/op
481
+ verify x 110 ops/sec @ 9ms/op
482
+
483
+ ed25519
484
+ init x 37 ops/sec @ 26ms/op
485
+ getPublicKey x 8,147 ops/sec @ 122μs/op
486
+ sign x 3,979 ops/sec @ 251μs/op
487
+ verify x 848 ops/sec @ 1ms/op
488
+
489
+ ed448
490
+ init x 17 ops/sec @ 58ms/op
491
+ getPublicKey x 3,083 ops/sec @ 324μs/op
492
+ sign x 1,473 ops/sec @ 678μs/op
493
+ verify x 323 ops/sec @ 3ms/op
494
+
495
+ bls12-381
496
+ init x 30 ops/sec @ 33ms/op
497
+ getPublicKey x 788 ops/sec @ 1ms/op
498
+ sign x 45 ops/sec @ 21ms/op
499
+ verify x 32 ops/sec @ 30ms/op
500
+ pairing x 88 ops/sec @ 11ms/op
501
+
502
+ stark
503
+ init x 31 ops/sec @ 31ms/op
479
504
  pedersen
480
- old x 85 ops/sec @ 11ms/op
481
- noble x 1,216 ops/sec @ 822μs/op
505
+ ├─old x 84 ops/sec @ 11ms/op
506
+ └─noble x 802 ops/sec @ 1ms/op
507
+ poseidon x 7,466 ops/sec @ 133μs/op
482
508
  verify
483
- old x 302 ops/sec @ 3ms/op
484
- noble x 698 ops/sec @ 1ms/op
509
+ ├─old x 300 ops/sec @ 3ms/op
510
+ └─noble x 474 ops/sec @ 2ms/op
485
511
  ```
486
512
 
487
513
  ## Upgrading
488
514
 
489
- Differences from @noble/secp256k1 1.7:
490
-
491
- 1. Different double() formula (but same addition)
492
- 2. Different sqrt() function
493
- 3. DRBG supports outputLen bigger than outputLen of hmac
494
- 4. Support for different hash functions
495
-
496
- Differences from @noble/ed25519 1.7:
497
-
498
- 1. Variable field element lengths between EDDSA/ECDH:
499
- EDDSA (RFC8032) is 456 bits / 57 bytes, ECDH (RFC7748) is 448 bits / 56 bytes
500
- 2. Different addition formula (doubling is same)
501
- 3. uvRatio differs between curves (half-expected, not only pow fn changes)
502
- 4. Point decompression code is different (unexpected), now using generalized formula
503
- 5. Domain function was no-op for ed25519, but adds some data even with empty context for ed448
504
-
515
+ If you're coming from single-curve noble packages, the following changes need to be kept in mind:
516
+
517
+ - 2d affine (x, y) points have been removed to reduce complexity and improve speed
518
+ - Removed `number` support as a type for private keys. `bigint` is still supported
519
+ - `mod`, `invert` are no longer present in `utils`. Use `@noble/curves/abstract/modular.js` now.
520
+
521
+ Upgrading from @noble/secp256k1 1.7:
522
+
523
+ - Compressed (33-byte) public keys are now returned by default, instead of uncompressed
524
+ - Methods are now synchronous. Setting `secp.utils.hmacSha256` is no longer required
525
+ - `sign()`
526
+ - `der`, `recovered` options were removed
527
+ - `canonical` was renamed to `lowS`
528
+ - Return type is now `{ r: bigint, s: bigint, recovery: number }` instance of `Signature`
529
+ - `verify()`
530
+ - `strict` was renamed to `lowS`
531
+ - `recoverPublicKey()`: moved to sig instance `Signature#recoverPublicKey(msgHash)`
532
+ - `Point` was removed: use `ProjectivePoint` in xyz coordinates
533
+ - `utils`: Many methods were removed, others were moved to `schnorr` namespace
534
+
535
+ Upgrading from @noble/ed25519 1.7:
536
+
537
+ - Methods are now synchronous. Setting `secp.utils.hmacSha256` is no longer required
538
+ - ed25519ph, ed25519ctx
539
+ - `Point` was removed: use `ExtendedPoint` in xyzt coordinates
540
+ - `Signature` was removed
541
+ - `getSharedSecret` was removed: use separate x25519 sub-module
542
+ - `bigint` is no longer allowed in `getPublicKey`, `sign`, `verify`. Reason: ed25519 is LE, can lead to bugs
505
543
 
506
544
  ## Contributing & testing
507
545
 
@@ -18,11 +18,11 @@ export declare function createCurve(curveDef: CurveDef, defHash: CHash): Readonl
18
18
  readonly hEff?: bigint | undefined;
19
19
  readonly Gx: bigint;
20
20
  readonly Gy: bigint;
21
- readonly wrapPrivateKey?: boolean | undefined;
22
21
  readonly allowInfinityPoint?: boolean | undefined;
23
22
  readonly a: bigint;
24
23
  readonly b: bigint;
25
- readonly normalizePrivateKey?: ((key: import("./abstract/utils.js").PrivKey) => import("./abstract/utils.js").PrivKey) | undefined;
24
+ readonly allowedPrivateKeyLengths?: readonly number[] | undefined;
25
+ readonly wrapPrivateKey?: boolean | undefined;
26
26
  readonly endo?: {
27
27
  beta: bigint;
28
28
  splitScalar: (k: bigint) => {
@@ -34,10 +34,10 @@ export declare function createCurve(curveDef: CurveDef, defHash: CHash): Readonl
34
34
  } | undefined;
35
35
  readonly isTorsionFree?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => boolean) | undefined;
36
36
  readonly clearCofactor?: ((c: import("./abstract/weierstrass.js").ProjConstructor<bigint>, point: import("./abstract/weierstrass.js").ProjPointType<bigint>) => import("./abstract/weierstrass.js").ProjPointType<bigint>) | undefined;
37
- lowS: boolean;
38
37
  readonly hash: CHash;
39
38
  readonly hmac: (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array;
40
39
  readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
40
+ lowS: boolean;
41
41
  readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
42
42
  readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
43
43
  }>;
@@ -46,7 +46,7 @@ export declare function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: n
46
46
  f: T;
47
47
  };
48
48
  };
49
- export declare type AbstractCurve<T> = {
49
+ export declare type BasicCurve<T> = {
50
50
  Fp: Field<T>;
51
51
  n: bigint;
52
52
  nBitLength?: number;
@@ -55,10 +55,9 @@ export declare type AbstractCurve<T> = {
55
55
  hEff?: bigint;
56
56
  Gx: T;
57
57
  Gy: T;
58
- wrapPrivateKey?: boolean;
59
58
  allowInfinityPoint?: boolean;
60
59
  };
61
- export declare function validateAbsOpts<FP, T>(curve: AbstractCurve<FP> & T): Readonly<{
60
+ export declare function validateBasic<FP, T>(curve: BasicCurve<FP> & T): Readonly<{
62
61
  readonly nBitLength: number;
63
62
  readonly nByteLength: number;
64
- } & AbstractCurve<FP> & T>;
63
+ } & BasicCurve<FP> & T>;
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateAbsOpts = exports.wNAF = void 0;
3
+ exports.validateBasic = exports.wNAF = void 0;
4
4
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
5
5
  // Abelian group utilities
6
6
  const modular_js_1 = require("./modular.js");
7
+ const utils_js_1 = require("./utils.js");
7
8
  const _0n = BigInt(0);
8
9
  const _1n = BigInt(1);
9
10
  // Elliptic curve multiplication of Point by scalar. Complicated and fragile. Uses wNAF method.
@@ -125,25 +126,18 @@ function wNAF(c, bits) {
125
126
  };
126
127
  }
127
128
  exports.wNAF = wNAF;
128
- function validateAbsOpts(curve) {
129
+ function validateBasic(curve) {
129
130
  (0, modular_js_1.validateField)(curve.Fp);
130
- for (const i of ['n', 'h']) {
131
- const val = curve[i];
132
- if (typeof val !== 'bigint')
133
- throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
134
- }
135
- if (!curve.Fp.isValid(curve.Gx))
136
- throw new Error('Invalid generator X coordinate Fp element');
137
- if (!curve.Fp.isValid(curve.Gy))
138
- throw new Error('Invalid generator Y coordinate Fp element');
139
- for (const i of ['nBitLength', 'nByteLength']) {
140
- const val = curve[i];
141
- if (val === undefined)
142
- continue; // Optional
143
- if (!Number.isSafeInteger(val))
144
- throw new Error(`Invalid param ${i}=${val} (${typeof val})`);
145
- }
131
+ (0, utils_js_1.validateObject)(curve, {
132
+ n: 'bigint',
133
+ h: 'bigint',
134
+ Gx: 'field',
135
+ Gy: 'field',
136
+ }, {
137
+ nBitLength: 'isSafeInteger',
138
+ nByteLength: 'isSafeInteger',
139
+ });
146
140
  // Set defaults
147
141
  return Object.freeze({ ...(0, modular_js_1.nLength)(curve.n, curve.nBitLength), ...curve });
148
142
  }
149
- exports.validateAbsOpts = validateAbsOpts;
143
+ exports.validateBasic = validateBasic;
@@ -1,6 +1,7 @@
1
+ import * as ut from './utils.js';
1
2
  import { FHash, Hex } from './utils.js';
2
- import { Group, GroupConstructor, AbstractCurve, AffinePoint } from './curve.js';
3
- export declare type CurveType = AbstractCurve<bigint> & {
3
+ import { Group, GroupConstructor, BasicCurve, AffinePoint } from './curve.js';
4
+ export declare type CurveType = BasicCurve<bigint> & {
4
5
  a: bigint;
5
6
  d: bigint;
6
7
  hash: FHash;
@@ -23,11 +24,10 @@ declare function validateOpts(curve: CurveType): Readonly<{
23
24
  readonly hEff?: bigint | undefined;
24
25
  readonly Gx: bigint;
25
26
  readonly Gy: bigint;
26
- readonly wrapPrivateKey?: boolean | undefined;
27
27
  readonly allowInfinityPoint?: boolean | undefined;
28
28
  readonly a: bigint;
29
29
  readonly d: bigint;
30
- readonly hash: FHash;
30
+ readonly hash: ut.FHash;
31
31
  readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
32
32
  readonly adjustScalarBytes?: ((bytes: Uint8Array) => Uint8Array) | undefined;
33
33
  readonly domain?: ((data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array) | undefined;
@@ -35,7 +35,7 @@ declare function validateOpts(curve: CurveType): Readonly<{
35
35
  isValid: boolean;
36
36
  value: bigint;
37
37
  }) | undefined;
38
- readonly preHash?: FHash | undefined;
38
+ readonly preHash?: ut.FHash | undefined;
39
39
  readonly mapToCurve?: ((scalar: bigint[]) => AffinePoint<bigint>) | undefined;
40
40
  }>;
41
41
  export interface ExtPointType extends Group<ExtPointType> {
@@ -4,6 +4,7 @@ exports.twistedEdwards = void 0;
4
4
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
5
5
  // Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
6
6
  const modular_js_1 = require("./modular.js");
7
+ const ut = require("./utils.js");
7
8
  const utils_js_1 = require("./utils.js");
8
9
  const curve_js_1 = require("./curve.js");
9
10
  // Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
@@ -12,24 +13,18 @@ const _1n = BigInt(1);
12
13
  const _2n = BigInt(2);
13
14
  const _8n = BigInt(8);
14
15
  function validateOpts(curve) {
15
- const opts = (0, curve_js_1.validateAbsOpts)(curve);
16
- if (typeof opts.hash !== 'function')
17
- throw new Error('Invalid hash function');
18
- for (const i of ['a', 'd']) {
19
- const val = opts[i];
20
- if (typeof val !== 'bigint')
21
- throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
22
- }
23
- for (const fn of ['randomBytes']) {
24
- if (typeof opts[fn] !== 'function')
25
- throw new Error(`Invalid ${fn} function`);
26
- }
27
- for (const fn of ['adjustScalarBytes', 'domain', 'uvRatio', 'mapToCurve']) {
28
- if (opts[fn] === undefined)
29
- continue; // Optional
30
- if (typeof opts[fn] !== 'function')
31
- throw new Error(`Invalid ${fn} function`);
32
- }
16
+ const opts = (0, curve_js_1.validateBasic)(curve);
17
+ ut.validateObject(curve, {
18
+ hash: 'function',
19
+ a: 'bigint',
20
+ d: 'bigint',
21
+ randomBytes: 'function',
22
+ }, {
23
+ adjustScalarBytes: 'function',
24
+ domain: 'function',
25
+ uvRatio: 'function',
26
+ mapToCurve: 'function',
27
+ });
33
28
  // Set defaults
34
29
  return Object.freeze({ ...opts });
35
30
  }
@@ -114,7 +109,30 @@ function twistedEdwards(curveDef) {
114
109
  this._WINDOW_SIZE = windowSize;
115
110
  pointPrecomputes.delete(this);
116
111
  }
117
- assertValidity() { }
112
+ // Not required for fromHex(), which always creates valid points.
113
+ // Could be useful for fromAffine().
114
+ assertValidity() {
115
+ const { a, d } = CURVE;
116
+ if (this.is0())
117
+ throw new Error('bad point: ZERO'); // TODO: optimize, with vars below?
118
+ // Equation in affine coordinates: ax² + y² = 1 + dx²y²
119
+ // Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²
120
+ const { ex: X, ey: Y, ez: Z, et: T } = this;
121
+ const X2 = modP(X * X); // X²
122
+ const Y2 = modP(Y * Y); // Y²
123
+ const Z2 = modP(Z * Z); // Z²
124
+ const Z4 = modP(Z2 * Z2); // Z⁴
125
+ const aX2 = modP(X2 * a); // aX²
126
+ const left = modP(Z2 * modP(aX2 + Y2)); // (aX² + Y²)Z²
127
+ const right = modP(Z4 + modP(d * modP(X2 * Y2))); // Z⁴ + dX²Y²
128
+ if (left !== right)
129
+ throw new Error('bad point: equation left != right (1)');
130
+ // In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T
131
+ const XY = modP(X * Y);
132
+ const ZT = modP(Z * T);
133
+ if (XY !== ZT)
134
+ throw new Error('bad point: equation left != right (2)');
135
+ }
118
136
  // Compare one point to another.
119
137
  equals(other) {
120
138
  isPoint(other);
@@ -264,7 +282,7 @@ function twistedEdwards(curveDef) {
264
282
  const normed = hex.slice(); // copy again, we'll manipulate it
265
283
  const lastByte = hex[len - 1]; // select last byte
266
284
  normed[len - 1] = lastByte & ~0x80; // clear last bit
267
- const y = (0, utils_js_1.bytesToNumberLE)(normed);
285
+ const y = ut.bytesToNumberLE(normed);
268
286
  if (y === _0n) {
269
287
  // y=0 is allowed
270
288
  }
@@ -294,12 +312,12 @@ function twistedEdwards(curveDef) {
294
312
  }
295
313
  toRawBytes() {
296
314
  const { x, y } = this.toAffine();
297
- const bytes = (0, utils_js_1.numberToBytesLE)(y, Fp.BYTES); // each y has 2 x values (x, -y)
315
+ const bytes = ut.numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)
298
316
  bytes[bytes.length - 1] |= x & _1n ? 0x80 : 0; // when compressing, it's enough to store y
299
317
  return bytes; // and use the last byte to encode sign of x
300
318
  }
301
319
  toHex() {
302
- return (0, utils_js_1.bytesToHex)(this.toRawBytes()); // Same as toRawBytes, but returns string.
320
+ return ut.bytesToHex(this.toRawBytes()); // Same as toRawBytes, but returns string.
303
321
  }
304
322
  }
305
323
  Point.BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
@@ -311,7 +329,7 @@ function twistedEdwards(curveDef) {
311
329
  }
312
330
  // Little-endian SHA512 with modulo n
313
331
  function modN_LE(hash) {
314
- return modN((0, utils_js_1.bytesToNumberLE)(hash));
332
+ return modN(ut.bytesToNumberLE(hash));
315
333
  }
316
334
  function isHex(item, err) {
317
335
  if (typeof item !== 'string' && !(item instanceof Uint8Array))
@@ -337,7 +355,7 @@ function twistedEdwards(curveDef) {
337
355
  }
338
356
  // int('LE', SHA512(dom2(F, C) || msgs)) mod N
339
357
  function hashDomainToScalar(context = new Uint8Array(), ...msgs) {
340
- const msg = (0, utils_js_1.concatBytes)(...msgs);
358
+ const msg = ut.concatBytes(...msgs);
341
359
  return modN_LE(cHash(domain(msg, (0, utils_js_1.ensureBytes)(context), !!preHash)));
342
360
  }
343
361
  /** Signs message with privateKey. RFC8032 5.1.6 */
@@ -352,7 +370,7 @@ function twistedEdwards(curveDef) {
352
370
  const k = hashDomainToScalar(context, R, pointBytes, msg); // R || A || PH(M)
353
371
  const s = modN(r + k * scalar); // S = (r + k * s) mod L
354
372
  assertGE0(s); // 0 <= s < l
355
- const res = (0, utils_js_1.concatBytes)(R, (0, utils_js_1.numberToBytesLE)(s, Fp.BYTES));
373
+ const res = ut.concatBytes(R, ut.numberToBytesLE(s, Fp.BYTES));
356
374
  return (0, utils_js_1.ensureBytes)(res, nByteLength * 2); // 64-byte signature
357
375
  }
358
376
  function verify(sig, msg, publicKey, context) {
@@ -365,7 +383,7 @@ function twistedEdwards(curveDef) {
365
383
  msg = preHash(msg); // for ed25519ph, etc
366
384
  const A = Point.fromHex(publicKey, false); // Check for s bounds, hex validity
367
385
  const R = Point.fromHex(sig.slice(0, len), false); // 0 <= R < 2^256: ZIP215 R can be >= P
368
- const s = (0, utils_js_1.bytesToNumberLE)(sig.slice(len, 2 * len)); // 0 <= s < l
386
+ const s = ut.bytesToNumberLE(sig.slice(len, 2 * len)); // 0 <= s < l
369
387
  const SB = G.multiplyUnsafe(s);
370
388
  const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
371
389
  const RkA = R.add(A.multiplyUnsafe(k));
@@ -20,7 +20,7 @@ function validateOpts(opts) {
20
20
  exports.validateOpts = validateOpts;
21
21
  function stringToBytes(str) {
22
22
  if (typeof str !== 'string') {
23
- throw new TypeError(`utf8ToBytes expected string, got ${typeof str}`);
23
+ throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
24
24
  }
25
25
  return new TextEncoder().encode(str);
26
26
  }
@@ -42,7 +42,7 @@ export interface Field<T> {
42
42
  fromBytes(bytes: Uint8Array): T;
43
43
  cmov(a: T, b: T, c: boolean): T;
44
44
  }
45
- export declare function validateField<T>(field: Field<T>): void;
45
+ export declare function validateField<T>(field: Field<T>): Field<T>;
46
46
  export declare function FpPow<T>(f: Field<T>, num: T, power: bigint): T;
47
47
  export declare function FpInvertBatch<T>(f: Field<T>, nums: T[]): T[];
48
48
  export declare function FpDiv<T>(f: Field<T>, lhs: T, rhs: T | bigint): T;
@@ -39,7 +39,6 @@ function pow(num, power, modulo) {
39
39
  }
40
40
  exports.pow = pow;
41
41
  // Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)
42
- // TODO: Fp version?
43
42
  function pow2(x, power, modulo) {
44
43
  let res = x;
45
44
  while (power-- > _0n) {
@@ -203,18 +202,17 @@ const FIELD_FIELDS = [
203
202
  'addN', 'subN', 'mulN', 'sqrN'
204
203
  ];
205
204
  function validateField(field) {
206
- for (const i of ['ORDER', 'MASK']) {
207
- if (typeof field[i] !== 'bigint')
208
- throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
209
- }
210
- for (const i of ['BYTES', 'BITS']) {
211
- if (typeof field[i] !== 'number')
212
- throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
213
- }
214
- for (const i of FIELD_FIELDS) {
215
- if (typeof field[i] !== 'function')
216
- throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
217
- }
205
+ const initial = {
206
+ ORDER: 'bigint',
207
+ MASK: 'bigint',
208
+ BYTES: 'isSafeInteger',
209
+ BITS: 'isSafeInteger',
210
+ };
211
+ const opts = FIELD_FIELDS.reduce((map, val) => {
212
+ map[val] = 'function';
213
+ return map;
214
+ }, initial);
215
+ return (0, utils_js_1.validateObject)(field, opts);
218
216
  }
219
217
  exports.validateField = validateField;
220
218
  // Generic field functions