@noble/curves 0.3.1 → 0.4.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.
- package/README.md +2 -1
- package/lib/bls.d.ts +79 -0
- package/lib/bls.js +304 -0
- package/lib/edwards.d.ts +10 -6
- package/lib/edwards.js +16 -11
- package/lib/esm/bls.js +300 -0
- package/lib/esm/edwards.js +17 -12
- package/lib/esm/group.js +2 -2
- package/lib/esm/hashToCurve.js +105 -0
- package/lib/esm/modular.js +131 -50
- package/lib/esm/utils.js +25 -19
- package/lib/esm/weierstrass.js +351 -272
- package/lib/group.js +2 -2
- package/lib/hashToCurve.d.ts +13 -0
- package/lib/hashToCurve.js +112 -0
- package/lib/modular.d.ts +37 -17
- package/lib/modular.js +138 -54
- package/lib/utils.d.ts +28 -10
- package/lib/utils.js +31 -22
- package/lib/weierstrass.d.ts +106 -69
- package/lib/weierstrass.js +352 -272
- package/package.json +23 -44
- package/lib/crypto.d.ts +0 -4
- package/lib/crypto.js +0 -8
- package/lib/cryptoBrowser.d.ts +0 -4
- package/lib/cryptoBrowser.js +0 -7
- package/lib/definitions/_shortw_utils.d.ts +0 -63
- package/lib/definitions/_shortw_utils.js +0 -18
- package/lib/definitions/bn.d.ts +0 -7
- package/lib/definitions/bn.js +0 -23
- package/lib/definitions/ed25519.d.ts +0 -49
- package/lib/definitions/ed25519.js +0 -308
- package/lib/definitions/ed448.d.ts +0 -3
- package/lib/definitions/ed448.js +0 -127
- package/lib/definitions/index.d.ts +0 -0
- package/lib/definitions/index.js +0 -2
- package/lib/definitions/jubjub.d.ts +0 -7
- package/lib/definitions/jubjub.js +0 -55
- package/lib/definitions/p192.d.ts +0 -112
- package/lib/definitions/p192.js +0 -23
- package/lib/definitions/p224.d.ts +0 -112
- package/lib/definitions/p224.js +0 -24
- package/lib/definitions/p256.d.ts +0 -112
- package/lib/definitions/p256.js +0 -23
- package/lib/definitions/p384.d.ts +0 -112
- package/lib/definitions/p384.js +0 -24
- package/lib/definitions/p521.d.ts +0 -113
- package/lib/definitions/p521.js +0 -36
- package/lib/definitions/pasta.d.ts +0 -2
- package/lib/definitions/pasta.js +0 -32
- package/lib/definitions/secp256k1.d.ts +0 -87
- package/lib/definitions/secp256k1.js +0 -245
- package/lib/definitions/stark.d.ts +0 -62
- package/lib/definitions/stark.js +0 -248
- package/lib/esm/crypto.js +0 -5
- package/lib/esm/cryptoBrowser.js +0 -4
- package/lib/esm/definitions/_shortw_utils.js +0 -13
- package/lib/esm/definitions/bn.js +0 -20
- package/lib/esm/definitions/ed25519.js +0 -304
- package/lib/esm/definitions/ed448.js +0 -124
- package/lib/esm/definitions/index.js +0 -2
- package/lib/esm/definitions/jubjub.js +0 -50
- package/lib/esm/definitions/p192.js +0 -20
- package/lib/esm/definitions/p224.js +0 -21
- package/lib/esm/definitions/p256.js +0 -20
- package/lib/esm/definitions/p384.js +0 -21
- package/lib/esm/definitions/p521.js +0 -33
- package/lib/esm/definitions/pasta.js +0 -29
- package/lib/esm/definitions/secp256k1.js +0 -241
- package/lib/esm/definitions/stark.js +0 -227
package/lib/weierstrass.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
3
3
|
// Implementation of Short Weierstrass curve. The formula is: y² = x³ + ax + b
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.weierstrass = void 0;
|
|
5
|
+
exports.weierstrass = exports.weierstrassPoints = void 0;
|
|
6
6
|
// TODO: sync vs async naming
|
|
7
7
|
// TODO: default randomBytes
|
|
8
8
|
// Differences from @noble/secp256k1 1.7:
|
|
@@ -12,41 +12,9 @@ exports.weierstrass = void 0;
|
|
|
12
12
|
// 4. DRBG supports outputLen bigger than outputLen of hmac
|
|
13
13
|
const mod = require("./modular.js");
|
|
14
14
|
const utils_js_1 = require("./utils.js");
|
|
15
|
+
const utils = require("./utils.js");
|
|
16
|
+
const hashToCurve_js_1 = require("./hashToCurve.js");
|
|
15
17
|
const group_js_1 = require("./group.js");
|
|
16
|
-
// Should be separate from overrides, since overrides can use information about curve (for example nBits)
|
|
17
|
-
function validateOpts(curve) {
|
|
18
|
-
const opts = (0, utils_js_1.validateOpts)(curve);
|
|
19
|
-
for (const i of ['a', 'b']) {
|
|
20
|
-
if (typeof opts[i] !== 'bigint')
|
|
21
|
-
throw new Error(`Invalid curve param ${i}=${opts[i]} (${typeof opts[i]})`);
|
|
22
|
-
}
|
|
23
|
-
for (const fn of ['hash', 'hmac']) {
|
|
24
|
-
if (typeof opts[fn] !== 'function')
|
|
25
|
-
throw new Error(`Invalid ${fn} function`);
|
|
26
|
-
}
|
|
27
|
-
for (const fn of ['randomBytes']) {
|
|
28
|
-
if (opts[fn] === undefined)
|
|
29
|
-
continue; // Optional
|
|
30
|
-
if (typeof opts[fn] !== 'function')
|
|
31
|
-
throw new Error(`Invalid ${fn} function`);
|
|
32
|
-
}
|
|
33
|
-
if (!Number.isSafeInteger(opts.hash.outputLen))
|
|
34
|
-
throw new Error('Invalid hash function');
|
|
35
|
-
const endo = opts.endo;
|
|
36
|
-
if (endo) {
|
|
37
|
-
if (opts.a !== _0n) {
|
|
38
|
-
throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');
|
|
39
|
-
}
|
|
40
|
-
if (typeof endo !== 'object' ||
|
|
41
|
-
typeof endo.beta !== 'bigint' ||
|
|
42
|
-
typeof endo.splitScalar !== 'function') {
|
|
43
|
-
throw new Error('Expected endomorphism with beta: bigint and splitScalar: function');
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
// Set defaults
|
|
47
|
-
return Object.freeze({ lowS: true, randomBytes: utils_js_1.randomBytes, ...opts });
|
|
48
|
-
}
|
|
49
|
-
// TODO: convert bits to bytes aligned to 32 bits? (224 for example)
|
|
50
18
|
// DER encoding utilities
|
|
51
19
|
class DERError extends Error {
|
|
52
20
|
constructor(message) {
|
|
@@ -93,108 +61,73 @@ const _1n = BigInt(1);
|
|
|
93
61
|
const _2n = BigInt(2);
|
|
94
62
|
const _3n = BigInt(3);
|
|
95
63
|
const _8n = BigInt(8);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
this.hashLen = hashLen;
|
|
103
|
-
this.qByteLen = qByteLen;
|
|
104
|
-
this.hmacFn = hmacFn;
|
|
105
|
-
if (typeof hashLen !== 'number' || hashLen < 2)
|
|
106
|
-
throw new Error('hashLen must be a number');
|
|
107
|
-
if (typeof qByteLen !== 'number' || qByteLen < 2)
|
|
108
|
-
throw new Error('qByteLen must be a number');
|
|
109
|
-
if (typeof hmacFn !== 'function')
|
|
110
|
-
throw new Error('hmacFn must be a function');
|
|
111
|
-
// Step B, Step C: set hashLen to 8*ceil(hlen/8)
|
|
112
|
-
this.v = new Uint8Array(hashLen).fill(1);
|
|
113
|
-
this.k = new Uint8Array(hashLen).fill(0);
|
|
114
|
-
this.counter = 0;
|
|
115
|
-
}
|
|
116
|
-
hmacSync(...values) {
|
|
117
|
-
return this.hmacFn(this.k, ...values);
|
|
118
|
-
}
|
|
119
|
-
incr() {
|
|
120
|
-
if (this.counter >= 1000)
|
|
121
|
-
throw new Error('Tried 1,000 k values for sign(), all were invalid');
|
|
122
|
-
this.counter += 1;
|
|
64
|
+
function validatePointOpts(curve) {
|
|
65
|
+
const opts = utils.validateOpts(curve);
|
|
66
|
+
const Fp = opts.Fp;
|
|
67
|
+
for (const i of ['a', 'b']) {
|
|
68
|
+
if (!Fp.isValid(curve[i]))
|
|
69
|
+
throw new Error(`Invalid curve param ${i}=${opts[i]} (${typeof opts[i]})`);
|
|
123
70
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
this.k = this.hmacSync(this.v, Uint8Array.from([0x01]), seed);
|
|
130
|
-
this.v = this.hmacSync(this.v);
|
|
71
|
+
for (const i of ['isTorsionFree', 'clearCofactor', 'mapToCurve']) {
|
|
72
|
+
if (curve[i] === undefined)
|
|
73
|
+
continue; // Optional
|
|
74
|
+
if (typeof curve[i] !== 'function')
|
|
75
|
+
throw new Error(`Invalid ${i} function`);
|
|
131
76
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
len += this.v.length;
|
|
77
|
+
const endo = opts.endo;
|
|
78
|
+
if (endo) {
|
|
79
|
+
if (!Fp.equals(opts.a, Fp.ZERO)) {
|
|
80
|
+
throw new Error('Endomorphism can only be defined for Koblitz curves that have a=0');
|
|
81
|
+
}
|
|
82
|
+
if (typeof endo !== 'object' ||
|
|
83
|
+
typeof endo.beta !== 'bigint' ||
|
|
84
|
+
typeof endo.splitScalar !== 'function') {
|
|
85
|
+
throw new Error('Expected endomorphism with beta: bigint and splitScalar: function');
|
|
142
86
|
}
|
|
143
|
-
return (0, utils_js_1.concatBytes)(...out);
|
|
144
87
|
}
|
|
88
|
+
if (typeof opts.fromBytes !== 'function')
|
|
89
|
+
throw new Error('Invalid fromBytes function');
|
|
90
|
+
if (typeof opts.toBytes !== 'function')
|
|
91
|
+
throw new Error('Invalid fromBytes function');
|
|
92
|
+
// Requires including hashToCurve file
|
|
93
|
+
if (opts.htfDefaults !== undefined)
|
|
94
|
+
(0, hashToCurve_js_1.validateHTFOpts)(opts.htfDefaults);
|
|
95
|
+
// Set defaults
|
|
96
|
+
return Object.freeze({ ...opts });
|
|
145
97
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
const CURVE_ORDER = CURVE.n;
|
|
98
|
+
function weierstrassPoints(opts) {
|
|
99
|
+
const CURVE = validatePointOpts(opts);
|
|
100
|
+
const Fp = CURVE.Fp;
|
|
150
101
|
// Lengths
|
|
151
102
|
// All curves has same field / group length as for now, but it can be different for other curves
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
if (fieldLen > 2048)
|
|
155
|
-
throw new Error('Field lengths over 2048 are not supported');
|
|
156
|
-
const compressedLen = fieldLen + 1; // 33
|
|
157
|
-
const uncompressedLen = 2 * fieldLen + 1; // 65
|
|
103
|
+
const { nByteLength, nBitLength } = CURVE;
|
|
104
|
+
const groupLen = nByteLength;
|
|
158
105
|
// Not using ** operator with bigints for old engines.
|
|
159
106
|
// 2n ** (8n * 32n) == 2n << (8n * 32n - 1n)
|
|
160
|
-
const FIELD_MASK = _2n << (_8n * BigInt(fieldLen) - _1n);
|
|
161
|
-
function numToFieldStr(num) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
return num.toString(16).padStart(2 * fieldLen, '0');
|
|
167
|
-
}
|
|
168
|
-
function numToField(num) {
|
|
169
|
-
const b = (0, utils_js_1.hexToBytes)(numToFieldStr(num));
|
|
170
|
-
if (b.length !== fieldLen)
|
|
171
|
-
throw new Error(`Error: expected ${fieldLen} bytes`);
|
|
172
|
-
return b;
|
|
173
|
-
}
|
|
174
|
-
function modP(n, m = CURVE.P) {
|
|
175
|
-
return mod.mod(n, m);
|
|
176
|
-
}
|
|
107
|
+
//const FIELD_MASK = _2n << (_8n * BigInt(fieldLen) - _1n);
|
|
108
|
+
// function numToFieldStr(num: bigint): string {
|
|
109
|
+
// if (typeof num !== 'bigint') throw new Error('Expected bigint');
|
|
110
|
+
// if (!(_0n <= num && num < FIELD_MASK)) throw new Error(`Expected number < 2^${fieldLen * 8}`);
|
|
111
|
+
// return num.toString(16).padStart(2 * fieldLen, '0');
|
|
112
|
+
// }
|
|
177
113
|
/**
|
|
178
114
|
* y² = x³ + ax + b: Short weierstrass curve formula
|
|
179
115
|
* @returns y²
|
|
180
116
|
*/
|
|
181
117
|
function weierstrassEquation(x) {
|
|
182
118
|
const { a, b } = CURVE;
|
|
183
|
-
const x2 =
|
|
184
|
-
const x3 =
|
|
185
|
-
return
|
|
119
|
+
const x2 = Fp.square(x); // x * x
|
|
120
|
+
const x3 = Fp.multiply(x2, x); // x2 * x
|
|
121
|
+
return Fp.add(Fp.add(x3, Fp.multiply(x, a)), b); // x3 + a * x + b
|
|
186
122
|
}
|
|
187
123
|
function isWithinCurveOrder(num) {
|
|
188
124
|
return _0n < num && num < CURVE.n;
|
|
189
125
|
}
|
|
190
|
-
function isValidFieldElement(num) {
|
|
191
|
-
return _0n < num && num < CURVE.P;
|
|
192
|
-
}
|
|
193
126
|
function normalizePrivateKey(key) {
|
|
194
|
-
let num;
|
|
195
127
|
if (typeof CURVE.normalizePrivateKey === 'function') {
|
|
196
128
|
key = CURVE.normalizePrivateKey(key);
|
|
197
129
|
}
|
|
130
|
+
let num;
|
|
198
131
|
if (typeof key === 'bigint') {
|
|
199
132
|
num = key;
|
|
200
133
|
}
|
|
@@ -214,32 +147,12 @@ function weierstrass(curveDef) {
|
|
|
214
147
|
else {
|
|
215
148
|
throw new TypeError('Expected valid private key');
|
|
216
149
|
}
|
|
150
|
+
if (CURVE.wrapPrivateKey)
|
|
151
|
+
num = mod.mod(num, CURVE.n);
|
|
217
152
|
if (!isWithinCurveOrder(num))
|
|
218
153
|
throw new Error('Expected private key: 0 < key < n');
|
|
219
154
|
return num;
|
|
220
155
|
}
|
|
221
|
-
/**
|
|
222
|
-
* Normalizes hex, bytes, Point to Point. Checks for curve equation.
|
|
223
|
-
*/
|
|
224
|
-
function normalizePublicKey(publicKey) {
|
|
225
|
-
if (publicKey instanceof Point) {
|
|
226
|
-
publicKey.assertValidity();
|
|
227
|
-
return publicKey;
|
|
228
|
-
}
|
|
229
|
-
else if (publicKey instanceof Uint8Array || typeof publicKey === 'string') {
|
|
230
|
-
return Point.fromHex(publicKey);
|
|
231
|
-
// This can happen because PointType can be instance of different class
|
|
232
|
-
}
|
|
233
|
-
else
|
|
234
|
-
throw new Error(`Unknown type of public key: ${publicKey}`);
|
|
235
|
-
}
|
|
236
|
-
function isBiggerThanHalfOrder(number) {
|
|
237
|
-
const HALF = CURVE_ORDER >> _1n;
|
|
238
|
-
return number > HALF;
|
|
239
|
-
}
|
|
240
|
-
function normalizeS(s) {
|
|
241
|
-
return isBiggerThanHalfOrder(s) ? mod.mod(-s, CURVE_ORDER) : s;
|
|
242
|
-
}
|
|
243
156
|
function normalizeScalar(num) {
|
|
244
157
|
if (typeof num === 'number' && Number.isSafeInteger(num) && num > 0)
|
|
245
158
|
return BigInt(num);
|
|
@@ -247,20 +160,6 @@ function weierstrass(curveDef) {
|
|
|
247
160
|
return num;
|
|
248
161
|
throw new TypeError('Expected valid private scalar: 0 < scalar < curve.n');
|
|
249
162
|
}
|
|
250
|
-
const sqrtModCurve = CURVE.sqrtMod || mod.sqrt;
|
|
251
|
-
// Ensures ECDSA message hashes are 32 bytes and < curve order
|
|
252
|
-
function _truncateHash(hash, truncateOnly = false) {
|
|
253
|
-
const { n, nBitLength } = CURVE;
|
|
254
|
-
const byteLength = hash.length;
|
|
255
|
-
const delta = byteLength * 8 - nBitLength; // size of curve.n (252 bits)
|
|
256
|
-
let h = (0, utils_js_1.bytesToNumberBE)(hash);
|
|
257
|
-
if (delta > 0)
|
|
258
|
-
h = h >> BigInt(delta);
|
|
259
|
-
if (!truncateOnly && h >= n)
|
|
260
|
-
h -= n;
|
|
261
|
-
return h;
|
|
262
|
-
}
|
|
263
|
-
const truncateHash = CURVE.truncateHash || _truncateHash;
|
|
264
163
|
/**
|
|
265
164
|
* Jacobian Point works in 3d / jacobi coordinates: (x, y, z) ∋ (x=x/z², y=y/z³)
|
|
266
165
|
* Default Point works in 2d / affine coordinates: (x, y)
|
|
@@ -279,7 +178,7 @@ function weierstrass(curveDef) {
|
|
|
279
178
|
// fromAffine(x:0, y:0) would produce (x:0, y:0, z:1), but we need (x:0, y:1, z:0)
|
|
280
179
|
if (p.equals(Point.ZERO))
|
|
281
180
|
return JacobianPoint.ZERO;
|
|
282
|
-
return new JacobianPoint(p.x, p.y,
|
|
181
|
+
return new JacobianPoint(p.x, p.y, Fp.ONE);
|
|
283
182
|
}
|
|
284
183
|
/**
|
|
285
184
|
* Takes a bunch of Jacobian Points but executes only one
|
|
@@ -287,7 +186,7 @@ function weierstrass(curveDef) {
|
|
|
287
186
|
* so this improves performance massively.
|
|
288
187
|
*/
|
|
289
188
|
static toAffineBatch(points) {
|
|
290
|
-
const toInv =
|
|
189
|
+
const toInv = Fp.invertBatch(points.map((p) => p.z));
|
|
291
190
|
return points.map((p, i) => p.toAffine(toInv[i]));
|
|
292
191
|
}
|
|
293
192
|
static normalizeZ(points) {
|
|
@@ -301,19 +200,19 @@ function weierstrass(curveDef) {
|
|
|
301
200
|
throw new TypeError('JacobianPoint expected');
|
|
302
201
|
const { x: X1, y: Y1, z: Z1 } = this;
|
|
303
202
|
const { x: X2, y: Y2, z: Z2 } = other;
|
|
304
|
-
const Z1Z1 =
|
|
305
|
-
const Z2Z2 =
|
|
306
|
-
const U1 =
|
|
307
|
-
const U2 =
|
|
308
|
-
const S1 =
|
|
309
|
-
const S2 =
|
|
310
|
-
return U1
|
|
203
|
+
const Z1Z1 = Fp.square(Z1); // Z1 * Z1
|
|
204
|
+
const Z2Z2 = Fp.square(Z2); // Z2 * Z2
|
|
205
|
+
const U1 = Fp.multiply(X1, Z2Z2); // X1 * Z2Z2
|
|
206
|
+
const U2 = Fp.multiply(X2, Z1Z1); // X2 * Z1Z1
|
|
207
|
+
const S1 = Fp.multiply(Fp.multiply(Y1, Z2), Z2Z2); // Y1 * Z2 * Z2Z2
|
|
208
|
+
const S2 = Fp.multiply(Fp.multiply(Y2, Z1), Z1Z1); // Y2 * Z1 * Z1Z1
|
|
209
|
+
return Fp.equals(U1, U2) && Fp.equals(S1, S2);
|
|
311
210
|
}
|
|
312
211
|
/**
|
|
313
212
|
* Flips point to one corresponding to (x, -y) in Affine coordinates.
|
|
314
213
|
*/
|
|
315
214
|
negate() {
|
|
316
|
-
return new JacobianPoint(this.x,
|
|
215
|
+
return new JacobianPoint(this.x, Fp.negate(this.y), this.z);
|
|
317
216
|
}
|
|
318
217
|
// Fast algo for doubling 2 Jacobian Points.
|
|
319
218
|
// From: https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl
|
|
@@ -324,31 +223,31 @@ function weierstrass(curveDef) {
|
|
|
324
223
|
// Faster algorithm: when a=0
|
|
325
224
|
// From: https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
|
|
326
225
|
// Cost: 2M + 5S + 6add + 3*2 + 1*3 + 1*8.
|
|
327
|
-
if (a
|
|
328
|
-
const A =
|
|
329
|
-
const B =
|
|
330
|
-
const C =
|
|
331
|
-
const x1b = X1 + B
|
|
332
|
-
const D =
|
|
333
|
-
const E =
|
|
334
|
-
const F =
|
|
335
|
-
const X3 =
|
|
336
|
-
const Y3 =
|
|
337
|
-
const Z3 =
|
|
226
|
+
if (Fp.isZero(a)) {
|
|
227
|
+
const A = Fp.square(X1); // X1 * X1
|
|
228
|
+
const B = Fp.square(Y1); // Y1 * Y1
|
|
229
|
+
const C = Fp.square(B); // B * B
|
|
230
|
+
const x1b = Fp.addN(X1, B); // X1 + B
|
|
231
|
+
const D = Fp.multiply(Fp.subtractN(Fp.subtractN(Fp.square(x1b), A), C), _2n); // ((x1b * x1b) - A - C) * 2
|
|
232
|
+
const E = Fp.multiply(A, _3n); // A * 3
|
|
233
|
+
const F = Fp.square(E); // E * E
|
|
234
|
+
const X3 = Fp.subtract(F, Fp.multiplyN(D, _2n)); // F - 2 * D
|
|
235
|
+
const Y3 = Fp.subtract(Fp.multiplyN(E, Fp.subtractN(D, X3)), Fp.multiplyN(C, _8n)); // E * (D - X3) - 8 * C;
|
|
236
|
+
const Z3 = Fp.multiply(Fp.multiplyN(Y1, _2n), Z1); // 2 * Y1 * Z1
|
|
338
237
|
return new JacobianPoint(X3, Y3, Z3);
|
|
339
238
|
}
|
|
340
|
-
const XX =
|
|
341
|
-
const YY =
|
|
342
|
-
const YYYY =
|
|
343
|
-
const ZZ =
|
|
344
|
-
const tmp1 =
|
|
345
|
-
const S =
|
|
346
|
-
const M =
|
|
347
|
-
const T =
|
|
239
|
+
const XX = Fp.square(X1); // X1 * X1
|
|
240
|
+
const YY = Fp.square(Y1); // Y1 * Y1
|
|
241
|
+
const YYYY = Fp.square(YY); // YY * YY
|
|
242
|
+
const ZZ = Fp.square(Z1); // Z1 * Z1
|
|
243
|
+
const tmp1 = Fp.add(X1, YY); // X1 + YY
|
|
244
|
+
const S = Fp.multiply(Fp.subtractN(Fp.subtractN(Fp.square(tmp1), XX), YYYY), _2n); // 2*((X1+YY)^2-XX-YYYY)
|
|
245
|
+
const M = Fp.add(Fp.multiplyN(XX, _3n), Fp.multiplyN(Fp.square(ZZ), a)); // 3 * XX + a * ZZ^2
|
|
246
|
+
const T = Fp.subtract(Fp.square(M), Fp.multiplyN(S, _2n)); // M^2-2*S
|
|
348
247
|
const X3 = T;
|
|
349
|
-
const Y3 =
|
|
350
|
-
const y1az1 =
|
|
351
|
-
const Z3 =
|
|
248
|
+
const Y3 = Fp.subtract(Fp.multiplyN(M, Fp.subtractN(S, T)), Fp.multiplyN(YYYY, _8n)); // M*(S-T)-8*YYYY
|
|
249
|
+
const y1az1 = Fp.add(Y1, Z1); // (Y1+Z1)
|
|
250
|
+
const Z3 = Fp.subtract(Fp.subtractN(Fp.square(y1az1), YY), ZZ); // (Y1+Z1)^2-YY-ZZ
|
|
352
251
|
return new JacobianPoint(X3, Y3, Z3);
|
|
353
252
|
}
|
|
354
253
|
// Fast algo for adding 2 Jacobian Points.
|
|
@@ -360,28 +259,28 @@ function weierstrass(curveDef) {
|
|
|
360
259
|
throw new TypeError('JacobianPoint expected');
|
|
361
260
|
const { x: X1, y: Y1, z: Z1 } = this;
|
|
362
261
|
const { x: X2, y: Y2, z: Z2 } = other;
|
|
363
|
-
if (X2
|
|
262
|
+
if (Fp.isZero(X2) || Fp.isZero(Y2))
|
|
364
263
|
return this;
|
|
365
|
-
if (X1
|
|
264
|
+
if (Fp.isZero(X1) || Fp.isZero(Y1))
|
|
366
265
|
return other;
|
|
367
266
|
// We're using same code in equals()
|
|
368
|
-
const Z1Z1 =
|
|
369
|
-
const Z2Z2 =
|
|
370
|
-
const U1 =
|
|
371
|
-
const U2 =
|
|
372
|
-
const S1 =
|
|
373
|
-
const S2 =
|
|
374
|
-
const H =
|
|
375
|
-
const r =
|
|
267
|
+
const Z1Z1 = Fp.square(Z1); // Z1Z1 = Z1^2
|
|
268
|
+
const Z2Z2 = Fp.square(Z2); // Z2Z2 = Z2^2;
|
|
269
|
+
const U1 = Fp.multiply(X1, Z2Z2); // X1 * Z2Z2
|
|
270
|
+
const U2 = Fp.multiply(X2, Z1Z1); // X2 * Z1Z1
|
|
271
|
+
const S1 = Fp.multiply(Fp.multiply(Y1, Z2), Z2Z2); // Y1 * Z2 * Z2Z2
|
|
272
|
+
const S2 = Fp.multiply(Fp.multiply(Y2, Z1), Z1Z1); // Y2 * Z1 * Z1Z1
|
|
273
|
+
const H = Fp.subtractN(U2, U1); // H = U2 - U1
|
|
274
|
+
const r = Fp.subtractN(S2, S1); // S2 - S1
|
|
376
275
|
// H = 0 meaning it's the same point.
|
|
377
|
-
if (H
|
|
378
|
-
return r
|
|
379
|
-
const HH =
|
|
380
|
-
const HHH =
|
|
381
|
-
const V =
|
|
382
|
-
const X3 =
|
|
383
|
-
const Y3 =
|
|
384
|
-
const Z3 =
|
|
276
|
+
if (Fp.isZero(H))
|
|
277
|
+
return Fp.isZero(r) ? this.double() : JacobianPoint.ZERO;
|
|
278
|
+
const HH = Fp.square(H); // HH = H2
|
|
279
|
+
const HHH = Fp.multiply(H, HH); // HHH = H * HH
|
|
280
|
+
const V = Fp.multiply(U1, HH); // V = U1 * HH
|
|
281
|
+
const X3 = Fp.subtract(Fp.subtractN(Fp.squareN(r), HHH), Fp.multiplyN(V, _2n)); // X3 = r^2 - HHH - 2 * V;
|
|
282
|
+
const Y3 = Fp.subtract(Fp.multiplyN(r, Fp.subtractN(V, X3)), Fp.multiplyN(S1, HHH)); // Y3 = r * (V - X3) - S1 * HHH;
|
|
283
|
+
const Z3 = Fp.multiply(Fp.multiply(Z1, Z2), H); // Z3 = Z1 * Z2 * H;
|
|
385
284
|
return new JacobianPoint(X3, Y3, Z3);
|
|
386
285
|
}
|
|
387
286
|
subtract(other) {
|
|
@@ -420,7 +319,7 @@ function weierstrass(curveDef) {
|
|
|
420
319
|
k1p = k1p.negate();
|
|
421
320
|
if (k2neg)
|
|
422
321
|
k2p = k2p.negate();
|
|
423
|
-
k2p = new JacobianPoint(
|
|
322
|
+
k2p = new JacobianPoint(Fp.multiply(k2p.x, CURVE.endo.beta), k2p.y, k2p.z);
|
|
424
323
|
return k1p.add(k2p);
|
|
425
324
|
}
|
|
426
325
|
/**
|
|
@@ -461,7 +360,7 @@ function weierstrass(curveDef) {
|
|
|
461
360
|
let { p: k2p, f: f2p } = this.wNAF(k2, affinePoint);
|
|
462
361
|
k1p = wnaf.constTimeNegate(k1neg, k1p);
|
|
463
362
|
k2p = wnaf.constTimeNegate(k2neg, k2p);
|
|
464
|
-
k2p = new JacobianPoint(
|
|
363
|
+
k2p = new JacobianPoint(Fp.multiply(k2p.x, CURVE.endo.beta), k2p.y, k2p.z);
|
|
465
364
|
point = k1p.add(k2p);
|
|
466
365
|
fake = f1p.add(f2p);
|
|
467
366
|
}
|
|
@@ -481,25 +380,42 @@ function weierstrass(curveDef) {
|
|
|
481
380
|
const { x, y, z } = this;
|
|
482
381
|
const is0 = this.equals(JacobianPoint.ZERO);
|
|
483
382
|
// If invZ was 0, we return zero point. However we still want to execute
|
|
484
|
-
// all operations, so we replace invZ with a random number,
|
|
383
|
+
// all operations, so we replace invZ with a random number, 1.
|
|
485
384
|
if (invZ == null)
|
|
486
|
-
invZ = is0 ?
|
|
385
|
+
invZ = is0 ? Fp.ONE : Fp.invert(z);
|
|
487
386
|
const iz1 = invZ;
|
|
488
|
-
const iz2 =
|
|
489
|
-
const iz3 =
|
|
490
|
-
const ax =
|
|
491
|
-
const ay =
|
|
492
|
-
const zz =
|
|
387
|
+
const iz2 = Fp.square(iz1); // iz1 * iz1
|
|
388
|
+
const iz3 = Fp.multiply(iz2, iz1); // iz2 * iz1
|
|
389
|
+
const ax = Fp.multiply(x, iz2); // x * iz2
|
|
390
|
+
const ay = Fp.multiply(y, iz3); // y * iz3
|
|
391
|
+
const zz = Fp.multiply(z, iz1); // z * iz1
|
|
493
392
|
if (is0)
|
|
494
393
|
return Point.ZERO;
|
|
495
|
-
if (zz
|
|
394
|
+
if (!Fp.equals(zz, Fp.ONE))
|
|
496
395
|
throw new Error('invZ was invalid');
|
|
497
396
|
return new Point(ax, ay);
|
|
498
397
|
}
|
|
398
|
+
isTorsionFree() {
|
|
399
|
+
if (CURVE.h === _1n)
|
|
400
|
+
return true; // No subgroups, always torsion fee
|
|
401
|
+
if (CURVE.isTorsionFree)
|
|
402
|
+
return CURVE.isTorsionFree(JacobianPoint, this);
|
|
403
|
+
// is multiplyUnsafe(CURVE.n) is always ok, same as for edwards?
|
|
404
|
+
throw new Error('Unsupported!');
|
|
405
|
+
}
|
|
406
|
+
// Clear cofactor of G1
|
|
407
|
+
// https://eprint.iacr.org/2019/403
|
|
408
|
+
clearCofactor() {
|
|
409
|
+
if (CURVE.h === _1n)
|
|
410
|
+
return this; // Fast-path
|
|
411
|
+
if (CURVE.clearCofactor)
|
|
412
|
+
return CURVE.clearCofactor(JacobianPoint, this);
|
|
413
|
+
return this.multiplyUnsafe(CURVE.h);
|
|
414
|
+
}
|
|
499
415
|
}
|
|
500
|
-
JacobianPoint.BASE = new JacobianPoint(CURVE.Gx, CURVE.Gy,
|
|
501
|
-
JacobianPoint.ZERO = new JacobianPoint(
|
|
502
|
-
const wnaf = (0, group_js_1.wNAF)(JacobianPoint, CURVE.endo ?
|
|
416
|
+
JacobianPoint.BASE = new JacobianPoint(CURVE.Gx, CURVE.Gy, Fp.ONE);
|
|
417
|
+
JacobianPoint.ZERO = new JacobianPoint(Fp.ZERO, Fp.ONE, Fp.ZERO);
|
|
418
|
+
const wnaf = (0, group_js_1.wNAF)(JacobianPoint, CURVE.endo ? nBitLength / 2 : nBitLength);
|
|
503
419
|
// Stores precomputed values for points.
|
|
504
420
|
const pointPrecomputes = new WeakMap();
|
|
505
421
|
/**
|
|
@@ -517,87 +433,60 @@ function weierstrass(curveDef) {
|
|
|
517
433
|
}
|
|
518
434
|
// Checks for y % 2 == 0
|
|
519
435
|
hasEvenY() {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
* Supports compressed ECDSA points
|
|
524
|
-
* @returns Point instance
|
|
525
|
-
*/
|
|
526
|
-
static fromCompressedHex(bytes) {
|
|
527
|
-
const P = CURVE.P;
|
|
528
|
-
const x = (0, utils_js_1.bytesToNumberBE)(bytes.subarray(1));
|
|
529
|
-
if (!isValidFieldElement(x))
|
|
530
|
-
throw new Error('Point is not on curve');
|
|
531
|
-
const y2 = weierstrassEquation(x); // y² = x³ + ax + b
|
|
532
|
-
let y = sqrtModCurve(y2, P); // y = y² ^ (p+1)/4
|
|
533
|
-
const isYOdd = (y & _1n) === _1n;
|
|
534
|
-
// ECDSA
|
|
535
|
-
const isFirstByteOdd = (bytes[0] & 1) === 1;
|
|
536
|
-
if (isFirstByteOdd !== isYOdd)
|
|
537
|
-
y = modP(-y);
|
|
538
|
-
const point = new Point(x, y);
|
|
539
|
-
point.assertValidity();
|
|
540
|
-
return point;
|
|
541
|
-
}
|
|
542
|
-
static fromUncompressedHex(bytes) {
|
|
543
|
-
const x = (0, utils_js_1.bytesToNumberBE)(bytes.subarray(1, fieldLen + 1));
|
|
544
|
-
const y = (0, utils_js_1.bytesToNumberBE)(bytes.subarray(fieldLen + 1, 2 * fieldLen + 1));
|
|
545
|
-
const point = new Point(x, y);
|
|
546
|
-
point.assertValidity();
|
|
547
|
-
return point;
|
|
436
|
+
if (Fp.isOdd)
|
|
437
|
+
return !Fp.isOdd(this.y);
|
|
438
|
+
throw new Error("Field doesn't support isOdd");
|
|
548
439
|
}
|
|
549
440
|
/**
|
|
550
441
|
* Converts hash string or Uint8Array to Point.
|
|
551
442
|
* @param hex short/long ECDSA hex
|
|
552
443
|
*/
|
|
553
444
|
static fromHex(hex) {
|
|
554
|
-
const
|
|
555
|
-
const
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
if (len === compressedLen && (header === 0x02 || header === 0x03))
|
|
559
|
-
return this.fromCompressedHex(bytes);
|
|
560
|
-
if (len === uncompressedLen && header === 0x04)
|
|
561
|
-
return this.fromUncompressedHex(bytes);
|
|
562
|
-
throw new Error(`Point.fromHex: received invalid point. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes, not ${len}`);
|
|
445
|
+
const { x, y } = CURVE.fromBytes((0, utils_js_1.ensureBytes)(hex));
|
|
446
|
+
const point = new Point(x, y);
|
|
447
|
+
point.assertValidity();
|
|
448
|
+
return point;
|
|
563
449
|
}
|
|
564
450
|
// Multiplies generator point by privateKey.
|
|
565
451
|
static fromPrivateKey(privateKey) {
|
|
566
452
|
return Point.BASE.multiply(normalizePrivateKey(privateKey));
|
|
567
453
|
}
|
|
568
454
|
toRawBytes(isCompressed = false) {
|
|
569
|
-
|
|
455
|
+
this.assertValidity();
|
|
456
|
+
return CURVE.toBytes(Point, this, isCompressed);
|
|
570
457
|
}
|
|
571
458
|
toHex(isCompressed = false) {
|
|
572
|
-
|
|
573
|
-
if (isCompressed) {
|
|
574
|
-
const prefix = this.hasEvenY() ? '02' : '03';
|
|
575
|
-
return `${prefix}${x}`;
|
|
576
|
-
}
|
|
577
|
-
else {
|
|
578
|
-
return `04${x}${numToFieldStr(this.y)}`;
|
|
579
|
-
}
|
|
459
|
+
return (0, utils_js_1.bytesToHex)(this.toRawBytes(isCompressed));
|
|
580
460
|
}
|
|
581
461
|
// A point on curve is valid if it conforms to equation.
|
|
582
462
|
assertValidity() {
|
|
463
|
+
// Zero is valid point too!
|
|
464
|
+
if (this.equals(Point.ZERO)) {
|
|
465
|
+
if (CURVE.allowInfinityPoint)
|
|
466
|
+
return;
|
|
467
|
+
throw new Error('Point is infinity');
|
|
468
|
+
}
|
|
583
469
|
// Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
|
|
584
470
|
const msg = 'Point is not on elliptic curve';
|
|
585
471
|
const { x, y } = this;
|
|
586
|
-
if (!
|
|
472
|
+
if (!Fp.isValid(x) || !Fp.isValid(y))
|
|
587
473
|
throw new Error(msg);
|
|
588
|
-
const left =
|
|
474
|
+
const left = Fp.square(y);
|
|
589
475
|
const right = weierstrassEquation(x);
|
|
590
|
-
if (
|
|
476
|
+
if (!Fp.equals(left, right))
|
|
591
477
|
throw new Error(msg);
|
|
478
|
+
// TODO: flag to disable this?
|
|
479
|
+
if (!this.isTorsionFree())
|
|
480
|
+
throw new Error('Point must be of prime-order subgroup');
|
|
592
481
|
}
|
|
593
482
|
equals(other) {
|
|
594
483
|
if (!(other instanceof Point))
|
|
595
484
|
throw new TypeError('Point#equals: expected Point');
|
|
596
|
-
return this.x
|
|
485
|
+
return Fp.equals(this.x, other.x) && Fp.equals(this.y, other.y);
|
|
597
486
|
}
|
|
598
487
|
// Returns the same point with inverted `y`
|
|
599
488
|
negate() {
|
|
600
|
-
return new Point(this.x,
|
|
489
|
+
return new Point(this.x, Fp.negate(this.y));
|
|
601
490
|
}
|
|
602
491
|
// Adds point to itself
|
|
603
492
|
double() {
|
|
@@ -614,6 +503,15 @@ function weierstrass(curveDef) {
|
|
|
614
503
|
multiply(scalar) {
|
|
615
504
|
return JacobianPoint.fromAffine(this).multiply(scalar, this).toAffine();
|
|
616
505
|
}
|
|
506
|
+
multiplyUnsafe(scalar) {
|
|
507
|
+
return JacobianPoint.fromAffine(this).multiplyUnsafe(scalar).toAffine();
|
|
508
|
+
}
|
|
509
|
+
clearCofactor() {
|
|
510
|
+
return JacobianPoint.fromAffine(this).clearCofactor().toAffine();
|
|
511
|
+
}
|
|
512
|
+
isTorsionFree() {
|
|
513
|
+
return JacobianPoint.fromAffine(this).isTorsionFree();
|
|
514
|
+
}
|
|
617
515
|
/**
|
|
618
516
|
* Efficiently calculate `aP + bQ`.
|
|
619
517
|
* Unsafe, can expose private key, if used incorrectly.
|
|
@@ -627,6 +525,27 @@ function weierstrass(curveDef) {
|
|
|
627
525
|
const sum = aP.add(bQ);
|
|
628
526
|
return sum.equals(JacobianPoint.ZERO) ? undefined : sum.toAffine();
|
|
629
527
|
}
|
|
528
|
+
// Encodes byte string to elliptic curve
|
|
529
|
+
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
|
|
530
|
+
static hashToCurve(msg, options) {
|
|
531
|
+
if (!CURVE.mapToCurve)
|
|
532
|
+
throw new Error('No mapToCurve defined for curve');
|
|
533
|
+
msg = (0, utils_js_1.ensureBytes)(msg);
|
|
534
|
+
const u = (0, hashToCurve_js_1.hash_to_field)(msg, 2, { ...CURVE.htfDefaults, ...options });
|
|
535
|
+
const { x: x0, y: y0 } = CURVE.mapToCurve(u[0]);
|
|
536
|
+
const { x: x1, y: y1 } = CURVE.mapToCurve(u[1]);
|
|
537
|
+
const p = new Point(x0, y0).add(new Point(x1, y1)).clearCofactor();
|
|
538
|
+
return p;
|
|
539
|
+
}
|
|
540
|
+
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
|
|
541
|
+
static encodeToCurve(msg, options) {
|
|
542
|
+
if (!CURVE.mapToCurve)
|
|
543
|
+
throw new Error('No mapToCurve defined for curve');
|
|
544
|
+
msg = (0, utils_js_1.ensureBytes)(msg);
|
|
545
|
+
const u = (0, hashToCurve_js_1.hash_to_field)(msg, 1, { ...CURVE.htfDefaults, ...options });
|
|
546
|
+
const { x, y } = CURVE.mapToCurve(u[0]);
|
|
547
|
+
return new Point(x, y).clearCofactor();
|
|
548
|
+
}
|
|
630
549
|
}
|
|
631
550
|
/**
|
|
632
551
|
* Base point aka generator. public_key = Point.BASE * private_key
|
|
@@ -635,7 +554,168 @@ function weierstrass(curveDef) {
|
|
|
635
554
|
/**
|
|
636
555
|
* Identity point aka point at infinity. point = point + zero_point
|
|
637
556
|
*/
|
|
638
|
-
Point.ZERO = new Point(
|
|
557
|
+
Point.ZERO = new Point(Fp.ZERO, Fp.ZERO);
|
|
558
|
+
return {
|
|
559
|
+
Point: Point,
|
|
560
|
+
JacobianPoint: JacobianPoint,
|
|
561
|
+
normalizePrivateKey,
|
|
562
|
+
weierstrassEquation,
|
|
563
|
+
isWithinCurveOrder,
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
exports.weierstrassPoints = weierstrassPoints;
|
|
567
|
+
function validateOpts(curve) {
|
|
568
|
+
const opts = utils.validateOpts(curve);
|
|
569
|
+
if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
|
|
570
|
+
throw new Error('Invalid hash function');
|
|
571
|
+
if (typeof opts.hmac !== 'function')
|
|
572
|
+
throw new Error('Invalid hmac function');
|
|
573
|
+
if (typeof opts.randomBytes !== 'function')
|
|
574
|
+
throw new Error('Invalid randomBytes function');
|
|
575
|
+
// Set defaults
|
|
576
|
+
return Object.freeze({ lowS: true, ...opts });
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Minimal HMAC-DRBG (NIST 800-90) for signatures.
|
|
580
|
+
* Used only for RFC6979, does not fully implement DRBG spec.
|
|
581
|
+
*/
|
|
582
|
+
class HmacDrbg {
|
|
583
|
+
constructor(hashLen, qByteLen, hmacFn) {
|
|
584
|
+
this.hashLen = hashLen;
|
|
585
|
+
this.qByteLen = qByteLen;
|
|
586
|
+
this.hmacFn = hmacFn;
|
|
587
|
+
if (typeof hashLen !== 'number' || hashLen < 2)
|
|
588
|
+
throw new Error('hashLen must be a number');
|
|
589
|
+
if (typeof qByteLen !== 'number' || qByteLen < 2)
|
|
590
|
+
throw new Error('qByteLen must be a number');
|
|
591
|
+
if (typeof hmacFn !== 'function')
|
|
592
|
+
throw new Error('hmacFn must be a function');
|
|
593
|
+
// Step B, Step C: set hashLen to 8*ceil(hlen/8)
|
|
594
|
+
this.v = new Uint8Array(hashLen).fill(1);
|
|
595
|
+
this.k = new Uint8Array(hashLen).fill(0);
|
|
596
|
+
this.counter = 0;
|
|
597
|
+
}
|
|
598
|
+
hmacSync(...values) {
|
|
599
|
+
return this.hmacFn(this.k, ...values);
|
|
600
|
+
}
|
|
601
|
+
incr() {
|
|
602
|
+
if (this.counter >= 1000)
|
|
603
|
+
throw new Error('Tried 1,000 k values for sign(), all were invalid');
|
|
604
|
+
this.counter += 1;
|
|
605
|
+
}
|
|
606
|
+
reseedSync(seed = new Uint8Array()) {
|
|
607
|
+
this.k = this.hmacSync(this.v, Uint8Array.from([0x00]), seed);
|
|
608
|
+
this.v = this.hmacSync(this.v);
|
|
609
|
+
if (seed.length === 0)
|
|
610
|
+
return;
|
|
611
|
+
this.k = this.hmacSync(this.v, Uint8Array.from([0x01]), seed);
|
|
612
|
+
this.v = this.hmacSync(this.v);
|
|
613
|
+
}
|
|
614
|
+
// TODO: review
|
|
615
|
+
generateSync() {
|
|
616
|
+
this.incr();
|
|
617
|
+
let len = 0;
|
|
618
|
+
const out = [];
|
|
619
|
+
while (len < this.qByteLen) {
|
|
620
|
+
this.v = this.hmacSync(this.v);
|
|
621
|
+
const sl = this.v.slice();
|
|
622
|
+
out.push(sl);
|
|
623
|
+
len += this.v.length;
|
|
624
|
+
}
|
|
625
|
+
return (0, utils_js_1.concatBytes)(...out);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
function weierstrass(curveDef) {
|
|
629
|
+
const CURVE = validateOpts(curveDef);
|
|
630
|
+
const CURVE_ORDER = CURVE.n;
|
|
631
|
+
const Fp = CURVE.Fp;
|
|
632
|
+
const compressedLen = Fp.BYTES + 1; // 33
|
|
633
|
+
const uncompressedLen = 2 * Fp.BYTES + 1; // 65
|
|
634
|
+
function isValidFieldElement(num) {
|
|
635
|
+
// 0 is disallowed by arbitrary reasons. Probably because infinity point?
|
|
636
|
+
return _0n < num && num < Fp.ORDER;
|
|
637
|
+
}
|
|
638
|
+
const { Point, JacobianPoint, normalizePrivateKey, weierstrassEquation, isWithinCurveOrder } = weierstrassPoints({
|
|
639
|
+
...CURVE,
|
|
640
|
+
toBytes(c, point, isCompressed) {
|
|
641
|
+
if (isCompressed) {
|
|
642
|
+
return (0, utils_js_1.concatBytes)(new Uint8Array([point.hasEvenY() ? 0x02 : 0x03]), Fp.toBytes(point.x));
|
|
643
|
+
}
|
|
644
|
+
else {
|
|
645
|
+
return (0, utils_js_1.concatBytes)(new Uint8Array([0x04]), Fp.toBytes(point.x), Fp.toBytes(point.y));
|
|
646
|
+
}
|
|
647
|
+
},
|
|
648
|
+
fromBytes(bytes) {
|
|
649
|
+
const len = bytes.length;
|
|
650
|
+
const header = bytes[0];
|
|
651
|
+
// this.assertValidity() is done inside of fromHex
|
|
652
|
+
if (len === compressedLen && (header === 0x02 || header === 0x03)) {
|
|
653
|
+
const x = (0, utils_js_1.bytesToNumberBE)(bytes.subarray(1));
|
|
654
|
+
if (!isValidFieldElement(x))
|
|
655
|
+
throw new Error('Point is not on curve');
|
|
656
|
+
const y2 = weierstrassEquation(x); // y² = x³ + ax + b
|
|
657
|
+
let y = Fp.sqrt(y2); // y = y² ^ (p+1)/4
|
|
658
|
+
const isYOdd = (y & _1n) === _1n;
|
|
659
|
+
// ECDSA
|
|
660
|
+
const isFirstByteOdd = (bytes[0] & 1) === 1;
|
|
661
|
+
if (isFirstByteOdd !== isYOdd)
|
|
662
|
+
y = Fp.negate(y);
|
|
663
|
+
return { x, y };
|
|
664
|
+
}
|
|
665
|
+
else if (len === uncompressedLen && header === 0x04) {
|
|
666
|
+
const x = Fp.fromBytes(bytes.subarray(1, Fp.BYTES + 1));
|
|
667
|
+
const y = Fp.fromBytes(bytes.subarray(Fp.BYTES + 1, 2 * Fp.BYTES + 1));
|
|
668
|
+
return { x, y };
|
|
669
|
+
}
|
|
670
|
+
else {
|
|
671
|
+
throw new Error(`Point.fromHex: received invalid point. Expected ${compressedLen} compressed bytes or ${uncompressedLen} uncompressed bytes, not ${len}`);
|
|
672
|
+
}
|
|
673
|
+
},
|
|
674
|
+
});
|
|
675
|
+
// Do we need these functions at all?
|
|
676
|
+
function numToField(num) {
|
|
677
|
+
if (typeof num !== 'bigint')
|
|
678
|
+
throw new Error('Expected bigint');
|
|
679
|
+
if (!(_0n <= num && num < Fp.MASK))
|
|
680
|
+
throw new Error(`Expected number < 2^${Fp.BYTES * 8}`);
|
|
681
|
+
return Fp.toBytes(num);
|
|
682
|
+
}
|
|
683
|
+
const numToFieldStr = (num) => (0, utils_js_1.bytesToHex)(numToField(num));
|
|
684
|
+
/**
|
|
685
|
+
* Normalizes hex, bytes, Point to Point. Checks for curve equation.
|
|
686
|
+
*/
|
|
687
|
+
function normalizePublicKey(publicKey) {
|
|
688
|
+
if (publicKey instanceof Point) {
|
|
689
|
+
publicKey.assertValidity();
|
|
690
|
+
return publicKey;
|
|
691
|
+
}
|
|
692
|
+
else if (publicKey instanceof Uint8Array || typeof publicKey === 'string') {
|
|
693
|
+
return Point.fromHex(publicKey);
|
|
694
|
+
// This can happen because PointType can be instance of different class
|
|
695
|
+
}
|
|
696
|
+
else
|
|
697
|
+
throw new Error(`Unknown type of public key: ${publicKey}`);
|
|
698
|
+
}
|
|
699
|
+
function isBiggerThanHalfOrder(number) {
|
|
700
|
+
const HALF = CURVE_ORDER >> _1n;
|
|
701
|
+
return number > HALF;
|
|
702
|
+
}
|
|
703
|
+
function normalizeS(s) {
|
|
704
|
+
return isBiggerThanHalfOrder(s) ? mod.mod(-s, CURVE_ORDER) : s;
|
|
705
|
+
}
|
|
706
|
+
// Ensures ECDSA message hashes are 32 bytes and < curve order
|
|
707
|
+
function _truncateHash(hash, truncateOnly = false) {
|
|
708
|
+
const { n, nBitLength } = CURVE;
|
|
709
|
+
const byteLength = hash.length;
|
|
710
|
+
const delta = byteLength * 8 - nBitLength; // size of curve.n (252 bits)
|
|
711
|
+
let h = (0, utils_js_1.bytesToNumberBE)(hash);
|
|
712
|
+
if (delta > 0)
|
|
713
|
+
h = h >> BigInt(delta);
|
|
714
|
+
if (!truncateOnly && h >= n)
|
|
715
|
+
h -= n;
|
|
716
|
+
return h;
|
|
717
|
+
}
|
|
718
|
+
const truncateHash = CURVE.truncateHash || _truncateHash;
|
|
639
719
|
/**
|
|
640
720
|
* ECDSA signature with its (r, s) properties. Supports DER & compact representations.
|
|
641
721
|
*/
|
|
@@ -746,8 +826,8 @@ function weierstrass(curveDef) {
|
|
|
746
826
|
}
|
|
747
827
|
}
|
|
748
828
|
const utils = {
|
|
749
|
-
mod:
|
|
750
|
-
invert:
|
|
829
|
+
mod: (n, modulo = Fp.ORDER) => mod.mod(n, modulo),
|
|
830
|
+
invert: Fp.invert,
|
|
751
831
|
isValidPrivateKey(privateKey) {
|
|
752
832
|
try {
|
|
753
833
|
normalizePrivateKey(privateKey);
|
|
@@ -772,7 +852,7 @@ function weierstrass(curveDef) {
|
|
|
772
852
|
* Produces cryptographically secure private key from random of size (nBitLength+64)
|
|
773
853
|
* as per FIPS 186 B.4.1 with modulo bias being neglible.
|
|
774
854
|
*/
|
|
775
|
-
randomPrivateKey: () => utils.hashToPrivateKey(CURVE.randomBytes(
|
|
855
|
+
randomPrivateKey: () => utils.hashToPrivateKey(CURVE.randomBytes(Fp.BYTES + 8)),
|
|
776
856
|
/**
|
|
777
857
|
* 1. Returns cached point which you can use to pass to `getSharedSecret` or `#multiply` by it.
|
|
778
858
|
* 2. Precomputes point multiplication table. Is done by default on first `getPublicKey()` call.
|
|
@@ -832,7 +912,7 @@ function weierstrass(curveDef) {
|
|
|
832
912
|
}
|
|
833
913
|
// RFC6979 methods
|
|
834
914
|
function bits2int(bytes) {
|
|
835
|
-
const slice = bytes.length >
|
|
915
|
+
const slice = bytes.length > Fp.BYTES ? bytes.slice(0, Fp.BYTES) : bytes;
|
|
836
916
|
return (0, utils_js_1.bytesToNumberBE)(slice);
|
|
837
917
|
}
|
|
838
918
|
function bits2octets(bytes) {
|
|
@@ -856,10 +936,10 @@ function weierstrass(curveDef) {
|
|
|
856
936
|
// RFC6979 3.6: additional k' could be provided
|
|
857
937
|
if (extraEntropy != null) {
|
|
858
938
|
if (extraEntropy === true)
|
|
859
|
-
extraEntropy = CURVE.randomBytes(
|
|
939
|
+
extraEntropy = CURVE.randomBytes(Fp.BYTES);
|
|
860
940
|
const e = (0, utils_js_1.ensureBytes)(extraEntropy);
|
|
861
|
-
if (e.length !==
|
|
862
|
-
throw new Error(`sign: Expected ${
|
|
941
|
+
if (e.length !== Fp.BYTES)
|
|
942
|
+
throw new Error(`sign: Expected ${Fp.BYTES} bytes of extra data`);
|
|
863
943
|
seedArgs.push(e);
|
|
864
944
|
}
|
|
865
945
|
// seed is constructed from private key and message
|