@noble/curves 0.6.0 → 0.6.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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.bitMask = exports.bitSet = exports.bitGet = exports.bitLen = exports.equalBytes = exports.concatBytes = exports.ensureBytes = exports.numberToVarBytesBE = exports.numberToBytesLE = exports.numberToBytesBE = exports.bytesToNumberLE = exports.bytesToNumberBE = exports.hexToBytes = exports.hexToNumber = exports.numberToHexUnpadded = exports.bytesToHex = void 0;
3
+ exports.validateObject = exports.bitMask = exports.bitSet = exports.bitGet = exports.bitLen = exports.equalBytes = exports.concatBytes = exports.ensureBytes = exports.numberToVarBytesBE = exports.numberToBytesLE = exports.numberToBytesBE = exports.bytesToNumberLE = exports.bytesToNumberBE = exports.hexToBytes = exports.hexToNumber = exports.numberToHexUnpadded = exports.bytesToHex = void 0;
4
4
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
5
5
  const _0n = BigInt(0);
6
6
  const _1n = BigInt(1);
@@ -9,7 +9,7 @@ const u8a = (a) => a instanceof Uint8Array;
9
9
  const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
10
10
  function bytesToHex(bytes) {
11
11
  if (!u8a(bytes))
12
- throw new Error('Expected Uint8Array');
12
+ throw new Error('Uint8Array expected');
13
13
  // pre-caching improves the speed 6x
14
14
  let hex = '';
15
15
  for (let i = 0; i < bytes.length; i++) {
@@ -25,7 +25,7 @@ function numberToHexUnpadded(num) {
25
25
  exports.numberToHexUnpadded = numberToHexUnpadded;
26
26
  function hexToNumber(hex) {
27
27
  if (typeof hex !== 'string')
28
- throw new Error('hexToNumber: expected string, got ' + typeof hex);
28
+ throw new Error('string expected, got ' + typeof hex);
29
29
  // Big Endian
30
30
  return BigInt(`0x${hex}`);
31
31
  }
@@ -33,16 +33,16 @@ exports.hexToNumber = hexToNumber;
33
33
  // Caching slows it down 2-3x
34
34
  function hexToBytes(hex) {
35
35
  if (typeof hex !== 'string')
36
- throw new Error('hexToBytes: expected string, got ' + typeof hex);
36
+ throw new Error('string expected, got ' + typeof hex);
37
37
  if (hex.length % 2)
38
- throw new Error('hexToBytes: received invalid unpadded hex ' + hex.length);
38
+ throw new Error('hex string is invalid: unpadded ' + hex.length);
39
39
  const array = new Uint8Array(hex.length / 2);
40
40
  for (let i = 0; i < array.length; i++) {
41
41
  const j = i * 2;
42
42
  const hexByte = hex.slice(j, j + 2);
43
43
  const byte = Number.parseInt(hexByte, 16);
44
44
  if (Number.isNaN(byte) || byte < 0)
45
- throw new Error('Invalid byte sequence');
45
+ throw new Error('invalid byte sequence');
46
46
  array[i] = byte;
47
47
  }
48
48
  return array;
@@ -55,7 +55,7 @@ function bytesToNumberBE(bytes) {
55
55
  exports.bytesToNumberBE = bytesToNumberBE;
56
56
  function bytesToNumberLE(bytes) {
57
57
  if (!u8a(bytes))
58
- throw new Error('Expected Uint8Array');
58
+ throw new Error('Uint8Array expected');
59
59
  return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
60
60
  }
61
61
  exports.bytesToNumberLE = bytesToNumberLE;
@@ -64,12 +64,7 @@ exports.numberToBytesBE = numberToBytesBE;
64
64
  const numberToBytesLE = (n, len) => (0, exports.numberToBytesBE)(n, len).reverse();
65
65
  exports.numberToBytesLE = numberToBytesLE;
66
66
  // Returns variable number bytes (minimal bigint encoding?)
67
- const numberToVarBytesBE = (n) => {
68
- let hex = n.toString(16);
69
- if (hex.length & 1)
70
- hex = '0' + hex;
71
- return hexToBytes(hex);
72
- };
67
+ const numberToVarBytesBE = (n) => hexToBytes(numberToHexUnpadded(n));
73
68
  exports.numberToVarBytesBE = numberToVarBytesBE;
74
69
  function ensureBytes(hex, expectedLength) {
75
70
  // Uint8Array.from() instead of hash.slice() because node.js Buffer
@@ -81,19 +76,16 @@ function ensureBytes(hex, expectedLength) {
81
76
  }
82
77
  exports.ensureBytes = ensureBytes;
83
78
  // Copies several Uint8Arrays into one.
84
- function concatBytes(...arrays) {
85
- if (!arrays.every((b) => u8a(b)))
86
- throw new Error('Uint8Array list expected');
87
- if (arrays.length === 1)
88
- return arrays[0];
89
- const length = arrays.reduce((a, arr) => a + arr.length, 0);
90
- const result = new Uint8Array(length);
91
- for (let i = 0, pad = 0; i < arrays.length; i++) {
92
- const arr = arrays[i];
93
- result.set(arr, pad);
94
- pad += arr.length;
95
- }
96
- return result;
79
+ function concatBytes(...arrs) {
80
+ const r = new Uint8Array(arrs.reduce((sum, a) => sum + a.length, 0));
81
+ let pad = 0; // walk through each item, ensure they have proper type
82
+ arrs.forEach((a) => {
83
+ if (!u8a(a))
84
+ throw new Error('Uint8Array expected');
85
+ r.set(a, pad);
86
+ pad += a.length;
87
+ });
88
+ return r;
97
89
  }
98
90
  exports.concatBytes = concatBytes;
99
91
  function equalBytes(b1, b2) {
@@ -126,3 +118,33 @@ exports.bitSet = bitSet;
126
118
  // Not using ** operator with bigints for old engines.
127
119
  const bitMask = (n) => (_2n << BigInt(n - 1)) - _1n;
128
120
  exports.bitMask = bitMask;
121
+ function validateObject(object, validators, optValidators = {}) {
122
+ const validatorFns = {
123
+ bigint: (val) => typeof val === 'bigint',
124
+ function: (val) => typeof val === 'function',
125
+ boolean: (val) => typeof val === 'boolean',
126
+ string: (val) => typeof val === 'string',
127
+ isSafeInteger: (val) => Number.isSafeInteger(val),
128
+ array: (val) => Array.isArray(val),
129
+ field: (val) => object.Fp.isValid(val),
130
+ hash: (val) => typeof val === 'function' && Number.isSafeInteger(val.outputLen),
131
+ };
132
+ // type Key = keyof typeof validators;
133
+ const checkField = (fieldName, type, isOptional) => {
134
+ const checkVal = validatorFns[type];
135
+ if (typeof checkVal !== 'function')
136
+ throw new Error(`Invalid validator "${type}", expected function`);
137
+ const val = object[fieldName];
138
+ if (isOptional && val === undefined)
139
+ return;
140
+ if (!checkVal(val)) {
141
+ throw new Error(`Invalid param ${fieldName}=${val} (${typeof val}), expected ${type}`);
142
+ }
143
+ };
144
+ for (let [fieldName, type] of Object.entries(validators))
145
+ checkField(fieldName, type, false);
146
+ for (let [fieldName, type] of Object.entries(optValidators))
147
+ checkField(fieldName, type, true);
148
+ return object;
149
+ }
150
+ exports.validateObject = validateObject;
@@ -1,8 +1,8 @@
1
1
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
2
  import * as mod from './modular.js';
3
3
  import * as ut from './utils.js';
4
- import { Hex, PrivKey, CHash } from './utils.js';
5
- import { Group, GroupConstructor, AbstractCurve, AffinePoint } from './curve.js';
4
+ import { CHash, Hex, PrivKey } from './utils.js';
5
+ import { Group, GroupConstructor, BasicCurve, AffinePoint } from './curve.js';
6
6
  export type { AffinePoint };
7
7
  declare type HmacFnSync = (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array;
8
8
  declare type EndomorphismOpts = {
@@ -14,10 +14,10 @@ declare type EndomorphismOpts = {
14
14
  k2: bigint;
15
15
  };
16
16
  };
17
- export declare type BasicCurve<T> = AbstractCurve<T> & {
17
+ export declare type BasicWCurve<T> = BasicCurve<T> & {
18
18
  a: T;
19
19
  b: T;
20
- normalizePrivateKey?: (key: PrivKey) => PrivKey;
20
+ allowedPrivateKeyLengths?: readonly number[];
21
21
  wrapPrivateKey?: boolean;
22
22
  endo?: EndomorphismOpts;
23
23
  isTorsionFree?: (c: ProjConstructor<T>, point: ProjPointType<T>) => boolean;
@@ -77,7 +77,7 @@ export interface ProjConstructor<T> extends GroupConstructor<ProjPointType<T>> {
77
77
  fromPrivateKey(privateKey: PrivKey): ProjPointType<T>;
78
78
  normalizeZ(points: ProjPointType<T>[]): ProjPointType<T>[];
79
79
  }
80
- export declare type CurvePointsType<T> = BasicCurve<T> & {
80
+ export declare type CurvePointsType<T> = BasicWCurve<T> & {
81
81
  fromBytes: (bytes: Uint8Array) => AffinePoint<T>;
82
82
  toBytes: (c: ProjConstructor<T>, point: ProjPointType<T>, compressed: boolean) => Uint8Array;
83
83
  };
@@ -117,11 +117,11 @@ declare type SignatureLike = {
117
117
  s: bigint;
118
118
  };
119
119
  export declare type PubKey = Hex | ProjPointType<bigint>;
120
- export declare type CurveType = BasicCurve<bigint> & {
121
- lowS?: boolean;
120
+ export declare type CurveType = BasicWCurve<bigint> & {
122
121
  hash: CHash;
123
122
  hmac: HmacFnSync;
124
123
  randomBytes: (bytesLength?: number) => Uint8Array;
124
+ lowS?: boolean;
125
125
  bits2int?: (bytes: Uint8Array) => bigint;
126
126
  bits2int_modN?: (bytes: Uint8Array) => bigint;
127
127
  };
@@ -134,18 +134,18 @@ declare function validateOpts(curve: CurveType): Readonly<{
134
134
  readonly hEff?: bigint | undefined;
135
135
  readonly Gx: bigint;
136
136
  readonly Gy: bigint;
137
- readonly wrapPrivateKey?: boolean | undefined;
138
137
  readonly allowInfinityPoint?: boolean | undefined;
139
138
  readonly a: bigint;
140
139
  readonly b: bigint;
141
- readonly normalizePrivateKey?: ((key: ut.PrivKey) => ut.PrivKey) | undefined;
140
+ readonly allowedPrivateKeyLengths?: readonly number[] | undefined;
141
+ readonly wrapPrivateKey?: boolean | undefined;
142
142
  readonly endo?: EndomorphismOpts | undefined;
143
143
  readonly isTorsionFree?: ((c: ProjConstructor<bigint>, point: ProjPointType<bigint>) => boolean) | undefined;
144
144
  readonly clearCofactor?: ((c: ProjConstructor<bigint>, point: ProjPointType<bigint>) => ProjPointType<bigint>) | undefined;
145
- lowS: boolean;
146
145
  readonly hash: ut.CHash;
147
146
  readonly hmac: HmacFnSync;
148
147
  readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
148
+ lowS: boolean;
149
149
  readonly bits2int?: ((bytes: Uint8Array) => bigint) | undefined;
150
150
  readonly bits2int_modN?: ((bytes: Uint8Array) => bigint) | undefined;
151
151
  }>;
@@ -8,21 +8,21 @@ const ut = require("./utils.js");
8
8
  const utils_js_1 = require("./utils.js");
9
9
  const curve_js_1 = require("./curve.js");
10
10
  function validatePointOpts(curve) {
11
- const opts = (0, curve_js_1.validateAbsOpts)(curve);
12
- const Fp = opts.Fp;
13
- for (const i of ['a', 'b']) {
14
- if (!Fp.isValid(curve[i]))
15
- throw new Error(`Invalid curve param ${i}=${opts[i]} (${typeof opts[i]})`);
16
- }
17
- for (const i of ['isTorsionFree', 'clearCofactor']) {
18
- if (curve[i] === undefined)
19
- continue; // Optional
20
- if (typeof curve[i] !== 'function')
21
- throw new Error(`Invalid ${i} function`);
22
- }
23
- const endo = opts.endo;
11
+ const opts = (0, curve_js_1.validateBasic)(curve);
12
+ ut.validateObject(opts, {
13
+ a: 'field',
14
+ b: 'field',
15
+ fromBytes: 'function',
16
+ toBytes: 'function',
17
+ }, {
18
+ allowedPrivateKeyLengths: 'array',
19
+ wrapPrivateKey: 'boolean',
20
+ isTorsionFree: 'function',
21
+ clearCofactor: 'function',
22
+ });
23
+ const { endo, Fp, a } = opts;
24
24
  if (endo) {
25
- if (!Fp.eql(opts.a, Fp.ZERO)) {
25
+ if (!Fp.eql(a, Fp.ZERO)) {
26
26
  throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');
27
27
  }
28
28
  if (typeof endo !== 'object' ||
@@ -31,11 +31,6 @@ function validatePointOpts(curve) {
31
31
  throw new Error('Expected endomorphism with beta: bigint and splitScalar: function');
32
32
  }
33
33
  }
34
- if (typeof opts.fromBytes !== 'function')
35
- throw new Error('Invalid fromBytes function');
36
- if (typeof opts.toBytes !== 'function')
37
- throw new Error('Invalid fromBytes function');
38
- // Set defaults
39
34
  return Object.freeze({ ...opts });
40
35
  }
41
36
  // ASN.1 DER encoding utilities
@@ -116,39 +111,28 @@ function weierstrassPoints(opts) {
116
111
  if (!isWithinCurveOrder(num))
117
112
  throw new Error('Expected valid bigint: 0 < bigint < curve.n');
118
113
  }
119
- /**
120
- * Validates if a private key is valid and converts it to bigint form.
121
- * Supports two options, that are passed when CURVE is initialized:
122
- * - `normalizePrivateKey()` executed before all checks
123
- * - `wrapPrivateKey` when true, executed after most checks, but before `0 < key < n`
124
- */
114
+ // Validates if priv key is valid and converts it to bigint.
115
+ // Supports options CURVE.normalizePrivateKey and CURVE.wrapPrivateKey.
125
116
  function normalizePrivateKey(key) {
126
- const { normalizePrivateKey: custom, nByteLength: groupLen, wrapPrivateKey, n } = CURVE;
127
- if (typeof custom === 'function')
128
- key = custom(key);
129
- let num;
130
- if (typeof key === 'bigint') {
131
- // Curve order check is done below
132
- num = key;
117
+ const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
118
+ if (lengths && typeof key !== 'bigint') {
119
+ if (key instanceof Uint8Array)
120
+ key = ut.bytesToHex(key);
121
+ // Normalize to hex string, pad. E.g. P521 would norm 130-132 char hex to 132-char bytes
122
+ if (typeof key !== 'string' || !lengths.includes(key.length))
123
+ throw new Error('Invalid key');
124
+ key = key.padStart(nByteLength * 2, '0');
133
125
  }
134
- else if (typeof key === 'string') {
135
- if (key.length !== 2 * groupLen)
136
- throw new Error(`must be ${groupLen} bytes`);
137
- // Validates individual octets
138
- num = ut.bytesToNumberBE((0, utils_js_1.ensureBytes)(key));
139
- }
140
- else if (key instanceof Uint8Array) {
141
- if (key.length !== groupLen)
142
- throw new Error(`must be ${groupLen} bytes`);
143
- num = ut.bytesToNumberBE(key);
126
+ let num;
127
+ try {
128
+ num = typeof key === 'bigint' ? key : ut.bytesToNumberBE((0, utils_js_1.ensureBytes)(key, nByteLength));
144
129
  }
145
- else {
146
- throw new Error('private key must be bytes, hex or bigint, not ' + typeof key);
130
+ catch (error) {
131
+ throw new Error(`private key must be ${nByteLength} bytes, hex or bigint, not ${typeof key}`);
147
132
  }
148
- // Useful for curves with cofactor != 1
149
133
  if (wrapPrivateKey)
150
- num = mod.mod(num, n);
151
- assertGE(num);
134
+ num = mod.mod(num, n); // disabled by default, enabled for BLS
135
+ assertGE(num); // num in range [1..N-1]
152
136
  return num;
153
137
  }
154
138
  const pointPrecomputes = new Map();
@@ -503,14 +487,16 @@ function weierstrassPoints(opts) {
503
487
  }
504
488
  exports.weierstrassPoints = weierstrassPoints;
505
489
  function validateOpts(curve) {
506
- const opts = (0, curve_js_1.validateAbsOpts)(curve);
507
- if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
508
- throw new Error('Invalid hash function');
509
- if (typeof opts.hmac !== 'function')
510
- throw new Error('Invalid hmac function');
511
- if (typeof opts.randomBytes !== 'function')
512
- throw new Error('Invalid randomBytes function');
513
- // Set defaults
490
+ const opts = (0, curve_js_1.validateBasic)(curve);
491
+ ut.validateObject(opts, {
492
+ hash: 'hash',
493
+ hmac: 'function',
494
+ randomBytes: 'function',
495
+ }, {
496
+ bits2int: 'function',
497
+ bits2int_modN: 'function',
498
+ lowS: 'boolean',
499
+ });
514
500
  return Object.freeze({ lowS: true, ...opts });
515
501
  }
516
502
  const u8n = (data) => new Uint8Array(data); // creates Uint8Array
@@ -619,7 +605,7 @@ function weierstrass(curveDef) {
619
605
  return { x, y };
620
606
  }
621
607
  else {
622
- throw new Error(`Point.fromHex: received invalid point. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes, not ${len}`);
608
+ throw new Error(`Point of length ${len} was invalid. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes`);
623
609
  }
624
610
  },
625
611
  });
@@ -681,7 +667,7 @@ function weierstrass(curveDef) {
681
667
  const ir = invN(radj); // r^-1
682
668
  const u1 = modN(-h * ir); // -hr^-1
683
669
  const u2 = modN(s * ir); // sr^-1
684
- const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
670
+ const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
685
671
  if (!Q)
686
672
  throw new Error('point at infinify'); // unsafe is fine: no priv data leaked
687
673
  Q.assertValidity();
@@ -804,9 +790,10 @@ function weierstrass(curveDef) {
804
790
  const ORDER_MASK = ut.bitMask(CURVE.nBitLength);
805
791
  function int2octets(num) {
806
792
  if (typeof num !== 'bigint')
807
- throw new Error('Expected bigint');
793
+ throw new Error('bigint expected');
808
794
  if (!(_0n <= num && num < ORDER_MASK))
809
- throw new Error(`Expected number < 2^${CURVE.nBitLength}`);
795
+ // n in [0..ORDER_MASK-1]
796
+ throw new Error(`bigint expected < 2^${CURVE.nBitLength}`);
810
797
  // works with order, can have different size than numToField!
811
798
  return ut.numberToBytesBE(num, CURVE.nByteLength);
812
799
  }
@@ -816,6 +803,7 @@ function weierstrass(curveDef) {
816
803
  // NOTE: we cannot assume here that msgHash has same amount of bytes as curve order, this will be wrong at least for P521.
817
804
  // Also it can be bigger for P224 + SHA256
818
805
  function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
806
+ const { hash, randomBytes } = CURVE;
819
807
  if (msgHash == null)
820
808
  throw new Error(`sign: expected valid message hash, not "${msgHash}"`);
821
809
  if (['recovered', 'canonical'].some((k) => k in opts))
@@ -823,28 +811,20 @@ function weierstrass(curveDef) {
823
811
  throw new Error('sign() legacy options not supported');
824
812
  let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
825
813
  if (prehash)
826
- msgHash = CURVE.hash((0, utils_js_1.ensureBytes)(msgHash));
814
+ msgHash = hash((0, utils_js_1.ensureBytes)(msgHash));
827
815
  if (lowS == null)
828
- lowS = true; // RFC6979 3.2: we skip step A, because
829
- // Step A is ignored, since we already provide hash instead of msg
830
- // NOTE: instead of bits2int, we calling here truncateHash, since we need
831
- // custom truncation for stark. For other curves it is essentially same as calling bits2int + mod
832
- // However, we cannot later call bits2octets (which is truncateHash + int2octets), since nested bits2int is broken
833
- // for curves where nBitLength % 8 !== 0, so we unwrap it here as int2octets call.
834
- // const bits2octets = (bits)=>int2octets(bytesToNumberBE(truncateHash(bits)))
816
+ lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash
817
+ // We can't later call bits2octets, since nested bits2int is broken for curves
818
+ // with nBitLength % 8 !== 0. Because of that, we unwrap it here as int2octets call.
819
+ // const bits2octets = (bits) => int2octets(bits2int_modN(bits))
835
820
  const h1int = bits2int_modN((0, utils_js_1.ensureBytes)(msgHash));
836
- const h1octets = int2octets(h1int);
837
- const d = normalizePrivateKey(privateKey);
838
- // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
839
- const seedArgs = [int2octets(d), h1octets];
821
+ const d = normalizePrivateKey(privateKey); // validate private key, convert to bigint
822
+ const seedArgs = [int2octets(d), int2octets(h1int)];
823
+ // extraEntropy. RFC6979 3.6: additional k' (optional).
840
824
  if (ent != null) {
841
- // RFC6979 3.6: additional k' (optional)
842
- if (ent === true)
843
- ent = CURVE.randomBytes(Fp.BYTES);
844
- const e = (0, utils_js_1.ensureBytes)(ent);
845
- if (e.length !== Fp.BYTES)
846
- throw new Error(`sign: Expected ${Fp.BYTES} bytes of extra data`);
847
- seedArgs.push(e);
825
+ // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
826
+ // Either pass as-is, or generate random bytes. Then validate for being ui8a of size BYTES
827
+ seedArgs.push((0, utils_js_1.ensureBytes)(ent === true ? randomBytes(Fp.BYTES) : ent, Fp.BYTES));
848
828
  }
849
829
  const seed = ut.concatBytes(...seedArgs); // Step D of RFC6979 3.2
850
830
  const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
@@ -954,7 +934,6 @@ function weierstrass(curveDef) {
954
934
  getSharedSecret,
955
935
  sign,
956
936
  verify,
957
- // Point,
958
937
  ProjectivePoint: Point,
959
938
  Signature,
960
939
  utils,
@@ -1,6 +1,7 @@
1
1
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
2
  // Abelian group utilities
3
3
  import { validateField, nLength } from './modular.js';
4
+ import { validateObject } from './utils.js';
4
5
  const _0n = BigInt(0);
5
6
  const _1n = BigInt(1);
6
7
  // Elliptic curve multiplication of Point by scalar. Complicated and fragile. Uses wNAF method.
@@ -121,24 +122,17 @@ export function wNAF(c, bits) {
121
122
  },
122
123
  };
123
124
  }
124
- export function validateAbsOpts(curve) {
125
+ export function validateBasic(curve) {
125
126
  validateField(curve.Fp);
126
- for (const i of ['n', 'h']) {
127
- const val = curve[i];
128
- if (typeof val !== 'bigint')
129
- throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
130
- }
131
- if (!curve.Fp.isValid(curve.Gx))
132
- throw new Error('Invalid generator X coordinate Fp element');
133
- if (!curve.Fp.isValid(curve.Gy))
134
- throw new Error('Invalid generator Y coordinate Fp element');
135
- for (const i of ['nBitLength', 'nByteLength']) {
136
- const val = curve[i];
137
- if (val === undefined)
138
- continue; // Optional
139
- if (!Number.isSafeInteger(val))
140
- throw new Error(`Invalid param ${i}=${val} (${typeof val})`);
141
- }
127
+ validateObject(curve, {
128
+ n: 'bigint',
129
+ h: 'bigint',
130
+ Gx: 'field',
131
+ Gy: 'field',
132
+ }, {
133
+ nBitLength: 'isSafeInteger',
134
+ nByteLength: 'isSafeInteger',
135
+ });
142
136
  // Set defaults
143
137
  return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve });
144
138
  }
@@ -1,32 +1,27 @@
1
1
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
2
  // Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
3
3
  import { mod } from './modular.js';
4
- import { bytesToHex, bytesToNumberLE, concatBytes, ensureBytes, numberToBytesLE, } from './utils.js';
5
- import { wNAF, validateAbsOpts, } from './curve.js';
4
+ import * as ut from './utils.js';
5
+ import { ensureBytes } from './utils.js';
6
+ import { wNAF, validateBasic } from './curve.js';
6
7
  // Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
7
8
  const _0n = BigInt(0);
8
9
  const _1n = BigInt(1);
9
10
  const _2n = BigInt(2);
10
11
  const _8n = BigInt(8);
11
12
  function validateOpts(curve) {
12
- const opts = validateAbsOpts(curve);
13
- if (typeof opts.hash !== 'function')
14
- throw new Error('Invalid hash function');
15
- for (const i of ['a', 'd']) {
16
- const val = opts[i];
17
- if (typeof val !== 'bigint')
18
- throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
19
- }
20
- for (const fn of ['randomBytes']) {
21
- if (typeof opts[fn] !== 'function')
22
- throw new Error(`Invalid ${fn} function`);
23
- }
24
- for (const fn of ['adjustScalarBytes', 'domain', 'uvRatio', 'mapToCurve']) {
25
- if (opts[fn] === undefined)
26
- continue; // Optional
27
- if (typeof opts[fn] !== 'function')
28
- throw new Error(`Invalid ${fn} function`);
29
- }
13
+ const opts = validateBasic(curve);
14
+ ut.validateObject(curve, {
15
+ hash: 'function',
16
+ a: 'bigint',
17
+ d: 'bigint',
18
+ randomBytes: 'function',
19
+ }, {
20
+ adjustScalarBytes: 'function',
21
+ domain: 'function',
22
+ uvRatio: 'function',
23
+ mapToCurve: 'function',
24
+ });
30
25
  // Set defaults
31
26
  return Object.freeze({ ...opts });
32
27
  }
@@ -261,7 +256,7 @@ export function twistedEdwards(curveDef) {
261
256
  const normed = hex.slice(); // copy again, we'll manipulate it
262
257
  const lastByte = hex[len - 1]; // select last byte
263
258
  normed[len - 1] = lastByte & ~0x80; // clear last bit
264
- const y = bytesToNumberLE(normed);
259
+ const y = ut.bytesToNumberLE(normed);
265
260
  if (y === _0n) {
266
261
  // y=0 is allowed
267
262
  }
@@ -291,12 +286,12 @@ export function twistedEdwards(curveDef) {
291
286
  }
292
287
  toRawBytes() {
293
288
  const { x, y } = this.toAffine();
294
- const bytes = numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)
289
+ const bytes = ut.numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)
295
290
  bytes[bytes.length - 1] |= x & _1n ? 0x80 : 0; // when compressing, it's enough to store y
296
291
  return bytes; // and use the last byte to encode sign of x
297
292
  }
298
293
  toHex() {
299
- return bytesToHex(this.toRawBytes()); // Same as toRawBytes, but returns string.
294
+ return ut.bytesToHex(this.toRawBytes()); // Same as toRawBytes, but returns string.
300
295
  }
301
296
  }
302
297
  Point.BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
@@ -308,7 +303,7 @@ export function twistedEdwards(curveDef) {
308
303
  }
309
304
  // Little-endian SHA512 with modulo n
310
305
  function modN_LE(hash) {
311
- return modN(bytesToNumberLE(hash));
306
+ return modN(ut.bytesToNumberLE(hash));
312
307
  }
313
308
  function isHex(item, err) {
314
309
  if (typeof item !== 'string' && !(item instanceof Uint8Array))
@@ -334,7 +329,7 @@ export function twistedEdwards(curveDef) {
334
329
  }
335
330
  // int('LE', SHA512(dom2(F, C) || msgs)) mod N
336
331
  function hashDomainToScalar(context = new Uint8Array(), ...msgs) {
337
- const msg = concatBytes(...msgs);
332
+ const msg = ut.concatBytes(...msgs);
338
333
  return modN_LE(cHash(domain(msg, ensureBytes(context), !!preHash)));
339
334
  }
340
335
  /** Signs message with privateKey. RFC8032 5.1.6 */
@@ -349,7 +344,7 @@ export function twistedEdwards(curveDef) {
349
344
  const k = hashDomainToScalar(context, R, pointBytes, msg); // R || A || PH(M)
350
345
  const s = modN(r + k * scalar); // S = (r + k * s) mod L
351
346
  assertGE0(s); // 0 <= s < l
352
- const res = concatBytes(R, numberToBytesLE(s, Fp.BYTES));
347
+ const res = ut.concatBytes(R, ut.numberToBytesLE(s, Fp.BYTES));
353
348
  return ensureBytes(res, nByteLength * 2); // 64-byte signature
354
349
  }
355
350
  function verify(sig, msg, publicKey, context) {
@@ -362,7 +357,7 @@ export function twistedEdwards(curveDef) {
362
357
  msg = preHash(msg); // for ed25519ph, etc
363
358
  const A = Point.fromHex(publicKey, false); // Check for s bounds, hex validity
364
359
  const R = Point.fromHex(sig.slice(0, len), false); // 0 <= R < 2^256: ZIP215 R can be >= P
365
- const s = bytesToNumberLE(sig.slice(len, 2 * len)); // 0 <= s < l
360
+ const s = ut.bytesToNumberLE(sig.slice(len, 2 * len)); // 0 <= s < l
366
361
  const SB = G.multiplyUnsafe(s);
367
362
  const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
368
363
  const RkA = R.add(A.multiplyUnsafe(k));
@@ -16,7 +16,7 @@ export function validateOpts(opts) {
16
16
  }
17
17
  export function stringToBytes(str) {
18
18
  if (typeof str !== 'string') {
19
- throw new TypeError(`utf8ToBytes expected string, got ${typeof str}`);
19
+ throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
20
20
  }
21
21
  return new TextEncoder().encode(str);
22
22
  }
@@ -1,6 +1,6 @@
1
1
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
2
  // Utilities for modular arithmetics and finite fields
3
- import { bitMask, numberToBytesBE, numberToBytesLE, bytesToNumberBE, bytesToNumberLE, ensureBytes, } from './utils.js';
3
+ import { bitMask, numberToBytesBE, numberToBytesLE, bytesToNumberBE, bytesToNumberLE, ensureBytes, validateObject, } from './utils.js';
4
4
  // prettier-ignore
5
5
  const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
6
6
  // prettier-ignore
@@ -34,7 +34,6 @@ export function pow(num, power, modulo) {
34
34
  return res;
35
35
  }
36
36
  // Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)
37
- // TODO: Fp version?
38
37
  export function pow2(x, power, modulo) {
39
38
  let res = x;
40
39
  while (power-- > _0n) {
@@ -193,18 +192,17 @@ const FIELD_FIELDS = [
193
192
  'addN', 'subN', 'mulN', 'sqrN'
194
193
  ];
195
194
  export function validateField(field) {
196
- for (const i of ['ORDER', 'MASK']) {
197
- if (typeof field[i] !== 'bigint')
198
- throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
199
- }
200
- for (const i of ['BYTES', 'BITS']) {
201
- if (typeof field[i] !== 'number')
202
- throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
203
- }
204
- for (const i of FIELD_FIELDS) {
205
- if (typeof field[i] !== 'function')
206
- throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
207
- }
195
+ const initial = {
196
+ ORDER: 'bigint',
197
+ MASK: 'bigint',
198
+ BYTES: 'isSafeInteger',
199
+ BITS: 'isSafeInteger',
200
+ };
201
+ const opts = FIELD_FIELDS.reduce((map, val) => {
202
+ map[val] = 'function';
203
+ return map;
204
+ }, initial);
205
+ return validateObject(field, opts);
208
206
  }
209
207
  // Generic field functions
210
208
  export function FpPow(f, num, power) {