@noble/curves 0.5.2 → 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.
Files changed (61) hide show
  1. package/README.md +115 -41
  2. package/lib/_shortw_utils.d.ts +13 -24
  3. package/lib/abstract/bls.d.ts +39 -32
  4. package/lib/abstract/bls.js +74 -73
  5. package/lib/abstract/{group.d.ts → curve.d.ts} +30 -1
  6. package/lib/abstract/{group.js → curve.js} +33 -2
  7. package/lib/abstract/edwards.d.ts +30 -72
  8. package/lib/abstract/edwards.js +206 -389
  9. package/lib/abstract/hash-to-curve.d.ts +25 -6
  10. package/lib/abstract/hash-to-curve.js +40 -12
  11. package/lib/abstract/modular.d.ts +21 -8
  12. package/lib/abstract/modular.js +72 -48
  13. package/lib/abstract/montgomery.js +23 -68
  14. package/lib/abstract/poseidon.d.ts +29 -0
  15. package/lib/abstract/poseidon.js +115 -0
  16. package/lib/abstract/utils.d.ts +9 -37
  17. package/lib/abstract/utils.js +61 -87
  18. package/lib/abstract/weierstrass.d.ts +58 -81
  19. package/lib/abstract/weierstrass.js +485 -679
  20. package/lib/bls12-381.js +63 -58
  21. package/lib/bn.js +1 -1
  22. package/lib/ed25519.d.ts +7 -5
  23. package/lib/ed25519.js +82 -79
  24. package/lib/ed448.d.ts +3 -0
  25. package/lib/ed448.js +86 -83
  26. package/lib/esm/abstract/bls.js +75 -74
  27. package/lib/esm/abstract/{group.js → curve.js} +31 -1
  28. package/lib/esm/abstract/edwards.js +204 -387
  29. package/lib/esm/abstract/hash-to-curve.js +38 -11
  30. package/lib/esm/abstract/modular.js +69 -47
  31. package/lib/esm/abstract/montgomery.js +24 -69
  32. package/lib/esm/abstract/poseidon.js +109 -0
  33. package/lib/esm/abstract/utils.js +58 -82
  34. package/lib/esm/abstract/weierstrass.js +484 -678
  35. package/lib/esm/bls12-381.js +75 -70
  36. package/lib/esm/bn.js +1 -1
  37. package/lib/esm/ed25519.js +80 -78
  38. package/lib/esm/ed448.js +84 -82
  39. package/lib/esm/jubjub.js +1 -1
  40. package/lib/esm/p224.js +1 -1
  41. package/lib/esm/p256.js +11 -9
  42. package/lib/esm/p384.js +11 -9
  43. package/lib/esm/p521.js +12 -23
  44. package/lib/esm/secp256k1.js +124 -162
  45. package/lib/esm/stark.js +105 -41
  46. package/lib/jubjub.d.ts +2 -2
  47. package/lib/jubjub.js +1 -1
  48. package/lib/p192.d.ts +26 -48
  49. package/lib/p224.d.ts +26 -48
  50. package/lib/p224.js +1 -1
  51. package/lib/p256.d.ts +29 -48
  52. package/lib/p256.js +13 -10
  53. package/lib/p384.d.ts +29 -48
  54. package/lib/p384.js +13 -10
  55. package/lib/p521.d.ts +37 -57
  56. package/lib/p521.js +14 -24
  57. package/lib/secp256k1.d.ts +37 -46
  58. package/lib/secp256k1.js +124 -162
  59. package/lib/stark.d.ts +39 -22
  60. package/lib/stark.js +108 -41
  61. package/package.json +15 -10
@@ -1,77 +1,28 @@
1
1
  "use strict";
2
- /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
3
- // Short Weierstrass curve. The formula is: y² = x³ + ax + b
4
2
  Object.defineProperty(exports, "__esModule", { value: true });
5
3
  exports.mapToCurveSimpleSWU = exports.SWUFpSqrtRatio = exports.weierstrass = exports.weierstrassPoints = void 0;
6
- // Differences from @noble/secp256k1 1.7:
7
- // 1. Different double() formula (but same addition)
8
- // 2. Different sqrt() function
9
- // 3. truncateHash() truncateOnly mode
10
- // 4. DRBG supports outputLen bigger than outputLen of hmac
11
- // 5. Support for different hash functions
4
+ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
5
+ // Short Weierstrass curve. The formula is: = x³ + ax + b
12
6
  const mod = require("./modular.js");
13
7
  const ut = require("./utils.js");
14
8
  const utils_js_1 = require("./utils.js");
15
- const hash_to_curve_js_1 = require("./hash-to-curve.js");
16
- const group_js_1 = require("./group.js");
17
- // ASN.1 DER encoding utilities
18
- class DERError extends Error {
19
- constructor(message) {
20
- super(message);
21
- }
22
- }
23
- const DER = {
24
- slice(s) {
25
- // Proof: any([(i>=0x80) == (int(hex(i).replace('0x', '').zfill(2)[0], 16)>=8) for i in range(0, 256)])
26
- // Padding done by numberToHex
27
- return Number.parseInt(s[0], 16) >= 8 ? '00' + s : s;
28
- },
29
- parseInt(data) {
30
- if (data.length < 2 || data[0] !== 0x02) {
31
- throw new DERError(`Invalid signature integer tag: ${(0, utils_js_1.bytesToHex)(data)}`);
32
- }
33
- const len = data[1];
34
- const res = data.subarray(2, len + 2);
35
- if (!len || res.length !== len) {
36
- throw new DERError(`Invalid signature integer: wrong length`);
37
- }
38
- // Strange condition, its not about length, but about first bytes of number.
39
- if (res[0] === 0x00 && res[1] <= 0x7f) {
40
- throw new DERError('Invalid signature integer: trailing length');
41
- }
42
- return { data: ut.bytesToNumberBE(res), left: data.subarray(len + 2) };
43
- },
44
- parseSig(data) {
45
- if (data.length < 2 || data[0] != 0x30) {
46
- throw new DERError(`Invalid signature tag: ${(0, utils_js_1.bytesToHex)(data)}`);
47
- }
48
- if (data[1] !== data.length - 2) {
49
- throw new DERError('Invalid signature: incorrect length');
50
- }
51
- const { data: r, left: sBytes } = DER.parseInt(data.subarray(2));
52
- const { data: s, left: rBytesLeft } = DER.parseInt(sBytes);
53
- if (rBytesLeft.length) {
54
- throw new DERError(`Invalid signature: left bytes after parsing: ${(0, utils_js_1.bytesToHex)(rBytesLeft)}`);
55
- }
56
- return { r, s };
57
- },
58
- };
9
+ const curve_js_1 = require("./curve.js");
59
10
  function validatePointOpts(curve) {
60
- const opts = ut.validateOpts(curve);
61
- const Fp = opts.Fp;
62
- for (const i of ['a', 'b']) {
63
- if (!Fp.isValid(curve[i]))
64
- throw new Error(`Invalid curve param ${i}=${opts[i]} (${typeof opts[i]})`);
65
- }
66
- for (const i of ['isTorsionFree', 'clearCofactor', 'mapToCurve']) {
67
- if (curve[i] === undefined)
68
- continue; // Optional
69
- if (typeof curve[i] !== 'function')
70
- throw new Error(`Invalid ${i} function`);
71
- }
72
- 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;
73
24
  if (endo) {
74
- if (!Fp.equals(opts.a, Fp.ZERO)) {
25
+ if (!Fp.eql(a, Fp.ZERO)) {
75
26
  throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');
76
27
  }
77
28
  if (typeof endo !== 'object' ||
@@ -80,20 +31,65 @@ function validatePointOpts(curve) {
80
31
  throw new Error('Expected endomorphism with beta: bigint and splitScalar: function');
81
32
  }
82
33
  }
83
- if (typeof opts.fromBytes !== 'function')
84
- throw new Error('Invalid fromBytes function');
85
- if (typeof opts.toBytes !== 'function')
86
- throw new Error('Invalid fromBytes function');
87
- // Requires including hashToCurve file
88
- if (opts.htfDefaults !== undefined)
89
- (0, hash_to_curve_js_1.validateHTFOpts)(opts.htfDefaults);
90
- // Set defaults
91
34
  return Object.freeze({ ...opts });
92
35
  }
36
+ // ASN.1 DER encoding utilities
37
+ const { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;
38
+ const DER = {
39
+ // asn.1 DER encoding utils
40
+ Err: class DERErr extends Error {
41
+ constructor(m = '') {
42
+ super(m);
43
+ }
44
+ },
45
+ _parseInt(data) {
46
+ const { Err: E } = DER;
47
+ if (data.length < 2 || data[0] !== 0x02)
48
+ throw new E('Invalid signature integer tag');
49
+ const len = data[1];
50
+ const res = data.subarray(2, len + 2);
51
+ if (!len || res.length !== len)
52
+ throw new E('Invalid signature integer: wrong length');
53
+ if (res[0] === 0x00 && res[1] <= 0x7f)
54
+ throw new E('Invalid signature integer: trailing length');
55
+ // ^ Weird condition: not about length, but about first bytes of number.
56
+ return { d: b2n(res), l: data.subarray(len + 2) }; // d is data, l is left
57
+ },
58
+ toSig(hex) {
59
+ // parse DER signature
60
+ const { Err: E } = DER;
61
+ const data = typeof hex === 'string' ? h2b(hex) : hex;
62
+ if (!(data instanceof Uint8Array))
63
+ throw new Error('ui8a expected');
64
+ let l = data.length;
65
+ if (l < 2 || data[0] != 0x30)
66
+ throw new E('Invalid signature tag');
67
+ if (data[1] !== l - 2)
68
+ throw new E('Invalid signature: incorrect length');
69
+ const { d: r, l: sBytes } = DER._parseInt(data.subarray(2));
70
+ const { d: s, l: rBytesLeft } = DER._parseInt(sBytes);
71
+ if (rBytesLeft.length)
72
+ throw new E('Invalid signature: left bytes after parsing');
73
+ return { r, s };
74
+ },
75
+ hexFromSig(sig) {
76
+ const slice = (s) => (Number.parseInt(s[0], 16) >= 8 ? '00' + s : s); // slice DER
77
+ const h = (num) => {
78
+ const hex = num.toString(16);
79
+ return hex.length & 1 ? `0${hex}` : hex;
80
+ };
81
+ const s = slice(h(sig.s));
82
+ const r = slice(h(sig.r));
83
+ const shl = s.length / 2;
84
+ const rhl = r.length / 2;
85
+ const sl = h(shl);
86
+ const rl = h(rhl);
87
+ return `30${h(rhl + shl + 4)}02${rl}${r}02${sl}${s}`;
88
+ },
89
+ };
93
90
  // Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
94
91
  const _0n = BigInt(0);
95
92
  const _1n = BigInt(1);
96
- const _3n = BigInt(3);
97
93
  function weierstrassPoints(opts) {
98
94
  const CURVE = validatePointOpts(opts);
99
95
  const { Fp } = CURVE; // All curves has same field / group length as for now, but they can differ
@@ -103,115 +99,152 @@ function weierstrassPoints(opts) {
103
99
  */
104
100
  function weierstrassEquation(x) {
105
101
  const { a, b } = CURVE;
106
- const x2 = Fp.square(x); // x * x
102
+ const x2 = Fp.sqr(x); // x * x
107
103
  const x3 = Fp.mul(x2, x); // x2 * x
108
104
  return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x3 + a * x + b
109
105
  }
110
106
  // Valid group elements reside in range 1..n-1
111
107
  function isWithinCurveOrder(num) {
112
- return _0n < num && num < CURVE.n;
108
+ return typeof num === 'bigint' && _0n < num && num < CURVE.n;
113
109
  }
114
- /**
115
- * Validates if a private key is valid and converts it to bigint form.
116
- * Supports two options, that are passed when CURVE is initialized:
117
- * - `normalizePrivateKey()` executed before all checks
118
- * - `wrapPrivateKey` when true, executed after most checks, but before `0 < key < n`
119
- */
110
+ function assertGE(num) {
111
+ if (!isWithinCurveOrder(num))
112
+ throw new Error('Expected valid bigint: 0 < bigint < curve.n');
113
+ }
114
+ // Validates if priv key is valid and converts it to bigint.
115
+ // Supports options CURVE.normalizePrivateKey and CURVE.wrapPrivateKey.
120
116
  function normalizePrivateKey(key) {
121
- const { normalizePrivateKey: custom, nByteLength: groupLen, wrapPrivateKey, n: order } = CURVE;
122
- if (typeof custom === 'function')
123
- key = custom(key);
124
- let num;
125
- if (typeof key === 'bigint') {
126
- // Curve order check is done below
127
- num = key;
128
- }
129
- else if (ut.isPositiveInt(key)) {
130
- num = BigInt(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');
131
125
  }
132
- else if (typeof key === 'string') {
133
- if (key.length !== 2 * groupLen)
134
- throw new Error(`Expected ${groupLen} bytes of private key`);
135
- // Validates individual octets
136
- num = ut.hexToNumber(key);
137
- }
138
- else if (key instanceof Uint8Array) {
139
- if (key.length !== groupLen)
140
- throw new Error(`Expected ${groupLen} bytes of private key`);
141
- num = ut.bytesToNumberBE(key);
126
+ let num;
127
+ try {
128
+ num = typeof key === 'bigint' ? key : ut.bytesToNumberBE((0, utils_js_1.ensureBytes)(key, nByteLength));
142
129
  }
143
- else {
144
- throw new TypeError('Expected valid private key');
130
+ catch (error) {
131
+ throw new Error(`private key must be ${nByteLength} bytes, hex or bigint, not ${typeof key}`);
145
132
  }
146
- // Useful for curves with cofactor != 1
147
133
  if (wrapPrivateKey)
148
- num = mod.mod(num, order);
149
- if (!isWithinCurveOrder(num))
150
- throw new Error('Expected private key: 0 < key < n');
134
+ num = mod.mod(num, n); // disabled by default, enabled for BLS
135
+ assertGE(num); // num in range [1..N-1]
151
136
  return num;
152
137
  }
153
- /**
154
- * Validates if a scalar ("private number") is valid.
155
- * Scalars are valid only if they are less than curve order.
156
- */
157
- function normalizeScalar(num) {
158
- if (ut.isPositiveInt(num))
159
- return BigInt(num);
160
- if (typeof num === 'bigint' && isWithinCurveOrder(num))
161
- return num;
162
- throw new TypeError('Expected valid private scalar: 0 < scalar < curve.n');
138
+ const pointPrecomputes = new Map();
139
+ function assertPrjPoint(other) {
140
+ if (!(other instanceof Point))
141
+ throw new Error('ProjectivePoint expected');
163
142
  }
164
143
  /**
165
144
  * Projective Point works in 3d / projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
166
145
  * Default Point works in 2d / affine coordinates: (x, y)
167
146
  * We're doing calculations in projective, because its operations don't require costly inversion.
168
147
  */
169
- class ProjectivePoint {
170
- constructor(x, y, z) {
171
- this.x = x;
172
- this.y = y;
173
- this.z = z;
148
+ class Point {
149
+ constructor(px, py, pz) {
150
+ this.px = px;
151
+ this.py = py;
152
+ this.pz = pz;
153
+ if (px == null || !Fp.isValid(px))
154
+ throw new Error('x required');
155
+ if (py == null || !Fp.isValid(py))
156
+ throw new Error('y required');
157
+ if (pz == null || !Fp.isValid(pz))
158
+ throw new Error('z required');
174
159
  }
175
160
  static fromAffine(p) {
176
- if (!(p instanceof Point)) {
177
- throw new TypeError('ProjectivePoint#fromAffine: expected Point');
178
- }
161
+ const { x, y } = p || {};
162
+ if (!p || !Fp.isValid(x) || !Fp.isValid(y))
163
+ throw new Error('invalid affine point');
164
+ if (p instanceof Point)
165
+ throw new Error('projective point not allowed');
166
+ const is0 = (i) => Fp.eql(i, Fp.ZERO);
179
167
  // fromAffine(x:0, y:0) would produce (x:0, y:0, z:1), but we need (x:0, y:1, z:0)
180
- if (p.equals(Point.ZERO))
181
- return ProjectivePoint.ZERO;
182
- return new ProjectivePoint(p.x, p.y, Fp.ONE);
168
+ if (is0(x) && is0(y))
169
+ return Point.ZERO;
170
+ return new Point(x, y, Fp.ONE);
171
+ }
172
+ get x() {
173
+ return this.toAffine().x;
174
+ }
175
+ get y() {
176
+ return this.toAffine().y;
183
177
  }
184
178
  /**
185
179
  * Takes a bunch of Projective Points but executes only one
186
180
  * inversion on all of them. Inversion is very slow operation,
187
181
  * so this improves performance massively.
182
+ * Optimization: converts a list of projective points to a list of identical points with Z=1.
188
183
  */
189
- static toAffineBatch(points) {
190
- const toInv = Fp.invertBatch(points.map((p) => p.z));
191
- return points.map((p, i) => p.toAffine(toInv[i]));
184
+ static normalizeZ(points) {
185
+ const toInv = Fp.invertBatch(points.map((p) => p.pz));
186
+ return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
192
187
  }
193
188
  /**
194
- * Optimization: converts a list of projective points to a list of identical points with Z=1.
189
+ * Converts hash string or Uint8Array to Point.
190
+ * @param hex short/long ECDSA hex
195
191
  */
196
- static normalizeZ(points) {
197
- return ProjectivePoint.toAffineBatch(points).map(ProjectivePoint.fromAffine);
192
+ static fromHex(hex) {
193
+ const P = Point.fromAffine(CURVE.fromBytes((0, utils_js_1.ensureBytes)(hex)));
194
+ P.assertValidity();
195
+ return P;
196
+ }
197
+ // Multiplies generator point by privateKey.
198
+ static fromPrivateKey(privateKey) {
199
+ return Point.BASE.multiply(normalizePrivateKey(privateKey));
200
+ }
201
+ // "Private method", don't use it directly
202
+ _setWindowSize(windowSize) {
203
+ this._WINDOW_SIZE = windowSize;
204
+ pointPrecomputes.delete(this);
205
+ }
206
+ // A point on curve is valid if it conforms to equation.
207
+ assertValidity() {
208
+ // Zero is valid point too!
209
+ if (this.is0()) {
210
+ if (CURVE.allowInfinityPoint)
211
+ return;
212
+ throw new Error('bad point: ZERO');
213
+ }
214
+ // Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
215
+ const { x, y } = this.toAffine();
216
+ // Check if x, y are valid field elements
217
+ if (!Fp.isValid(x) || !Fp.isValid(y))
218
+ throw new Error('bad point: x or y not FE');
219
+ const left = Fp.sqr(y); // y²
220
+ const right = weierstrassEquation(x); // x³ + ax + b
221
+ if (!Fp.eql(left, right))
222
+ throw new Error('bad point: equation left != right');
223
+ if (!this.isTorsionFree())
224
+ throw new Error('bad point: not in prime-order subgroup');
225
+ }
226
+ hasEvenY() {
227
+ const { y } = this.toAffine();
228
+ if (Fp.isOdd)
229
+ return !Fp.isOdd(y);
230
+ throw new Error("Field doesn't support isOdd");
198
231
  }
199
232
  /**
200
233
  * Compare one point to another.
201
234
  */
202
235
  equals(other) {
203
236
  assertPrjPoint(other);
204
- const { x: X1, y: Y1, z: Z1 } = this;
205
- const { x: X2, y: Y2, z: Z2 } = other;
206
- const U1 = Fp.equals(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
207
- const U2 = Fp.equals(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
237
+ const { px: X1, py: Y1, pz: Z1 } = this;
238
+ const { px: X2, py: Y2, pz: Z2 } = other;
239
+ const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
240
+ const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
208
241
  return U1 && U2;
209
242
  }
210
243
  /**
211
244
  * Flips point to one corresponding to (x, -y) in Affine coordinates.
212
245
  */
213
246
  negate() {
214
- return new ProjectivePoint(this.x, Fp.negate(this.y), this.z);
247
+ return new Point(this.px, Fp.neg(this.py), this.pz);
215
248
  }
216
249
  // Renes-Costello-Batina exception-free doubling formula.
217
250
  // There is 30% faster Jacobian formula, but it is not complete.
@@ -220,7 +253,7 @@ function weierstrassPoints(opts) {
220
253
  double() {
221
254
  const { a, b } = CURVE;
222
255
  const b3 = Fp.mul(b, 3n);
223
- const { x: X1, y: Y1, z: Z1 } = this;
256
+ const { px: X1, py: Y1, pz: Z1 } = this;
224
257
  let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
225
258
  let t0 = Fp.mul(X1, X1); // step 1
226
259
  let t1 = Fp.mul(Y1, Y1);
@@ -253,7 +286,7 @@ function weierstrassPoints(opts) {
253
286
  Z3 = Fp.mul(t2, t1);
254
287
  Z3 = Fp.add(Z3, Z3); // step 30
255
288
  Z3 = Fp.add(Z3, Z3);
256
- return new ProjectivePoint(X3, Y3, Z3);
289
+ return new Point(X3, Y3, Z3);
257
290
  }
258
291
  // Renes-Costello-Batina exception-free addition formula.
259
292
  // There is 30% faster Jacobian formula, but it is not complete.
@@ -261,8 +294,8 @@ function weierstrassPoints(opts) {
261
294
  // Cost: 12M + 0S + 3*a + 3*b3 + 23add.
262
295
  add(other) {
263
296
  assertPrjPoint(other);
264
- const { x: X1, y: Y1, z: Z1 } = this;
265
- const { x: X2, y: Y2, z: Z2 } = other;
297
+ const { px: X1, py: Y1, pz: Z1 } = this;
298
+ const { px: X2, py: Y2, pz: Z2 } = other;
266
299
  let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
267
300
  const a = CURVE.a;
268
301
  const b3 = Fp.mul(CURVE.b, 3n);
@@ -306,30 +339,39 @@ function weierstrassPoints(opts) {
306
339
  t0 = Fp.mul(t3, t1);
307
340
  Z3 = Fp.mul(t5, Z3);
308
341
  Z3 = Fp.add(Z3, t0); // step 40
309
- return new ProjectivePoint(X3, Y3, Z3);
342
+ return new Point(X3, Y3, Z3);
310
343
  }
311
344
  subtract(other) {
312
345
  return this.add(other.negate());
313
346
  }
347
+ is0() {
348
+ return this.equals(Point.ZERO);
349
+ }
350
+ wNAF(n) {
351
+ return wnaf.wNAFCached(this, pointPrecomputes, n, (comp) => {
352
+ const toInv = Fp.invertBatch(comp.map((p) => p.pz));
353
+ return comp.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
354
+ });
355
+ }
314
356
  /**
315
357
  * Non-constant-time multiplication. Uses double-and-add algorithm.
316
358
  * It's faster, but should only be used when you don't care about
317
359
  * an exposed private key e.g. sig verification, which works over *public* keys.
318
360
  */
319
- multiplyUnsafe(scalar) {
320
- const P0 = ProjectivePoint.ZERO;
321
- if (typeof scalar === 'bigint' && scalar === _0n)
322
- return P0;
323
- // Will throw on 0
324
- let n = normalizeScalar(scalar);
361
+ multiplyUnsafe(n) {
362
+ const I = Point.ZERO;
363
+ if (n === _0n)
364
+ return I;
365
+ assertGE(n); // Will throw on 0
325
366
  if (n === _1n)
326
367
  return this;
327
- if (!CURVE.endo)
368
+ const { endo } = CURVE;
369
+ if (!endo)
328
370
  return wnaf.unsafeLadder(this, n);
329
371
  // Apply endomorphism
330
- let { k1neg, k1, k2neg, k2 } = CURVE.endo.splitScalar(n);
331
- let k1p = P0;
332
- let k2p = P0;
372
+ let { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
373
+ let k1p = I;
374
+ let k2p = I;
333
375
  let d = this;
334
376
  while (k1 > _0n || k2 > _0n) {
335
377
  if (k1 & _1n)
@@ -344,27 +386,9 @@ function weierstrassPoints(opts) {
344
386
  k1p = k1p.negate();
345
387
  if (k2neg)
346
388
  k2p = k2p.negate();
347
- k2p = new ProjectivePoint(Fp.mul(k2p.x, CURVE.endo.beta), k2p.y, k2p.z);
389
+ k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
348
390
  return k1p.add(k2p);
349
391
  }
350
- /**
351
- * Implements w-ary non-adjacent form for calculating ec multiplication.
352
- */
353
- wNAF(n, affinePoint) {
354
- if (!affinePoint && this.equals(ProjectivePoint.BASE))
355
- affinePoint = Point.BASE;
356
- const W = (affinePoint && affinePoint._WINDOW_SIZE) || 1;
357
- // Calculate precomputes on a first run, reuse them after
358
- let precomputes = affinePoint && pointPrecomputes.get(affinePoint);
359
- if (!precomputes) {
360
- precomputes = wnaf.precomputeWindow(this, W);
361
- if (affinePoint && W !== 1) {
362
- precomputes = ProjectivePoint.normalizeZ(precomputes);
363
- pointPrecomputes.set(affinePoint, precomputes);
364
- }
365
- }
366
- return wnaf.wNAF(W, precomputes, n);
367
- }
368
392
  /**
369
393
  * Constant time multiplication.
370
394
  * Uses wNAF method. Windowed method may be 10% faster,
@@ -373,55 +397,65 @@ function weierstrassPoints(opts) {
373
397
  * @param affinePoint optional point ot save cached precompute windows on it
374
398
  * @returns New point
375
399
  */
376
- multiply(scalar, affinePoint) {
377
- let n = normalizeScalar(scalar);
378
- // Real point.
379
- let point;
380
- // Fake point, we use it to achieve constant-time multiplication.
381
- let fake;
382
- if (CURVE.endo) {
383
- const { k1neg, k1, k2neg, k2 } = CURVE.endo.splitScalar(n);
384
- let { p: k1p, f: f1p } = this.wNAF(k1, affinePoint);
385
- let { p: k2p, f: f2p } = this.wNAF(k2, affinePoint);
400
+ multiply(scalar) {
401
+ assertGE(scalar);
402
+ let n = scalar;
403
+ let point, fake; // Fake point is used to const-time mult
404
+ const { endo } = CURVE;
405
+ if (endo) {
406
+ const { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
407
+ let { p: k1p, f: f1p } = this.wNAF(k1);
408
+ let { p: k2p, f: f2p } = this.wNAF(k2);
386
409
  k1p = wnaf.constTimeNegate(k1neg, k1p);
387
410
  k2p = wnaf.constTimeNegate(k2neg, k2p);
388
- k2p = new ProjectivePoint(Fp.mul(k2p.x, CURVE.endo.beta), k2p.y, k2p.z);
411
+ k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
389
412
  point = k1p.add(k2p);
390
413
  fake = f1p.add(f2p);
391
414
  }
392
415
  else {
393
- const { p, f } = this.wNAF(n, affinePoint);
416
+ const { p, f } = this.wNAF(n);
394
417
  point = p;
395
418
  fake = f;
396
419
  }
397
420
  // Normalize `z` for both points, but return only real one
398
- return ProjectivePoint.normalizeZ([point, fake])[0];
421
+ return Point.normalizeZ([point, fake])[0];
422
+ }
423
+ /**
424
+ * Efficiently calculate `aP + bQ`. Unsafe, can expose private key, if used incorrectly.
425
+ * @returns non-zero affine point
426
+ */
427
+ multiplyAndAddUnsafe(Q, a, b) {
428
+ const G = Point.BASE; // No Strauss-Shamir trick: we have 10% faster G precomputes
429
+ const mul = (P, a // Select faster multiply() method
430
+ ) => (a === _0n || a === _1n || !P.equals(G) ? P.multiplyUnsafe(a) : P.multiply(a));
431
+ const sum = mul(this, a).add(mul(Q, b));
432
+ return sum.is0() ? undefined : sum;
399
433
  }
400
434
  // Converts Projective point to affine (x, y) coordinates.
401
435
  // Can accept precomputed Z^-1 - for example, from invertBatch.
402
436
  // (x, y, z) ∋ (x=x/z, y=y/z)
403
- toAffine(invZ) {
404
- const { x, y, z } = this;
405
- const is0 = this.equals(ProjectivePoint.ZERO);
437
+ toAffine(iz) {
438
+ const { px: x, py: y, pz: z } = this;
439
+ const is0 = this.is0();
406
440
  // If invZ was 0, we return zero point. However we still want to execute
407
441
  // all operations, so we replace invZ with a random number, 1.
408
- if (invZ == null)
409
- invZ = is0 ? Fp.ONE : Fp.invert(z);
410
- const ax = Fp.mul(x, invZ);
411
- const ay = Fp.mul(y, invZ);
412
- const zz = Fp.mul(z, invZ);
442
+ if (iz == null)
443
+ iz = is0 ? Fp.ONE : Fp.inv(z);
444
+ const ax = Fp.mul(x, iz);
445
+ const ay = Fp.mul(y, iz);
446
+ const zz = Fp.mul(z, iz);
413
447
  if (is0)
414
- return Point.ZERO;
415
- if (!Fp.equals(zz, Fp.ONE))
448
+ return { x: Fp.ZERO, y: Fp.ZERO };
449
+ if (!Fp.eql(zz, Fp.ONE))
416
450
  throw new Error('invZ was invalid');
417
- return new Point(ax, ay);
451
+ return { x: ax, y: ay };
418
452
  }
419
453
  isTorsionFree() {
420
454
  const { h: cofactor, isTorsionFree } = CURVE;
421
455
  if (cofactor === _1n)
422
456
  return true; // No subgroups, always torsion-free
423
457
  if (isTorsionFree)
424
- return isTorsionFree(ProjectivePoint, this);
458
+ return isTorsionFree(Point, this);
425
459
  throw new Error('isTorsionFree() has not been declared for the elliptic curve');
426
460
  }
427
461
  clearCofactor() {
@@ -429,162 +463,23 @@ function weierstrassPoints(opts) {
429
463
  if (cofactor === _1n)
430
464
  return this; // Fast-path
431
465
  if (clearCofactor)
432
- return clearCofactor(ProjectivePoint, this);
466
+ return clearCofactor(Point, this);
433
467
  return this.multiplyUnsafe(CURVE.h);
434
468
  }
435
- }
436
- ProjectivePoint.BASE = new ProjectivePoint(CURVE.Gx, CURVE.Gy, Fp.ONE);
437
- ProjectivePoint.ZERO = new ProjectivePoint(Fp.ZERO, Fp.ONE, Fp.ZERO);
438
- const _bits = CURVE.nBitLength;
439
- const wnaf = (0, group_js_1.wNAF)(ProjectivePoint, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
440
- function assertPrjPoint(other) {
441
- if (!(other instanceof ProjectivePoint))
442
- throw new TypeError('ProjectivePoint expected');
443
- }
444
- // Stores precomputed values for points.
445
- const pointPrecomputes = new WeakMap();
446
- /**
447
- * Default Point works in default aka affine coordinates: (x, y)
448
- */
449
- class Point {
450
- constructor(x, y) {
451
- this.x = x;
452
- this.y = y;
453
- }
454
- // "Private method", don't use it directly
455
- _setWindowSize(windowSize) {
456
- this._WINDOW_SIZE = windowSize;
457
- pointPrecomputes.delete(this);
458
- }
459
- // Checks for y % 2 == 0
460
- hasEvenY() {
461
- if (Fp.isOdd)
462
- return !Fp.isOdd(this.y);
463
- throw new Error("Field doesn't support isOdd");
464
- }
465
- /**
466
- * Converts hash string or Uint8Array to Point.
467
- * @param hex short/long ECDSA hex
468
- */
469
- static fromHex(hex) {
470
- const { x, y } = CURVE.fromBytes(ut.ensureBytes(hex));
471
- const point = new Point(x, y);
472
- point.assertValidity();
473
- return point;
474
- }
475
- // Multiplies generator point by privateKey.
476
- static fromPrivateKey(privateKey) {
477
- return Point.BASE.multiply(normalizePrivateKey(privateKey));
478
- }
479
- toRawBytes(isCompressed = false) {
469
+ toRawBytes(isCompressed = true) {
480
470
  this.assertValidity();
481
471
  return CURVE.toBytes(Point, this, isCompressed);
482
472
  }
483
- toHex(isCompressed = false) {
484
- return (0, utils_js_1.bytesToHex)(this.toRawBytes(isCompressed));
485
- }
486
- // A point on curve is valid if it conforms to equation.
487
- assertValidity() {
488
- // Zero is valid point too!
489
- if (this.equals(Point.ZERO)) {
490
- if (CURVE.allowInfinityPoint)
491
- return;
492
- throw new Error('Point at infinity');
493
- }
494
- // Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
495
- const msg = 'Point is not on elliptic curve';
496
- const { x, y } = this;
497
- // Check if x, y are valid field elements
498
- if (!Fp.isValid(x) || !Fp.isValid(y))
499
- throw new Error(msg);
500
- const left = Fp.square(y); // y²
501
- const right = weierstrassEquation(x); // x³ + ax + b
502
- if (!Fp.equals(left, right))
503
- throw new Error(msg);
504
- if (!this.isTorsionFree())
505
- throw new Error('Point must be of prime-order subgroup');
506
- }
507
- equals(other) {
508
- if (!(other instanceof Point))
509
- throw new TypeError('Point#equals: expected Point');
510
- return Fp.equals(this.x, other.x) && Fp.equals(this.y, other.y);
511
- }
512
- // Returns the same point with inverted `y`
513
- negate() {
514
- return new Point(this.x, Fp.negate(this.y));
515
- }
516
- toProj() {
517
- return ProjectivePoint.fromAffine(this);
518
- }
519
- // Adds point to itself
520
- double() {
521
- return this.toProj().double().toAffine();
522
- }
523
- add(other) {
524
- return this.toProj().add(ProjectivePoint.fromAffine(other)).toAffine();
525
- }
526
- subtract(other) {
527
- return this.add(other.negate());
528
- }
529
- multiply(scalar) {
530
- return this.toProj().multiply(scalar, this).toAffine();
531
- }
532
- multiplyUnsafe(scalar) {
533
- return this.toProj().multiplyUnsafe(scalar).toAffine();
534
- }
535
- clearCofactor() {
536
- return this.toProj().clearCofactor().toAffine();
537
- }
538
- isTorsionFree() {
539
- return this.toProj().isTorsionFree();
540
- }
541
- /**
542
- * Efficiently calculate `aP + bQ`.
543
- * Unsafe, can expose private key, if used incorrectly.
544
- * TODO: Utilize Shamir's trick
545
- * @returns non-zero affine point
546
- */
547
- multiplyAndAddUnsafe(Q, a, b) {
548
- const P = this.toProj();
549
- const aP = a === _0n || a === _1n || this !== Point.BASE ? P.multiplyUnsafe(a) : P.multiply(a);
550
- const bQ = ProjectivePoint.fromAffine(Q).multiplyUnsafe(b);
551
- const sum = aP.add(bQ);
552
- return sum.equals(ProjectivePoint.ZERO) ? undefined : sum.toAffine();
553
- }
554
- // Encodes byte string to elliptic curve
555
- // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
556
- static hashToCurve(msg, options) {
557
- const { mapToCurve } = CURVE;
558
- if (!mapToCurve)
559
- throw new Error('CURVE.mapToCurve() has not been defined');
560
- msg = ut.ensureBytes(msg);
561
- const u = (0, hash_to_curve_js_1.hash_to_field)(msg, 2, { ...CURVE.htfDefaults, ...options });
562
- const { x: x0, y: y0 } = mapToCurve(u[0]);
563
- const { x: x1, y: y1 } = mapToCurve(u[1]);
564
- return new Point(x0, y0).add(new Point(x1, y1)).clearCofactor();
565
- }
566
- // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
567
- static encodeToCurve(msg, options) {
568
- const { mapToCurve } = CURVE;
569
- if (!mapToCurve)
570
- throw new Error('CURVE.mapToCurve() has not been defined');
571
- msg = ut.ensureBytes(msg);
572
- const u = (0, hash_to_curve_js_1.hash_to_field)(msg, 1, { ...CURVE.htfDefaults, ...options });
573
- const { x, y } = mapToCurve(u[0]);
574
- return new Point(x, y).clearCofactor();
473
+ toHex(isCompressed = true) {
474
+ return ut.bytesToHex(this.toRawBytes(isCompressed));
575
475
  }
576
476
  }
577
- /**
578
- * Base point aka generator. Any public_key = Point.BASE * private_key
579
- */
580
- Point.BASE = new Point(CURVE.Gx, CURVE.Gy);
581
- /**
582
- * Identity point aka point at infinity. p - p = zero_p; p + zero_p = p
583
- */
584
- Point.ZERO = new Point(Fp.ZERO, Fp.ZERO);
477
+ Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
478
+ Point.ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO);
479
+ const _bits = CURVE.nBitLength;
480
+ const wnaf = (0, curve_js_1.wNAF)(Point, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
585
481
  return {
586
- Point: Point,
587
- ProjectivePoint: ProjectivePoint,
482
+ ProjectivePoint: Point,
588
483
  normalizePrivateKey,
589
484
  weierstrassEquation,
590
485
  isWithinCurveOrder,
@@ -592,65 +487,70 @@ function weierstrassPoints(opts) {
592
487
  }
593
488
  exports.weierstrassPoints = weierstrassPoints;
594
489
  function validateOpts(curve) {
595
- const opts = ut.validateOpts(curve);
596
- if (typeof opts.hash !== 'function' || !ut.isPositiveInt(opts.hash.outputLen))
597
- throw new Error('Invalid hash function');
598
- if (typeof opts.hmac !== 'function')
599
- throw new Error('Invalid hmac function');
600
- if (typeof opts.randomBytes !== 'function')
601
- throw new Error('Invalid randomBytes function');
602
- // 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
+ });
603
500
  return Object.freeze({ lowS: true, ...opts });
604
501
  }
605
- /**
606
- * Minimal HMAC-DRBG (NIST 800-90) for signatures.
607
- * Used only for RFC6979, does not fully implement DRBG spec.
608
- */
609
- class HmacDrbg {
610
- constructor(hashLen, qByteLen, hmacFn) {
611
- this.hashLen = hashLen;
612
- this.qByteLen = qByteLen;
613
- this.hmacFn = hmacFn;
614
- if (typeof hashLen !== 'number' || hashLen < 2)
615
- throw new Error('hashLen must be a number');
616
- if (typeof qByteLen !== 'number' || qByteLen < 2)
617
- throw new Error('qByteLen must be a number');
618
- if (typeof hmacFn !== 'function')
619
- throw new Error('hmacFn must be a function');
620
- // Step B, Step C: set hashLen to 8*ceil(hlen/8)
621
- this.v = new Uint8Array(hashLen).fill(1);
622
- this.k = new Uint8Array(hashLen).fill(0);
623
- this.counter = 0;
624
- }
625
- hmacSync(...values) {
626
- return this.hmacFn(this.k, ...values);
627
- }
628
- incr() {
629
- if (this.counter >= 1000)
630
- throw new Error('Tried 1,000 k values for sign(), all were invalid');
631
- this.counter += 1;
632
- }
633
- reseedSync(seed = new Uint8Array()) {
634
- this.k = this.hmacSync(this.v, Uint8Array.from([0x00]), seed);
635
- this.v = this.hmacSync(this.v);
502
+ const u8n = (data) => new Uint8Array(data); // creates Uint8Array
503
+ const u8fr = (arr) => Uint8Array.from(arr); // another shortcut
504
+ function hmacDrbg(hashLen, qByteLen, hmacFn) {
505
+ if (typeof hashLen !== 'number' || hashLen < 2)
506
+ throw new Error('hashLen must be a number');
507
+ if (typeof qByteLen !== 'number' || qByteLen < 2)
508
+ throw new Error('qByteLen must be a number');
509
+ if (typeof hmacFn !== 'function')
510
+ throw new Error('hmacFn must be a function');
511
+ // Step B, Step C: set hashLen to 8*ceil(hlen/8)
512
+ let v = u8n(hashLen); // Minimal non-full-spec HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
513
+ let k = u8n(hashLen); // Steps B and C of RFC6979 3.2: set hashLen, in our case always same
514
+ let i = 0; // Iterations counter, will throw when over 1000
515
+ const reset = () => {
516
+ v.fill(1);
517
+ k.fill(0);
518
+ i = 0;
519
+ };
520
+ const h = (...b) => hmacFn(k, v, ...b); // hmac(k)(v, ...values)
521
+ const reseed = (seed = u8n()) => {
522
+ // HMAC-DRBG reseed() function. Steps D-G
523
+ k = h(u8fr([0x00]), seed); // k = hmac(k || v || 0x00 || seed)
524
+ v = h(); // v = hmac(k || v)
636
525
  if (seed.length === 0)
637
526
  return;
638
- this.k = this.hmacSync(this.v, Uint8Array.from([0x01]), seed);
639
- this.v = this.hmacSync(this.v);
640
- }
641
- // TODO: review
642
- generateSync() {
643
- this.incr();
527
+ k = h(u8fr([0x01]), seed); // k = hmac(k || v || 0x01 || seed)
528
+ v = h(); // v = hmac(k || v)
529
+ };
530
+ const gen = () => {
531
+ // HMAC-DRBG generate() function
532
+ if (i++ >= 1000)
533
+ throw new Error('drbg: tried 1000 values');
644
534
  let len = 0;
645
535
  const out = [];
646
- while (len < this.qByteLen) {
647
- this.v = this.hmacSync(this.v);
648
- const sl = this.v.slice();
536
+ while (len < qByteLen) {
537
+ v = h();
538
+ const sl = v.slice();
649
539
  out.push(sl);
650
- len += this.v.length;
540
+ len += v.length;
651
541
  }
652
542
  return ut.concatBytes(...out);
653
- }
543
+ };
544
+ const genUntil = (seed, pred) => {
545
+ reset();
546
+ reseed(seed); // Steps D-G
547
+ let res = undefined; // Step H: grind until k is in [1..n-1]
548
+ while (!(res = pred(gen())))
549
+ reseed();
550
+ reset();
551
+ return res;
552
+ };
553
+ return genUntil;
654
554
  }
655
555
  function weierstrass(curveDef) {
656
556
  const CURVE = validateOpts(curveDef);
@@ -659,93 +559,66 @@ function weierstrass(curveDef) {
659
559
  const compressedLen = Fp.BYTES + 1; // e.g. 33 for 32
660
560
  const uncompressedLen = 2 * Fp.BYTES + 1; // e.g. 65 for 32
661
561
  function isValidFieldElement(num) {
662
- // 0 is disallowed by arbitrary reasons. Probably because infinity point?
663
- return _0n < num && num < Fp.ORDER;
562
+ return _0n < num && num < Fp.ORDER; // 0 is banned since it's not invertible FE
563
+ }
564
+ function modN(a) {
565
+ return mod.mod(a, CURVE_ORDER);
664
566
  }
665
- const { Point, ProjectivePoint, normalizePrivateKey, weierstrassEquation, isWithinCurveOrder } = weierstrassPoints({
567
+ function invN(a) {
568
+ return mod.invert(a, CURVE_ORDER);
569
+ }
570
+ const { ProjectivePoint: Point, normalizePrivateKey, weierstrassEquation, isWithinCurveOrder, } = weierstrassPoints({
666
571
  ...CURVE,
667
572
  toBytes(c, point, isCompressed) {
668
- const x = Fp.toBytes(point.x);
573
+ const a = point.toAffine();
574
+ const x = Fp.toBytes(a.x);
669
575
  const cat = ut.concatBytes;
670
576
  if (isCompressed) {
577
+ // TODO: hasEvenY
671
578
  return cat(Uint8Array.from([point.hasEvenY() ? 0x02 : 0x03]), x);
672
579
  }
673
580
  else {
674
- return cat(Uint8Array.from([0x04]), x, Fp.toBytes(point.y));
581
+ return cat(Uint8Array.from([0x04]), x, Fp.toBytes(a.y));
675
582
  }
676
583
  },
677
584
  fromBytes(bytes) {
678
585
  const len = bytes.length;
679
- const header = bytes[0];
586
+ const head = bytes[0];
587
+ const tail = bytes.subarray(1);
680
588
  // this.assertValidity() is done inside of fromHex
681
- if (len === compressedLen && (header === 0x02 || header === 0x03)) {
682
- const x = ut.bytesToNumberBE(bytes.subarray(1));
589
+ if (len === compressedLen && (head === 0x02 || head === 0x03)) {
590
+ const x = ut.bytesToNumberBE(tail);
683
591
  if (!isValidFieldElement(x))
684
592
  throw new Error('Point is not on curve');
685
593
  const y2 = weierstrassEquation(x); // y² = x³ + ax + b
686
594
  let y = Fp.sqrt(y2); // y = y² ^ (p+1)/4
687
595
  const isYOdd = (y & _1n) === _1n;
688
596
  // ECDSA
689
- const isFirstByteOdd = (bytes[0] & 1) === 1;
690
- if (isFirstByteOdd !== isYOdd)
691
- y = Fp.negate(y);
597
+ const isHeadOdd = (head & 1) === 1;
598
+ if (isHeadOdd !== isYOdd)
599
+ y = Fp.neg(y);
692
600
  return { x, y };
693
601
  }
694
- else if (len === uncompressedLen && header === 0x04) {
695
- const x = Fp.fromBytes(bytes.subarray(1, Fp.BYTES + 1));
696
- const y = Fp.fromBytes(bytes.subarray(Fp.BYTES + 1, 2 * Fp.BYTES + 1));
602
+ else if (len === uncompressedLen && head === 0x04) {
603
+ const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES));
604
+ const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES));
697
605
  return { x, y };
698
606
  }
699
607
  else {
700
- 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`);
701
609
  }
702
610
  },
703
611
  });
704
- // Do we need these functions at all?
705
- function numToField(num) {
706
- if (typeof num !== 'bigint')
707
- throw new Error('Expected bigint');
708
- if (!(_0n <= num && num < Fp.MASK))
709
- throw new Error(`Expected number < 2^${Fp.BYTES * 8}`);
710
- return Fp.toBytes(num);
711
- }
712
- const numToFieldStr = (num) => (0, utils_js_1.bytesToHex)(numToField(num));
713
- /**
714
- * Normalizes hex, bytes, Point to Point. Checks for curve equation.
715
- */
716
- function normalizePublicKey(publicKey) {
717
- if (publicKey instanceof Point) {
718
- publicKey.assertValidity();
719
- return publicKey;
720
- }
721
- else if (publicKey instanceof Uint8Array || typeof publicKey === 'string') {
722
- return Point.fromHex(publicKey);
723
- // This can happen because PointType can be instance of different class
724
- }
725
- else
726
- throw new Error(`Unknown type of public key: ${publicKey}`);
727
- }
612
+ const numToNByteStr = (num) => ut.bytesToHex(ut.numberToBytesBE(num, CURVE.nByteLength));
728
613
  function isBiggerThanHalfOrder(number) {
729
614
  const HALF = CURVE_ORDER >> _1n;
730
615
  return number > HALF;
731
616
  }
732
617
  function normalizeS(s) {
733
- return isBiggerThanHalfOrder(s) ? mod.mod(-s, CURVE_ORDER) : s;
734
- }
735
- function bits2int_2(bytes) {
736
- const delta = bytes.length * 8 - CURVE.nBitLength;
737
- const num = ut.bytesToNumberBE(bytes);
738
- return delta > 0 ? num >> BigInt(delta) : num;
618
+ return isBiggerThanHalfOrder(s) ? modN(-s) : s;
739
619
  }
740
- // Ensures ECDSA message hashes are 32 bytes and < curve order
741
- function _truncateHash(hash, truncateOnly = false) {
742
- const h = bits2int_2(hash);
743
- if (truncateOnly)
744
- return h;
745
- const { n } = CURVE;
746
- return h >= n ? h - n : h;
747
- }
748
- const truncateHash = CURVE.truncateHash || _truncateHash;
620
+ // slice bytes num
621
+ const slcNum = (b, from, to) => ut.bytesToNumberBE(b.slice(from, to));
749
622
  /**
750
623
  * ECDSA signature with its (r, s) properties. Supports DER & compact representations.
751
624
  */
@@ -758,108 +631,68 @@ function weierstrass(curveDef) {
758
631
  }
759
632
  // pair (bytes of r, bytes of s)
760
633
  static fromCompact(hex) {
761
- const arr = hex instanceof Uint8Array;
762
- const name = 'Signature.fromCompact';
763
- if (typeof hex !== 'string' && !arr)
764
- throw new TypeError(`${name}: Expected string or Uint8Array`);
765
- const str = arr ? (0, utils_js_1.bytesToHex)(hex) : hex;
766
- const gl = CURVE.nByteLength * 2; // group length in hex, not ui8a
767
- if (str.length !== 2 * gl)
768
- throw new Error(`${name}: Expected ${gl / 2}-byte hex`);
769
- const slice = (from, to) => ut.hexToNumber(str.slice(from, to));
770
- return new Signature(slice(0, gl), slice(gl, 2 * gl));
634
+ const gl = CURVE.nByteLength;
635
+ hex = (0, utils_js_1.ensureBytes)(hex, gl * 2);
636
+ return new Signature(slcNum(hex, 0, gl), slcNum(hex, gl, 2 * gl));
771
637
  }
772
638
  // DER encoded ECDSA signature
773
639
  // https://bitcoin.stackexchange.com/questions/57644/what-are-the-parts-of-a-bitcoin-transaction-input-script
774
640
  static fromDER(hex) {
775
- const arr = hex instanceof Uint8Array;
776
- if (typeof hex !== 'string' && !arr)
777
- throw new TypeError(`Signature.fromDER: Expected string or Uint8Array`);
778
- const { r, s } = DER.parseSig(arr ? hex : ut.hexToBytes(hex));
641
+ if (typeof hex !== 'string' && !(hex instanceof Uint8Array))
642
+ throw new Error(`Signature.fromDER: Expected string or Uint8Array`);
643
+ const { r, s } = DER.toSig((0, utils_js_1.ensureBytes)(hex));
779
644
  return new Signature(r, s);
780
645
  }
781
646
  assertValidity() {
782
- const { r, s } = this;
783
- if (!isWithinCurveOrder(r))
784
- throw new Error('Invalid Signature: r must be 0 < r < n');
785
- if (!isWithinCurveOrder(s))
786
- throw new Error('Invalid Signature: s must be 0 < s < n');
647
+ // can use assertGE here
648
+ if (!isWithinCurveOrder(this.r))
649
+ throw new Error('r must be 0 < r < n');
650
+ if (!isWithinCurveOrder(this.s))
651
+ throw new Error('s must be 0 < s < n');
787
652
  }
788
- copyWithRecoveryBit(recovery) {
653
+ addRecoveryBit(recovery) {
789
654
  return new Signature(this.r, this.s, recovery);
790
655
  }
791
- /**
792
- * Recovers public key from signature with recovery bit. Throws on invalid hash.
793
- * https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Public_key_recovery
794
- * It's also possible to recover key without bit: try all 4 bit values and check for sig match.
795
- *
796
- * ```
797
- * recover(r, s, h) where
798
- * u1 = hs^-1 mod n
799
- * u2 = sr^-1 mod n
800
- * Q = u1⋅G + u2⋅R
801
- * ```
802
- *
803
- * @param msgHash message hash
804
- * @returns Point corresponding to public key
805
- */
806
656
  recoverPublicKey(msgHash) {
807
- const { r, s, recovery } = this;
808
- if (recovery == null)
809
- throw new Error('Cannot recover: recovery bit is not present');
810
- if (![0, 1, 2, 3].includes(recovery))
811
- throw new Error('Cannot recover: invalid recovery bit');
812
- const h = truncateHash(ut.ensureBytes(msgHash));
813
- const { n } = CURVE;
814
- const radj = recovery === 2 || recovery === 3 ? r + n : r;
657
+ const { n: N } = CURVE; // ECDSA public key recovery secg.org/sec1-v2.pdf 4.1.6
658
+ const { r, s, recovery: rec } = this;
659
+ const h = bits2int_modN((0, utils_js_1.ensureBytes)(msgHash)); // Truncate hash
660
+ if (rec == null || ![0, 1, 2, 3].includes(rec))
661
+ throw new Error('recovery id invalid');
662
+ const radj = rec === 2 || rec === 3 ? r + N : r;
815
663
  if (radj >= Fp.ORDER)
816
- throw new Error('Cannot recover: bit 2/3 is invalid with current r');
817
- const rinv = mod.invert(radj, n);
818
- // Q = u1⋅G + u2⋅R
819
- const u1 = mod.mod(-h * rinv, n);
820
- const u2 = mod.mod(s * rinv, n);
821
- const prefix = recovery & 1 ? '03' : '02';
822
- const R = Point.fromHex(prefix + numToFieldStr(radj));
823
- const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // unsafe is fine: no priv data leaked
664
+ throw new Error('recovery id 2 or 3 invalid');
665
+ const prefix = (rec & 1) === 0 ? '02' : '03';
666
+ const R = Point.fromHex(prefix + numToNByteStr(radj));
667
+ const ir = invN(radj); // r^-1
668
+ const u1 = modN(-h * ir); // -hr^-1
669
+ const u2 = modN(s * ir); // sr^-1
670
+ const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
824
671
  if (!Q)
825
- throw new Error('Cannot recover: point at infinify');
672
+ throw new Error('point at infinify'); // unsafe is fine: no priv data leaked
826
673
  Q.assertValidity();
827
674
  return Q;
828
675
  }
829
- /**
830
- * Default signatures are always low-s, to prevent malleability.
831
- * `sign(lowS: true)` always produces low-s sigs.
832
- * `verify(lowS: true)` always fails for high-s.
833
- */
676
+ // Signatures should be low-s, to prevent malleability.
834
677
  hasHighS() {
835
678
  return isBiggerThanHalfOrder(this.s);
836
679
  }
837
680
  normalizeS() {
838
- return this.hasHighS()
839
- ? new Signature(this.r, mod.mod(-this.s, CURVE_ORDER), this.recovery)
840
- : this;
681
+ return this.hasHighS() ? new Signature(this.r, modN(-this.s), this.recovery) : this;
841
682
  }
842
683
  // DER-encoded
843
684
  toDERRawBytes() {
844
685
  return ut.hexToBytes(this.toDERHex());
845
686
  }
846
687
  toDERHex() {
847
- const { numberToHexUnpadded: toHex } = ut;
848
- const sHex = DER.slice(toHex(this.s));
849
- const rHex = DER.slice(toHex(this.r));
850
- const sHexL = sHex.length / 2;
851
- const rHexL = rHex.length / 2;
852
- const sLen = toHex(sHexL);
853
- const rLen = toHex(rHexL);
854
- const length = toHex(rHexL + sHexL + 4);
855
- return `30${length}02${rLen}${rHex}02${sLen}${sHex}`;
688
+ return DER.hexFromSig({ r: this.r, s: this.s });
856
689
  }
857
690
  // padded bytes of r, then padded bytes of s
858
691
  toCompactRawBytes() {
859
692
  return ut.hexToBytes(this.toCompactHex());
860
693
  }
861
694
  toCompactHex() {
862
- return numToFieldStr(this.r) + numToFieldStr(this.s);
695
+ return numToNByteStr(this.r) + numToNByteStr(this.s);
863
696
  }
864
697
  }
865
698
  const utils = {
@@ -872,17 +705,11 @@ function weierstrass(curveDef) {
872
705
  return false;
873
706
  }
874
707
  },
875
- _bigintToBytes: numToField,
876
- _bigintToString: numToFieldStr,
877
708
  _normalizePrivateKey: normalizePrivateKey,
878
- _normalizePublicKey: normalizePublicKey,
879
- _isWithinCurveOrder: isWithinCurveOrder,
880
- _isValidFieldElement: isValidFieldElement,
881
- _weierstrassEquation: weierstrassEquation,
882
709
  /**
883
710
  * Converts some bytes to a valid private key. Needs at least (nBitLength+64) bytes.
884
711
  */
885
- hashToPrivateKey: (hash) => numToField(ut.hashToPrivateScalar(hash, CURVE_ORDER)),
712
+ hashToPrivateKey: (hash) => ut.numberToBytesBE(mod.hashToPrivateScalar(hash, CURVE_ORDER), CURVE.nByteLength),
886
713
  /**
887
714
  * Produces cryptographically secure private key from random of size (nBitLength+64)
888
715
  * as per FIPS 186 B.4.1 with modulo bias being neglible.
@@ -897,10 +724,9 @@ function weierstrass(curveDef) {
897
724
  * @returns cached point
898
725
  */
899
726
  precompute(windowSize = 8, point = Point.BASE) {
900
- const cached = point === Point.BASE ? point : new Point(point.x, point.y);
901
- cached._setWindowSize(windowSize);
902
- cached.multiply(_3n);
903
- return cached;
727
+ point._setWindowSize(windowSize);
728
+ point.multiply(BigInt(3));
729
+ return point;
904
730
  },
905
731
  };
906
732
  /**
@@ -909,7 +735,7 @@ function weierstrass(curveDef) {
909
735
  * @param isCompressed whether to return compact (default), or full key
910
736
  * @returns Public key, full when isCompressed=false; short when isCompressed=true
911
737
  */
912
- function getPublicKey(privateKey, isCompressed = false) {
738
+ function getPublicKey(privateKey, isCompressed = true) {
913
739
  return Point.fromPrivateKey(privateKey).toRawBytes(isCompressed);
914
740
  }
915
741
  /**
@@ -936,101 +762,98 @@ function weierstrass(curveDef) {
936
762
  * @param isCompressed whether to return compact (default), or full key
937
763
  * @returns shared public key
938
764
  */
939
- function getSharedSecret(privateA, publicB, isCompressed = false) {
765
+ function getSharedSecret(privateA, publicB, isCompressed = true) {
940
766
  if (isProbPub(privateA))
941
- throw new TypeError('getSharedSecret: first arg must be private key');
767
+ throw new Error('first arg must be private key');
942
768
  if (!isProbPub(publicB))
943
- throw new TypeError('getSharedSecret: second arg must be public key');
944
- const b = normalizePublicKey(publicB);
945
- b.assertValidity();
769
+ throw new Error('second arg must be public key');
770
+ const b = Point.fromHex(publicB); // check for being on-curve
946
771
  return b.multiply(normalizePrivateKey(privateA)).toRawBytes(isCompressed);
947
772
  }
948
- // RFC6979 methods
949
- function bits2int(bytes) {
950
- const { nByteLength } = CURVE;
951
- if (!(bytes instanceof Uint8Array))
952
- throw new Error('Expected Uint8Array');
953
- const slice = bytes.length > nByteLength ? bytes.slice(0, nByteLength) : bytes;
954
- // const slice = bytes; nByteLength; nBitLength;
955
- let num = ut.bytesToNumberBE(slice);
956
- // const { nBitLength } = CURVE;
957
- // const delta = (bytes.length * 8) - nBitLength;
958
- // if (delta > 0) {
959
- // // console.log('bits=', bytes.length*8, 'CURVE n=', nBitLength, 'delta=', delta);
960
- // // console.log(bytes.length, nBitLength, delta);
961
- // // console.log(bytes, new Error().stack);
962
- // num >>= BigInt(delta);
963
- // }
964
- return num;
965
- }
966
- function bits2octets(bytes) {
967
- const z1 = bits2int(bytes);
968
- const z2 = mod.mod(z1, CURVE_ORDER);
969
- return int2octets(z2 < _0n ? z1 : z2);
970
- }
773
+ // RFC6979: ensure ECDSA msg is X bytes and < N. RFC suggests optional truncating via bits2octets.
774
+ // FIPS 186-4 4.6 suggests the leftmost min(nBitLen, outLen) bits, which matches bits2int.
775
+ // bits2int can produce res>N, we can do mod(res, N) since the bitLen is the same.
776
+ // int2octets can't be used; pads small msgs with 0: unacceptatble for trunc as per RFC vectors
777
+ const bits2int = CURVE.bits2int ||
778
+ function (bytes) {
779
+ // For curves with nBitLength % 8 !== 0: bits2octets(bits2octets(m)) !== bits2octets(m)
780
+ // for some cases, since bytes.length * 8 is not actual bitLength.
781
+ const delta = bytes.length * 8 - CURVE.nBitLength; // truncate to nBitLength leftmost bits
782
+ const num = ut.bytesToNumberBE(bytes); // check for == u8 done here
783
+ return delta > 0 ? num >> BigInt(delta) : num;
784
+ };
785
+ const bits2int_modN = CURVE.bits2int_modN ||
786
+ function (bytes) {
787
+ return modN(bits2int(bytes)); // can't use bytesToNumberBE here
788
+ };
789
+ // NOTE: pads output with zero as per spec
790
+ const ORDER_MASK = ut.bitMask(CURVE.nBitLength);
971
791
  function int2octets(num) {
972
- return numToField(num); // prohibits >nByteLength bytes
792
+ if (typeof num !== 'bigint')
793
+ throw new Error('bigint expected');
794
+ if (!(_0n <= num && num < ORDER_MASK))
795
+ // n in [0..ORDER_MASK-1]
796
+ throw new Error(`bigint expected < 2^${CURVE.nBitLength}`);
797
+ // works with order, can have different size than numToField!
798
+ return ut.numberToBytesBE(num, CURVE.nByteLength);
973
799
  }
974
800
  // Steps A, D of RFC6979 3.2
975
801
  // Creates RFC6979 seed; converts msg/privKey to numbers.
976
- function initSigArgs(msgHash, privateKey, extraEntropy) {
802
+ // Used only in sign, not in verify.
803
+ // NOTE: we cannot assume here that msgHash has same amount of bytes as curve order, this will be wrong at least for P521.
804
+ // Also it can be bigger for P224 + SHA256
805
+ function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
806
+ const { hash, randomBytes } = CURVE;
977
807
  if (msgHash == null)
978
808
  throw new Error(`sign: expected valid message hash, not "${msgHash}"`);
979
- // Step A is ignored, since we already provide hash instead of msg
980
- const h1 = numToField(truncateHash(ut.ensureBytes(msgHash)));
981
- const d = normalizePrivateKey(privateKey);
982
- // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
983
- const seedArgs = [int2octets(d), bits2octets(h1)];
984
- // RFC6979 3.6: additional k' could be provided
985
- if (extraEntropy != null) {
986
- if (extraEntropy === true)
987
- extraEntropy = CURVE.randomBytes(Fp.BYTES);
988
- const e = ut.ensureBytes(extraEntropy);
989
- if (e.length !== Fp.BYTES)
990
- throw new Error(`sign: Expected ${Fp.BYTES} bytes of extra data`);
991
- seedArgs.push(e);
992
- }
993
- // seed is constructed from private key and message
994
- // Step D
995
- // V, 0x00 are done in HmacDRBG constructor.
996
- const seed = ut.concatBytes(...seedArgs);
997
- const m = bits2int(h1);
998
- return { seed, m, d };
999
- }
1000
- /**
1001
- * Converts signature params into point & r/s, checks them for validity.
1002
- * k must be in range [1, n-1]
1003
- * @param k signature's k param: deterministic in our case, random in non-rfc6979 sigs
1004
- * @param m message that would be signed
1005
- * @param d private key
1006
- * @returns Signature with its point on curve Q OR undefined if params were invalid
1007
- */
1008
- function kmdToSig(kBytes, m, d, lowS = true) {
1009
- const { n } = CURVE;
1010
- const k = truncateHash(kBytes, true);
1011
- if (!isWithinCurveOrder(k))
1012
- return;
1013
- // Important: all mod() calls in the function must be done over `n`
1014
- const kinv = mod.invert(k, n);
1015
- const q = Point.BASE.multiply(k);
1016
- // r = x mod n
1017
- const r = mod.mod(q.x, n);
1018
- if (r === _0n)
1019
- return;
1020
- // s = (m + dr)/k mod n where x/k == x*inv(k)
1021
- const s = mod.mod(kinv * mod.mod(m + mod.mod(d * r, n), n), n);
1022
- if (s === _0n)
1023
- return;
1024
- // recovery bit is usually 0 or 1; rarely it's 2 or 3, when q.x > n
1025
- let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n);
1026
- let normS = s;
1027
- if (lowS && isBiggerThanHalfOrder(s)) {
1028
- normS = normalizeS(s);
1029
- recovery ^= 1;
809
+ if (['recovered', 'canonical'].some((k) => k in opts))
810
+ // Ban legacy options
811
+ throw new Error('sign() legacy options not supported');
812
+ let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
813
+ if (prehash)
814
+ msgHash = hash((0, utils_js_1.ensureBytes)(msgHash));
815
+ if (lowS == null)
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))
820
+ const h1int = bits2int_modN((0, utils_js_1.ensureBytes)(msgHash));
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).
824
+ if (ent != null) {
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));
828
+ }
829
+ const seed = ut.concatBytes(...seedArgs); // Step D of RFC6979 3.2
830
+ const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
831
+ // Converts signature params into point w r/s, checks result for validity.
832
+ function k2sig(kBytes) {
833
+ // RFC 6979 Section 3.2, step 3: k = bits2int(T)
834
+ const k = bits2int(kBytes); // Cannot use fields methods, since it is group element
835
+ if (!isWithinCurveOrder(k))
836
+ return; // Important: all mod() calls here must be done over N
837
+ const ik = invN(k); // k^-1 mod n
838
+ const q = Point.BASE.multiply(k).toAffine(); // q = Gk
839
+ const r = modN(q.x); // r = q.x mod n
840
+ if (r === _0n)
841
+ return;
842
+ const s = modN(ik * modN(m + modN(d * r))); // s = k^-1(m + rd) mod n
843
+ if (s === _0n)
844
+ return;
845
+ let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n); // recovery bit (2 or 3, when q.x > n)
846
+ let normS = s;
847
+ if (lowS && isBiggerThanHalfOrder(s)) {
848
+ normS = normalizeS(s); // if lowS was passed, ensure s is always
849
+ recovery ^= 1; // // in the bottom half of N
850
+ }
851
+ return new Signature(r, normS, recovery); // use normS, not s
1030
852
  }
1031
- return new Signature(r, normS, recovery);
853
+ return { seed, k2sig };
1032
854
  }
1033
- const defaultSigOpts = { lowS: CURVE.lowS };
855
+ const defaultSigOpts = { lowS: CURVE.lowS, prehash: false };
856
+ const defaultVerOpts = { lowS: CURVE.lowS, prehash: false };
1034
857
  /**
1035
858
  * Signs message hash (not message: you need to hash it by yourself).
1036
859
  * ```
@@ -1039,28 +862,16 @@ function weierstrass(curveDef) {
1039
862
  * r = x mod n
1040
863
  * s = (m + dr)/k mod n
1041
864
  * ```
1042
- * @param opts `lowS, extraEntropy`
865
+ * @param opts `lowS, extraEntropy, prehash`
1043
866
  */
1044
867
  function sign(msgHash, privKey, opts = defaultSigOpts) {
1045
- // Steps A, D of RFC6979 3.2.
1046
- const { seed, m, d } = initSigArgs(msgHash, privKey, opts.extraEntropy);
1047
- // Steps B, C, D, E, F, G
1048
- const drbg = new HmacDrbg(CURVE.hash.outputLen, CURVE.nByteLength, CURVE.hmac);
1049
- drbg.reseedSync(seed);
1050
- // Step H3, repeat until k is in range [1, n-1]
1051
- let sig;
1052
- while (!(sig = kmdToSig(drbg.generateSync(), m, d, opts.lowS)))
1053
- drbg.reseedSync();
1054
- return sig;
1055
- }
1056
- /**
1057
- * Signs a message (not message hash).
1058
- */
1059
- function signUnhashed(msg, privKey, opts = defaultSigOpts) {
1060
- return sign(CURVE.hash(ut.ensureBytes(msg)), privKey, opts);
868
+ const { seed, k2sig } = prepSig(msgHash, privKey, opts); // Steps A, D of RFC6979 3.2.
869
+ const genUntil = hmacDrbg(CURVE.hash.outputLen, CURVE.nByteLength, CURVE.hmac);
870
+ return genUntil(seed, k2sig); // Steps B, C, D, E, F, G
1061
871
  }
1062
872
  // Enable precomputes. Slows down first publicKey computation by 20ms.
1063
873
  Point.BASE._setWindowSize(8);
874
+ // utils.precompute(8, ProjectivePoint.BASE)
1064
875
  /**
1065
876
  * Verifies a signature against message hash and public key.
1066
877
  * Rejects lowS signatures by default: to override,
@@ -1074,50 +885,47 @@ function weierstrass(curveDef) {
1074
885
  * mod(R.x, n) == r
1075
886
  * ```
1076
887
  */
1077
- function verify(signature, msgHash, publicKey, opts = { lowS: CURVE.lowS }) {
888
+ function verify(signature, msgHash, publicKey, opts = defaultVerOpts) {
889
+ let P;
890
+ let _sig = undefined;
891
+ if (publicKey instanceof Point)
892
+ throw new Error('publicKey must be hex');
1078
893
  try {
1079
- if (signature instanceof Signature) {
1080
- signature.assertValidity();
894
+ if (signature && typeof signature === 'object' && !(signature instanceof Uint8Array)) {
895
+ const { r, s } = signature;
896
+ _sig = new Signature(r, s); // assertValidity() is executed on creation
1081
897
  }
1082
898
  else {
1083
- // Signature can be represented in 2 ways: compact (64-byte) & DER (variable-length).
1084
- // Since DER can also be 64 bytes, we check for it first.
899
+ // Signature can be represented in 2 ways: compact (2*nByteLength) & DER (variable-length).
900
+ // Since DER can also be 2*nByteLength bytes, we check for it first.
1085
901
  try {
1086
- signature = Signature.fromDER(signature);
902
+ _sig = Signature.fromDER(signature);
1087
903
  }
1088
904
  catch (derError) {
1089
- if (!(derError instanceof DERError))
905
+ if (!(derError instanceof DER.Err))
1090
906
  throw derError;
1091
- signature = Signature.fromCompact(signature);
907
+ _sig = Signature.fromCompact(signature);
1092
908
  }
1093
909
  }
1094
- msgHash = ut.ensureBytes(msgHash);
910
+ msgHash = (0, utils_js_1.ensureBytes)(msgHash);
911
+ P = Point.fromHex(publicKey);
1095
912
  }
1096
913
  catch (error) {
1097
914
  return false;
1098
915
  }
1099
- if (opts.lowS && signature.hasHighS())
916
+ if (opts.lowS && _sig.hasHighS())
1100
917
  return false;
1101
- let P;
1102
- try {
1103
- P = normalizePublicKey(publicKey);
1104
- }
1105
- catch (error) {
1106
- return false;
1107
- }
1108
- const { n } = CURVE;
1109
- const { r, s } = signature;
1110
- const h = truncateHash(msgHash);
1111
- const sinv = mod.invert(s, n); // s^-1
1112
- // R = u1⋅G - u2⋅P
1113
- const u1 = mod.mod(h * sinv, n);
1114
- const u2 = mod.mod(r * sinv, n);
1115
- // Some implementations compare R.x in projective, without inversion.
1116
- // The speed-up is <5%, so we don't complicate the code.
1117
- const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2);
918
+ if (opts.prehash)
919
+ msgHash = CURVE.hash(msgHash);
920
+ const { r, s } = _sig;
921
+ const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element
922
+ const is = invN(s); // s^-1
923
+ const u1 = modN(h * is); // u1 = hs^-1 mod n
924
+ const u2 = modN(r * is); // u2 = rs^-1 mod n
925
+ const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2)?.toAffine(); // R = u1⋅G + u2⋅P
1118
926
  if (!R)
1119
927
  return false;
1120
- const v = mod.mod(R.x, n);
928
+ const v = modN(R.x);
1121
929
  return v === r;
1122
930
  }
1123
931
  return {
@@ -1125,17 +933,15 @@ function weierstrass(curveDef) {
1125
933
  getPublicKey,
1126
934
  getSharedSecret,
1127
935
  sign,
1128
- signUnhashed,
1129
936
  verify,
1130
- Point,
1131
- ProjectivePoint,
937
+ ProjectivePoint: Point,
1132
938
  Signature,
1133
939
  utils,
1134
940
  };
1135
941
  }
1136
942
  exports.weierstrass = weierstrass;
1137
943
  // Implementation of the Shallue and van de Woestijne method for any Weierstrass curve
1138
- // TODO: check if there is a way to merge this with uvRation in Edwards && move to modular?
944
+ // TODO: check if there is a way to merge this with uvRatio in Edwards && move to modular?
1139
945
  // b = True and y = sqrt(u / v) if (u / v) is square in F, and
1140
946
  // b = False and y = sqrt(Z * (u / v)) otherwise.
1141
947
  function SWUFpSqrtRatio(Fp, Z) {
@@ -1154,7 +960,7 @@ function SWUFpSqrtRatio(Fp, Z) {
1154
960
  let sqrtRatio = (u, v) => {
1155
961
  let tv1 = c6; // 1. tv1 = c6
1156
962
  let tv2 = Fp.pow(v, c4); // 2. tv2 = v^c4
1157
- let tv3 = Fp.square(tv2); // 3. tv3 = tv2^2
963
+ let tv3 = Fp.sqr(tv2); // 3. tv3 = tv2^2
1158
964
  tv3 = Fp.mul(tv3, v); // 4. tv3 = tv3 * v
1159
965
  let tv5 = Fp.mul(u, tv3); // 5. tv5 = u * tv3
1160
966
  tv5 = Fp.pow(tv5, c3); // 6. tv5 = tv5^c3
@@ -1163,7 +969,7 @@ function SWUFpSqrtRatio(Fp, Z) {
1163
969
  tv3 = Fp.mul(tv5, u); // 9. tv3 = tv5 * u
1164
970
  let tv4 = Fp.mul(tv3, tv2); // 10. tv4 = tv3 * tv2
1165
971
  tv5 = Fp.pow(tv4, c5); // 11. tv5 = tv4^c5
1166
- let isQR = Fp.equals(tv5, Fp.ONE); // 12. isQR = tv5 == 1
972
+ let isQR = Fp.eql(tv5, Fp.ONE); // 12. isQR = tv5 == 1
1167
973
  tv2 = Fp.mul(tv3, c7); // 13. tv2 = tv3 * c7
1168
974
  tv5 = Fp.mul(tv4, tv1); // 14. tv5 = tv4 * tv1
1169
975
  tv3 = Fp.cmov(tv2, tv3, isQR); // 15. tv3 = CMOV(tv2, tv3, isQR)
@@ -1172,7 +978,7 @@ function SWUFpSqrtRatio(Fp, Z) {
1172
978
  for (let i = c1; i > 1; i--) {
1173
979
  let tv5 = 2n ** (i - 2n); // 18. tv5 = i - 2; 19. tv5 = 2^tv5
1174
980
  let tvv5 = Fp.pow(tv4, tv5); // 20. tv5 = tv4^tv5
1175
- const e1 = Fp.equals(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
981
+ const e1 = Fp.eql(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
1176
982
  tv2 = Fp.mul(tv3, tv1); // 22. tv2 = tv3 * tv1
1177
983
  tv1 = Fp.mul(tv1, tv1); // 23. tv1 = tv1 * tv1
1178
984
  tvv5 = Fp.mul(tv4, tv1); // 24. tv5 = tv4 * tv1
@@ -1184,16 +990,16 @@ function SWUFpSqrtRatio(Fp, Z) {
1184
990
  if (Fp.ORDER % 4n === 3n) {
1185
991
  // sqrt_ratio_3mod4(u, v)
1186
992
  const c1 = (Fp.ORDER - 3n) / 4n; // 1. c1 = (q - 3) / 4 # Integer arithmetic
1187
- const c2 = Fp.sqrt(Fp.negate(Z)); // 2. c2 = sqrt(-Z)
993
+ const c2 = Fp.sqrt(Fp.neg(Z)); // 2. c2 = sqrt(-Z)
1188
994
  sqrtRatio = (u, v) => {
1189
- let tv1 = Fp.square(v); // 1. tv1 = v^2
995
+ let tv1 = Fp.sqr(v); // 1. tv1 = v^2
1190
996
  const tv2 = Fp.mul(u, v); // 2. tv2 = u * v
1191
997
  tv1 = Fp.mul(tv1, tv2); // 3. tv1 = tv1 * tv2
1192
998
  let y1 = Fp.pow(tv1, c1); // 4. y1 = tv1^c1
1193
999
  y1 = Fp.mul(y1, tv2); // 5. y1 = y1 * tv2
1194
1000
  const y2 = Fp.mul(y1, c2); // 6. y2 = y1 * c2
1195
- const tv3 = Fp.mul(Fp.square(y1), v); // 7. tv3 = y1^2; 8. tv3 = tv3 * v
1196
- const isQR = Fp.equals(tv3, u); // 9. isQR = tv3 == u
1001
+ const tv3 = Fp.mul(Fp.sqr(y1), v); // 7. tv3 = y1^2; 8. tv3 = tv3 * v
1002
+ const isQR = Fp.eql(tv3, u); // 9. isQR = tv3 == u
1197
1003
  let y = Fp.cmov(y2, y1, isQR); // 10. y = CMOV(y2, y1, isQR)
1198
1004
  return { isValid: isQR, value: y }; // 11. return (isQR, y) isQR ? y : y*c2
1199
1005
  };
@@ -1216,16 +1022,16 @@ function mapToCurveSimpleSWU(Fp, opts) {
1216
1022
  return (u) => {
1217
1023
  // prettier-ignore
1218
1024
  let tv1, tv2, tv3, tv4, tv5, tv6, x, y;
1219
- tv1 = Fp.square(u); // 1. tv1 = u^2
1025
+ tv1 = Fp.sqr(u); // 1. tv1 = u^2
1220
1026
  tv1 = Fp.mul(tv1, opts.Z); // 2. tv1 = Z * tv1
1221
- tv2 = Fp.square(tv1); // 3. tv2 = tv1^2
1027
+ tv2 = Fp.sqr(tv1); // 3. tv2 = tv1^2
1222
1028
  tv2 = Fp.add(tv2, tv1); // 4. tv2 = tv2 + tv1
1223
1029
  tv3 = Fp.add(tv2, Fp.ONE); // 5. tv3 = tv2 + 1
1224
1030
  tv3 = Fp.mul(tv3, opts.B); // 6. tv3 = B * tv3
1225
- tv4 = Fp.cmov(opts.Z, Fp.negate(tv2), !Fp.equals(tv2, Fp.ZERO)); // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
1031
+ tv4 = Fp.cmov(opts.Z, Fp.neg(tv2), !Fp.eql(tv2, Fp.ZERO)); // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
1226
1032
  tv4 = Fp.mul(tv4, opts.A); // 8. tv4 = A * tv4
1227
- tv2 = Fp.square(tv3); // 9. tv2 = tv3^2
1228
- tv6 = Fp.square(tv4); // 10. tv6 = tv4^2
1033
+ tv2 = Fp.sqr(tv3); // 9. tv2 = tv3^2
1034
+ tv6 = Fp.sqr(tv4); // 10. tv6 = tv4^2
1229
1035
  tv5 = Fp.mul(tv6, opts.A); // 11. tv5 = A * tv6
1230
1036
  tv2 = Fp.add(tv2, tv5); // 12. tv2 = tv2 + tv5
1231
1037
  tv2 = Fp.mul(tv2, tv3); // 13. tv2 = tv2 * tv3
@@ -1239,7 +1045,7 @@ function mapToCurveSimpleSWU(Fp, opts) {
1239
1045
  x = Fp.cmov(x, tv3, isValid); // 21. x = CMOV(x, tv3, is_gx1_square)
1240
1046
  y = Fp.cmov(y, value, isValid); // 22. y = CMOV(y, y1, is_gx1_square)
1241
1047
  const e1 = Fp.isOdd(u) === Fp.isOdd(y); // 23. e1 = sgn0(u) == sgn0(y)
1242
- y = Fp.cmov(Fp.negate(y), y, e1); // 24. y = CMOV(-y, y, e1)
1048
+ y = Fp.cmov(Fp.neg(y), y, e1); // 24. y = CMOV(-y, y, e1)
1243
1049
  x = Fp.div(x, tv4); // 25. x = x / tv4
1244
1050
  return { x, y };
1245
1051
  };