@noble/curves 0.6.3 → 0.7.0

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 (172) hide show
  1. package/README.md +429 -281
  2. package/{lib/_shortw_utils.d.ts → _shortw_utils.d.ts} +3 -1
  3. package/_shortw_utils.d.ts.map +1 -0
  4. package/{lib/_shortw_utils.js → _shortw_utils.js} +2 -0
  5. package/_shortw_utils.js.map +1 -0
  6. package/{lib/abstract → abstract}/bls.d.ts +4 -9
  7. package/abstract/bls.d.ts.map +1 -0
  8. package/{lib/abstract → abstract}/bls.js +12 -25
  9. package/abstract/bls.js.map +1 -0
  10. package/{lib/abstract → abstract}/curve.d.ts +1 -0
  11. package/abstract/curve.d.ts.map +1 -0
  12. package/{lib/abstract → abstract}/curve.js +1 -0
  13. package/abstract/curve.js.map +1 -0
  14. package/{lib/abstract → abstract}/edwards.d.ts +1 -0
  15. package/abstract/edwards.d.ts.map +1 -0
  16. package/{lib/abstract → abstract}/edwards.js +9 -15
  17. package/abstract/edwards.js.map +1 -0
  18. package/{lib/abstract → abstract}/hash-to-curve.d.ts +5 -5
  19. package/abstract/hash-to-curve.d.ts.map +1 -0
  20. package/{lib/abstract → abstract}/hash-to-curve.js +41 -38
  21. package/abstract/hash-to-curve.js.map +1 -0
  22. package/{lib/abstract → abstract}/modular.d.ts +1 -0
  23. package/abstract/modular.d.ts.map +1 -0
  24. package/{lib/abstract → abstract}/modular.js +2 -1
  25. package/abstract/modular.js.map +1 -0
  26. package/{lib/abstract → abstract}/montgomery.d.ts +1 -0
  27. package/abstract/montgomery.d.ts.map +1 -0
  28. package/{lib/abstract → abstract}/montgomery.js +3 -2
  29. package/abstract/montgomery.js.map +1 -0
  30. package/{lib/abstract → abstract}/poseidon.d.ts +1 -0
  31. package/abstract/poseidon.d.ts.map +1 -0
  32. package/{lib/abstract → abstract}/poseidon.js +1 -0
  33. package/abstract/poseidon.js.map +1 -0
  34. package/{lib/abstract → abstract}/utils.d.ts +12 -1
  35. package/abstract/utils.d.ts.map +1 -0
  36. package/{lib/abstract → abstract}/utils.js +96 -10
  37. package/abstract/utils.js.map +1 -0
  38. package/{lib/abstract → abstract}/weierstrass.d.ts +6 -4
  39. package/abstract/weierstrass.d.ts.map +1 -0
  40. package/{lib/abstract → abstract}/weierstrass.js +55 -93
  41. package/abstract/weierstrass.js.map +1 -0
  42. package/{lib/bls12-381.d.ts → bls12-381.d.ts} +1 -0
  43. package/bls12-381.d.ts.map +1 -0
  44. package/{lib/bls12-381.js → bls12-381.js} +41 -7
  45. package/bls12-381.js.map +1 -0
  46. package/{lib/bn.d.ts → bn.d.ts} +1 -0
  47. package/bn.d.ts.map +1 -0
  48. package/{lib/bn.js → bn.js} +1 -0
  49. package/bn.js.map +1 -0
  50. package/{lib/ed25519.d.ts → ed25519.d.ts} +2 -1
  51. package/ed25519.d.ts.map +1 -0
  52. package/{lib/ed25519.js → ed25519.js} +4 -3
  53. package/ed25519.js.map +1 -0
  54. package/{lib/ed448.d.ts → ed448.d.ts} +2 -1
  55. package/ed448.d.ts.map +1 -0
  56. package/{lib/ed448.js → ed448.js} +2 -1
  57. package/ed448.js.map +1 -0
  58. package/{lib/esm → esm}/_shortw_utils.js +2 -0
  59. package/esm/_shortw_utils.js.map +1 -0
  60. package/{lib/esm → esm}/abstract/bls.js +13 -26
  61. package/esm/abstract/bls.js.map +1 -0
  62. package/{lib/esm → esm}/abstract/curve.js +1 -0
  63. package/esm/abstract/curve.js.map +1 -0
  64. package/{lib/esm → esm}/abstract/edwards.js +9 -15
  65. package/esm/abstract/edwards.js.map +1 -0
  66. package/{lib/esm → esm}/abstract/hash-to-curve.js +40 -36
  67. package/esm/abstract/hash-to-curve.js.map +1 -0
  68. package/{lib/esm → esm}/abstract/modular.js +2 -1
  69. package/esm/abstract/modular.js.map +1 -0
  70. package/{lib/esm → esm}/abstract/montgomery.js +3 -2
  71. package/esm/abstract/montgomery.js.map +1 -0
  72. package/{lib/esm → esm}/abstract/poseidon.js +1 -0
  73. package/esm/abstract/poseidon.js.map +1 -0
  74. package/{lib/esm → esm}/abstract/utils.js +93 -9
  75. package/esm/abstract/utils.js.map +1 -0
  76. package/{lib/esm → esm}/abstract/weierstrass.js +55 -93
  77. package/esm/abstract/weierstrass.js.map +1 -0
  78. package/{lib/esm → esm}/bls12-381.js +41 -7
  79. package/esm/bls12-381.js.map +1 -0
  80. package/{lib/esm → esm}/bn.js +1 -0
  81. package/esm/bn.js.map +1 -0
  82. package/{lib/esm → esm}/ed25519.js +5 -4
  83. package/esm/ed25519.js.map +1 -0
  84. package/{lib/esm → esm}/ed448.js +2 -1
  85. package/esm/ed448.js.map +1 -0
  86. package/{lib → esm}/index.js +1 -0
  87. package/esm/index.js.map +1 -0
  88. package/{lib/esm → esm}/jubjub.js +1 -0
  89. package/esm/jubjub.js.map +1 -0
  90. package/{lib/esm → esm}/p192.js +1 -0
  91. package/esm/p192.js.map +1 -0
  92. package/{lib/esm → esm}/p224.js +1 -0
  93. package/esm/p224.js.map +1 -0
  94. package/{lib/esm → esm}/p256.js +2 -1
  95. package/esm/p256.js.map +1 -0
  96. package/{lib/esm → esm}/p384.js +2 -1
  97. package/esm/p384.js.map +1 -0
  98. package/{lib/esm → esm}/p521.js +2 -1
  99. package/esm/p521.js.map +1 -0
  100. package/{lib/esm → esm}/package.json +0 -0
  101. package/{lib/esm → esm}/pasta.js +1 -0
  102. package/esm/pasta.js.map +1 -0
  103. package/{lib/esm → esm}/secp256k1.js +41 -50
  104. package/esm/secp256k1.js.map +1 -0
  105. package/{lib/esm → esm}/stark.js +1 -0
  106. package/esm/stark.js.map +1 -0
  107. package/index.d.ts +1 -0
  108. package/index.d.ts.map +1 -0
  109. package/index.js +3 -0
  110. package/index.js.map +1 -0
  111. package/{lib/jubjub.d.ts → jubjub.d.ts} +1 -0
  112. package/jubjub.d.ts.map +1 -0
  113. package/{lib/jubjub.js → jubjub.js} +1 -0
  114. package/jubjub.js.map +1 -0
  115. package/{lib/p192.d.ts → p192.d.ts} +5 -2
  116. package/p192.d.ts.map +1 -0
  117. package/{lib/p192.js → p192.js} +1 -0
  118. package/p192.js.map +1 -0
  119. package/{lib/p224.d.ts → p224.d.ts} +5 -2
  120. package/p224.d.ts.map +1 -0
  121. package/{lib/p224.js → p224.js} +1 -0
  122. package/p224.js.map +1 -0
  123. package/{lib/p256.d.ts → p256.d.ts} +6 -3
  124. package/p256.d.ts.map +1 -0
  125. package/{lib/p256.js → p256.js} +2 -1
  126. package/p256.js.map +1 -0
  127. package/{lib/p384.d.ts → p384.d.ts} +6 -3
  128. package/p384.d.ts.map +1 -0
  129. package/{lib/p384.js → p384.js} +2 -1
  130. package/p384.js.map +1 -0
  131. package/{lib/p521.d.ts → p521.d.ts} +6 -3
  132. package/p521.d.ts.map +1 -0
  133. package/{lib/p521.js → p521.js} +2 -1
  134. package/p521.js.map +1 -0
  135. package/package.json +84 -79
  136. package/{lib/pasta.d.ts → pasta.d.ts} +1 -0
  137. package/pasta.d.ts.map +1 -0
  138. package/{lib/pasta.js → pasta.js} +1 -0
  139. package/pasta.js.map +1 -0
  140. package/{lib/secp256k1.d.ts → secp256k1.d.ts} +17 -6
  141. package/secp256k1.d.ts.map +1 -0
  142. package/{lib/secp256k1.js → secp256k1.js} +38 -47
  143. package/secp256k1.js.map +1 -0
  144. package/src/_shortw_utils.ts +20 -0
  145. package/src/abstract/bls.ts +376 -0
  146. package/src/abstract/curve.ts +199 -0
  147. package/src/abstract/edwards.ts +479 -0
  148. package/src/abstract/hash-to-curve.ts +220 -0
  149. package/src/abstract/modular.ts +417 -0
  150. package/src/abstract/montgomery.ts +184 -0
  151. package/src/abstract/poseidon.ts +119 -0
  152. package/src/abstract/utils.ts +246 -0
  153. package/src/abstract/weierstrass.ts +1175 -0
  154. package/src/bls12-381.ts +1274 -0
  155. package/src/bn.ts +21 -0
  156. package/src/ed25519.ts +428 -0
  157. package/src/ed448.ts +241 -0
  158. package/{lib/esm/index.js → src/index.ts} +0 -1
  159. package/src/jubjub.ts +58 -0
  160. package/src/p192.ts +25 -0
  161. package/src/p224.ts +25 -0
  162. package/src/p256.ts +53 -0
  163. package/src/p384.ts +57 -0
  164. package/src/p521.ts +57 -0
  165. package/src/pasta.ts +31 -0
  166. package/src/secp256k1.ts +260 -0
  167. package/src/stark.ts +356 -0
  168. package/{lib/stark.d.ts → stark.d.ts} +3 -1
  169. package/stark.d.ts.map +1 -0
  170. package/{lib/stark.js → stark.js} +1 -0
  171. package/stark.js.map +1 -0
  172. package/lib/index.d.ts +0 -0
@@ -0,0 +1,1175 @@
1
+ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
+ // Short Weierstrass curve. The formula is: y² = x³ + ax + b
3
+ import * as mod from './modular.js';
4
+ import * as ut from './utils.js';
5
+ import { CHash, Hex, PrivKey, ensureBytes } from './utils.js';
6
+ import { Group, GroupConstructor, wNAF, BasicCurve, validateBasic, AffinePoint } from './curve.js';
7
+
8
+ export type { AffinePoint };
9
+ type HmacFnSync = (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array;
10
+ type EndomorphismOpts = {
11
+ beta: bigint;
12
+ splitScalar: (k: bigint) => { k1neg: boolean; k1: bigint; k2neg: boolean; k2: bigint };
13
+ };
14
+ export type BasicWCurve<T> = BasicCurve<T> & {
15
+ // Params: a, b
16
+ a: T;
17
+ b: T;
18
+
19
+ // Optional params
20
+ allowedPrivateKeyLengths?: readonly number[]; // for P521
21
+ wrapPrivateKey?: boolean; // bls12-381 requires mod(n) instead of rejecting keys >= n
22
+ endo?: EndomorphismOpts; // Endomorphism options for Koblitz curves
23
+ // When a cofactor != 1, there can be an effective methods to:
24
+ // 1. Determine whether a point is torsion-free
25
+ isTorsionFree?: (c: ProjConstructor<T>, point: ProjPointType<T>) => boolean;
26
+ // 2. Clear torsion component
27
+ clearCofactor?: (c: ProjConstructor<T>, point: ProjPointType<T>) => ProjPointType<T>;
28
+ };
29
+
30
+ type Entropy = Hex | true;
31
+ export type SignOpts = { lowS?: boolean; extraEntropy?: Entropy; prehash?: boolean };
32
+ export type VerOpts = { lowS?: boolean; prehash?: boolean };
33
+
34
+ /**
35
+ * ### Design rationale for types
36
+ *
37
+ * * Interaction between classes from different curves should fail:
38
+ * `k256.Point.BASE.add(p256.Point.BASE)`
39
+ * * For this purpose we want to use `instanceof` operator, which is fast and works during runtime
40
+ * * Different calls of `curve()` would return different classes -
41
+ * `curve(params) !== curve(params)`: if somebody decided to monkey-patch their curve,
42
+ * it won't affect others
43
+ *
44
+ * TypeScript can't infer types for classes created inside a function. Classes is one instance of nominative types in TypeScript and interfaces only check for shape, so it's hard to create unique type for every function call.
45
+ *
46
+ * We can use generic types via some param, like curve opts, but that would:
47
+ * 1. Enable interaction between `curve(params)` and `curve(params)` (curves of same params)
48
+ * which is hard to debug.
49
+ * 2. Params can be generic and we can't enforce them to be constant value:
50
+ * if somebody creates curve from non-constant params,
51
+ * it would be allowed to interact with other curves with non-constant params
52
+ *
53
+ * TODO: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#unique-symbol
54
+ */
55
+
56
+ // Instance for 3d XYZ points
57
+ export interface ProjPointType<T> extends Group<ProjPointType<T>> {
58
+ readonly px: T;
59
+ readonly py: T;
60
+ readonly pz: T;
61
+ multiply(scalar: bigint): ProjPointType<T>;
62
+ toAffine(iz?: T): AffinePoint<T>;
63
+ isTorsionFree(): boolean;
64
+ clearCofactor(): ProjPointType<T>;
65
+ assertValidity(): void;
66
+ hasEvenY(): boolean;
67
+ toRawBytes(isCompressed?: boolean): Uint8Array;
68
+ toHex(isCompressed?: boolean): string;
69
+
70
+ multiplyUnsafe(scalar: bigint): ProjPointType<T>;
71
+ multiplyAndAddUnsafe(Q: ProjPointType<T>, a: bigint, b: bigint): ProjPointType<T> | undefined;
72
+ _setWindowSize(windowSize: number): void;
73
+ }
74
+ // Static methods for 3d XYZ points
75
+ export interface ProjConstructor<T> extends GroupConstructor<ProjPointType<T>> {
76
+ new (x: T, y: T, z: T): ProjPointType<T>;
77
+ fromAffine(p: AffinePoint<T>): ProjPointType<T>;
78
+ fromHex(hex: Hex): ProjPointType<T>;
79
+ fromPrivateKey(privateKey: PrivKey): ProjPointType<T>;
80
+ normalizeZ(points: ProjPointType<T>[]): ProjPointType<T>[];
81
+ }
82
+
83
+ export type CurvePointsType<T> = BasicWCurve<T> & {
84
+ // Bytes
85
+ fromBytes: (bytes: Uint8Array) => AffinePoint<T>;
86
+ toBytes: (c: ProjConstructor<T>, point: ProjPointType<T>, compressed: boolean) => Uint8Array;
87
+ };
88
+
89
+ function validatePointOpts<T>(curve: CurvePointsType<T>) {
90
+ const opts = validateBasic(curve);
91
+ ut.validateObject(
92
+ opts,
93
+ {
94
+ a: 'field',
95
+ b: 'field',
96
+ fromBytes: 'function',
97
+ toBytes: 'function',
98
+ },
99
+ {
100
+ allowedPrivateKeyLengths: 'array',
101
+ wrapPrivateKey: 'boolean',
102
+ isTorsionFree: 'function',
103
+ clearCofactor: 'function',
104
+ allowInfinityPoint: 'boolean',
105
+ }
106
+ );
107
+ const { endo, Fp, a } = opts;
108
+ if (endo) {
109
+ if (!Fp.eql(a, Fp.ZERO)) {
110
+ throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');
111
+ }
112
+ if (
113
+ typeof endo !== 'object' ||
114
+ typeof endo.beta !== 'bigint' ||
115
+ typeof endo.splitScalar !== 'function'
116
+ ) {
117
+ throw new Error('Expected endomorphism with beta: bigint and splitScalar: function');
118
+ }
119
+ }
120
+ return Object.freeze({ ...opts } as const);
121
+ }
122
+
123
+ export type CurvePointsRes<T> = {
124
+ ProjectivePoint: ProjConstructor<T>;
125
+ normalizePrivateKey: (key: PrivKey) => bigint;
126
+ weierstrassEquation: (x: T) => T;
127
+ isWithinCurveOrder: (num: bigint) => boolean;
128
+ };
129
+
130
+ // ASN.1 DER encoding utilities
131
+ const { bytesToNumberBE: b2n, hexToBytes: h2b } = ut;
132
+ const DER = {
133
+ // asn.1 DER encoding utils
134
+ Err: class DERErr extends Error {
135
+ constructor(m = '') {
136
+ super(m);
137
+ }
138
+ },
139
+ _parseInt(data: Uint8Array): { d: bigint; l: Uint8Array } {
140
+ const { Err: E } = DER;
141
+ if (data.length < 2 || data[0] !== 0x02) throw new E('Invalid signature integer tag');
142
+ const len = data[1];
143
+ const res = data.subarray(2, len + 2);
144
+ if (!len || res.length !== len) throw new E('Invalid signature integer: wrong length');
145
+ if (res[0] === 0x00 && res[1] <= 0x7f)
146
+ throw new E('Invalid signature integer: trailing length');
147
+ // ^ Weird condition: not about length, but about first bytes of number.
148
+ return { d: b2n(res), l: data.subarray(len + 2) }; // d is data, l is left
149
+ },
150
+ toSig(hex: string | Uint8Array): { r: bigint; s: bigint } {
151
+ // parse DER signature
152
+ const { Err: E } = DER;
153
+ const data = typeof hex === 'string' ? h2b(hex) : hex;
154
+ if (!(data instanceof Uint8Array)) throw new Error('ui8a expected');
155
+ let l = data.length;
156
+ if (l < 2 || data[0] != 0x30) throw new E('Invalid signature tag');
157
+ if (data[1] !== l - 2) throw new E('Invalid signature: incorrect length');
158
+ const { d: r, l: sBytes } = DER._parseInt(data.subarray(2));
159
+ const { d: s, l: rBytesLeft } = DER._parseInt(sBytes);
160
+ if (rBytesLeft.length) throw new E('Invalid signature: left bytes after parsing');
161
+ return { r, s };
162
+ },
163
+ hexFromSig(sig: { r: bigint; s: bigint }): string {
164
+ const slice = (s: string): string => (Number.parseInt(s[0], 16) >= 8 ? '00' + s : s); // slice DER
165
+ const h = (num: number | bigint) => {
166
+ const hex = num.toString(16);
167
+ return hex.length & 1 ? `0${hex}` : hex;
168
+ };
169
+ const s = slice(h(sig.s));
170
+ const r = slice(h(sig.r));
171
+ const shl = s.length / 2;
172
+ const rhl = r.length / 2;
173
+ const sl = h(shl);
174
+ const rl = h(rhl);
175
+ return `30${h(rhl + shl + 4)}02${rl}${r}02${sl}${s}`;
176
+ },
177
+ };
178
+
179
+ // Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
180
+ const _0n = BigInt(0);
181
+ const _1n = BigInt(1);
182
+
183
+ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
184
+ const CURVE = validatePointOpts(opts);
185
+ const { Fp } = CURVE; // All curves has same field / group length as for now, but they can differ
186
+
187
+ /**
188
+ * y² = x³ + ax + b: Short weierstrass curve formula
189
+ * @returns y²
190
+ */
191
+ function weierstrassEquation(x: T): T {
192
+ const { a, b } = CURVE;
193
+ const x2 = Fp.sqr(x); // x * x
194
+ const x3 = Fp.mul(x2, x); // x2 * x
195
+ return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x3 + a * x + b
196
+ }
197
+
198
+ // Valid group elements reside in range 1..n-1
199
+ function isWithinCurveOrder(num: bigint): boolean {
200
+ return typeof num === 'bigint' && _0n < num && num < CURVE.n;
201
+ }
202
+ function assertGE(num: bigint) {
203
+ if (!isWithinCurveOrder(num)) throw new Error('Expected valid bigint: 0 < bigint < curve.n');
204
+ }
205
+ // Validates if priv key is valid and converts it to bigint.
206
+ // Supports options CURVE.normalizePrivateKey and CURVE.wrapPrivateKey.
207
+ function normalizePrivateKey(key: PrivKey): bigint {
208
+ const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n } = CURVE;
209
+ if (lengths && typeof key !== 'bigint') {
210
+ if (key instanceof Uint8Array) key = ut.bytesToHex(key);
211
+ // Normalize to hex string, pad. E.g. P521 would norm 130-132 char hex to 132-char bytes
212
+ if (typeof key !== 'string' || !lengths.includes(key.length)) throw new Error('Invalid key');
213
+ key = key.padStart(nByteLength * 2, '0');
214
+ }
215
+ let num: bigint;
216
+ try {
217
+ num =
218
+ typeof key === 'bigint'
219
+ ? key
220
+ : ut.bytesToNumberBE(ensureBytes('private key', key, nByteLength));
221
+ } catch (error) {
222
+ throw new Error(`private key must be ${nByteLength} bytes, hex or bigint, not ${typeof key}`);
223
+ }
224
+ if (wrapPrivateKey) num = mod.mod(num, n); // disabled by default, enabled for BLS
225
+ assertGE(num); // num in range [1..N-1]
226
+ return num;
227
+ }
228
+
229
+ const pointPrecomputes = new Map<Point, Point[]>();
230
+ function assertPrjPoint(other: unknown) {
231
+ if (!(other instanceof Point)) throw new Error('ProjectivePoint expected');
232
+ }
233
+ /**
234
+ * Projective Point works in 3d / projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
235
+ * Default Point works in 2d / affine coordinates: (x, y)
236
+ * We're doing calculations in projective, because its operations don't require costly inversion.
237
+ */
238
+ class Point implements ProjPointType<T> {
239
+ static readonly BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
240
+ static readonly ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO);
241
+
242
+ constructor(readonly px: T, readonly py: T, readonly pz: T) {
243
+ if (px == null || !Fp.isValid(px)) throw new Error('x required');
244
+ if (py == null || !Fp.isValid(py)) throw new Error('y required');
245
+ if (pz == null || !Fp.isValid(pz)) throw new Error('z required');
246
+ }
247
+
248
+ // Does not validate if the point is on-curve.
249
+ // Use fromHex instead, or call assertValidity() later.
250
+ static fromAffine(p: AffinePoint<T>): Point {
251
+ const { x, y } = p || {};
252
+ if (!p || !Fp.isValid(x) || !Fp.isValid(y)) throw new Error('invalid affine point');
253
+ if (p instanceof Point) throw new Error('projective point not allowed');
254
+ const is0 = (i: T) => Fp.eql(i, Fp.ZERO);
255
+ // fromAffine(x:0, y:0) would produce (x:0, y:0, z:1), but we need (x:0, y:1, z:0)
256
+ if (is0(x) && is0(y)) return Point.ZERO;
257
+ return new Point(x, y, Fp.ONE);
258
+ }
259
+
260
+ get x(): T {
261
+ return this.toAffine().x;
262
+ }
263
+ get y(): T {
264
+ return this.toAffine().y;
265
+ }
266
+
267
+ /**
268
+ * Takes a bunch of Projective Points but executes only one
269
+ * inversion on all of them. Inversion is very slow operation,
270
+ * so this improves performance massively.
271
+ * Optimization: converts a list of projective points to a list of identical points with Z=1.
272
+ */
273
+ static normalizeZ(points: Point[]): Point[] {
274
+ const toInv = Fp.invertBatch(points.map((p) => p.pz));
275
+ return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
276
+ }
277
+
278
+ /**
279
+ * Converts hash string or Uint8Array to Point.
280
+ * @param hex short/long ECDSA hex
281
+ */
282
+ static fromHex(hex: Hex): Point {
283
+ const P = Point.fromAffine(CURVE.fromBytes(ensureBytes('pointHex', hex)));
284
+ P.assertValidity();
285
+ return P;
286
+ }
287
+
288
+ // Multiplies generator point by privateKey.
289
+ static fromPrivateKey(privateKey: PrivKey) {
290
+ return Point.BASE.multiply(normalizePrivateKey(privateKey));
291
+ }
292
+
293
+ // We calculate precomputes for elliptic curve point multiplication
294
+ // using windowed method. This specifies window size and
295
+ // stores precomputed values. Usually only base point would be precomputed.
296
+ _WINDOW_SIZE?: number;
297
+
298
+ // "Private method", don't use it directly
299
+ _setWindowSize(windowSize: number) {
300
+ this._WINDOW_SIZE = windowSize;
301
+ pointPrecomputes.delete(this);
302
+ }
303
+
304
+ // A point on curve is valid if it conforms to equation.
305
+ assertValidity(): void {
306
+ // Zero is valid point too!
307
+ if (this.is0()) {
308
+ if (CURVE.allowInfinityPoint) return;
309
+ throw new Error('bad point: ZERO');
310
+ }
311
+ // Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
312
+ const { x, y } = this.toAffine();
313
+ // Check if x, y are valid field elements
314
+ if (!Fp.isValid(x) || !Fp.isValid(y)) throw new Error('bad point: x or y not FE');
315
+ const left = Fp.sqr(y); // y²
316
+ const right = weierstrassEquation(x); // x³ + ax + b
317
+ if (!Fp.eql(left, right)) throw new Error('bad point: equation left != right');
318
+ if (!this.isTorsionFree()) throw new Error('bad point: not in prime-order subgroup');
319
+ }
320
+ hasEvenY(): boolean {
321
+ const { y } = this.toAffine();
322
+ if (Fp.isOdd) return !Fp.isOdd(y);
323
+ throw new Error("Field doesn't support isOdd");
324
+ }
325
+
326
+ /**
327
+ * Compare one point to another.
328
+ */
329
+ equals(other: Point): boolean {
330
+ assertPrjPoint(other);
331
+ const { px: X1, py: Y1, pz: Z1 } = this;
332
+ const { px: X2, py: Y2, pz: Z2 } = other;
333
+ const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
334
+ const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
335
+ return U1 && U2;
336
+ }
337
+
338
+ /**
339
+ * Flips point to one corresponding to (x, -y) in Affine coordinates.
340
+ */
341
+ negate(): Point {
342
+ return new Point(this.px, Fp.neg(this.py), this.pz);
343
+ }
344
+
345
+ // Renes-Costello-Batina exception-free doubling formula.
346
+ // There is 30% faster Jacobian formula, but it is not complete.
347
+ // https://eprint.iacr.org/2015/1060, algorithm 3
348
+ // Cost: 8M + 3S + 3*a + 2*b3 + 15add.
349
+ double() {
350
+ const { a, b } = CURVE;
351
+ const b3 = Fp.mul(b, 3n);
352
+ const { px: X1, py: Y1, pz: Z1 } = this;
353
+ let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
354
+ let t0 = Fp.mul(X1, X1); // step 1
355
+ let t1 = Fp.mul(Y1, Y1);
356
+ let t2 = Fp.mul(Z1, Z1);
357
+ let t3 = Fp.mul(X1, Y1);
358
+ t3 = Fp.add(t3, t3); // step 5
359
+ Z3 = Fp.mul(X1, Z1);
360
+ Z3 = Fp.add(Z3, Z3);
361
+ X3 = Fp.mul(a, Z3);
362
+ Y3 = Fp.mul(b3, t2);
363
+ Y3 = Fp.add(X3, Y3); // step 10
364
+ X3 = Fp.sub(t1, Y3);
365
+ Y3 = Fp.add(t1, Y3);
366
+ Y3 = Fp.mul(X3, Y3);
367
+ X3 = Fp.mul(t3, X3);
368
+ Z3 = Fp.mul(b3, Z3); // step 15
369
+ t2 = Fp.mul(a, t2);
370
+ t3 = Fp.sub(t0, t2);
371
+ t3 = Fp.mul(a, t3);
372
+ t3 = Fp.add(t3, Z3);
373
+ Z3 = Fp.add(t0, t0); // step 20
374
+ t0 = Fp.add(Z3, t0);
375
+ t0 = Fp.add(t0, t2);
376
+ t0 = Fp.mul(t0, t3);
377
+ Y3 = Fp.add(Y3, t0);
378
+ t2 = Fp.mul(Y1, Z1); // step 25
379
+ t2 = Fp.add(t2, t2);
380
+ t0 = Fp.mul(t2, t3);
381
+ X3 = Fp.sub(X3, t0);
382
+ Z3 = Fp.mul(t2, t1);
383
+ Z3 = Fp.add(Z3, Z3); // step 30
384
+ Z3 = Fp.add(Z3, Z3);
385
+ return new Point(X3, Y3, Z3);
386
+ }
387
+
388
+ // Renes-Costello-Batina exception-free addition formula.
389
+ // There is 30% faster Jacobian formula, but it is not complete.
390
+ // https://eprint.iacr.org/2015/1060, algorithm 1
391
+ // Cost: 12M + 0S + 3*a + 3*b3 + 23add.
392
+ add(other: Point): Point {
393
+ assertPrjPoint(other);
394
+ const { px: X1, py: Y1, pz: Z1 } = this;
395
+ const { px: X2, py: Y2, pz: Z2 } = other;
396
+ let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
397
+ const a = CURVE.a;
398
+ const b3 = Fp.mul(CURVE.b, 3n);
399
+ let t0 = Fp.mul(X1, X2); // step 1
400
+ let t1 = Fp.mul(Y1, Y2);
401
+ let t2 = Fp.mul(Z1, Z2);
402
+ let t3 = Fp.add(X1, Y1);
403
+ let t4 = Fp.add(X2, Y2); // step 5
404
+ t3 = Fp.mul(t3, t4);
405
+ t4 = Fp.add(t0, t1);
406
+ t3 = Fp.sub(t3, t4);
407
+ t4 = Fp.add(X1, Z1);
408
+ let t5 = Fp.add(X2, Z2); // step 10
409
+ t4 = Fp.mul(t4, t5);
410
+ t5 = Fp.add(t0, t2);
411
+ t4 = Fp.sub(t4, t5);
412
+ t5 = Fp.add(Y1, Z1);
413
+ X3 = Fp.add(Y2, Z2); // step 15
414
+ t5 = Fp.mul(t5, X3);
415
+ X3 = Fp.add(t1, t2);
416
+ t5 = Fp.sub(t5, X3);
417
+ Z3 = Fp.mul(a, t4);
418
+ X3 = Fp.mul(b3, t2); // step 20
419
+ Z3 = Fp.add(X3, Z3);
420
+ X3 = Fp.sub(t1, Z3);
421
+ Z3 = Fp.add(t1, Z3);
422
+ Y3 = Fp.mul(X3, Z3);
423
+ t1 = Fp.add(t0, t0); // step 25
424
+ t1 = Fp.add(t1, t0);
425
+ t2 = Fp.mul(a, t2);
426
+ t4 = Fp.mul(b3, t4);
427
+ t1 = Fp.add(t1, t2);
428
+ t2 = Fp.sub(t0, t2); // step 30
429
+ t2 = Fp.mul(a, t2);
430
+ t4 = Fp.add(t4, t2);
431
+ t0 = Fp.mul(t1, t4);
432
+ Y3 = Fp.add(Y3, t0);
433
+ t0 = Fp.mul(t5, t4); // step 35
434
+ X3 = Fp.mul(t3, X3);
435
+ X3 = Fp.sub(X3, t0);
436
+ t0 = Fp.mul(t3, t1);
437
+ Z3 = Fp.mul(t5, Z3);
438
+ Z3 = Fp.add(Z3, t0); // step 40
439
+ return new Point(X3, Y3, Z3);
440
+ }
441
+
442
+ subtract(other: Point) {
443
+ return this.add(other.negate());
444
+ }
445
+
446
+ private is0() {
447
+ return this.equals(Point.ZERO);
448
+ }
449
+ private wNAF(n: bigint): { p: Point; f: Point } {
450
+ return wnaf.wNAFCached(this, pointPrecomputes, n, (comp: Point[]) => {
451
+ const toInv = Fp.invertBatch(comp.map((p) => p.pz));
452
+ return comp.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
453
+ });
454
+ }
455
+
456
+ /**
457
+ * Non-constant-time multiplication. Uses double-and-add algorithm.
458
+ * It's faster, but should only be used when you don't care about
459
+ * an exposed private key e.g. sig verification, which works over *public* keys.
460
+ */
461
+ multiplyUnsafe(n: bigint): Point {
462
+ const I = Point.ZERO;
463
+ if (n === _0n) return I;
464
+ assertGE(n); // Will throw on 0
465
+ if (n === _1n) return this;
466
+ const { endo } = CURVE;
467
+ if (!endo) return wnaf.unsafeLadder(this, n);
468
+
469
+ // Apply endomorphism
470
+ let { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
471
+ let k1p = I;
472
+ let k2p = I;
473
+ let d: Point = this;
474
+ while (k1 > _0n || k2 > _0n) {
475
+ if (k1 & _1n) k1p = k1p.add(d);
476
+ if (k2 & _1n) k2p = k2p.add(d);
477
+ d = d.double();
478
+ k1 >>= _1n;
479
+ k2 >>= _1n;
480
+ }
481
+ if (k1neg) k1p = k1p.negate();
482
+ if (k2neg) k2p = k2p.negate();
483
+ k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
484
+ return k1p.add(k2p);
485
+ }
486
+
487
+ /**
488
+ * Constant time multiplication.
489
+ * Uses wNAF method. Windowed method may be 10% faster,
490
+ * but takes 2x longer to generate and consumes 2x memory.
491
+ * @param scalar by which the point would be multiplied
492
+ * @param affinePoint optional point ot save cached precompute windows on it
493
+ * @returns New point
494
+ */
495
+ multiply(scalar: bigint): Point {
496
+ assertGE(scalar);
497
+ let n = scalar;
498
+ let point: Point, fake: Point; // Fake point is used to const-time mult
499
+ const { endo } = CURVE;
500
+ if (endo) {
501
+ const { k1neg, k1, k2neg, k2 } = endo.splitScalar(n);
502
+ let { p: k1p, f: f1p } = this.wNAF(k1);
503
+ let { p: k2p, f: f2p } = this.wNAF(k2);
504
+ k1p = wnaf.constTimeNegate(k1neg, k1p);
505
+ k2p = wnaf.constTimeNegate(k2neg, k2p);
506
+ k2p = new Point(Fp.mul(k2p.px, endo.beta), k2p.py, k2p.pz);
507
+ point = k1p.add(k2p);
508
+ fake = f1p.add(f2p);
509
+ } else {
510
+ const { p, f } = this.wNAF(n);
511
+ point = p;
512
+ fake = f;
513
+ }
514
+ // Normalize `z` for both points, but return only real one
515
+ return Point.normalizeZ([point, fake])[0];
516
+ }
517
+
518
+ /**
519
+ * Efficiently calculate `aP + bQ`. Unsafe, can expose private key, if used incorrectly.
520
+ * @returns non-zero affine point
521
+ */
522
+ multiplyAndAddUnsafe(Q: Point, a: bigint, b: bigint): Point | undefined {
523
+ const G = Point.BASE; // No Strauss-Shamir trick: we have 10% faster G precomputes
524
+ const mul = (
525
+ P: Point,
526
+ a: bigint // Select faster multiply() method
527
+ ) => (a === _0n || a === _1n || !P.equals(G) ? P.multiplyUnsafe(a) : P.multiply(a));
528
+ const sum = mul(this, a).add(mul(Q, b));
529
+ return sum.is0() ? undefined : sum;
530
+ }
531
+
532
+ // Converts Projective point to affine (x, y) coordinates.
533
+ // Can accept precomputed Z^-1 - for example, from invertBatch.
534
+ // (x, y, z) ∋ (x=x/z, y=y/z)
535
+ toAffine(iz?: T): AffinePoint<T> {
536
+ const { px: x, py: y, pz: z } = this;
537
+ const is0 = this.is0();
538
+ // If invZ was 0, we return zero point. However we still want to execute
539
+ // all operations, so we replace invZ with a random number, 1.
540
+ if (iz == null) iz = is0 ? Fp.ONE : Fp.inv(z);
541
+ const ax = Fp.mul(x, iz);
542
+ const ay = Fp.mul(y, iz);
543
+ const zz = Fp.mul(z, iz);
544
+ if (is0) return { x: Fp.ZERO, y: Fp.ZERO };
545
+ if (!Fp.eql(zz, Fp.ONE)) throw new Error('invZ was invalid');
546
+ return { x: ax, y: ay };
547
+ }
548
+ isTorsionFree(): boolean {
549
+ const { h: cofactor, isTorsionFree } = CURVE;
550
+ if (cofactor === _1n) return true; // No subgroups, always torsion-free
551
+ if (isTorsionFree) return isTorsionFree(Point, this);
552
+ throw new Error('isTorsionFree() has not been declared for the elliptic curve');
553
+ }
554
+ clearCofactor(): Point {
555
+ const { h: cofactor, clearCofactor } = CURVE;
556
+ if (cofactor === _1n) return this; // Fast-path
557
+ if (clearCofactor) return clearCofactor(Point, this) as Point;
558
+ return this.multiplyUnsafe(CURVE.h);
559
+ }
560
+
561
+ toRawBytes(isCompressed = true): Uint8Array {
562
+ this.assertValidity();
563
+ return CURVE.toBytes(Point, this, isCompressed);
564
+ }
565
+
566
+ toHex(isCompressed = true): string {
567
+ return ut.bytesToHex(this.toRawBytes(isCompressed));
568
+ }
569
+ }
570
+ const _bits = CURVE.nBitLength;
571
+ const wnaf = wNAF(Point, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
572
+
573
+ return {
574
+ ProjectivePoint: Point as ProjConstructor<T>,
575
+ normalizePrivateKey,
576
+ weierstrassEquation,
577
+ isWithinCurveOrder,
578
+ };
579
+ }
580
+
581
+ // Instance
582
+ export interface SignatureType {
583
+ readonly r: bigint;
584
+ readonly s: bigint;
585
+ readonly recovery?: number;
586
+ assertValidity(): void;
587
+ addRecoveryBit(recovery: number): SignatureType;
588
+ hasHighS(): boolean;
589
+ normalizeS(): SignatureType;
590
+ recoverPublicKey(msgHash: Hex): ProjPointType<bigint>;
591
+ toCompactRawBytes(): Uint8Array;
592
+ toCompactHex(): string;
593
+ // DER-encoded
594
+ toDERRawBytes(isCompressed?: boolean): Uint8Array;
595
+ toDERHex(isCompressed?: boolean): string;
596
+ }
597
+ // Static methods
598
+ export type SignatureConstructor = {
599
+ new (r: bigint, s: bigint): SignatureType;
600
+ fromCompact(hex: Hex): SignatureType;
601
+ fromDER(hex: Hex): SignatureType;
602
+ };
603
+ type SignatureLike = { r: bigint; s: bigint };
604
+
605
+ export type PubKey = Hex | ProjPointType<bigint>;
606
+
607
+ export type CurveType = BasicWCurve<bigint> & {
608
+ hash: CHash; // CHash not FHash because we need outputLen for DRBG
609
+ hmac: HmacFnSync;
610
+ randomBytes: (bytesLength?: number) => Uint8Array;
611
+ lowS?: boolean;
612
+ bits2int?: (bytes: Uint8Array) => bigint;
613
+ bits2int_modN?: (bytes: Uint8Array) => bigint;
614
+ };
615
+
616
+ function validateOpts(curve: CurveType) {
617
+ const opts = validateBasic(curve);
618
+ ut.validateObject(
619
+ opts,
620
+ {
621
+ hash: 'hash',
622
+ hmac: 'function',
623
+ randomBytes: 'function',
624
+ },
625
+ {
626
+ bits2int: 'function',
627
+ bits2int_modN: 'function',
628
+ lowS: 'boolean',
629
+ }
630
+ );
631
+ return Object.freeze({ lowS: true, ...opts } as const);
632
+ }
633
+
634
+ export type CurveFn = {
635
+ CURVE: ReturnType<typeof validateOpts>;
636
+ getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
637
+ getSharedSecret: (privateA: PrivKey, publicB: Hex, isCompressed?: boolean) => Uint8Array;
638
+ sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
639
+ verify: (signature: Hex | SignatureLike, msgHash: Hex, publicKey: Hex, opts?: VerOpts) => boolean;
640
+ ProjectivePoint: ProjConstructor<bigint>;
641
+ Signature: SignatureConstructor;
642
+ utils: {
643
+ normPrivateKeyToScalar: (key: PrivKey) => bigint;
644
+ isValidPrivateKey(privateKey: PrivKey): boolean;
645
+ hashToPrivateKey: (hash: Hex) => Uint8Array;
646
+ randomPrivateKey: () => Uint8Array;
647
+ precompute: (windowSize?: number, point?: ProjPointType<bigint>) => ProjPointType<bigint>;
648
+ };
649
+ };
650
+
651
+ export function weierstrass(curveDef: CurveType): CurveFn {
652
+ const CURVE = validateOpts(curveDef) as ReturnType<typeof validateOpts>;
653
+ const CURVE_ORDER = CURVE.n;
654
+ const Fp = CURVE.Fp;
655
+ const compressedLen = Fp.BYTES + 1; // e.g. 33 for 32
656
+ const uncompressedLen = 2 * Fp.BYTES + 1; // e.g. 65 for 32
657
+
658
+ function isValidFieldElement(num: bigint): boolean {
659
+ return _0n < num && num < Fp.ORDER; // 0 is banned since it's not invertible FE
660
+ }
661
+ function modN(a: bigint) {
662
+ return mod.mod(a, CURVE_ORDER);
663
+ }
664
+ function invN(a: bigint) {
665
+ return mod.invert(a, CURVE_ORDER);
666
+ }
667
+
668
+ const {
669
+ ProjectivePoint: Point,
670
+ normalizePrivateKey,
671
+ weierstrassEquation,
672
+ isWithinCurveOrder,
673
+ } = weierstrassPoints({
674
+ ...CURVE,
675
+ toBytes(c, point, isCompressed: boolean): Uint8Array {
676
+ const a = point.toAffine();
677
+ const x = Fp.toBytes(a.x);
678
+ const cat = ut.concatBytes;
679
+ if (isCompressed) {
680
+ // TODO: hasEvenY
681
+ return cat(Uint8Array.from([point.hasEvenY() ? 0x02 : 0x03]), x);
682
+ } else {
683
+ return cat(Uint8Array.from([0x04]), x, Fp.toBytes(a.y));
684
+ }
685
+ },
686
+ fromBytes(bytes: Uint8Array) {
687
+ const len = bytes.length;
688
+ const head = bytes[0];
689
+ const tail = bytes.subarray(1);
690
+ // this.assertValidity() is done inside of fromHex
691
+ if (len === compressedLen && (head === 0x02 || head === 0x03)) {
692
+ const x = ut.bytesToNumberBE(tail);
693
+ if (!isValidFieldElement(x)) throw new Error('Point is not on curve');
694
+ const y2 = weierstrassEquation(x); // y² = x³ + ax + b
695
+ let y = Fp.sqrt(y2); // y = y² ^ (p+1)/4
696
+ const isYOdd = (y & _1n) === _1n;
697
+ // ECDSA
698
+ const isHeadOdd = (head & 1) === 1;
699
+ if (isHeadOdd !== isYOdd) y = Fp.neg(y);
700
+ return { x, y };
701
+ } else if (len === uncompressedLen && head === 0x04) {
702
+ const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES));
703
+ const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES));
704
+ return { x, y };
705
+ } else {
706
+ throw new Error(
707
+ `Point of length ${len} was invalid. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes`
708
+ );
709
+ }
710
+ },
711
+ });
712
+ const numToNByteStr = (num: bigint): string =>
713
+ ut.bytesToHex(ut.numberToBytesBE(num, CURVE.nByteLength));
714
+
715
+ function isBiggerThanHalfOrder(number: bigint) {
716
+ const HALF = CURVE_ORDER >> _1n;
717
+ return number > HALF;
718
+ }
719
+
720
+ function normalizeS(s: bigint) {
721
+ return isBiggerThanHalfOrder(s) ? modN(-s) : s;
722
+ }
723
+ // slice bytes num
724
+ const slcNum = (b: Uint8Array, from: number, to: number) => ut.bytesToNumberBE(b.slice(from, to));
725
+
726
+ /**
727
+ * ECDSA signature with its (r, s) properties. Supports DER & compact representations.
728
+ */
729
+ class Signature implements SignatureType {
730
+ constructor(readonly r: bigint, readonly s: bigint, readonly recovery?: number) {
731
+ this.assertValidity();
732
+ }
733
+
734
+ // pair (bytes of r, bytes of s)
735
+ static fromCompact(hex: Hex) {
736
+ const l = CURVE.nByteLength;
737
+ hex = ensureBytes('compactSignature', hex, l * 2);
738
+ return new Signature(slcNum(hex, 0, l), slcNum(hex, l, 2 * l));
739
+ }
740
+
741
+ // DER encoded ECDSA signature
742
+ // https://bitcoin.stackexchange.com/questions/57644/what-are-the-parts-of-a-bitcoin-transaction-input-script
743
+ static fromDER(hex: Hex) {
744
+ const { r, s } = DER.toSig(ensureBytes('DER', hex));
745
+ return new Signature(r, s);
746
+ }
747
+
748
+ assertValidity(): void {
749
+ // can use assertGE here
750
+ if (!isWithinCurveOrder(this.r)) throw new Error('r must be 0 < r < CURVE.n');
751
+ if (!isWithinCurveOrder(this.s)) throw new Error('s must be 0 < s < CURVE.n');
752
+ }
753
+
754
+ addRecoveryBit(recovery: number) {
755
+ return new Signature(this.r, this.s, recovery);
756
+ }
757
+
758
+ recoverPublicKey(msgHash: Hex): typeof Point.BASE {
759
+ const { r, s, recovery: rec } = this;
760
+ const h = bits2int_modN(ensureBytes('msgHash', msgHash)); // Truncate hash
761
+ if (rec == null || ![0, 1, 2, 3].includes(rec)) throw new Error('recovery id invalid');
762
+ const radj = rec === 2 || rec === 3 ? r + CURVE.n : r;
763
+ if (radj >= Fp.ORDER) throw new Error('recovery id 2 or 3 invalid');
764
+ const prefix = (rec & 1) === 0 ? '02' : '03';
765
+ const R = Point.fromHex(prefix + numToNByteStr(radj));
766
+ const ir = invN(radj); // r^-1
767
+ const u1 = modN(-h * ir); // -hr^-1
768
+ const u2 = modN(s * ir); // sr^-1
769
+ const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); // (sr^-1)R-(hr^-1)G = -(hr^-1)G + (sr^-1)
770
+ if (!Q) throw new Error('point at infinify'); // unsafe is fine: no priv data leaked
771
+ Q.assertValidity();
772
+ return Q;
773
+ }
774
+
775
+ // Signatures should be low-s, to prevent malleability.
776
+ hasHighS(): boolean {
777
+ return isBiggerThanHalfOrder(this.s);
778
+ }
779
+
780
+ normalizeS() {
781
+ return this.hasHighS() ? new Signature(this.r, modN(-this.s), this.recovery) : this;
782
+ }
783
+
784
+ // DER-encoded
785
+ toDERRawBytes() {
786
+ return ut.hexToBytes(this.toDERHex());
787
+ }
788
+ toDERHex() {
789
+ return DER.hexFromSig({ r: this.r, s: this.s });
790
+ }
791
+
792
+ // padded bytes of r, then padded bytes of s
793
+ toCompactRawBytes() {
794
+ return ut.hexToBytes(this.toCompactHex());
795
+ }
796
+ toCompactHex() {
797
+ return numToNByteStr(this.r) + numToNByteStr(this.s);
798
+ }
799
+ }
800
+
801
+ const utils = {
802
+ isValidPrivateKey(privateKey: PrivKey) {
803
+ try {
804
+ normalizePrivateKey(privateKey);
805
+ return true;
806
+ } catch (error) {
807
+ return false;
808
+ }
809
+ },
810
+ normPrivateKeyToScalar: normalizePrivateKey,
811
+
812
+ /**
813
+ * Converts some bytes to a valid private key. Needs at least (nBitLength+64) bytes.
814
+ */
815
+ hashToPrivateKey: (hash: Hex): Uint8Array =>
816
+ ut.numberToBytesBE(mod.hashToPrivateScalar(hash, CURVE_ORDER), CURVE.nByteLength),
817
+
818
+ /**
819
+ * Produces cryptographically secure private key from random of size (nBitLength+64)
820
+ * as per FIPS 186 B.4.1 with modulo bias being neglible.
821
+ */
822
+ randomPrivateKey: (): Uint8Array => utils.hashToPrivateKey(CURVE.randomBytes(Fp.BYTES + 8)),
823
+
824
+ /**
825
+ * 1. Returns cached point which you can use to pass to `getSharedSecret` or `#multiply` by it.
826
+ * 2. Precomputes point multiplication table. Is done by default on first `getPublicKey()` call.
827
+ * If you want your first getPublicKey to take 0.16ms instead of 20ms, make sure to call
828
+ * utils.precompute() somewhere without arguments first.
829
+ * @param windowSize 2, 4, 8, 16
830
+ * @returns cached point
831
+ */
832
+ precompute(windowSize = 8, point = Point.BASE): typeof Point.BASE {
833
+ point._setWindowSize(windowSize);
834
+ point.multiply(BigInt(3));
835
+ return point;
836
+ },
837
+ };
838
+
839
+ /**
840
+ * Computes public key for a private key. Checks for validity of the private key.
841
+ * @param privateKey private key
842
+ * @param isCompressed whether to return compact (default), or full key
843
+ * @returns Public key, full when isCompressed=false; short when isCompressed=true
844
+ */
845
+ function getPublicKey(privateKey: PrivKey, isCompressed = true): Uint8Array {
846
+ return Point.fromPrivateKey(privateKey).toRawBytes(isCompressed);
847
+ }
848
+
849
+ /**
850
+ * Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
851
+ */
852
+ function isProbPub(item: PrivKey | PubKey): boolean {
853
+ const arr = item instanceof Uint8Array;
854
+ const str = typeof item === 'string';
855
+ const len = (arr || str) && (item as Hex).length;
856
+ if (arr) return len === compressedLen || len === uncompressedLen;
857
+ if (str) return len === 2 * compressedLen || len === 2 * uncompressedLen;
858
+ if (item instanceof Point) return true;
859
+ return false;
860
+ }
861
+
862
+ /**
863
+ * ECDH (Elliptic Curve Diffie Hellman).
864
+ * Computes shared public key from private key and public key.
865
+ * Checks: 1) private key validity 2) shared key is on-curve
866
+ * @param privateA private key
867
+ * @param publicB different public key
868
+ * @param isCompressed whether to return compact (default), or full key
869
+ * @returns shared public key
870
+ */
871
+ function getSharedSecret(privateA: PrivKey, publicB: Hex, isCompressed = true): Uint8Array {
872
+ if (isProbPub(privateA)) throw new Error('first arg must be private key');
873
+ if (!isProbPub(publicB)) throw new Error('second arg must be public key');
874
+ const b = Point.fromHex(publicB); // check for being on-curve
875
+ return b.multiply(normalizePrivateKey(privateA)).toRawBytes(isCompressed);
876
+ }
877
+
878
+ // RFC6979: ensure ECDSA msg is X bytes and < N. RFC suggests optional truncating via bits2octets.
879
+ // FIPS 186-4 4.6 suggests the leftmost min(nBitLen, outLen) bits, which matches bits2int.
880
+ // bits2int can produce res>N, we can do mod(res, N) since the bitLen is the same.
881
+ // int2octets can't be used; pads small msgs with 0: unacceptatble for trunc as per RFC vectors
882
+ const bits2int =
883
+ CURVE.bits2int ||
884
+ function (bytes: Uint8Array): bigint {
885
+ // For curves with nBitLength % 8 !== 0: bits2octets(bits2octets(m)) !== bits2octets(m)
886
+ // for some cases, since bytes.length * 8 is not actual bitLength.
887
+ const num = ut.bytesToNumberBE(bytes); // check for == u8 done here
888
+ const delta = bytes.length * 8 - CURVE.nBitLength; // truncate to nBitLength leftmost bits
889
+ return delta > 0 ? num >> BigInt(delta) : num;
890
+ };
891
+ const bits2int_modN =
892
+ CURVE.bits2int_modN ||
893
+ function (bytes: Uint8Array): bigint {
894
+ return modN(bits2int(bytes)); // can't use bytesToNumberBE here
895
+ };
896
+ // NOTE: pads output with zero as per spec
897
+ const ORDER_MASK = ut.bitMask(CURVE.nBitLength);
898
+ function int2octets(num: bigint): Uint8Array {
899
+ if (typeof num !== 'bigint') throw new Error('bigint expected');
900
+ if (!(_0n <= num && num < ORDER_MASK))
901
+ // n in [0..ORDER_MASK-1]
902
+ throw new Error(`bigint expected < 2^${CURVE.nBitLength}`);
903
+ // works with order, can have different size than numToField!
904
+ return ut.numberToBytesBE(num, CURVE.nByteLength);
905
+ }
906
+
907
+ // Steps A, D of RFC6979 3.2
908
+ // Creates RFC6979 seed; converts msg/privKey to numbers.
909
+ // Used only in sign, not in verify.
910
+ // NOTE: we cannot assume here that msgHash has same amount of bytes as curve order, this will be wrong at least for P521.
911
+ // Also it can be bigger for P224 + SHA256
912
+ function prepSig(msgHash: Hex, privateKey: PrivKey, opts = defaultSigOpts) {
913
+ if (['recovered', 'canonical'].some((k) => k in opts))
914
+ throw new Error('sign() legacy options not supported');
915
+ const { hash, randomBytes } = CURVE;
916
+ let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
917
+ if (lowS == null) lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash
918
+ msgHash = ensureBytes('msgHash', msgHash);
919
+ if (prehash) msgHash = ensureBytes('prehashed msgHash', hash(msgHash));
920
+
921
+ // We can't later call bits2octets, since nested bits2int is broken for curves
922
+ // with nBitLength % 8 !== 0. Because of that, we unwrap it here as int2octets call.
923
+ // const bits2octets = (bits) => int2octets(bits2int_modN(bits))
924
+ const h1int = bits2int_modN(msgHash);
925
+ const d = normalizePrivateKey(privateKey); // validate private key, convert to bigint
926
+ const seedArgs = [int2octets(d), int2octets(h1int)];
927
+ // extraEntropy. RFC6979 3.6: additional k' (optional).
928
+ if (ent != null) {
929
+ // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
930
+ const e = ent === true ? randomBytes(Fp.BYTES) : ent; // generate random bytes OR pass as-is
931
+ seedArgs.push(ensureBytes('extraEntropy', e, Fp.BYTES)); // check for being of size BYTES
932
+ }
933
+ const seed = ut.concatBytes(...seedArgs); // Step D of RFC6979 3.2
934
+ const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
935
+ // Converts signature params into point w r/s, checks result for validity.
936
+ function k2sig(kBytes: Uint8Array): Signature | undefined {
937
+ // RFC 6979 Section 3.2, step 3: k = bits2int(T)
938
+ const k = bits2int(kBytes); // Cannot use fields methods, since it is group element
939
+ if (!isWithinCurveOrder(k)) return; // Important: all mod() calls here must be done over N
940
+ const ik = invN(k); // k^-1 mod n
941
+ const q = Point.BASE.multiply(k).toAffine(); // q = Gk
942
+ const r = modN(q.x); // r = q.x mod n
943
+ if (r === _0n) return;
944
+ // X blinding according to https://tches.iacr.org/index.php/TCHES/article/view/7337/6509
945
+ // b * m + b * r * d ∈ [0,q−1] exposed via side-channel, but d (private scalar) is not.
946
+ // NOTE: there is still probable some leak in multiplication, since it is not constant-time
947
+ const b = ut.bytesToNumberBE(utils.randomPrivateKey()); // random scalar, b ∈ [1,q−1]
948
+ const bi = invN(b); // b^-1
949
+ const bdr = modN(b * d * r); // b * d * r
950
+ const bm = modN(b * m); // b * m
951
+ const mrx = modN(bi * modN(bdr + bm)); // b^-1(bm + bdr) -> m + rd
952
+
953
+ const s = modN(ik * mrx); // s = k^-1(m + rd) mod n
954
+ if (s === _0n) return;
955
+ let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n); // recovery bit (2 or 3, when q.x > n)
956
+ let normS = s;
957
+ if (lowS && isBiggerThanHalfOrder(s)) {
958
+ normS = normalizeS(s); // if lowS was passed, ensure s is always
959
+ recovery ^= 1; // // in the bottom half of N
960
+ }
961
+ return new Signature(r, normS, recovery); // use normS, not s
962
+ }
963
+ return { seed, k2sig };
964
+ }
965
+ const defaultSigOpts: SignOpts = { lowS: CURVE.lowS, prehash: false };
966
+ const defaultVerOpts: VerOpts = { lowS: CURVE.lowS, prehash: false };
967
+
968
+ /**
969
+ * Signs message hash (not message: you need to hash it by yourself).
970
+ * ```
971
+ * sign(m, d, k) where
972
+ * (x, y) = G × k
973
+ * r = x mod n
974
+ * s = (m + dr)/k mod n
975
+ * ```
976
+ * @param opts `lowS, extraEntropy, prehash`
977
+ */
978
+ function sign(msgHash: Hex, privKey: PrivKey, opts = defaultSigOpts): Signature {
979
+ const { seed, k2sig } = prepSig(msgHash, privKey, opts); // Steps A, D of RFC6979 3.2.
980
+ const drbg = ut.createHmacDrbg<Signature>(CURVE.hash.outputLen, CURVE.nByteLength, CURVE.hmac);
981
+ return drbg(seed, k2sig); // Steps B, C, D, E, F, G
982
+ }
983
+
984
+ // Enable precomputes. Slows down first publicKey computation by 20ms.
985
+ Point.BASE._setWindowSize(8);
986
+ // utils.precompute(8, ProjectivePoint.BASE)
987
+
988
+ /**
989
+ * Verifies a signature against message hash and public key.
990
+ * Rejects lowS signatures by default: to override,
991
+ * specify option `{lowS: false}`. Implements section 4.1.4 from https://www.secg.org/sec1-v2.pdf:
992
+ *
993
+ * ```
994
+ * verify(r, s, h, P) where
995
+ * U1 = hs^-1 mod n
996
+ * U2 = rs^-1 mod n
997
+ * R = U1⋅G - U2⋅P
998
+ * mod(R.x, n) == r
999
+ * ```
1000
+ */
1001
+ function verify(
1002
+ signature: Hex | SignatureLike,
1003
+ msgHash: Hex,
1004
+ publicKey: Hex,
1005
+ opts = defaultVerOpts
1006
+ ): boolean {
1007
+ const sg = signature;
1008
+ msgHash = ensureBytes('msgHash', msgHash);
1009
+ publicKey = ensureBytes('publicKey', publicKey);
1010
+ if ('strict' in opts) throw new Error('options.strict was renamed to lowS');
1011
+ const { lowS, prehash } = opts;
1012
+
1013
+ let _sig: Signature | undefined = undefined;
1014
+ let P: ProjPointType<bigint>;
1015
+ try {
1016
+ if (typeof sg === 'string' || sg instanceof Uint8Array) {
1017
+ // Signature can be represented in 2 ways: compact (2*nByteLength) & DER (variable-length).
1018
+ // Since DER can also be 2*nByteLength bytes, we check for it first.
1019
+ try {
1020
+ _sig = Signature.fromDER(sg);
1021
+ } catch (derError) {
1022
+ if (!(derError instanceof DER.Err)) throw derError;
1023
+ _sig = Signature.fromCompact(sg);
1024
+ }
1025
+ } else if (typeof sg === 'object' && typeof sg.r === 'bigint' && typeof sg.s === 'bigint') {
1026
+ const { r, s } = sg;
1027
+ _sig = new Signature(r, s);
1028
+ } else {
1029
+ throw new Error('PARSE');
1030
+ }
1031
+ P = Point.fromHex(publicKey);
1032
+ } catch (error) {
1033
+ if ((error as Error).message === 'PARSE')
1034
+ throw new Error(`signature must be Signature instance, Uint8Array or hex string`);
1035
+ return false;
1036
+ }
1037
+ if (lowS && _sig.hasHighS()) return false;
1038
+ if (prehash) msgHash = CURVE.hash(msgHash);
1039
+ const { r, s } = _sig;
1040
+ const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element
1041
+ const is = invN(s); // s^-1
1042
+ const u1 = modN(h * is); // u1 = hs^-1 mod n
1043
+ const u2 = modN(r * is); // u2 = rs^-1 mod n
1044
+ const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2)?.toAffine(); // R = u1⋅G + u2⋅P
1045
+ if (!R) return false;
1046
+ const v = modN(R.x);
1047
+ return v === r;
1048
+ }
1049
+ return {
1050
+ CURVE,
1051
+ getPublicKey,
1052
+ getSharedSecret,
1053
+ sign,
1054
+ verify,
1055
+ ProjectivePoint: Point,
1056
+ Signature,
1057
+ utils,
1058
+ };
1059
+ }
1060
+
1061
+ // Implementation of the Shallue and van de Woestijne method for any Weierstrass curve
1062
+
1063
+ // TODO: check if there is a way to merge this with uvRatio in Edwards && move to modular?
1064
+ // b = True and y = sqrt(u / v) if (u / v) is square in F, and
1065
+ // b = False and y = sqrt(Z * (u / v)) otherwise.
1066
+ export function SWUFpSqrtRatio<T>(Fp: mod.Field<T>, Z: T) {
1067
+ // Generic implementation
1068
+ const q = Fp.ORDER;
1069
+ let l = 0n;
1070
+ for (let o = q - 1n; o % 2n === 0n; o /= 2n) l += 1n;
1071
+ const c1 = l; // 1. c1, the largest integer such that 2^c1 divides q - 1.
1072
+ const c2 = (q - 1n) / 2n ** c1; // 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
1073
+ const c3 = (c2 - 1n) / 2n; // 3. c3 = (c2 - 1) / 2 # Integer arithmetic
1074
+ const c4 = 2n ** c1 - 1n; // 4. c4 = 2^c1 - 1 # Integer arithmetic
1075
+ const c5 = 2n ** (c1 - 1n); // 5. c5 = 2^(c1 - 1) # Integer arithmetic
1076
+ const c6 = Fp.pow(Z, c2); // 6. c6 = Z^c2
1077
+ const c7 = Fp.pow(Z, (c2 + 1n) / 2n); // 7. c7 = Z^((c2 + 1) / 2)
1078
+ let sqrtRatio = (u: T, v: T): { isValid: boolean; value: T } => {
1079
+ let tv1 = c6; // 1. tv1 = c6
1080
+ let tv2 = Fp.pow(v, c4); // 2. tv2 = v^c4
1081
+ let tv3 = Fp.sqr(tv2); // 3. tv3 = tv2^2
1082
+ tv3 = Fp.mul(tv3, v); // 4. tv3 = tv3 * v
1083
+ let tv5 = Fp.mul(u, tv3); // 5. tv5 = u * tv3
1084
+ tv5 = Fp.pow(tv5, c3); // 6. tv5 = tv5^c3
1085
+ tv5 = Fp.mul(tv5, tv2); // 7. tv5 = tv5 * tv2
1086
+ tv2 = Fp.mul(tv5, v); // 8. tv2 = tv5 * v
1087
+ tv3 = Fp.mul(tv5, u); // 9. tv3 = tv5 * u
1088
+ let tv4 = Fp.mul(tv3, tv2); // 10. tv4 = tv3 * tv2
1089
+ tv5 = Fp.pow(tv4, c5); // 11. tv5 = tv4^c5
1090
+ let isQR = Fp.eql(tv5, Fp.ONE); // 12. isQR = tv5 == 1
1091
+ tv2 = Fp.mul(tv3, c7); // 13. tv2 = tv3 * c7
1092
+ tv5 = Fp.mul(tv4, tv1); // 14. tv5 = tv4 * tv1
1093
+ tv3 = Fp.cmov(tv2, tv3, isQR); // 15. tv3 = CMOV(tv2, tv3, isQR)
1094
+ tv4 = Fp.cmov(tv5, tv4, isQR); // 16. tv4 = CMOV(tv5, tv4, isQR)
1095
+ // 17. for i in (c1, c1 - 1, ..., 2):
1096
+ for (let i = c1; i > 1; i--) {
1097
+ let tv5 = 2n ** (i - 2n); // 18. tv5 = i - 2; 19. tv5 = 2^tv5
1098
+ let tvv5 = Fp.pow(tv4, tv5); // 20. tv5 = tv4^tv5
1099
+ const e1 = Fp.eql(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
1100
+ tv2 = Fp.mul(tv3, tv1); // 22. tv2 = tv3 * tv1
1101
+ tv1 = Fp.mul(tv1, tv1); // 23. tv1 = tv1 * tv1
1102
+ tvv5 = Fp.mul(tv4, tv1); // 24. tv5 = tv4 * tv1
1103
+ tv3 = Fp.cmov(tv2, tv3, e1); // 25. tv3 = CMOV(tv2, tv3, e1)
1104
+ tv4 = Fp.cmov(tvv5, tv4, e1); // 26. tv4 = CMOV(tv5, tv4, e1)
1105
+ }
1106
+ return { isValid: isQR, value: tv3 };
1107
+ };
1108
+ if (Fp.ORDER % 4n === 3n) {
1109
+ // sqrt_ratio_3mod4(u, v)
1110
+ const c1 = (Fp.ORDER - 3n) / 4n; // 1. c1 = (q - 3) / 4 # Integer arithmetic
1111
+ const c2 = Fp.sqrt(Fp.neg(Z)); // 2. c2 = sqrt(-Z)
1112
+ sqrtRatio = (u: T, v: T) => {
1113
+ let tv1 = Fp.sqr(v); // 1. tv1 = v^2
1114
+ const tv2 = Fp.mul(u, v); // 2. tv2 = u * v
1115
+ tv1 = Fp.mul(tv1, tv2); // 3. tv1 = tv1 * tv2
1116
+ let y1 = Fp.pow(tv1, c1); // 4. y1 = tv1^c1
1117
+ y1 = Fp.mul(y1, tv2); // 5. y1 = y1 * tv2
1118
+ const y2 = Fp.mul(y1, c2); // 6. y2 = y1 * c2
1119
+ const tv3 = Fp.mul(Fp.sqr(y1), v); // 7. tv3 = y1^2; 8. tv3 = tv3 * v
1120
+ const isQR = Fp.eql(tv3, u); // 9. isQR = tv3 == u
1121
+ let y = Fp.cmov(y2, y1, isQR); // 10. y = CMOV(y2, y1, isQR)
1122
+ return { isValid: isQR, value: y }; // 11. return (isQR, y) isQR ? y : y*c2
1123
+ };
1124
+ }
1125
+ // No curves uses that
1126
+ // if (Fp.ORDER % 8n === 5n) // sqrt_ratio_5mod8
1127
+ return sqrtRatio;
1128
+ }
1129
+ // From draft-irtf-cfrg-hash-to-curve-16
1130
+ export function mapToCurveSimpleSWU<T>(
1131
+ Fp: mod.Field<T>,
1132
+ opts: {
1133
+ A: T;
1134
+ B: T;
1135
+ Z: T;
1136
+ }
1137
+ ) {
1138
+ mod.validateField(Fp);
1139
+ if (!Fp.isValid(opts.A) || !Fp.isValid(opts.B) || !Fp.isValid(opts.Z))
1140
+ throw new Error('mapToCurveSimpleSWU: invalid opts');
1141
+ const sqrtRatio = SWUFpSqrtRatio(Fp, opts.Z);
1142
+ if (!Fp.isOdd) throw new Error('Fp.isOdd is not implemented!');
1143
+ // Input: u, an element of F.
1144
+ // Output: (x, y), a point on E.
1145
+ return (u: T): { x: T; y: T } => {
1146
+ // prettier-ignore
1147
+ let tv1, tv2, tv3, tv4, tv5, tv6, x, y;
1148
+ tv1 = Fp.sqr(u); // 1. tv1 = u^2
1149
+ tv1 = Fp.mul(tv1, opts.Z); // 2. tv1 = Z * tv1
1150
+ tv2 = Fp.sqr(tv1); // 3. tv2 = tv1^2
1151
+ tv2 = Fp.add(tv2, tv1); // 4. tv2 = tv2 + tv1
1152
+ tv3 = Fp.add(tv2, Fp.ONE); // 5. tv3 = tv2 + 1
1153
+ tv3 = Fp.mul(tv3, opts.B); // 6. tv3 = B * tv3
1154
+ tv4 = Fp.cmov(opts.Z, Fp.neg(tv2), !Fp.eql(tv2, Fp.ZERO)); // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
1155
+ tv4 = Fp.mul(tv4, opts.A); // 8. tv4 = A * tv4
1156
+ tv2 = Fp.sqr(tv3); // 9. tv2 = tv3^2
1157
+ tv6 = Fp.sqr(tv4); // 10. tv6 = tv4^2
1158
+ tv5 = Fp.mul(tv6, opts.A); // 11. tv5 = A * tv6
1159
+ tv2 = Fp.add(tv2, tv5); // 12. tv2 = tv2 + tv5
1160
+ tv2 = Fp.mul(tv2, tv3); // 13. tv2 = tv2 * tv3
1161
+ tv6 = Fp.mul(tv6, tv4); // 14. tv6 = tv6 * tv4
1162
+ tv5 = Fp.mul(tv6, opts.B); // 15. tv5 = B * tv6
1163
+ tv2 = Fp.add(tv2, tv5); // 16. tv2 = tv2 + tv5
1164
+ x = Fp.mul(tv1, tv3); // 17. x = tv1 * tv3
1165
+ const { isValid, value } = sqrtRatio(tv2, tv6); // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6)
1166
+ y = Fp.mul(tv1, u); // 19. y = tv1 * u -> Z * u^3 * y1
1167
+ y = Fp.mul(y, value); // 20. y = y * y1
1168
+ x = Fp.cmov(x, tv3, isValid); // 21. x = CMOV(x, tv3, is_gx1_square)
1169
+ y = Fp.cmov(y, value, isValid); // 22. y = CMOV(y, y1, is_gx1_square)
1170
+ const e1 = Fp.isOdd!(u) === Fp.isOdd!(y); // 23. e1 = sgn0(u) == sgn0(y)
1171
+ y = Fp.cmov(Fp.neg(y), y, e1); // 24. y = CMOV(-y, y, e1)
1172
+ x = Fp.div(x, tv4); // 25. x = x / tv4
1173
+ return { x, y };
1174
+ };
1175
+ }