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