@noble/curves 1.9.2 → 1.9.3
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 +186 -206
- package/_shortw_utils.d.ts +1 -0
- package/_shortw_utils.d.ts.map +1 -1
- package/_shortw_utils.js +1 -0
- package/_shortw_utils.js.map +1 -1
- package/abstract/bls.d.ts +87 -62
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +170 -163
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +109 -23
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +158 -156
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +124 -70
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +212 -62
- package/abstract/edwards.js.map +1 -1
- package/abstract/hash-to-curve.d.ts +8 -4
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +23 -11
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +8 -3
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +79 -35
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +17 -4
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +19 -3
- package/abstract/montgomery.js.map +1 -1
- package/abstract/tower.d.ts +3 -3
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js.map +1 -1
- package/abstract/weierstrass.d.ts +142 -116
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +414 -335
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +4 -4
- package/bls12-381.js.map +1 -1
- package/ed25519.d.ts +52 -66
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +128 -155
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +57 -58
- package/ed448.d.ts.map +1 -1
- package/ed448.js +114 -131
- package/ed448.js.map +1 -1
- package/esm/_shortw_utils.d.ts +1 -0
- package/esm/_shortw_utils.d.ts.map +1 -1
- package/esm/_shortw_utils.js +1 -0
- package/esm/_shortw_utils.js.map +1 -1
- package/esm/abstract/bls.d.ts +87 -62
- package/esm/abstract/bls.d.ts.map +1 -1
- package/esm/abstract/bls.js +171 -164
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/curve.d.ts +109 -23
- package/esm/abstract/curve.d.ts.map +1 -1
- package/esm/abstract/curve.js +156 -155
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.d.ts +124 -70
- package/esm/abstract/edwards.d.ts.map +1 -1
- package/esm/abstract/edwards.js +210 -62
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/hash-to-curve.d.ts +8 -4
- package/esm/abstract/hash-to-curve.d.ts.map +1 -1
- package/esm/abstract/hash-to-curve.js +22 -11
- package/esm/abstract/hash-to-curve.js.map +1 -1
- package/esm/abstract/modular.d.ts +8 -3
- package/esm/abstract/modular.d.ts.map +1 -1
- package/esm/abstract/modular.js +79 -35
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.d.ts +17 -4
- package/esm/abstract/montgomery.d.ts.map +1 -1
- package/esm/abstract/montgomery.js +19 -3
- package/esm/abstract/montgomery.js.map +1 -1
- package/esm/abstract/tower.d.ts +3 -3
- package/esm/abstract/tower.d.ts.map +1 -1
- package/esm/abstract/tower.js.map +1 -1
- package/esm/abstract/weierstrass.d.ts +142 -116
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +411 -333
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.d.ts.map +1 -1
- package/esm/bls12-381.js +4 -4
- package/esm/bls12-381.js.map +1 -1
- package/esm/ed25519.d.ts +52 -66
- package/esm/ed25519.d.ts.map +1 -1
- package/esm/ed25519.js +131 -157
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.d.ts +57 -58
- package/esm/ed448.d.ts.map +1 -1
- package/esm/ed448.js +116 -132
- package/esm/ed448.js.map +1 -1
- package/esm/index.js +7 -9
- package/esm/index.js.map +1 -1
- package/esm/jubjub.d.ts +3 -3
- package/esm/jubjub.d.ts.map +1 -1
- package/esm/jubjub.js +3 -3
- package/esm/jubjub.js.map +1 -1
- package/esm/misc.d.ts +3 -5
- package/esm/misc.d.ts.map +1 -1
- package/esm/misc.js +0 -3
- package/esm/misc.js.map +1 -1
- package/esm/nist.d.ts +0 -6
- package/esm/nist.d.ts.map +1 -1
- package/esm/nist.js +31 -15
- package/esm/nist.js.map +1 -1
- package/esm/p256.d.ts +4 -0
- package/esm/p256.d.ts.map +1 -1
- package/esm/p256.js +4 -0
- package/esm/p256.js.map +1 -1
- package/esm/p384.d.ts +4 -1
- package/esm/p384.d.ts.map +1 -1
- package/esm/p384.js +4 -1
- package/esm/p384.js.map +1 -1
- package/esm/p521.d.ts +4 -0
- package/esm/p521.d.ts.map +1 -1
- package/esm/p521.js +4 -0
- package/esm/p521.js.map +1 -1
- package/esm/secp256k1.d.ts +32 -15
- package/esm/secp256k1.d.ts.map +1 -1
- package/esm/secp256k1.js +72 -67
- package/esm/secp256k1.js.map +1 -1
- package/esm/utils.d.ts +1 -1
- package/esm/utils.js +1 -1
- package/index.js +7 -9
- package/index.js.map +1 -1
- package/jubjub.d.ts +3 -3
- package/jubjub.d.ts.map +1 -1
- package/jubjub.js +3 -3
- package/jubjub.js.map +1 -1
- package/misc.d.ts +3 -5
- package/misc.d.ts.map +1 -1
- package/misc.js +0 -3
- package/misc.js.map +1 -1
- package/nist.d.ts +0 -6
- package/nist.d.ts.map +1 -1
- package/nist.js +31 -15
- package/nist.js.map +1 -1
- package/p256.d.ts +4 -0
- package/p256.d.ts.map +1 -1
- package/p256.js +4 -0
- package/p256.js.map +1 -1
- package/p384.d.ts +4 -1
- package/p384.d.ts.map +1 -1
- package/p384.js +4 -1
- package/p384.js.map +1 -1
- package/p521.d.ts +4 -0
- package/p521.d.ts.map +1 -1
- package/p521.js +4 -0
- package/p521.js.map +1 -1
- package/package.json +4 -2
- package/secp256k1.d.ts +32 -15
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +70 -65
- package/secp256k1.js.map +1 -1
- package/src/_shortw_utils.ts +1 -0
- package/src/abstract/bls.ts +319 -257
- package/src/abstract/curve.ts +226 -170
- package/src/abstract/edwards.ts +350 -139
- package/src/abstract/hash-to-curve.ts +33 -16
- package/src/abstract/modular.ts +86 -35
- package/src/abstract/montgomery.ts +36 -9
- package/src/abstract/tower.ts +4 -4
- package/src/abstract/weierstrass.ts +567 -474
- package/src/bls12-381.ts +28 -20
- package/src/ed25519.ts +161 -179
- package/src/ed448.ts +150 -156
- package/src/index.ts +7 -9
- package/src/jubjub.ts +3 -3
- package/src/misc.ts +3 -7
- package/src/nist.ts +40 -16
- package/src/p256.ts +4 -0
- package/src/p384.ts +4 -2
- package/src/p521.ts +4 -0
- package/src/secp256k1.ts +91 -73
- package/src/utils.ts +1 -1
- package/utils.d.ts +1 -1
- package/utils.js +1 -1
package/abstract/weierstrass.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DER = exports.DERErr = void 0;
|
|
4
|
+
exports._splitEndoScalar = _splitEndoScalar;
|
|
4
5
|
exports._legacyHelperEquat = _legacyHelperEquat;
|
|
5
|
-
exports.
|
|
6
|
+
exports._normFnElement = _normFnElement;
|
|
6
7
|
exports.weierstrassN = weierstrassN;
|
|
7
8
|
exports.weierstrassPoints = weierstrassPoints;
|
|
8
|
-
exports.ecdsa = ecdsa;
|
|
9
|
-
exports.weierstrass = weierstrass;
|
|
10
9
|
exports.SWUFpSqrtRatio = SWUFpSqrtRatio;
|
|
11
10
|
exports.mapToCurveSimpleSWU = mapToCurveSimpleSWU;
|
|
11
|
+
exports.ecdsa = ecdsa;
|
|
12
|
+
exports.weierstrass = weierstrass;
|
|
12
13
|
/**
|
|
13
14
|
* Short Weierstrass curve methods. The formula is: y² = x³ + ax + b.
|
|
14
15
|
*
|
|
@@ -37,9 +38,40 @@ exports.mapToCurveSimpleSWU = mapToCurveSimpleSWU;
|
|
|
37
38
|
*/
|
|
38
39
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
39
40
|
const hmac_js_1 = require("@noble/hashes/hmac.js");
|
|
41
|
+
const utils_1 = require("@noble/hashes/utils");
|
|
40
42
|
const utils_ts_1 = require("../utils.js");
|
|
41
43
|
const curve_ts_1 = require("./curve.js");
|
|
42
44
|
const modular_ts_1 = require("./modular.js");
|
|
45
|
+
// We construct basis in such way that den is always positive and equals n, but num sign depends on basis (not on secret value)
|
|
46
|
+
const divNearest = (num, den) => (num + (num >= 0 ? den : -den) / _2n) / den;
|
|
47
|
+
/**
|
|
48
|
+
* Splits scalar for GLV endomorphism.
|
|
49
|
+
*/
|
|
50
|
+
function _splitEndoScalar(k, basis, n) {
|
|
51
|
+
// Split scalar into two such that part is ~half bits: `abs(part) < sqrt(N)`
|
|
52
|
+
// Since part can be negative, we need to do this on point.
|
|
53
|
+
// TODO: verifyScalar function which consumes lambda
|
|
54
|
+
const [[a1, b1], [a2, b2]] = basis;
|
|
55
|
+
const c1 = divNearest(b2 * k, n);
|
|
56
|
+
const c2 = divNearest(-b1 * k, n);
|
|
57
|
+
// |k1|/|k2| is < sqrt(N), but can be negative.
|
|
58
|
+
// If we do `k1 mod N`, we'll get big scalar (`> sqrt(N)`): so, we do cheaper negation instead.
|
|
59
|
+
let k1 = k - c1 * a1 - c2 * a2;
|
|
60
|
+
let k2 = -c1 * b1 - c2 * b2;
|
|
61
|
+
const k1neg = k1 < _0n;
|
|
62
|
+
const k2neg = k2 < _0n;
|
|
63
|
+
if (k1neg)
|
|
64
|
+
k1 = -k1;
|
|
65
|
+
if (k2neg)
|
|
66
|
+
k2 = -k2;
|
|
67
|
+
// Double check that resulting scalar less than half bits of N: otherwise wNAF will fail.
|
|
68
|
+
// This should only happen on wrong basises. Also, math inside is too complex and I don't trust it.
|
|
69
|
+
const MAX_NUM = (0, utils_ts_1.bitMask)(Math.ceil((0, utils_ts_1.bitLen)(n) / 2)) + _1n; // Half bits of N
|
|
70
|
+
if (k1 < _0n || k1 >= MAX_NUM || k2 < _0n || k2 >= MAX_NUM) {
|
|
71
|
+
throw new Error('splitScalar (endomorphism): failed, k=' + k);
|
|
72
|
+
}
|
|
73
|
+
return { k1neg, k1, k2neg, k2 };
|
|
74
|
+
}
|
|
43
75
|
function validateSigVerOpts(opts) {
|
|
44
76
|
if (opts.lowS !== undefined)
|
|
45
77
|
(0, utils_ts_1.abool)('lowS', opts.lowS);
|
|
@@ -179,37 +211,24 @@ function _legacyHelperEquat(Fp, a, b) {
|
|
|
179
211
|
}
|
|
180
212
|
return weierstrassEquation;
|
|
181
213
|
}
|
|
182
|
-
function
|
|
214
|
+
function _normFnElement(Fn, key) {
|
|
183
215
|
const { BYTES: expected } = Fn;
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
216
|
+
let num;
|
|
217
|
+
if (typeof key === 'bigint') {
|
|
218
|
+
num = key;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
let bytes = (0, utils_ts_1.ensureBytes)('private key', key);
|
|
222
|
+
try {
|
|
223
|
+
num = Fn.fromBytes(bytes);
|
|
189
224
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if (allowedPrivateKeyLengths) {
|
|
193
|
-
if (!allowedPrivateKeyLengths.includes(bytes.length * 2))
|
|
194
|
-
throw new Error('invalid private key');
|
|
195
|
-
const padded = new Uint8Array(expected);
|
|
196
|
-
padded.set(bytes, padded.length - bytes.length);
|
|
197
|
-
bytes = padded;
|
|
198
|
-
}
|
|
199
|
-
try {
|
|
200
|
-
num = Fn.fromBytes(bytes);
|
|
201
|
-
}
|
|
202
|
-
catch (error) {
|
|
203
|
-
throw new Error(`invalid private key: expected ui8a of size ${expected}, got ${typeof key}`);
|
|
204
|
-
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
throw new Error(`invalid private key: expected ui8a of size ${expected}, got ${typeof key}`);
|
|
205
227
|
}
|
|
206
|
-
if (wrapPrivateKey)
|
|
207
|
-
num = Fn.create(num); // disabled by default, enabled for BLS
|
|
208
|
-
if (!Fn.isValidNot0(num))
|
|
209
|
-
throw new Error('invalid private key: out of range [1..N-1]');
|
|
210
|
-
return num;
|
|
211
228
|
}
|
|
212
|
-
|
|
229
|
+
if (!Fn.isValidNot0(num))
|
|
230
|
+
throw new Error('invalid private key: out of range [1..N-1]');
|
|
231
|
+
return num;
|
|
213
232
|
}
|
|
214
233
|
function weierstrassN(CURVE, curveOpts = {}) {
|
|
215
234
|
const { Fp, Fn } = (0, curve_ts_1._createCurveFields)('weierstrass', CURVE, curveOpts);
|
|
@@ -226,10 +245,8 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
226
245
|
const { endo } = curveOpts;
|
|
227
246
|
if (endo) {
|
|
228
247
|
// validateObject(endo, { beta: 'bigint', splitScalar: 'function' });
|
|
229
|
-
if (!Fp.is0(CURVE.a) ||
|
|
230
|
-
|
|
231
|
-
typeof endo.splitScalar !== 'function') {
|
|
232
|
-
throw new Error('invalid endo: expected "beta": bigint and "splitScalar": function');
|
|
248
|
+
if (!Fp.is0(CURVE.a) || typeof endo.beta !== 'bigint' || !Array.isArray(endo.basises)) {
|
|
249
|
+
throw new Error('invalid endo: expected "beta": bigint and "basises": array');
|
|
233
250
|
}
|
|
234
251
|
}
|
|
235
252
|
function assertCompressionIsSupported() {
|
|
@@ -321,28 +338,33 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
321
338
|
if (!(other instanceof Point))
|
|
322
339
|
throw new Error('ProjectivePoint expected');
|
|
323
340
|
}
|
|
341
|
+
function splitEndoScalarN(k) {
|
|
342
|
+
if (!endo || !endo.basises)
|
|
343
|
+
throw new Error('no endo');
|
|
344
|
+
return _splitEndoScalar(k, endo.basises, Fn.ORDER);
|
|
345
|
+
}
|
|
324
346
|
// Memoized toAffine / validity check. They are heavy. Points are immutable.
|
|
325
347
|
// Converts Projective point to affine (x, y) coordinates.
|
|
326
348
|
// Can accept precomputed Z^-1 - for example, from invertBatch.
|
|
327
349
|
// (X, Y, Z) ∋ (x=X/Z, y=Y/Z)
|
|
328
350
|
const toAffineMemo = (0, utils_ts_1.memoized)((p, iz) => {
|
|
329
|
-
const {
|
|
351
|
+
const { X, Y, Z } = p;
|
|
330
352
|
// Fast-path for normalized points
|
|
331
|
-
if (Fp.eql(
|
|
332
|
-
return { x, y };
|
|
353
|
+
if (Fp.eql(Z, Fp.ONE))
|
|
354
|
+
return { x: X, y: Y };
|
|
333
355
|
const is0 = p.is0();
|
|
334
356
|
// If invZ was 0, we return zero point. However we still want to execute
|
|
335
357
|
// all operations, so we replace invZ with a random number, 1.
|
|
336
358
|
if (iz == null)
|
|
337
|
-
iz = is0 ? Fp.ONE : Fp.inv(
|
|
338
|
-
const
|
|
339
|
-
const
|
|
340
|
-
const zz = Fp.mul(
|
|
359
|
+
iz = is0 ? Fp.ONE : Fp.inv(Z);
|
|
360
|
+
const x = Fp.mul(X, iz);
|
|
361
|
+
const y = Fp.mul(Y, iz);
|
|
362
|
+
const zz = Fp.mul(Z, iz);
|
|
341
363
|
if (is0)
|
|
342
364
|
return { x: Fp.ZERO, y: Fp.ZERO };
|
|
343
365
|
if (!Fp.eql(zz, Fp.ONE))
|
|
344
366
|
throw new Error('invZ was invalid');
|
|
345
|
-
return { x
|
|
367
|
+
return { x, y };
|
|
346
368
|
});
|
|
347
369
|
// NOTE: on exception this will crash 'cached' and no value will be set.
|
|
348
370
|
// Otherwise true will be return
|
|
@@ -351,7 +373,7 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
351
373
|
// (0, 1, 0) aka ZERO is invalid in most contexts.
|
|
352
374
|
// In BLS, ZERO can be serialized, so we allow it.
|
|
353
375
|
// (0, 0, 0) is invalid representation of ZERO.
|
|
354
|
-
if (curveOpts.allowInfinityPoint && !Fp.is0(p.
|
|
376
|
+
if (curveOpts.allowInfinityPoint && !Fp.is0(p.Y))
|
|
355
377
|
return;
|
|
356
378
|
throw new Error('bad point: ZERO');
|
|
357
379
|
}
|
|
@@ -366,7 +388,7 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
366
388
|
return true;
|
|
367
389
|
});
|
|
368
390
|
function finishEndo(endoBeta, k1p, k2p, k1neg, k2neg) {
|
|
369
|
-
k2p = new Point(Fp.mul(k2p.
|
|
391
|
+
k2p = new Point(Fp.mul(k2p.X, endoBeta), k2p.Y, k2p.Z);
|
|
370
392
|
k1p = (0, curve_ts_1.negateCt)(k1neg, k1p);
|
|
371
393
|
k2p = (0, curve_ts_1.negateCt)(k2neg, k2p);
|
|
372
394
|
return k1p.add(k2p);
|
|
@@ -378,10 +400,10 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
378
400
|
*/
|
|
379
401
|
class Point {
|
|
380
402
|
/** Does NOT validate if the point is valid. Use `.assertValidity()`. */
|
|
381
|
-
constructor(
|
|
382
|
-
this.
|
|
383
|
-
this.
|
|
384
|
-
this.
|
|
403
|
+
constructor(X, Y, Z) {
|
|
404
|
+
this.X = acoord('x', X);
|
|
405
|
+
this.Y = acoord('y', Y, true);
|
|
406
|
+
this.Z = acoord('z', Z);
|
|
385
407
|
Object.freeze(this);
|
|
386
408
|
}
|
|
387
409
|
/** Does NOT validate if the point is valid. Use `.assertValidity()`. */
|
|
@@ -402,8 +424,18 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
402
424
|
get y() {
|
|
403
425
|
return this.toAffine().y;
|
|
404
426
|
}
|
|
427
|
+
// TODO: remove
|
|
428
|
+
get px() {
|
|
429
|
+
return this.X;
|
|
430
|
+
}
|
|
431
|
+
get py() {
|
|
432
|
+
return this.X;
|
|
433
|
+
}
|
|
434
|
+
get pz() {
|
|
435
|
+
return this.Z;
|
|
436
|
+
}
|
|
405
437
|
static normalizeZ(points) {
|
|
406
|
-
return (0, curve_ts_1.normalizeZ)(Point,
|
|
438
|
+
return (0, curve_ts_1.normalizeZ)(Point, points);
|
|
407
439
|
}
|
|
408
440
|
static fromBytes(bytes) {
|
|
409
441
|
(0, utils_ts_1.abytes)(bytes);
|
|
@@ -417,13 +449,15 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
417
449
|
}
|
|
418
450
|
/** Multiplies generator point by privateKey. */
|
|
419
451
|
static fromPrivateKey(privateKey) {
|
|
420
|
-
|
|
421
|
-
return Point.BASE.multiply(normPrivateKeyToScalar(privateKey));
|
|
452
|
+
return Point.BASE.multiply(_normFnElement(Fn, privateKey));
|
|
422
453
|
}
|
|
423
|
-
|
|
454
|
+
// TODO: remove
|
|
424
455
|
static msm(points, scalars) {
|
|
425
456
|
return (0, curve_ts_1.pippenger)(Point, Fn, points, scalars);
|
|
426
457
|
}
|
|
458
|
+
_setWindowSize(windowSize) {
|
|
459
|
+
this.precompute(windowSize);
|
|
460
|
+
}
|
|
427
461
|
/**
|
|
428
462
|
*
|
|
429
463
|
* @param windowSize
|
|
@@ -431,15 +465,11 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
431
465
|
* @returns
|
|
432
466
|
*/
|
|
433
467
|
precompute(windowSize = 8, isLazy = true) {
|
|
434
|
-
wnaf.
|
|
468
|
+
wnaf.createCache(this, windowSize);
|
|
435
469
|
if (!isLazy)
|
|
436
470
|
this.multiply(_3n); // random number
|
|
437
471
|
return this;
|
|
438
472
|
}
|
|
439
|
-
/** "Private method", don't use it directly */
|
|
440
|
-
_setWindowSize(windowSize) {
|
|
441
|
-
this.precompute(windowSize);
|
|
442
|
-
}
|
|
443
473
|
// TODO: return `this`
|
|
444
474
|
/** A point on curve is valid if it conforms to equation. */
|
|
445
475
|
assertValidity() {
|
|
@@ -454,15 +484,15 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
454
484
|
/** Compare one point to another. */
|
|
455
485
|
equals(other) {
|
|
456
486
|
aprjpoint(other);
|
|
457
|
-
const {
|
|
458
|
-
const {
|
|
487
|
+
const { X: X1, Y: Y1, Z: Z1 } = this;
|
|
488
|
+
const { X: X2, Y: Y2, Z: Z2 } = other;
|
|
459
489
|
const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
|
|
460
490
|
const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
|
|
461
491
|
return U1 && U2;
|
|
462
492
|
}
|
|
463
493
|
/** Flips point to one corresponding to (x, -y) in Affine coordinates. */
|
|
464
494
|
negate() {
|
|
465
|
-
return new Point(this.
|
|
495
|
+
return new Point(this.X, Fp.neg(this.Y), this.Z);
|
|
466
496
|
}
|
|
467
497
|
// Renes-Costello-Batina exception-free doubling formula.
|
|
468
498
|
// There is 30% faster Jacobian formula, but it is not complete.
|
|
@@ -471,7 +501,7 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
471
501
|
double() {
|
|
472
502
|
const { a, b } = CURVE;
|
|
473
503
|
const b3 = Fp.mul(b, _3n);
|
|
474
|
-
const {
|
|
504
|
+
const { X: X1, Y: Y1, Z: Z1 } = this;
|
|
475
505
|
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
|
|
476
506
|
let t0 = Fp.mul(X1, X1); // step 1
|
|
477
507
|
let t1 = Fp.mul(Y1, Y1);
|
|
@@ -512,8 +542,8 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
512
542
|
// Cost: 12M + 0S + 3*a + 3*b3 + 23add.
|
|
513
543
|
add(other) {
|
|
514
544
|
aprjpoint(other);
|
|
515
|
-
const {
|
|
516
|
-
const {
|
|
545
|
+
const { X: X1, Y: Y1, Z: Z1 } = this;
|
|
546
|
+
const { X: X2, Y: Y2, Z: Z2 } = other;
|
|
517
547
|
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
|
|
518
548
|
const a = CURVE.a;
|
|
519
549
|
const b3 = Fp.mul(CURVE.b, _3n);
|
|
@@ -579,10 +609,10 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
579
609
|
if (!Fn.isValidNot0(scalar))
|
|
580
610
|
throw new Error('invalid scalar: out of range'); // 0 is invalid
|
|
581
611
|
let point, fake; // Fake point is used to const-time mult
|
|
582
|
-
const mul = (n) => wnaf.
|
|
612
|
+
const mul = (n) => wnaf.cached(this, n, (p) => (0, curve_ts_1.normalizeZ)(Point, p));
|
|
583
613
|
/** See docs for {@link EndomorphismOpts} */
|
|
584
614
|
if (endo) {
|
|
585
|
-
const { k1neg, k1, k2neg, k2 } =
|
|
615
|
+
const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(scalar);
|
|
586
616
|
const { p: k1p, f: k1f } = mul(k1);
|
|
587
617
|
const { p: k2p, f: k2f } = mul(k2);
|
|
588
618
|
fake = k1f.add(k2f);
|
|
@@ -594,12 +624,12 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
594
624
|
fake = f;
|
|
595
625
|
}
|
|
596
626
|
// Normalize `z` for both points, but return only real one
|
|
597
|
-
return
|
|
627
|
+
return (0, curve_ts_1.normalizeZ)(Point, [point, fake])[0];
|
|
598
628
|
}
|
|
599
629
|
/**
|
|
600
630
|
* Non-constant-time multiplication. Uses double-and-add algorithm.
|
|
601
631
|
* It's faster, but should only be used when you don't care about
|
|
602
|
-
* an exposed
|
|
632
|
+
* an exposed secret key e.g. sig verification, which works over *public* keys.
|
|
603
633
|
*/
|
|
604
634
|
multiplyUnsafe(sc) {
|
|
605
635
|
const { endo } = curveOpts;
|
|
@@ -610,16 +640,15 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
610
640
|
return Point.ZERO;
|
|
611
641
|
if (sc === _1n)
|
|
612
642
|
return p; // fast-path
|
|
613
|
-
if (wnaf.
|
|
643
|
+
if (wnaf.hasCache(this))
|
|
614
644
|
return this.multiply(sc);
|
|
615
645
|
if (endo) {
|
|
616
|
-
const { k1neg, k1, k2neg, k2 } =
|
|
617
|
-
|
|
618
|
-
const { p1, p2 } = (0, curve_ts_1.mulEndoUnsafe)(Point, p, k1, k2);
|
|
646
|
+
const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(sc);
|
|
647
|
+
const { p1, p2 } = (0, curve_ts_1.mulEndoUnsafe)(Point, p, k1, k2); // 30% faster vs wnaf.unsafe
|
|
619
648
|
return finishEndo(endo.beta, p1, p2, k1neg, k2neg);
|
|
620
649
|
}
|
|
621
650
|
else {
|
|
622
|
-
return wnaf.
|
|
651
|
+
return wnaf.unsafe(p, sc);
|
|
623
652
|
}
|
|
624
653
|
}
|
|
625
654
|
multiplyAndAddUnsafe(Q, a, b) {
|
|
@@ -643,7 +672,7 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
643
672
|
return true;
|
|
644
673
|
if (isTorsionFree)
|
|
645
674
|
return isTorsionFree(Point, this);
|
|
646
|
-
return wnaf.
|
|
675
|
+
return wnaf.unsafe(this, CURVE_ORDER).is0();
|
|
647
676
|
}
|
|
648
677
|
clearCofactor() {
|
|
649
678
|
const { clearCofactor } = curveOpts;
|
|
@@ -653,6 +682,10 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
653
682
|
return clearCofactor(Point, this);
|
|
654
683
|
return this.multiplyUnsafe(cofactor);
|
|
655
684
|
}
|
|
685
|
+
isSmallOrder() {
|
|
686
|
+
// can we use this.clearCofactor()?
|
|
687
|
+
return this.multiplyUnsafe(cofactor).is0();
|
|
688
|
+
}
|
|
656
689
|
toBytes(isCompressed = true) {
|
|
657
690
|
(0, utils_ts_1.abool)('isCompressed', isCompressed);
|
|
658
691
|
this.assertValidity();
|
|
@@ -677,10 +710,11 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
677
710
|
Point.Fp = Fp;
|
|
678
711
|
Point.Fn = Fn;
|
|
679
712
|
const bits = Fn.BITS;
|
|
680
|
-
const wnaf =
|
|
713
|
+
const wnaf = new curve_ts_1.wNAF(Point, curveOpts.endo ? Math.ceil(bits / 2) : bits);
|
|
681
714
|
return Point;
|
|
682
715
|
}
|
|
683
716
|
// _legacyWeierstrass
|
|
717
|
+
// TODO: remove
|
|
684
718
|
/** @deprecated use `weierstrassN` */
|
|
685
719
|
function weierstrassPoints(c) {
|
|
686
720
|
const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
|
|
@@ -691,8 +725,136 @@ function weierstrassPoints(c) {
|
|
|
691
725
|
function pprefix(hasEvenY) {
|
|
692
726
|
return Uint8Array.of(hasEvenY ? 0x02 : 0x03);
|
|
693
727
|
}
|
|
694
|
-
|
|
695
|
-
|
|
728
|
+
/**
|
|
729
|
+
* Implementation of the Shallue and van de Woestijne method for any weierstrass curve.
|
|
730
|
+
* TODO: check if there is a way to merge this with uvRatio in Edwards; move to modular.
|
|
731
|
+
* b = True and y = sqrt(u / v) if (u / v) is square in F, and
|
|
732
|
+
* b = False and y = sqrt(Z * (u / v)) otherwise.
|
|
733
|
+
* @param Fp
|
|
734
|
+
* @param Z
|
|
735
|
+
* @returns
|
|
736
|
+
*/
|
|
737
|
+
function SWUFpSqrtRatio(Fp, Z) {
|
|
738
|
+
// Generic implementation
|
|
739
|
+
const q = Fp.ORDER;
|
|
740
|
+
let l = _0n;
|
|
741
|
+
for (let o = q - _1n; o % _2n === _0n; o /= _2n)
|
|
742
|
+
l += _1n;
|
|
743
|
+
const c1 = l; // 1. c1, the largest integer such that 2^c1 divides q - 1.
|
|
744
|
+
// We need 2n ** c1 and 2n ** (c1-1). We can't use **; but we can use <<.
|
|
745
|
+
// 2n ** c1 == 2n << (c1-1)
|
|
746
|
+
const _2n_pow_c1_1 = _2n << (c1 - _1n - _1n);
|
|
747
|
+
const _2n_pow_c1 = _2n_pow_c1_1 * _2n;
|
|
748
|
+
const c2 = (q - _1n) / _2n_pow_c1; // 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
|
|
749
|
+
const c3 = (c2 - _1n) / _2n; // 3. c3 = (c2 - 1) / 2 # Integer arithmetic
|
|
750
|
+
const c4 = _2n_pow_c1 - _1n; // 4. c4 = 2^c1 - 1 # Integer arithmetic
|
|
751
|
+
const c5 = _2n_pow_c1_1; // 5. c5 = 2^(c1 - 1) # Integer arithmetic
|
|
752
|
+
const c6 = Fp.pow(Z, c2); // 6. c6 = Z^c2
|
|
753
|
+
const c7 = Fp.pow(Z, (c2 + _1n) / _2n); // 7. c7 = Z^((c2 + 1) / 2)
|
|
754
|
+
let sqrtRatio = (u, v) => {
|
|
755
|
+
let tv1 = c6; // 1. tv1 = c6
|
|
756
|
+
let tv2 = Fp.pow(v, c4); // 2. tv2 = v^c4
|
|
757
|
+
let tv3 = Fp.sqr(tv2); // 3. tv3 = tv2^2
|
|
758
|
+
tv3 = Fp.mul(tv3, v); // 4. tv3 = tv3 * v
|
|
759
|
+
let tv5 = Fp.mul(u, tv3); // 5. tv5 = u * tv3
|
|
760
|
+
tv5 = Fp.pow(tv5, c3); // 6. tv5 = tv5^c3
|
|
761
|
+
tv5 = Fp.mul(tv5, tv2); // 7. tv5 = tv5 * tv2
|
|
762
|
+
tv2 = Fp.mul(tv5, v); // 8. tv2 = tv5 * v
|
|
763
|
+
tv3 = Fp.mul(tv5, u); // 9. tv3 = tv5 * u
|
|
764
|
+
let tv4 = Fp.mul(tv3, tv2); // 10. tv4 = tv3 * tv2
|
|
765
|
+
tv5 = Fp.pow(tv4, c5); // 11. tv5 = tv4^c5
|
|
766
|
+
let isQR = Fp.eql(tv5, Fp.ONE); // 12. isQR = tv5 == 1
|
|
767
|
+
tv2 = Fp.mul(tv3, c7); // 13. tv2 = tv3 * c7
|
|
768
|
+
tv5 = Fp.mul(tv4, tv1); // 14. tv5 = tv4 * tv1
|
|
769
|
+
tv3 = Fp.cmov(tv2, tv3, isQR); // 15. tv3 = CMOV(tv2, tv3, isQR)
|
|
770
|
+
tv4 = Fp.cmov(tv5, tv4, isQR); // 16. tv4 = CMOV(tv5, tv4, isQR)
|
|
771
|
+
// 17. for i in (c1, c1 - 1, ..., 2):
|
|
772
|
+
for (let i = c1; i > _1n; i--) {
|
|
773
|
+
let tv5 = i - _2n; // 18. tv5 = i - 2
|
|
774
|
+
tv5 = _2n << (tv5 - _1n); // 19. tv5 = 2^tv5
|
|
775
|
+
let tvv5 = Fp.pow(tv4, tv5); // 20. tv5 = tv4^tv5
|
|
776
|
+
const e1 = Fp.eql(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
|
|
777
|
+
tv2 = Fp.mul(tv3, tv1); // 22. tv2 = tv3 * tv1
|
|
778
|
+
tv1 = Fp.mul(tv1, tv1); // 23. tv1 = tv1 * tv1
|
|
779
|
+
tvv5 = Fp.mul(tv4, tv1); // 24. tv5 = tv4 * tv1
|
|
780
|
+
tv3 = Fp.cmov(tv2, tv3, e1); // 25. tv3 = CMOV(tv2, tv3, e1)
|
|
781
|
+
tv4 = Fp.cmov(tvv5, tv4, e1); // 26. tv4 = CMOV(tv5, tv4, e1)
|
|
782
|
+
}
|
|
783
|
+
return { isValid: isQR, value: tv3 };
|
|
784
|
+
};
|
|
785
|
+
if (Fp.ORDER % _4n === _3n) {
|
|
786
|
+
// sqrt_ratio_3mod4(u, v)
|
|
787
|
+
const c1 = (Fp.ORDER - _3n) / _4n; // 1. c1 = (q - 3) / 4 # Integer arithmetic
|
|
788
|
+
const c2 = Fp.sqrt(Fp.neg(Z)); // 2. c2 = sqrt(-Z)
|
|
789
|
+
sqrtRatio = (u, v) => {
|
|
790
|
+
let tv1 = Fp.sqr(v); // 1. tv1 = v^2
|
|
791
|
+
const tv2 = Fp.mul(u, v); // 2. tv2 = u * v
|
|
792
|
+
tv1 = Fp.mul(tv1, tv2); // 3. tv1 = tv1 * tv2
|
|
793
|
+
let y1 = Fp.pow(tv1, c1); // 4. y1 = tv1^c1
|
|
794
|
+
y1 = Fp.mul(y1, tv2); // 5. y1 = y1 * tv2
|
|
795
|
+
const y2 = Fp.mul(y1, c2); // 6. y2 = y1 * c2
|
|
796
|
+
const tv3 = Fp.mul(Fp.sqr(y1), v); // 7. tv3 = y1^2; 8. tv3 = tv3 * v
|
|
797
|
+
const isQR = Fp.eql(tv3, u); // 9. isQR = tv3 == u
|
|
798
|
+
let y = Fp.cmov(y2, y1, isQR); // 10. y = CMOV(y2, y1, isQR)
|
|
799
|
+
return { isValid: isQR, value: y }; // 11. return (isQR, y) isQR ? y : y*c2
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
// No curves uses that
|
|
803
|
+
// if (Fp.ORDER % _8n === _5n) // sqrt_ratio_5mod8
|
|
804
|
+
return sqrtRatio;
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Simplified Shallue-van de Woestijne-Ulas Method
|
|
808
|
+
* https://www.rfc-editor.org/rfc/rfc9380#section-6.6.2
|
|
809
|
+
*/
|
|
810
|
+
function mapToCurveSimpleSWU(Fp, opts) {
|
|
811
|
+
(0, modular_ts_1.validateField)(Fp);
|
|
812
|
+
const { A, B, Z } = opts;
|
|
813
|
+
if (!Fp.isValid(A) || !Fp.isValid(B) || !Fp.isValid(Z))
|
|
814
|
+
throw new Error('mapToCurveSimpleSWU: invalid opts');
|
|
815
|
+
const sqrtRatio = SWUFpSqrtRatio(Fp, Z);
|
|
816
|
+
if (!Fp.isOdd)
|
|
817
|
+
throw new Error('Field does not have .isOdd()');
|
|
818
|
+
// Input: u, an element of F.
|
|
819
|
+
// Output: (x, y), a point on E.
|
|
820
|
+
return (u) => {
|
|
821
|
+
// prettier-ignore
|
|
822
|
+
let tv1, tv2, tv3, tv4, tv5, tv6, x, y;
|
|
823
|
+
tv1 = Fp.sqr(u); // 1. tv1 = u^2
|
|
824
|
+
tv1 = Fp.mul(tv1, Z); // 2. tv1 = Z * tv1
|
|
825
|
+
tv2 = Fp.sqr(tv1); // 3. tv2 = tv1^2
|
|
826
|
+
tv2 = Fp.add(tv2, tv1); // 4. tv2 = tv2 + tv1
|
|
827
|
+
tv3 = Fp.add(tv2, Fp.ONE); // 5. tv3 = tv2 + 1
|
|
828
|
+
tv3 = Fp.mul(tv3, B); // 6. tv3 = B * tv3
|
|
829
|
+
tv4 = Fp.cmov(Z, Fp.neg(tv2), !Fp.eql(tv2, Fp.ZERO)); // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
|
|
830
|
+
tv4 = Fp.mul(tv4, A); // 8. tv4 = A * tv4
|
|
831
|
+
tv2 = Fp.sqr(tv3); // 9. tv2 = tv3^2
|
|
832
|
+
tv6 = Fp.sqr(tv4); // 10. tv6 = tv4^2
|
|
833
|
+
tv5 = Fp.mul(tv6, A); // 11. tv5 = A * tv6
|
|
834
|
+
tv2 = Fp.add(tv2, tv5); // 12. tv2 = tv2 + tv5
|
|
835
|
+
tv2 = Fp.mul(tv2, tv3); // 13. tv2 = tv2 * tv3
|
|
836
|
+
tv6 = Fp.mul(tv6, tv4); // 14. tv6 = tv6 * tv4
|
|
837
|
+
tv5 = Fp.mul(tv6, B); // 15. tv5 = B * tv6
|
|
838
|
+
tv2 = Fp.add(tv2, tv5); // 16. tv2 = tv2 + tv5
|
|
839
|
+
x = Fp.mul(tv1, tv3); // 17. x = tv1 * tv3
|
|
840
|
+
const { isValid, value } = sqrtRatio(tv2, tv6); // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6)
|
|
841
|
+
y = Fp.mul(tv1, u); // 19. y = tv1 * u -> Z * u^3 * y1
|
|
842
|
+
y = Fp.mul(y, value); // 20. y = y * y1
|
|
843
|
+
x = Fp.cmov(x, tv3, isValid); // 21. x = CMOV(x, tv3, is_gx1_square)
|
|
844
|
+
y = Fp.cmov(y, value, isValid); // 22. y = CMOV(y, y1, is_gx1_square)
|
|
845
|
+
const e1 = Fp.isOdd(u) === Fp.isOdd(y); // 23. e1 = sgn0(u) == sgn0(y)
|
|
846
|
+
y = Fp.cmov(Fp.neg(y), y, e1); // 24. y = CMOV(-y, y, e1)
|
|
847
|
+
const tv4_inv = (0, modular_ts_1.FpInvertBatch)(Fp, [tv4], true)[0];
|
|
848
|
+
x = Fp.mul(x, tv4_inv); // 25. x = x / tv4
|
|
849
|
+
return { x, y };
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Creates ECDSA for given elliptic curve Point and hash function.
|
|
854
|
+
*/
|
|
855
|
+
function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
856
|
+
(0, utils_1.ahash)(hash);
|
|
857
|
+
(0, utils_ts_1._validateObject)(ecdsaOpts, {}, {
|
|
696
858
|
hmac: 'function',
|
|
697
859
|
lowS: 'boolean',
|
|
698
860
|
randomBytes: 'function',
|
|
@@ -701,9 +863,17 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
701
863
|
});
|
|
702
864
|
const randomBytes_ = ecdsaOpts.randomBytes || utils_ts_1.randomBytes;
|
|
703
865
|
const hmac_ = ecdsaOpts.hmac ||
|
|
704
|
-
((key, ...msgs) => (0, hmac_js_1.hmac)(
|
|
866
|
+
((key, ...msgs) => (0, hmac_js_1.hmac)(hash, key, (0, utils_ts_1.concatBytes)(...msgs)));
|
|
705
867
|
const { Fp, Fn } = Point;
|
|
706
868
|
const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
|
|
869
|
+
const seedLen = (0, modular_ts_1.getMinHashLength)(CURVE_ORDER);
|
|
870
|
+
const lengths = {
|
|
871
|
+
secret: Fn.BYTES,
|
|
872
|
+
public: 1 + Fp.BYTES,
|
|
873
|
+
publicUncompressed: 1 + 2 * Fp.BYTES,
|
|
874
|
+
signature: 2 * Fn.BYTES,
|
|
875
|
+
seed: seedLen,
|
|
876
|
+
};
|
|
707
877
|
function isBiggerThanHalfOrder(number) {
|
|
708
878
|
const HALF = CURVE_ORDER >> _1n;
|
|
709
879
|
return number > HALF;
|
|
@@ -728,23 +898,24 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
728
898
|
this.recovery = recovery;
|
|
729
899
|
Object.freeze(this);
|
|
730
900
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
901
|
+
static fromBytes(bytes, format = 'compact') {
|
|
902
|
+
if (format === 'compact') {
|
|
903
|
+
const L = Fn.BYTES;
|
|
904
|
+
(0, utils_ts_1.abytes)(bytes, L * 2);
|
|
905
|
+
const r = bytes.subarray(0, L);
|
|
906
|
+
const s = bytes.subarray(L, L * 2);
|
|
907
|
+
return new Signature(Fn.fromBytes(r), Fn.fromBytes(s));
|
|
908
|
+
}
|
|
909
|
+
if (format === 'der') {
|
|
910
|
+
(0, utils_ts_1.abytes)(bytes);
|
|
911
|
+
const { r, s } = exports.DER.toSig(bytes);
|
|
912
|
+
return new Signature(r, s);
|
|
913
|
+
}
|
|
914
|
+
throw new Error('invalid format');
|
|
736
915
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
static fromDER(hex) {
|
|
740
|
-
const { r, s } = exports.DER.toSig((0, utils_ts_1.ensureBytes)('DER', hex));
|
|
741
|
-
return new Signature(r, s);
|
|
916
|
+
static fromHex(hex, format) {
|
|
917
|
+
return this.fromBytes((0, utils_ts_1.hexToBytes)(hex), format);
|
|
742
918
|
}
|
|
743
|
-
/**
|
|
744
|
-
* @todo remove
|
|
745
|
-
* @deprecated
|
|
746
|
-
*/
|
|
747
|
-
assertValidity() { }
|
|
748
919
|
addRecoveryBit(recovery) {
|
|
749
920
|
return new Signature(this.r, this.s, recovery);
|
|
750
921
|
}
|
|
@@ -788,21 +959,30 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
788
959
|
normalizeS() {
|
|
789
960
|
return this.hasHighS() ? new Signature(this.r, Fn.neg(this.s), this.recovery) : this;
|
|
790
961
|
}
|
|
791
|
-
toBytes(format) {
|
|
962
|
+
toBytes(format = 'compact') {
|
|
792
963
|
if (format === 'compact')
|
|
793
964
|
return (0, utils_ts_1.concatBytes)(Fn.toBytes(this.r), Fn.toBytes(this.s));
|
|
794
965
|
if (format === 'der')
|
|
795
966
|
return (0, utils_ts_1.hexToBytes)(exports.DER.hexFromSig(this));
|
|
796
967
|
throw new Error('invalid format');
|
|
797
968
|
}
|
|
798
|
-
|
|
969
|
+
toHex(format) {
|
|
970
|
+
return (0, utils_ts_1.bytesToHex)(this.toBytes(format));
|
|
971
|
+
}
|
|
972
|
+
// TODO: remove
|
|
973
|
+
assertValidity() { }
|
|
974
|
+
static fromCompact(hex) {
|
|
975
|
+
return Signature.fromBytes((0, utils_ts_1.ensureBytes)('sig', hex), 'compact');
|
|
976
|
+
}
|
|
977
|
+
static fromDER(hex) {
|
|
978
|
+
return Signature.fromBytes((0, utils_ts_1.ensureBytes)('sig', hex), 'der');
|
|
979
|
+
}
|
|
799
980
|
toDERRawBytes() {
|
|
800
981
|
return this.toBytes('der');
|
|
801
982
|
}
|
|
802
983
|
toDERHex() {
|
|
803
984
|
return (0, utils_ts_1.bytesToHex)(this.toBytes('der'));
|
|
804
985
|
}
|
|
805
|
-
// padded bytes of r, then padded bytes of s
|
|
806
986
|
toCompactRawBytes() {
|
|
807
987
|
return this.toBytes('compact');
|
|
808
988
|
}
|
|
@@ -810,76 +990,85 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
810
990
|
return (0, utils_ts_1.bytesToHex)(this.toBytes('compact'));
|
|
811
991
|
}
|
|
812
992
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
993
|
+
function isValidSecretKey(privateKey) {
|
|
994
|
+
try {
|
|
995
|
+
return !!_normFnElement(Fn, privateKey);
|
|
996
|
+
}
|
|
997
|
+
catch (error) {
|
|
998
|
+
return false;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
function isValidPublicKey(publicKey, isCompressed) {
|
|
1002
|
+
try {
|
|
1003
|
+
const l = publicKey.length;
|
|
1004
|
+
if (isCompressed === true && l !== lengths.public)
|
|
821
1005
|
return false;
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
1006
|
+
if (isCompressed === false && l !== lengths.publicUncompressed)
|
|
1007
|
+
return false;
|
|
1008
|
+
return !!Point.fromBytes(publicKey);
|
|
1009
|
+
}
|
|
1010
|
+
catch (error) {
|
|
1011
|
+
return false;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Produces cryptographically secure secret key from random of size
|
|
1016
|
+
* (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
|
|
1017
|
+
*/
|
|
1018
|
+
function randomSecretKey(seed = randomBytes_(seedLen)) {
|
|
1019
|
+
return (0, modular_ts_1.mapHashToField)(seed, CURVE_ORDER);
|
|
1020
|
+
}
|
|
1021
|
+
const utils = {
|
|
1022
|
+
isValidSecretKey,
|
|
1023
|
+
isValidPublicKey,
|
|
1024
|
+
randomSecretKey,
|
|
1025
|
+
// TODO: remove
|
|
1026
|
+
isValidPrivateKey: isValidSecretKey,
|
|
1027
|
+
randomPrivateKey: randomSecretKey,
|
|
1028
|
+
normPrivateKeyToScalar: (key) => _normFnElement(Fn, key),
|
|
833
1029
|
precompute(windowSize = 8, point = Point.BASE) {
|
|
834
1030
|
return point.precompute(windowSize, false);
|
|
835
1031
|
},
|
|
836
1032
|
};
|
|
837
1033
|
/**
|
|
838
|
-
* Computes public key for a
|
|
839
|
-
* @param privateKey private key
|
|
1034
|
+
* Computes public key for a secret key. Checks for validity of the secret key.
|
|
840
1035
|
* @param isCompressed whether to return compact (default), or full key
|
|
841
1036
|
* @returns Public key, full when isCompressed=false; short when isCompressed=true
|
|
842
1037
|
*/
|
|
843
|
-
function getPublicKey(
|
|
844
|
-
return Point.
|
|
1038
|
+
function getPublicKey(secretKey, isCompressed = true) {
|
|
1039
|
+
return Point.BASE.multiply(_normFnElement(Fn, secretKey)).toBytes(isCompressed);
|
|
845
1040
|
}
|
|
846
1041
|
/**
|
|
847
1042
|
* Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
|
|
848
1043
|
*/
|
|
849
1044
|
function isProbPub(item) {
|
|
1045
|
+
// TODO: remove
|
|
850
1046
|
if (typeof item === 'bigint')
|
|
851
1047
|
return false;
|
|
1048
|
+
// TODO: remove
|
|
852
1049
|
if (item instanceof Point)
|
|
853
1050
|
return true;
|
|
854
|
-
|
|
855
|
-
const length = arr.length;
|
|
856
|
-
const L = Fp.BYTES;
|
|
857
|
-
const LC = L + 1; // e.g. 33 for 32
|
|
858
|
-
const LU = 2 * L + 1; // e.g. 65 for 32
|
|
859
|
-
if (curveOpts.allowedPrivateKeyLengths || Fn.BYTES === LC) {
|
|
1051
|
+
if (Fn.allowedLengths || lengths.secret === lengths.public)
|
|
860
1052
|
return undefined;
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
return length === LC || length === LU;
|
|
864
|
-
}
|
|
1053
|
+
const l = (0, utils_ts_1.ensureBytes)('key', item).length;
|
|
1054
|
+
return l === lengths.public || l === lengths.publicUncompressed;
|
|
865
1055
|
}
|
|
866
1056
|
/**
|
|
867
1057
|
* ECDH (Elliptic Curve Diffie Hellman).
|
|
868
|
-
* Computes shared public key from
|
|
869
|
-
* Checks: 1)
|
|
1058
|
+
* Computes shared public key from secret key A and public key B.
|
|
1059
|
+
* Checks: 1) secret key validity 2) shared key is on-curve.
|
|
870
1060
|
* Does NOT hash the result.
|
|
871
|
-
* @param privateA private key
|
|
872
|
-
* @param publicB different public key
|
|
873
1061
|
* @param isCompressed whether to return compact (default), or full key
|
|
874
1062
|
* @returns shared public key
|
|
875
1063
|
*/
|
|
876
|
-
function getSharedSecret(
|
|
877
|
-
if (isProbPub(
|
|
1064
|
+
function getSharedSecret(secretKeyA, publicKeyB, isCompressed = true) {
|
|
1065
|
+
if (isProbPub(secretKeyA) === true)
|
|
878
1066
|
throw new Error('first arg must be private key');
|
|
879
|
-
if (isProbPub(
|
|
1067
|
+
if (isProbPub(publicKeyB) === false)
|
|
880
1068
|
throw new Error('second arg must be public key');
|
|
881
|
-
const
|
|
882
|
-
|
|
1069
|
+
const s = _normFnElement(Fn, secretKeyA);
|
|
1070
|
+
const b = Point.fromHex(publicKeyB); // checks for being on-curve
|
|
1071
|
+
return b.multiply(s).toBytes(isCompressed);
|
|
883
1072
|
}
|
|
884
1073
|
// RFC6979: ensure ECDSA msg is X bytes and < N. RFC suggests optional truncating via bits2octets.
|
|
885
1074
|
// FIPS 186-4 4.6 suggests the leftmost min(nBitLen, outLen) bits, which matches bits2int.
|
|
@@ -918,7 +1107,6 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
918
1107
|
function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
|
|
919
1108
|
if (['recovered', 'canonical'].some((k) => k in opts))
|
|
920
1109
|
throw new Error('sign() legacy options not supported');
|
|
921
|
-
const { hash } = ecdsaOpts;
|
|
922
1110
|
let { lowS, prehash, extraEntropy: ent } = opts; // generates low-s sigs by default
|
|
923
1111
|
if (lowS == null)
|
|
924
1112
|
lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash
|
|
@@ -930,17 +1118,21 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
930
1118
|
// with fnBits % 8 !== 0. Because of that, we unwrap it here as int2octets call.
|
|
931
1119
|
// const bits2octets = (bits) => int2octets(bits2int_modN(bits))
|
|
932
1120
|
const h1int = bits2int_modN(msgHash);
|
|
933
|
-
const d =
|
|
1121
|
+
const d = _normFnElement(Fn, privateKey); // validate secret key, convert to bigint
|
|
934
1122
|
const seedArgs = [int2octets(d), int2octets(h1int)];
|
|
935
1123
|
// extraEntropy. RFC6979 3.6: additional k' (optional).
|
|
936
1124
|
if (ent != null && ent !== false) {
|
|
937
1125
|
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
|
|
938
|
-
const e = ent === true ? randomBytes_(
|
|
1126
|
+
const e = ent === true ? randomBytes_(lengths.secret) : ent; // gen random bytes OR pass as-is
|
|
939
1127
|
seedArgs.push((0, utils_ts_1.ensureBytes)('extraEntropy', e)); // check for being bytes
|
|
940
1128
|
}
|
|
941
1129
|
const seed = (0, utils_ts_1.concatBytes)(...seedArgs); // Step D of RFC6979 3.2
|
|
942
1130
|
const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
|
|
943
1131
|
// Converts signature params into point w r/s, checks result for validity.
|
|
1132
|
+
// To transform k => Signature:
|
|
1133
|
+
// q = k⋅G
|
|
1134
|
+
// r = q.x mod n
|
|
1135
|
+
// s = k^-1(m + rd) mod n
|
|
944
1136
|
// Can use scalar blinding b^-1(bm + bdr) where b ∈ [1,q−1] according to
|
|
945
1137
|
// https://tches.iacr.org/index.php/TCHES/article/view/7337/6509. We've decided against it:
|
|
946
1138
|
// a) dependency on CSPRNG b) 15% slowdown c) doesn't really help since bigints are not CT
|
|
@@ -951,7 +1143,7 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
951
1143
|
if (!Fn.isValidNot0(k))
|
|
952
1144
|
return; // Valid scalars (including k) must be in 1..N-1
|
|
953
1145
|
const ik = Fn.inv(k); // k^-1 mod n
|
|
954
|
-
const q = Point.BASE.multiply(k).toAffine(); // q =
|
|
1146
|
+
const q = Point.BASE.multiply(k).toAffine(); // q = k⋅G
|
|
955
1147
|
const r = Fn.create(q.x); // r = q.x mod n
|
|
956
1148
|
if (r === _0n)
|
|
957
1149
|
return;
|
|
@@ -971,21 +1163,17 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
971
1163
|
const defaultSigOpts = { lowS: ecdsaOpts.lowS, prehash: false };
|
|
972
1164
|
const defaultVerOpts = { lowS: ecdsaOpts.lowS, prehash: false };
|
|
973
1165
|
/**
|
|
974
|
-
* Signs message hash with a
|
|
1166
|
+
* Signs message hash with a secret key.
|
|
975
1167
|
* ```
|
|
976
1168
|
* sign(m, d, k) where
|
|
977
1169
|
* (x, y) = G × k
|
|
978
1170
|
* r = x mod n
|
|
979
1171
|
* s = (m + dr)/k mod n
|
|
980
1172
|
* ```
|
|
981
|
-
* @param msgHash NOT message. msg needs to be hashed to `msgHash`, or use `prehash`.
|
|
982
|
-
* @param privKey private key
|
|
983
|
-
* @param opts lowS for non-malleable sigs. extraEntropy for mixing randomness into k. prehash will hash first arg.
|
|
984
|
-
* @returns signature with recovery param
|
|
985
1173
|
*/
|
|
986
|
-
function sign(msgHash,
|
|
987
|
-
const { seed, k2sig } = prepSig(msgHash,
|
|
988
|
-
const drbg = (0, utils_ts_1.createHmacDrbg)(
|
|
1174
|
+
function sign(msgHash, secretKey, opts = defaultSigOpts) {
|
|
1175
|
+
const { seed, k2sig } = prepSig(msgHash, secretKey, opts); // Steps A, D of RFC6979 3.2.
|
|
1176
|
+
const drbg = (0, utils_ts_1.createHmacDrbg)(hash.outputLen, Fn.BYTES, hmac_);
|
|
989
1177
|
return drbg(seed, k2sig); // Steps B, C, D, E, F, G
|
|
990
1178
|
}
|
|
991
1179
|
// Enable precomputes. Slows down first publicKey computation by 20ms.
|
|
@@ -1013,88 +1201,98 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
1013
1201
|
// TODO: remove
|
|
1014
1202
|
if ('strict' in opts)
|
|
1015
1203
|
throw new Error('options.strict was renamed to lowS');
|
|
1016
|
-
if (format !== undefined && !['compact', 'der', 'js'].includes(format))
|
|
1017
|
-
throw new Error('format must be "compact", "der" or "js"');
|
|
1018
|
-
const isHex = typeof sg === 'string' || (0, utils_ts_1.isBytes)(sg);
|
|
1019
|
-
const isObj = !isHex &&
|
|
1020
|
-
!format &&
|
|
1021
|
-
typeof sg === 'object' &&
|
|
1022
|
-
sg !== null &&
|
|
1023
|
-
typeof sg.r === 'bigint' &&
|
|
1024
|
-
typeof sg.s === 'bigint';
|
|
1025
|
-
if (!isHex && !isObj)
|
|
1026
|
-
throw new Error('invalid signature, expected Uint8Array, hex string or Signature instance');
|
|
1027
1204
|
let _sig = undefined;
|
|
1028
1205
|
let P;
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
// }
|
|
1206
|
+
if (format === undefined) {
|
|
1207
|
+
// Try to deduce format
|
|
1208
|
+
const isHex = typeof sg === 'string' || (0, utils_ts_1.isBytes)(sg);
|
|
1209
|
+
const isObj = !isHex &&
|
|
1210
|
+
sg !== null &&
|
|
1211
|
+
typeof sg === 'object' &&
|
|
1212
|
+
typeof sg.r === 'bigint' &&
|
|
1213
|
+
typeof sg.s === 'bigint';
|
|
1214
|
+
if (!isHex && !isObj)
|
|
1215
|
+
throw new Error('invalid signature, expected Uint8Array, hex string or Signature instance');
|
|
1040
1216
|
if (isObj) {
|
|
1041
|
-
|
|
1042
|
-
_sig = new Signature(sg.r, sg.s);
|
|
1043
|
-
}
|
|
1044
|
-
else {
|
|
1045
|
-
throw new Error('invalid format');
|
|
1046
|
-
}
|
|
1217
|
+
_sig = new Signature(sg.r, sg.s);
|
|
1047
1218
|
}
|
|
1048
|
-
if (isHex) {
|
|
1219
|
+
else if (isHex) {
|
|
1049
1220
|
// TODO: remove this malleable check
|
|
1050
1221
|
// Signature can be represented in 2 ways: compact (2*Fn.BYTES) & DER (variable-length).
|
|
1051
1222
|
// Since DER can also be 2*Fn.BYTES bytes, we check for it first.
|
|
1052
1223
|
try {
|
|
1053
|
-
|
|
1054
|
-
_sig = Signature.fromDER(sg);
|
|
1224
|
+
_sig = Signature.fromDER(sg);
|
|
1055
1225
|
}
|
|
1056
1226
|
catch (derError) {
|
|
1057
1227
|
if (!(derError instanceof exports.DER.Err))
|
|
1058
1228
|
throw derError;
|
|
1059
1229
|
}
|
|
1060
|
-
if (!_sig
|
|
1061
|
-
|
|
1230
|
+
if (!_sig) {
|
|
1231
|
+
try {
|
|
1232
|
+
_sig = Signature.fromCompact(sg);
|
|
1233
|
+
}
|
|
1234
|
+
catch (error) {
|
|
1235
|
+
return false;
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1062
1238
|
}
|
|
1063
|
-
P = Point.fromHex(publicKey);
|
|
1064
1239
|
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1240
|
+
else {
|
|
1241
|
+
if (format === 'compact' || format === 'der') {
|
|
1242
|
+
if (typeof sg !== 'string' && !(0, utils_ts_1.isBytes)(sg))
|
|
1243
|
+
throw new Error('"der" / "compact" format expects Uint8Array signature');
|
|
1244
|
+
_sig = Signature.fromBytes((0, utils_ts_1.ensureBytes)('sig', sg), format);
|
|
1245
|
+
}
|
|
1246
|
+
else if (format === 'js') {
|
|
1247
|
+
if (!(sg instanceof Signature))
|
|
1248
|
+
throw new Error('"js" format expects Signature instance');
|
|
1249
|
+
_sig = sg;
|
|
1250
|
+
}
|
|
1251
|
+
else {
|
|
1252
|
+
throw new Error('format must be "compact", "der" or "js"');
|
|
1253
|
+
}
|
|
1067
1254
|
}
|
|
1068
1255
|
if (!_sig)
|
|
1069
1256
|
return false;
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1257
|
+
try {
|
|
1258
|
+
P = Point.fromHex(publicKey);
|
|
1259
|
+
if (lowS && _sig.hasHighS())
|
|
1260
|
+
return false;
|
|
1261
|
+
// todo: optional.hash => hash
|
|
1262
|
+
if (prehash)
|
|
1263
|
+
msgHash = hash(msgHash);
|
|
1264
|
+
const { r, s } = _sig;
|
|
1265
|
+
const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element
|
|
1266
|
+
const is = Fn.inv(s); // s^-1
|
|
1267
|
+
const u1 = Fn.create(h * is); // u1 = hs^-1 mod n
|
|
1268
|
+
const u2 = Fn.create(r * is); // u2 = rs^-1 mod n
|
|
1269
|
+
const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2));
|
|
1270
|
+
if (R.is0())
|
|
1271
|
+
return false;
|
|
1272
|
+
const v = Fn.create(R.x); // v = r.x mod n
|
|
1273
|
+
return v === r;
|
|
1274
|
+
}
|
|
1275
|
+
catch (e) {
|
|
1082
1276
|
return false;
|
|
1083
|
-
|
|
1084
|
-
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
function keygen(seed) {
|
|
1280
|
+
const secretKey = utils.randomSecretKey(seed);
|
|
1281
|
+
return { secretKey, publicKey: getPublicKey(secretKey) };
|
|
1085
1282
|
}
|
|
1086
|
-
// TODO: clarify API for cloning .clone({hash: sha512}) ? .createWith({hash: sha512})?
|
|
1087
|
-
// const clone = (hash: CHash): ECDSA => ecdsa(Point, { ...ecdsaOpts, ...getHash(hash) }, curveOpts);
|
|
1088
1283
|
return Object.freeze({
|
|
1284
|
+
keygen,
|
|
1089
1285
|
getPublicKey,
|
|
1090
|
-
getSharedSecret,
|
|
1091
1286
|
sign,
|
|
1092
1287
|
verify,
|
|
1288
|
+
getSharedSecret,
|
|
1093
1289
|
utils,
|
|
1094
1290
|
Point,
|
|
1095
1291
|
Signature,
|
|
1292
|
+
info: { type: 'weierstrass', lengths, publicKeyHasPrefix: true },
|
|
1096
1293
|
});
|
|
1097
1294
|
}
|
|
1295
|
+
// TODO: remove
|
|
1098
1296
|
function _weierstrass_legacy_opts_to_new(c) {
|
|
1099
1297
|
const CURVE = {
|
|
1100
1298
|
a: c.a,
|
|
@@ -1106,14 +1304,19 @@ function _weierstrass_legacy_opts_to_new(c) {
|
|
|
1106
1304
|
Gy: c.Gy,
|
|
1107
1305
|
};
|
|
1108
1306
|
const Fp = c.Fp;
|
|
1109
|
-
|
|
1307
|
+
let allowedLengths = c.allowedPrivateKeyLengths
|
|
1308
|
+
? Array.from(new Set(c.allowedPrivateKeyLengths.map((l) => Math.ceil(l / 2))))
|
|
1309
|
+
: undefined;
|
|
1310
|
+
const Fn = (0, modular_ts_1.Field)(CURVE.n, {
|
|
1311
|
+
BITS: c.nBitLength,
|
|
1312
|
+
allowedLengths: allowedLengths,
|
|
1313
|
+
modOnDecode: c.wrapPrivateKey,
|
|
1314
|
+
});
|
|
1110
1315
|
const curveOpts = {
|
|
1111
1316
|
Fp,
|
|
1112
1317
|
Fn,
|
|
1113
|
-
allowedPrivateKeyLengths: c.allowedPrivateKeyLengths,
|
|
1114
1318
|
allowInfinityPoint: c.allowInfinityPoint,
|
|
1115
1319
|
endo: c.endo,
|
|
1116
|
-
wrapPrivateKey: c.wrapPrivateKey,
|
|
1117
1320
|
isTorsionFree: c.isTorsionFree,
|
|
1118
1321
|
clearCofactor: c.clearCofactor,
|
|
1119
1322
|
fromBytes: c.fromBytes,
|
|
@@ -1124,15 +1327,15 @@ function _weierstrass_legacy_opts_to_new(c) {
|
|
|
1124
1327
|
function _ecdsa_legacy_opts_to_new(c) {
|
|
1125
1328
|
const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
|
|
1126
1329
|
const ecdsaOpts = {
|
|
1127
|
-
hash: c.hash,
|
|
1128
1330
|
hmac: c.hmac,
|
|
1129
1331
|
randomBytes: c.randomBytes,
|
|
1130
1332
|
lowS: c.lowS,
|
|
1131
1333
|
bits2int: c.bits2int,
|
|
1132
1334
|
bits2int_modN: c.bits2int_modN,
|
|
1133
1335
|
};
|
|
1134
|
-
return { CURVE, curveOpts, ecdsaOpts };
|
|
1336
|
+
return { CURVE, curveOpts, hash: c.hash, ecdsaOpts };
|
|
1135
1337
|
}
|
|
1338
|
+
// TODO: remove
|
|
1136
1339
|
function _weierstrass_new_output_to_legacy(c, Point) {
|
|
1137
1340
|
const { Fp, Fn } = Point;
|
|
1138
1341
|
// TODO: remove
|
|
@@ -1140,16 +1343,16 @@ function _weierstrass_new_output_to_legacy(c, Point) {
|
|
|
1140
1343
|
return (0, utils_ts_1.inRange)(num, _1n, Fn.ORDER);
|
|
1141
1344
|
}
|
|
1142
1345
|
const weierstrassEquation = _legacyHelperEquat(Fp, c.a, c.b);
|
|
1143
|
-
const normPrivateKeyToScalar = _legacyHelperNormPriv(Fn, c.allowedPrivateKeyLengths, c.wrapPrivateKey);
|
|
1144
1346
|
return Object.assign({}, {
|
|
1145
1347
|
CURVE: c,
|
|
1146
1348
|
Point: Point,
|
|
1147
1349
|
ProjectivePoint: Point,
|
|
1148
|
-
normPrivateKeyToScalar,
|
|
1350
|
+
normPrivateKeyToScalar: (key) => _normFnElement(Fn, key),
|
|
1149
1351
|
weierstrassEquation,
|
|
1150
1352
|
isWithinCurveOrder,
|
|
1151
1353
|
});
|
|
1152
1354
|
}
|
|
1355
|
+
// TODO: remove
|
|
1153
1356
|
function _ecdsa_new_output_to_legacy(c, ecdsa) {
|
|
1154
1357
|
return Object.assign({}, ecdsa, {
|
|
1155
1358
|
ProjectivePoint: ecdsa.Point,
|
|
@@ -1158,133 +1361,9 @@ function _ecdsa_new_output_to_legacy(c, ecdsa) {
|
|
|
1158
1361
|
}
|
|
1159
1362
|
// _ecdsa_legacy
|
|
1160
1363
|
function weierstrass(c) {
|
|
1161
|
-
const { CURVE, curveOpts, ecdsaOpts } = _ecdsa_legacy_opts_to_new(c);
|
|
1364
|
+
const { CURVE, curveOpts, hash, ecdsaOpts } = _ecdsa_legacy_opts_to_new(c);
|
|
1162
1365
|
const Point = weierstrassN(CURVE, curveOpts);
|
|
1163
|
-
const signs = ecdsa(Point,
|
|
1366
|
+
const signs = ecdsa(Point, hash, ecdsaOpts);
|
|
1164
1367
|
return _ecdsa_new_output_to_legacy(c, signs);
|
|
1165
1368
|
}
|
|
1166
|
-
/**
|
|
1167
|
-
* Implementation of the Shallue and van de Woestijne method for any weierstrass curve.
|
|
1168
|
-
* TODO: check if there is a way to merge this with uvRatio in Edwards; move to modular.
|
|
1169
|
-
* b = True and y = sqrt(u / v) if (u / v) is square in F, and
|
|
1170
|
-
* b = False and y = sqrt(Z * (u / v)) otherwise.
|
|
1171
|
-
* @param Fp
|
|
1172
|
-
* @param Z
|
|
1173
|
-
* @returns
|
|
1174
|
-
*/
|
|
1175
|
-
function SWUFpSqrtRatio(Fp, Z) {
|
|
1176
|
-
// Generic implementation
|
|
1177
|
-
const q = Fp.ORDER;
|
|
1178
|
-
let l = _0n;
|
|
1179
|
-
for (let o = q - _1n; o % _2n === _0n; o /= _2n)
|
|
1180
|
-
l += _1n;
|
|
1181
|
-
const c1 = l; // 1. c1, the largest integer such that 2^c1 divides q - 1.
|
|
1182
|
-
// We need 2n ** c1 and 2n ** (c1-1). We can't use **; but we can use <<.
|
|
1183
|
-
// 2n ** c1 == 2n << (c1-1)
|
|
1184
|
-
const _2n_pow_c1_1 = _2n << (c1 - _1n - _1n);
|
|
1185
|
-
const _2n_pow_c1 = _2n_pow_c1_1 * _2n;
|
|
1186
|
-
const c2 = (q - _1n) / _2n_pow_c1; // 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
|
|
1187
|
-
const c3 = (c2 - _1n) / _2n; // 3. c3 = (c2 - 1) / 2 # Integer arithmetic
|
|
1188
|
-
const c4 = _2n_pow_c1 - _1n; // 4. c4 = 2^c1 - 1 # Integer arithmetic
|
|
1189
|
-
const c5 = _2n_pow_c1_1; // 5. c5 = 2^(c1 - 1) # Integer arithmetic
|
|
1190
|
-
const c6 = Fp.pow(Z, c2); // 6. c6 = Z^c2
|
|
1191
|
-
const c7 = Fp.pow(Z, (c2 + _1n) / _2n); // 7. c7 = Z^((c2 + 1) / 2)
|
|
1192
|
-
let sqrtRatio = (u, v) => {
|
|
1193
|
-
let tv1 = c6; // 1. tv1 = c6
|
|
1194
|
-
let tv2 = Fp.pow(v, c4); // 2. tv2 = v^c4
|
|
1195
|
-
let tv3 = Fp.sqr(tv2); // 3. tv3 = tv2^2
|
|
1196
|
-
tv3 = Fp.mul(tv3, v); // 4. tv3 = tv3 * v
|
|
1197
|
-
let tv5 = Fp.mul(u, tv3); // 5. tv5 = u * tv3
|
|
1198
|
-
tv5 = Fp.pow(tv5, c3); // 6. tv5 = tv5^c3
|
|
1199
|
-
tv5 = Fp.mul(tv5, tv2); // 7. tv5 = tv5 * tv2
|
|
1200
|
-
tv2 = Fp.mul(tv5, v); // 8. tv2 = tv5 * v
|
|
1201
|
-
tv3 = Fp.mul(tv5, u); // 9. tv3 = tv5 * u
|
|
1202
|
-
let tv4 = Fp.mul(tv3, tv2); // 10. tv4 = tv3 * tv2
|
|
1203
|
-
tv5 = Fp.pow(tv4, c5); // 11. tv5 = tv4^c5
|
|
1204
|
-
let isQR = Fp.eql(tv5, Fp.ONE); // 12. isQR = tv5 == 1
|
|
1205
|
-
tv2 = Fp.mul(tv3, c7); // 13. tv2 = tv3 * c7
|
|
1206
|
-
tv5 = Fp.mul(tv4, tv1); // 14. tv5 = tv4 * tv1
|
|
1207
|
-
tv3 = Fp.cmov(tv2, tv3, isQR); // 15. tv3 = CMOV(tv2, tv3, isQR)
|
|
1208
|
-
tv4 = Fp.cmov(tv5, tv4, isQR); // 16. tv4 = CMOV(tv5, tv4, isQR)
|
|
1209
|
-
// 17. for i in (c1, c1 - 1, ..., 2):
|
|
1210
|
-
for (let i = c1; i > _1n; i--) {
|
|
1211
|
-
let tv5 = i - _2n; // 18. tv5 = i - 2
|
|
1212
|
-
tv5 = _2n << (tv5 - _1n); // 19. tv5 = 2^tv5
|
|
1213
|
-
let tvv5 = Fp.pow(tv4, tv5); // 20. tv5 = tv4^tv5
|
|
1214
|
-
const e1 = Fp.eql(tvv5, Fp.ONE); // 21. e1 = tv5 == 1
|
|
1215
|
-
tv2 = Fp.mul(tv3, tv1); // 22. tv2 = tv3 * tv1
|
|
1216
|
-
tv1 = Fp.mul(tv1, tv1); // 23. tv1 = tv1 * tv1
|
|
1217
|
-
tvv5 = Fp.mul(tv4, tv1); // 24. tv5 = tv4 * tv1
|
|
1218
|
-
tv3 = Fp.cmov(tv2, tv3, e1); // 25. tv3 = CMOV(tv2, tv3, e1)
|
|
1219
|
-
tv4 = Fp.cmov(tvv5, tv4, e1); // 26. tv4 = CMOV(tv5, tv4, e1)
|
|
1220
|
-
}
|
|
1221
|
-
return { isValid: isQR, value: tv3 };
|
|
1222
|
-
};
|
|
1223
|
-
if (Fp.ORDER % _4n === _3n) {
|
|
1224
|
-
// sqrt_ratio_3mod4(u, v)
|
|
1225
|
-
const c1 = (Fp.ORDER - _3n) / _4n; // 1. c1 = (q - 3) / 4 # Integer arithmetic
|
|
1226
|
-
const c2 = Fp.sqrt(Fp.neg(Z)); // 2. c2 = sqrt(-Z)
|
|
1227
|
-
sqrtRatio = (u, v) => {
|
|
1228
|
-
let tv1 = Fp.sqr(v); // 1. tv1 = v^2
|
|
1229
|
-
const tv2 = Fp.mul(u, v); // 2. tv2 = u * v
|
|
1230
|
-
tv1 = Fp.mul(tv1, tv2); // 3. tv1 = tv1 * tv2
|
|
1231
|
-
let y1 = Fp.pow(tv1, c1); // 4. y1 = tv1^c1
|
|
1232
|
-
y1 = Fp.mul(y1, tv2); // 5. y1 = y1 * tv2
|
|
1233
|
-
const y2 = Fp.mul(y1, c2); // 6. y2 = y1 * c2
|
|
1234
|
-
const tv3 = Fp.mul(Fp.sqr(y1), v); // 7. tv3 = y1^2; 8. tv3 = tv3 * v
|
|
1235
|
-
const isQR = Fp.eql(tv3, u); // 9. isQR = tv3 == u
|
|
1236
|
-
let y = Fp.cmov(y2, y1, isQR); // 10. y = CMOV(y2, y1, isQR)
|
|
1237
|
-
return { isValid: isQR, value: y }; // 11. return (isQR, y) isQR ? y : y*c2
|
|
1238
|
-
};
|
|
1239
|
-
}
|
|
1240
|
-
// No curves uses that
|
|
1241
|
-
// if (Fp.ORDER % _8n === _5n) // sqrt_ratio_5mod8
|
|
1242
|
-
return sqrtRatio;
|
|
1243
|
-
}
|
|
1244
|
-
/**
|
|
1245
|
-
* Simplified Shallue-van de Woestijne-Ulas Method
|
|
1246
|
-
* https://www.rfc-editor.org/rfc/rfc9380#section-6.6.2
|
|
1247
|
-
*/
|
|
1248
|
-
function mapToCurveSimpleSWU(Fp, opts) {
|
|
1249
|
-
(0, modular_ts_1.validateField)(Fp);
|
|
1250
|
-
const { A, B, Z } = opts;
|
|
1251
|
-
if (!Fp.isValid(A) || !Fp.isValid(B) || !Fp.isValid(Z))
|
|
1252
|
-
throw new Error('mapToCurveSimpleSWU: invalid opts');
|
|
1253
|
-
const sqrtRatio = SWUFpSqrtRatio(Fp, Z);
|
|
1254
|
-
if (!Fp.isOdd)
|
|
1255
|
-
throw new Error('Field does not have .isOdd()');
|
|
1256
|
-
// Input: u, an element of F.
|
|
1257
|
-
// Output: (x, y), a point on E.
|
|
1258
|
-
return (u) => {
|
|
1259
|
-
// prettier-ignore
|
|
1260
|
-
let tv1, tv2, tv3, tv4, tv5, tv6, x, y;
|
|
1261
|
-
tv1 = Fp.sqr(u); // 1. tv1 = u^2
|
|
1262
|
-
tv1 = Fp.mul(tv1, Z); // 2. tv1 = Z * tv1
|
|
1263
|
-
tv2 = Fp.sqr(tv1); // 3. tv2 = tv1^2
|
|
1264
|
-
tv2 = Fp.add(tv2, tv1); // 4. tv2 = tv2 + tv1
|
|
1265
|
-
tv3 = Fp.add(tv2, Fp.ONE); // 5. tv3 = tv2 + 1
|
|
1266
|
-
tv3 = Fp.mul(tv3, B); // 6. tv3 = B * tv3
|
|
1267
|
-
tv4 = Fp.cmov(Z, Fp.neg(tv2), !Fp.eql(tv2, Fp.ZERO)); // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
|
|
1268
|
-
tv4 = Fp.mul(tv4, A); // 8. tv4 = A * tv4
|
|
1269
|
-
tv2 = Fp.sqr(tv3); // 9. tv2 = tv3^2
|
|
1270
|
-
tv6 = Fp.sqr(tv4); // 10. tv6 = tv4^2
|
|
1271
|
-
tv5 = Fp.mul(tv6, A); // 11. tv5 = A * tv6
|
|
1272
|
-
tv2 = Fp.add(tv2, tv5); // 12. tv2 = tv2 + tv5
|
|
1273
|
-
tv2 = Fp.mul(tv2, tv3); // 13. tv2 = tv2 * tv3
|
|
1274
|
-
tv6 = Fp.mul(tv6, tv4); // 14. tv6 = tv6 * tv4
|
|
1275
|
-
tv5 = Fp.mul(tv6, B); // 15. tv5 = B * tv6
|
|
1276
|
-
tv2 = Fp.add(tv2, tv5); // 16. tv2 = tv2 + tv5
|
|
1277
|
-
x = Fp.mul(tv1, tv3); // 17. x = tv1 * tv3
|
|
1278
|
-
const { isValid, value } = sqrtRatio(tv2, tv6); // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6)
|
|
1279
|
-
y = Fp.mul(tv1, u); // 19. y = tv1 * u -> Z * u^3 * y1
|
|
1280
|
-
y = Fp.mul(y, value); // 20. y = y * y1
|
|
1281
|
-
x = Fp.cmov(x, tv3, isValid); // 21. x = CMOV(x, tv3, is_gx1_square)
|
|
1282
|
-
y = Fp.cmov(y, value, isValid); // 22. y = CMOV(y, y1, is_gx1_square)
|
|
1283
|
-
const e1 = Fp.isOdd(u) === Fp.isOdd(y); // 23. e1 = sgn0(u) == sgn0(y)
|
|
1284
|
-
y = Fp.cmov(Fp.neg(y), y, e1); // 24. y = CMOV(-y, y, e1)
|
|
1285
|
-
const tv4_inv = (0, modular_ts_1.FpInvertBatch)(Fp, [tv4], true)[0];
|
|
1286
|
-
x = Fp.mul(x, tv4_inv); // 25. x = x / tv4
|
|
1287
|
-
return { x, y };
|
|
1288
|
-
};
|
|
1289
|
-
}
|
|
1290
1369
|
//# sourceMappingURL=weierstrass.js.map
|