@noble/curves 0.5.1 → 0.6.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 +49 -8
- package/lib/_shortw_utils.d.ts +11 -26
- package/lib/abstract/bls.d.ts +51 -35
- package/lib/abstract/bls.js +77 -139
- package/lib/abstract/{group.d.ts → curve.d.ts} +31 -1
- package/lib/abstract/{group.js → curve.js} +39 -2
- package/lib/abstract/edwards.d.ts +30 -81
- package/lib/abstract/edwards.js +225 -420
- package/lib/abstract/hash-to-curve.d.ts +25 -6
- package/lib/abstract/hash-to-curve.js +40 -12
- package/lib/abstract/modular.d.ts +20 -7
- package/lib/abstract/modular.js +80 -51
- package/lib/abstract/montgomery.js +3 -4
- package/lib/abstract/poseidon.d.ts +29 -0
- package/lib/abstract/poseidon.js +115 -0
- package/lib/abstract/utils.d.ts +5 -34
- package/lib/abstract/utils.js +23 -63
- package/lib/abstract/weierstrass.d.ts +56 -79
- package/lib/abstract/weierstrass.js +509 -641
- package/lib/bls12-381.d.ts +1 -0
- package/lib/bls12-381.js +75 -65
- package/lib/bn.js +1 -1
- package/lib/ed25519.d.ts +7 -5
- package/lib/ed25519.js +87 -84
- package/lib/ed448.d.ts +3 -0
- package/lib/ed448.js +88 -84
- package/lib/esm/abstract/bls.js +77 -139
- package/lib/esm/abstract/{group.js → curve.js} +37 -1
- package/lib/esm/abstract/edwards.js +223 -418
- package/lib/esm/abstract/hash-to-curve.js +38 -11
- package/lib/esm/abstract/modular.js +77 -50
- package/lib/esm/abstract/montgomery.js +4 -7
- package/lib/esm/abstract/poseidon.js +109 -0
- package/lib/esm/abstract/utils.js +21 -59
- package/lib/esm/abstract/weierstrass.js +508 -640
- package/lib/esm/bls12-381.js +86 -76
- package/lib/esm/bn.js +1 -1
- package/lib/esm/ed25519.js +85 -83
- package/lib/esm/ed448.js +86 -83
- package/lib/esm/jubjub.js +6 -5
- package/lib/esm/p256.js +11 -9
- package/lib/esm/p384.js +11 -9
- package/lib/esm/p521.js +13 -12
- package/lib/esm/secp256k1.js +118 -157
- package/lib/esm/stark.js +104 -39
- package/lib/jubjub.d.ts +3 -2
- package/lib/jubjub.js +6 -5
- package/lib/p192.d.ts +22 -52
- package/lib/p224.d.ts +22 -52
- package/lib/p256.d.ts +25 -52
- package/lib/p256.js +13 -10
- package/lib/p384.d.ts +25 -52
- package/lib/p384.js +13 -10
- package/lib/p521.d.ts +25 -52
- package/lib/p521.js +15 -13
- package/lib/secp256k1.d.ts +26 -42
- package/lib/secp256k1.js +118 -157
- package/lib/stark.d.ts +36 -21
- package/lib/stark.js +107 -39
- package/package.json +14 -9
package/lib/abstract/edwards.js
CHANGED
|
@@ -1,138 +1,144 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
3
|
-
// Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
|
|
4
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
3
|
exports.twistedEdwards = void 0;
|
|
6
|
-
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// 4. Point decompression code is different too (unexpected), now using generalized formula
|
|
12
|
-
// 5. Domain function was no-op for ed25519, but adds some data even with empty context for ed448
|
|
13
|
-
const mod = require("./modular.js");
|
|
14
|
-
const utils_js_1 = require("./utils.js"); // TODO: import * as u from './utils.js'?
|
|
15
|
-
const group_js_1 = require("./group.js");
|
|
16
|
-
const hash_to_curve_js_1 = require("./hash-to-curve.js");
|
|
4
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
5
|
+
// Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
|
|
6
|
+
const modular_js_1 = require("./modular.js");
|
|
7
|
+
const utils_js_1 = require("./utils.js");
|
|
8
|
+
const curve_js_1 = require("./curve.js");
|
|
17
9
|
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
|
|
18
10
|
const _0n = BigInt(0);
|
|
19
11
|
const _1n = BigInt(1);
|
|
20
12
|
const _2n = BigInt(2);
|
|
21
13
|
const _8n = BigInt(8);
|
|
22
|
-
// Should be separate from overrides, since overrides can use information about curve (for example nBits)
|
|
23
14
|
function validateOpts(curve) {
|
|
24
|
-
const opts = (0,
|
|
25
|
-
if (typeof opts.hash !== 'function'
|
|
15
|
+
const opts = (0, curve_js_1.validateAbsOpts)(curve);
|
|
16
|
+
if (typeof opts.hash !== 'function')
|
|
26
17
|
throw new Error('Invalid hash function');
|
|
27
18
|
for (const i of ['a', 'd']) {
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
const val = opts[i];
|
|
20
|
+
if (typeof val !== 'bigint')
|
|
21
|
+
throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
|
|
30
22
|
}
|
|
31
23
|
for (const fn of ['randomBytes']) {
|
|
32
24
|
if (typeof opts[fn] !== 'function')
|
|
33
25
|
throw new Error(`Invalid ${fn} function`);
|
|
34
26
|
}
|
|
35
|
-
for (const fn of [
|
|
36
|
-
'adjustScalarBytes',
|
|
37
|
-
'domain',
|
|
38
|
-
'uvRatio',
|
|
39
|
-
'mapToCurve',
|
|
40
|
-
'clearCofactor',
|
|
41
|
-
]) {
|
|
27
|
+
for (const fn of ['adjustScalarBytes', 'domain', 'uvRatio', 'mapToCurve']) {
|
|
42
28
|
if (opts[fn] === undefined)
|
|
43
29
|
continue; // Optional
|
|
44
30
|
if (typeof opts[fn] !== 'function')
|
|
45
31
|
throw new Error(`Invalid ${fn} function`);
|
|
46
32
|
}
|
|
47
|
-
if (opts.htfDefaults !== undefined)
|
|
48
|
-
(0, hash_to_curve_js_1.validateHTFOpts)(opts.htfDefaults);
|
|
49
33
|
// Set defaults
|
|
50
34
|
return Object.freeze({ ...opts });
|
|
51
35
|
}
|
|
52
|
-
//
|
|
36
|
+
// It is not generic twisted curve for now, but ed25519/ed448 generic implementation
|
|
53
37
|
function twistedEdwards(curveDef) {
|
|
54
38
|
const CURVE = validateOpts(curveDef);
|
|
55
|
-
const Fp = CURVE
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
if (fieldLen > 2048)
|
|
59
|
-
throw new Error('Field lengths over 2048 are not supported');
|
|
60
|
-
const groupLen = CURVE.nByteLength;
|
|
61
|
-
// (2n ** 256n).toString(16);
|
|
62
|
-
const maxGroupElement = _2n ** BigInt(groupLen * 8); // previous POW_2_256
|
|
63
|
-
// Function overrides
|
|
64
|
-
const { randomBytes } = CURVE;
|
|
65
|
-
const modP = Fp.create;
|
|
39
|
+
const { Fp, n: CURVE_ORDER, preHash, hash: cHash, randomBytes, nByteLength, h: cofactor } = CURVE;
|
|
40
|
+
const MASK = _2n ** BigInt(nByteLength * 8);
|
|
41
|
+
const modP = Fp.create; // Function overrides
|
|
66
42
|
// sqrt(u/v)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
43
|
+
const uvRatio = CURVE.uvRatio ||
|
|
44
|
+
((u, v) => {
|
|
45
|
+
try {
|
|
46
|
+
return { isValid: true, value: Fp.sqrt(u * Fp.inv(v)) };
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
return { isValid: false, value: _0n };
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
const adjustScalarBytes = CURVE.adjustScalarBytes || ((bytes) => bytes); // NOOP
|
|
53
|
+
const domain = CURVE.domain ||
|
|
54
|
+
((data, ctx, phflag) => {
|
|
55
|
+
if (ctx.length || phflag)
|
|
56
|
+
throw new Error('Contexts/pre-hash are not supported');
|
|
57
|
+
return data;
|
|
58
|
+
}); // NOOP
|
|
59
|
+
const inBig = (n) => typeof n === 'bigint' && 0n < n; // n in [1..]
|
|
60
|
+
const inRange = (n, max) => inBig(n) && inBig(max) && n < max; // n in [1..max-1]
|
|
61
|
+
const in0MaskRange = (n) => n === _0n || inRange(n, MASK); // n in [0..MASK-1]
|
|
62
|
+
function assertInRange(n, max) {
|
|
63
|
+
// n in [1..max-1]
|
|
64
|
+
if (inRange(n, max))
|
|
65
|
+
return n;
|
|
66
|
+
throw new Error(`Expected valid scalar < ${max}, got ${typeof n} ${n}`);
|
|
75
67
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
function _domain(data, ctx, phflag) {
|
|
80
|
-
if (ctx.length || phflag)
|
|
81
|
-
throw new Error('Contexts/pre-hash are not supported');
|
|
82
|
-
return data;
|
|
68
|
+
function assertGE0(n) {
|
|
69
|
+
// n in [0..CURVE_ORDER-1]
|
|
70
|
+
return n === _0n ? n : assertInRange(n, CURVE_ORDER); // GE = prime subgroup, not full group
|
|
83
71
|
}
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
this.
|
|
94
|
-
this.
|
|
95
|
-
this.
|
|
72
|
+
const pointPrecomputes = new Map();
|
|
73
|
+
function isPoint(other) {
|
|
74
|
+
if (!(other instanceof Point))
|
|
75
|
+
throw new Error('ExtendedPoint expected');
|
|
76
|
+
}
|
|
77
|
+
// Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy).
|
|
78
|
+
// https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates
|
|
79
|
+
class Point {
|
|
80
|
+
constructor(ex, ey, ez, et) {
|
|
81
|
+
this.ex = ex;
|
|
82
|
+
this.ey = ey;
|
|
83
|
+
this.ez = ez;
|
|
84
|
+
this.et = et;
|
|
85
|
+
if (!in0MaskRange(ex))
|
|
86
|
+
throw new Error('x required');
|
|
87
|
+
if (!in0MaskRange(ey))
|
|
88
|
+
throw new Error('y required');
|
|
89
|
+
if (!in0MaskRange(ez))
|
|
90
|
+
throw new Error('z required');
|
|
91
|
+
if (!in0MaskRange(et))
|
|
92
|
+
throw new Error('t required');
|
|
93
|
+
}
|
|
94
|
+
get x() {
|
|
95
|
+
return this.toAffine().x;
|
|
96
|
+
}
|
|
97
|
+
get y() {
|
|
98
|
+
return this.toAffine().y;
|
|
96
99
|
}
|
|
97
100
|
static fromAffine(p) {
|
|
98
|
-
if (
|
|
99
|
-
throw new
|
|
100
|
-
}
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
return new
|
|
104
|
-
}
|
|
105
|
-
// Takes a bunch of Jacobian Points but executes only one
|
|
106
|
-
// invert on all of them. invert is very slow operation,
|
|
107
|
-
// so this improves performance massively.
|
|
108
|
-
static toAffineBatch(points) {
|
|
109
|
-
const toInv = Fp.invertBatch(points.map((p) => p.z));
|
|
110
|
-
return points.map((p, i) => p.toAffine(toInv[i]));
|
|
101
|
+
if (p instanceof Point)
|
|
102
|
+
throw new Error('extended point not allowed');
|
|
103
|
+
const { x, y } = p || {};
|
|
104
|
+
if (!in0MaskRange(x) || !in0MaskRange(y))
|
|
105
|
+
throw new Error('invalid affine point');
|
|
106
|
+
return new Point(x, y, _1n, modP(x * y));
|
|
111
107
|
}
|
|
112
108
|
static normalizeZ(points) {
|
|
113
|
-
|
|
109
|
+
const toInv = Fp.invertBatch(points.map((p) => p.ez));
|
|
110
|
+
return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
|
|
114
111
|
}
|
|
112
|
+
// "Private method", don't use it directly
|
|
113
|
+
_setWindowSize(windowSize) {
|
|
114
|
+
this._WINDOW_SIZE = windowSize;
|
|
115
|
+
pointPrecomputes.delete(this);
|
|
116
|
+
}
|
|
117
|
+
assertValidity() { }
|
|
115
118
|
// Compare one point to another.
|
|
116
119
|
equals(other) {
|
|
117
|
-
|
|
118
|
-
const {
|
|
119
|
-
const {
|
|
120
|
+
isPoint(other);
|
|
121
|
+
const { ex: X1, ey: Y1, ez: Z1 } = this;
|
|
122
|
+
const { ex: X2, ey: Y2, ez: Z2 } = other;
|
|
120
123
|
const X1Z2 = modP(X1 * Z2);
|
|
121
124
|
const X2Z1 = modP(X2 * Z1);
|
|
122
125
|
const Y1Z2 = modP(Y1 * Z2);
|
|
123
126
|
const Y2Z1 = modP(Y2 * Z1);
|
|
124
127
|
return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;
|
|
125
128
|
}
|
|
126
|
-
|
|
129
|
+
is0() {
|
|
130
|
+
return this.equals(Point.ZERO);
|
|
131
|
+
}
|
|
127
132
|
negate() {
|
|
128
|
-
|
|
133
|
+
// Flips point sign to a negative one (-x, y in affine coords)
|
|
134
|
+
return new Point(modP(-this.ex), this.ey, this.ez, modP(-this.et));
|
|
129
135
|
}
|
|
130
136
|
// Fast algo for doubling Extended Point.
|
|
131
137
|
// https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd
|
|
132
138
|
// Cost: 4M + 4S + 1*a + 6add + 1*2.
|
|
133
139
|
double() {
|
|
134
140
|
const { a } = CURVE;
|
|
135
|
-
const {
|
|
141
|
+
const { ex: X1, ey: Y1, ez: Z1 } = this;
|
|
136
142
|
const A = modP(X1 * X1); // A = X12
|
|
137
143
|
const B = modP(Y1 * Y1); // B = Y12
|
|
138
144
|
const C = modP(_2n * modP(Z1 * Z1)); // C = 2*Z12
|
|
@@ -146,16 +152,16 @@ function twistedEdwards(curveDef) {
|
|
|
146
152
|
const Y3 = modP(G * H); // Y3 = G*H
|
|
147
153
|
const T3 = modP(E * H); // T3 = E*H
|
|
148
154
|
const Z3 = modP(F * G); // Z3 = F*G
|
|
149
|
-
return new
|
|
155
|
+
return new Point(X3, Y3, Z3, T3);
|
|
150
156
|
}
|
|
151
157
|
// Fast algo for adding 2 Extended Points.
|
|
152
158
|
// https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-add-2008-hwcd
|
|
153
159
|
// Cost: 9M + 1*a + 1*d + 7add.
|
|
154
160
|
add(other) {
|
|
155
|
-
|
|
161
|
+
isPoint(other);
|
|
156
162
|
const { a, d } = CURVE;
|
|
157
|
-
const {
|
|
158
|
-
const {
|
|
163
|
+
const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this;
|
|
164
|
+
const { ex: X2, ey: Y2, ez: Z2, et: T2 } = other;
|
|
159
165
|
// Faster algo for adding 2 Extended Points when curve's a=-1.
|
|
160
166
|
// http://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-4
|
|
161
167
|
// Cost: 8M + 8add + 2*2.
|
|
@@ -175,7 +181,7 @@ function twistedEdwards(curveDef) {
|
|
|
175
181
|
const Y3 = modP(G * H);
|
|
176
182
|
const T3 = modP(E * H);
|
|
177
183
|
const Z3 = modP(F * G);
|
|
178
|
-
return new
|
|
184
|
+
return new Point(X3, Y3, Z3, T3);
|
|
179
185
|
}
|
|
180
186
|
const A = modP(X1 * X2); // A = X1*X2
|
|
181
187
|
const B = modP(Y1 * Y2); // B = Y1*Y2
|
|
@@ -189,386 +195,188 @@ function twistedEdwards(curveDef) {
|
|
|
189
195
|
const Y3 = modP(G * H); // Y3 = G*H
|
|
190
196
|
const T3 = modP(E * H); // T3 = E*H
|
|
191
197
|
const Z3 = modP(F * G); // Z3 = F*G
|
|
192
|
-
return new
|
|
198
|
+
return new Point(X3, Y3, Z3, T3);
|
|
193
199
|
}
|
|
194
200
|
subtract(other) {
|
|
195
201
|
return this.add(other.negate());
|
|
196
202
|
}
|
|
197
|
-
wNAF(n
|
|
198
|
-
|
|
199
|
-
affinePoint = Point.BASE;
|
|
200
|
-
const W = (affinePoint && affinePoint._WINDOW_SIZE) || 1;
|
|
201
|
-
let precomputes = affinePoint && pointPrecomputes.get(affinePoint);
|
|
202
|
-
if (!precomputes) {
|
|
203
|
-
precomputes = wnaf.precomputeWindow(this, W);
|
|
204
|
-
if (affinePoint && W !== 1) {
|
|
205
|
-
precomputes = ExtendedPoint.normalizeZ(precomputes);
|
|
206
|
-
pointPrecomputes.set(affinePoint, precomputes);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
const { p, f } = wnaf.wNAF(W, precomputes, n);
|
|
210
|
-
return ExtendedPoint.normalizeZ([p, f])[0];
|
|
203
|
+
wNAF(n) {
|
|
204
|
+
return wnaf.wNAFCached(this, pointPrecomputes, n, Point.normalizeZ);
|
|
211
205
|
}
|
|
212
|
-
// Constant
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
return this.wNAF(normalizeScalar(scalar, CURVE_ORDER), affinePoint);
|
|
206
|
+
// Constant-time multiplication.
|
|
207
|
+
multiply(scalar) {
|
|
208
|
+
const { p, f } = this.wNAF(assertInRange(scalar, CURVE_ORDER));
|
|
209
|
+
return Point.normalizeZ([p, f])[0];
|
|
217
210
|
}
|
|
218
211
|
// Non-constant-time multiplication. Uses double-and-add algorithm.
|
|
219
212
|
// It's faster, but should only be used when you don't care about
|
|
220
213
|
// an exposed private key e.g. sig verification.
|
|
221
|
-
// Allows scalar bigger than curve order, but less than 2^256
|
|
222
214
|
multiplyUnsafe(scalar) {
|
|
223
|
-
let n =
|
|
224
|
-
const G = ExtendedPoint.BASE;
|
|
225
|
-
const P0 = ExtendedPoint.ZERO;
|
|
215
|
+
let n = assertGE0(scalar);
|
|
226
216
|
if (n === _0n)
|
|
227
|
-
return
|
|
228
|
-
if (this.equals(
|
|
217
|
+
return I;
|
|
218
|
+
if (this.equals(I) || n === _1n)
|
|
229
219
|
return this;
|
|
230
220
|
if (this.equals(G))
|
|
231
|
-
return this.wNAF(n);
|
|
221
|
+
return this.wNAF(n).p;
|
|
232
222
|
return wnaf.unsafeLadder(this, n);
|
|
233
223
|
}
|
|
224
|
+
// Checks if point is of small order.
|
|
225
|
+
// If you add something to small order point, you will have "dirty"
|
|
226
|
+
// point with torsion component.
|
|
234
227
|
// Multiplies point by cofactor and checks if the result is 0.
|
|
235
228
|
isSmallOrder() {
|
|
236
|
-
return this.multiplyUnsafe(
|
|
229
|
+
return this.multiplyUnsafe(cofactor).is0();
|
|
237
230
|
}
|
|
238
|
-
// Multiplies point by
|
|
231
|
+
// Multiplies point by curve order and checks if the result is 0.
|
|
232
|
+
// Returns `false` is the point is dirty.
|
|
239
233
|
isTorsionFree() {
|
|
240
|
-
return
|
|
234
|
+
return wnaf.unsafeLadder(this, CURVE_ORDER).is0();
|
|
241
235
|
}
|
|
242
236
|
// Converts Extended point to default (x, y) coordinates.
|
|
243
237
|
// Can accept precomputed Z^-1 - for example, from invertBatch.
|
|
244
|
-
toAffine(
|
|
245
|
-
const { x, y, z } = this;
|
|
246
|
-
const is0 = this.
|
|
247
|
-
if (
|
|
248
|
-
|
|
249
|
-
const ax = modP(x *
|
|
250
|
-
const ay = modP(y *
|
|
251
|
-
const zz = modP(z *
|
|
238
|
+
toAffine(iz) {
|
|
239
|
+
const { ex: x, ey: y, ez: z } = this;
|
|
240
|
+
const is0 = this.is0();
|
|
241
|
+
if (iz == null)
|
|
242
|
+
iz = is0 ? _8n : Fp.inv(z); // 8 was chosen arbitrarily
|
|
243
|
+
const ax = modP(x * iz);
|
|
244
|
+
const ay = modP(y * iz);
|
|
245
|
+
const zz = modP(z * iz);
|
|
252
246
|
if (is0)
|
|
253
|
-
return
|
|
247
|
+
return { x: _0n, y: _1n };
|
|
254
248
|
if (zz !== _1n)
|
|
255
249
|
throw new Error('invZ was invalid');
|
|
256
|
-
return
|
|
250
|
+
return { x: ax, y: ay };
|
|
257
251
|
}
|
|
258
252
|
clearCofactor() {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if (CURVE.clearCofactor)
|
|
264
|
-
return CURVE.clearCofactor(ExtendedPoint, this);
|
|
265
|
-
return this.multiplyUnsafe(CURVE.h);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
ExtendedPoint.BASE = new ExtendedPoint(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
|
|
269
|
-
ExtendedPoint.ZERO = new ExtendedPoint(_0n, _1n, _1n, _0n);
|
|
270
|
-
const wnaf = (0, group_js_1.wNAF)(ExtendedPoint, groupLen * 8);
|
|
271
|
-
function assertExtPoint(other) {
|
|
272
|
-
if (!(other instanceof ExtendedPoint))
|
|
273
|
-
throw new TypeError('ExtendedPoint expected');
|
|
274
|
-
}
|
|
275
|
-
// Stores precomputed values for points.
|
|
276
|
-
const pointPrecomputes = new WeakMap();
|
|
277
|
-
/**
|
|
278
|
-
* Default Point works in affine coordinates: (x, y)
|
|
279
|
-
*/
|
|
280
|
-
class Point {
|
|
281
|
-
constructor(x, y) {
|
|
282
|
-
this.x = x;
|
|
283
|
-
this.y = y;
|
|
284
|
-
}
|
|
285
|
-
// "Private method", don't use it directly.
|
|
286
|
-
_setWindowSize(windowSize) {
|
|
287
|
-
this._WINDOW_SIZE = windowSize;
|
|
288
|
-
pointPrecomputes.delete(this);
|
|
253
|
+
const { h: cofactor } = CURVE;
|
|
254
|
+
if (cofactor === _1n)
|
|
255
|
+
return this;
|
|
256
|
+
return this.multiplyUnsafe(cofactor);
|
|
289
257
|
}
|
|
290
258
|
// Converts hash string or Uint8Array to Point.
|
|
291
259
|
// Uses algo from RFC8032 5.1.3.
|
|
292
260
|
static fromHex(hex, strict = true) {
|
|
293
261
|
const { d, a } = CURVE;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
// resulting value is >= p, decoding fails.
|
|
300
|
-
const normed = hex.slice();
|
|
301
|
-
const lastByte = hex[fieldLen - 1];
|
|
302
|
-
normed[fieldLen - 1] = lastByte & ~0x80;
|
|
262
|
+
const len = Fp.BYTES;
|
|
263
|
+
hex = (0, utils_js_1.ensureBytes)(hex, len); // copy hex to a new array
|
|
264
|
+
const normed = hex.slice(); // copy again, we'll manipulate it
|
|
265
|
+
const lastByte = hex[len - 1]; // select last byte
|
|
266
|
+
normed[len - 1] = lastByte & ~0x80; // clear last bit
|
|
303
267
|
const y = (0, utils_js_1.bytesToNumberLE)(normed);
|
|
304
|
-
if (
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
//
|
|
315
|
-
//
|
|
316
|
-
//
|
|
317
|
-
const
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
let { isValid, value: x } = uvRatio(u, v);
|
|
268
|
+
if (y === _0n) {
|
|
269
|
+
// y=0 is allowed
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
// RFC8032 prohibits >= p, but ZIP215 doesn't
|
|
273
|
+
if (strict)
|
|
274
|
+
assertInRange(y, Fp.ORDER); // strict=true [1..P-1] (2^255-19-1 for ed25519)
|
|
275
|
+
else
|
|
276
|
+
assertInRange(y, MASK); // strict=false [1..MASK-1] (2^256-1 for ed25519)
|
|
277
|
+
}
|
|
278
|
+
// Ed25519: x² = (y²-1)/(dy²+1) mod p. Ed448: x² = (y²-1)/(dy²-1) mod p. Generic case:
|
|
279
|
+
// ax²+y²=1+dx²y² => y²-1=dx²y²-ax² => y²-1=x²(dy²-a) => x²=(y²-1)/(dy²-a)
|
|
280
|
+
const y2 = modP(y * y); // denominator is always non-0 mod p.
|
|
281
|
+
const u = modP(y2 - _1n); // u = y² - 1
|
|
282
|
+
const v = modP(d * y2 - a); // v = d y² + 1.
|
|
283
|
+
let { isValid, value: x } = uvRatio(u, v); // √(u/v)
|
|
321
284
|
if (!isValid)
|
|
322
285
|
throw new Error('Point.fromHex: invalid y coordinate');
|
|
323
|
-
//
|
|
324
|
-
|
|
325
|
-
// 2, set x <-- p - x. Return the decoded point (x,y).
|
|
326
|
-
const isXOdd = (x & _1n) === _1n;
|
|
327
|
-
const isLastByteOdd = (lastByte & 0x80) !== 0;
|
|
286
|
+
const isXOdd = (x & _1n) === _1n; // There are 2 square roots. Use x_0 bit to select proper
|
|
287
|
+
const isLastByteOdd = (lastByte & 0x80) !== 0; // if x=0 and x_0 = 1, fail
|
|
328
288
|
if (isLastByteOdd !== isXOdd)
|
|
329
|
-
x = modP(-x);
|
|
330
|
-
return
|
|
289
|
+
x = modP(-x); // if x_0 != x mod 2, set x = p-x
|
|
290
|
+
return Point.fromAffine({ x, y });
|
|
331
291
|
}
|
|
332
|
-
static fromPrivateKey(
|
|
333
|
-
return getExtendedPublicKey(
|
|
292
|
+
static fromPrivateKey(privKey) {
|
|
293
|
+
return getExtendedPublicKey(privKey).point;
|
|
334
294
|
}
|
|
335
|
-
// There can always be only two x values (x, -x) for any y
|
|
336
|
-
// When compressing point, it's enough to only store its y coordinate
|
|
337
|
-
// and use the last byte to encode sign of x.
|
|
338
295
|
toRawBytes() {
|
|
339
|
-
const
|
|
340
|
-
bytes
|
|
341
|
-
|
|
296
|
+
const { x, y } = this.toAffine();
|
|
297
|
+
const bytes = (0, utils_js_1.numberToBytesLE)(y, Fp.BYTES); // each y has 2 x values (x, -y)
|
|
298
|
+
bytes[bytes.length - 1] |= x & _1n ? 0x80 : 0; // when compressing, it's enough to store y
|
|
299
|
+
return bytes; // and use the last byte to encode sign of x
|
|
342
300
|
}
|
|
343
|
-
// Same as toRawBytes, but returns string.
|
|
344
301
|
toHex() {
|
|
345
|
-
return (0, utils_js_1.bytesToHex)(this.toRawBytes());
|
|
346
|
-
}
|
|
347
|
-
isTorsionFree() {
|
|
348
|
-
return ExtendedPoint.fromAffine(this).isTorsionFree();
|
|
349
|
-
}
|
|
350
|
-
equals(other) {
|
|
351
|
-
if (!(other instanceof Point))
|
|
352
|
-
throw new TypeError('Point#equals: expected Point');
|
|
353
|
-
return this.x === other.x && this.y === other.y;
|
|
354
|
-
}
|
|
355
|
-
negate() {
|
|
356
|
-
return new Point(modP(-this.x), this.y);
|
|
357
|
-
}
|
|
358
|
-
double() {
|
|
359
|
-
return ExtendedPoint.fromAffine(this).double().toAffine();
|
|
360
|
-
}
|
|
361
|
-
add(other) {
|
|
362
|
-
return ExtendedPoint.fromAffine(this).add(ExtendedPoint.fromAffine(other)).toAffine();
|
|
363
|
-
}
|
|
364
|
-
subtract(other) {
|
|
365
|
-
return this.add(other.negate());
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
|
-
* Constant time multiplication.
|
|
369
|
-
* @param scalar Big-Endian number
|
|
370
|
-
* @returns new point
|
|
371
|
-
*/
|
|
372
|
-
multiply(scalar) {
|
|
373
|
-
return ExtendedPoint.fromAffine(this).multiply(scalar, this).toAffine();
|
|
374
|
-
}
|
|
375
|
-
clearCofactor() {
|
|
376
|
-
return ExtendedPoint.fromAffine(this).clearCofactor().toAffine();
|
|
377
|
-
}
|
|
378
|
-
// Encodes byte string to elliptic curve
|
|
379
|
-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
|
|
380
|
-
static hashToCurve(msg, options) {
|
|
381
|
-
if (!CURVE.mapToCurve)
|
|
382
|
-
throw new Error('No mapToCurve defined for curve');
|
|
383
|
-
msg = (0, utils_js_1.ensureBytes)(msg);
|
|
384
|
-
const u = (0, hash_to_curve_js_1.hash_to_field)(msg, 2, { ...CURVE.htfDefaults, ...options });
|
|
385
|
-
const { x: x0, y: y0 } = CURVE.mapToCurve(u[0]);
|
|
386
|
-
const { x: x1, y: y1 } = CURVE.mapToCurve(u[1]);
|
|
387
|
-
const p = new Point(x0, y0).add(new Point(x1, y1)).clearCofactor();
|
|
388
|
-
return p;
|
|
389
|
-
}
|
|
390
|
-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
|
|
391
|
-
static encodeToCurve(msg, options) {
|
|
392
|
-
if (!CURVE.mapToCurve)
|
|
393
|
-
throw new Error('No mapToCurve defined for curve');
|
|
394
|
-
msg = (0, utils_js_1.ensureBytes)(msg);
|
|
395
|
-
const u = (0, hash_to_curve_js_1.hash_to_field)(msg, 1, { ...CURVE.htfDefaults, ...options });
|
|
396
|
-
const { x, y } = CURVE.mapToCurve(u[0]);
|
|
397
|
-
return new Point(x, y).clearCofactor();
|
|
302
|
+
return (0, utils_js_1.bytesToHex)(this.toRawBytes()); // Same as toRawBytes, but returns string.
|
|
398
303
|
}
|
|
399
304
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* EDDSA signature.
|
|
408
|
-
*/
|
|
409
|
-
class Signature {
|
|
410
|
-
constructor(r, s) {
|
|
411
|
-
this.r = r;
|
|
412
|
-
this.s = s;
|
|
413
|
-
this.assertValidity();
|
|
414
|
-
}
|
|
415
|
-
static fromHex(hex) {
|
|
416
|
-
const bytes = (0, utils_js_1.ensureBytes)(hex, 2 * fieldLen);
|
|
417
|
-
const r = Point.fromHex(bytes.slice(0, fieldLen), false);
|
|
418
|
-
const s = (0, utils_js_1.bytesToNumberLE)(bytes.slice(fieldLen, 2 * fieldLen));
|
|
419
|
-
return new Signature(r, s);
|
|
420
|
-
}
|
|
421
|
-
assertValidity() {
|
|
422
|
-
const { r, s } = this;
|
|
423
|
-
if (!(r instanceof Point))
|
|
424
|
-
throw new Error('Expected Point instance');
|
|
425
|
-
// 0 <= s < l
|
|
426
|
-
normalizeScalar(s, CURVE_ORDER, false);
|
|
427
|
-
return this;
|
|
428
|
-
}
|
|
429
|
-
toRawBytes() {
|
|
430
|
-
return (0, utils_js_1.concatBytes)(this.r.toRawBytes(), (0, utils_js_1.numberToBytesLE)(this.s, fieldLen));
|
|
431
|
-
}
|
|
432
|
-
toHex() {
|
|
433
|
-
return (0, utils_js_1.bytesToHex)(this.toRawBytes());
|
|
434
|
-
}
|
|
305
|
+
Point.BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
|
|
306
|
+
Point.ZERO = new Point(_0n, _1n, _1n, _0n); // 0, 1, 1, 0
|
|
307
|
+
const { BASE: G, ZERO: I } = Point;
|
|
308
|
+
const wnaf = (0, curve_js_1.wNAF)(Point, nByteLength * 8);
|
|
309
|
+
function modN(a) {
|
|
310
|
+
return (0, modular_js_1.mod)(a, CURVE_ORDER);
|
|
435
311
|
}
|
|
436
312
|
// Little-endian SHA512 with modulo n
|
|
437
|
-
function
|
|
438
|
-
return
|
|
439
|
-
}
|
|
440
|
-
/**
|
|
441
|
-
* Checks for num to be in range:
|
|
442
|
-
* For strict == true: `0 < num < max`.
|
|
443
|
-
* For strict == false: `0 <= num < max`.
|
|
444
|
-
* Converts non-float safe numbers to bigints.
|
|
445
|
-
*/
|
|
446
|
-
function normalizeScalar(num, max, strict = true) {
|
|
447
|
-
if (!max)
|
|
448
|
-
throw new TypeError('Specify max value');
|
|
449
|
-
if (typeof num === 'number' && Number.isSafeInteger(num))
|
|
450
|
-
num = BigInt(num);
|
|
451
|
-
if (typeof num === 'bigint' && num < max) {
|
|
452
|
-
if (strict) {
|
|
453
|
-
if (_0n < num)
|
|
454
|
-
return num;
|
|
455
|
-
}
|
|
456
|
-
else {
|
|
457
|
-
if (_0n <= num)
|
|
458
|
-
return num;
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
throw new TypeError('Expected valid scalar: 0 < scalar < max');
|
|
462
|
-
}
|
|
463
|
-
function checkPrivateKey(key) {
|
|
464
|
-
// Normalize bigint / number / string to Uint8Array
|
|
465
|
-
key =
|
|
466
|
-
typeof key === 'bigint' || typeof key === 'number'
|
|
467
|
-
? (0, utils_js_1.numberToBytesLE)(normalizeScalar(key, maxGroupElement), groupLen)
|
|
468
|
-
: (0, utils_js_1.ensureBytes)(key);
|
|
469
|
-
if (key.length !== groupLen)
|
|
470
|
-
throw new Error(`Expected ${groupLen} bytes, got ${key.length}`);
|
|
471
|
-
return key;
|
|
313
|
+
function modN_LE(hash) {
|
|
314
|
+
return modN((0, utils_js_1.bytesToNumberLE)(hash));
|
|
472
315
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
// clears 3 bits of it to produce a random field element.
|
|
477
|
-
const head = adjustScalarBytes(hashed.slice(0, groupLen));
|
|
478
|
-
// Second 32 bytes is called key prefix (5.1.6)
|
|
479
|
-
const prefix = hashed.slice(groupLen, 2 * groupLen);
|
|
480
|
-
// The actual private scalar
|
|
481
|
-
const scalar = modlLE(head);
|
|
482
|
-
// Point on Edwards curve aka public key
|
|
483
|
-
const point = Point.BASE.multiply(scalar);
|
|
484
|
-
const pointBytes = point.toRawBytes();
|
|
485
|
-
return { head, prefix, scalar, point, pointBytes };
|
|
316
|
+
function isHex(item, err) {
|
|
317
|
+
if (typeof item !== 'string' && !(item instanceof Uint8Array))
|
|
318
|
+
throw new Error(`${err} must be hex string or Uint8Array`);
|
|
486
319
|
}
|
|
487
320
|
/** Convenience method that creates public key and other stuff. RFC8032 5.1.5 */
|
|
488
321
|
function getExtendedPublicKey(key) {
|
|
489
|
-
|
|
322
|
+
isHex(key, 'private key');
|
|
323
|
+
const len = nByteLength;
|
|
324
|
+
// Hash private key with curve's hash function to produce uniformingly random input
|
|
325
|
+
// Check byte lengths: ensure(64, h(ensure(32, key)))
|
|
326
|
+
const hashed = (0, utils_js_1.ensureBytes)(cHash((0, utils_js_1.ensureBytes)(key, len)), 2 * len);
|
|
327
|
+
const head = adjustScalarBytes(hashed.slice(0, len)); // clear first half bits, produce FE
|
|
328
|
+
const prefix = hashed.slice(len, 2 * len); // second half is called key prefix (5.1.6)
|
|
329
|
+
const scalar = modN_LE(head); // The actual private scalar
|
|
330
|
+
const point = G.multiply(scalar); // Point on Edwards curve aka public key
|
|
331
|
+
const pointBytes = point.toRawBytes(); // Uint8Array representation
|
|
332
|
+
return { head, prefix, scalar, point, pointBytes };
|
|
490
333
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
* 2. 3 least significant bits of the first byte are cleared
|
|
495
|
-
*/
|
|
496
|
-
function getPublicKey(privateKey) {
|
|
497
|
-
return getExtendedPublicKey(privateKey).pointBytes;
|
|
334
|
+
// Calculates EdDSA pub key. RFC8032 5.1.5. Privkey is hashed. Use first half with 3 bits cleared
|
|
335
|
+
function getPublicKey(privKey) {
|
|
336
|
+
return getExtendedPublicKey(privKey).pointBytes;
|
|
498
337
|
}
|
|
499
|
-
|
|
500
|
-
function hashDomainToScalar(
|
|
501
|
-
|
|
502
|
-
return
|
|
338
|
+
// int('LE', SHA512(dom2(F, C) || msgs)) mod N
|
|
339
|
+
function hashDomainToScalar(context = new Uint8Array(), ...msgs) {
|
|
340
|
+
const msg = (0, utils_js_1.concatBytes)(...msgs);
|
|
341
|
+
return modN_LE(cHash(domain(msg, (0, utils_js_1.ensureBytes)(context), !!preHash)));
|
|
503
342
|
}
|
|
504
343
|
/** Signs message with privateKey. RFC8032 5.1.6 */
|
|
505
|
-
function sign(
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
const
|
|
511
|
-
const
|
|
512
|
-
const
|
|
513
|
-
const
|
|
514
|
-
|
|
344
|
+
function sign(msg, privKey, context) {
|
|
345
|
+
isHex(msg, 'message');
|
|
346
|
+
msg = (0, utils_js_1.ensureBytes)(msg);
|
|
347
|
+
if (preHash)
|
|
348
|
+
msg = preHash(msg); // for ed25519ph etc.
|
|
349
|
+
const { prefix, scalar, pointBytes } = getExtendedPublicKey(privKey);
|
|
350
|
+
const r = hashDomainToScalar(context, prefix, msg); // r = dom2(F, C) || prefix || PH(M)
|
|
351
|
+
const R = G.multiply(r).toRawBytes(); // R = rG
|
|
352
|
+
const k = hashDomainToScalar(context, R, pointBytes, msg); // R || A || PH(M)
|
|
353
|
+
const s = modN(r + k * scalar); // S = (r + k * s) mod L
|
|
354
|
+
assertGE0(s); // 0 <= s < l
|
|
355
|
+
const res = (0, utils_js_1.concatBytes)(R, (0, utils_js_1.numberToBytesLE)(s, Fp.BYTES));
|
|
356
|
+
return (0, utils_js_1.ensureBytes)(res, nByteLength * 2); // 64-byte signature
|
|
515
357
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
// When Point instance is passed, we assume it has already been checked, for performance.
|
|
531
|
-
// If user passes Point/Sig instance, we assume it has been already verified.
|
|
532
|
-
// We don't check its equations for performance. We do check for valid bounds for s though
|
|
533
|
-
// We always check for: a) s bounds. b) hex validity
|
|
534
|
-
if (publicKey instanceof Point) {
|
|
535
|
-
// ignore
|
|
536
|
-
}
|
|
537
|
-
else if (publicKey instanceof Uint8Array || typeof publicKey === 'string') {
|
|
538
|
-
publicKey = Point.fromHex(publicKey, false);
|
|
539
|
-
}
|
|
540
|
-
else {
|
|
541
|
-
throw new Error(`Invalid publicKey: ${publicKey}`);
|
|
542
|
-
}
|
|
543
|
-
if (sig instanceof Signature)
|
|
544
|
-
sig.assertValidity();
|
|
545
|
-
else if (sig instanceof Uint8Array || typeof sig === 'string')
|
|
546
|
-
sig = Signature.fromHex(sig);
|
|
547
|
-
else
|
|
548
|
-
throw new Error(`Wrong signature: ${sig}`);
|
|
549
|
-
const { r, s } = sig;
|
|
550
|
-
const SB = ExtendedPoint.BASE.multiplyUnsafe(s);
|
|
551
|
-
const k = hashDomainToScalar((0, utils_js_1.concatBytes)(r.toRawBytes(), publicKey.toRawBytes(), message), context);
|
|
552
|
-
const kA = ExtendedPoint.fromAffine(publicKey).multiplyUnsafe(k);
|
|
553
|
-
const RkA = ExtendedPoint.fromAffine(r).add(kA);
|
|
358
|
+
function verify(sig, msg, publicKey, context) {
|
|
359
|
+
isHex(sig, 'sig');
|
|
360
|
+
isHex(msg, 'message');
|
|
361
|
+
const len = Fp.BYTES; // Verifies EdDSA signature against message and public key. RFC8032 5.1.7.
|
|
362
|
+
sig = (0, utils_js_1.ensureBytes)(sig, 2 * len); // An extended group equation is checked.
|
|
363
|
+
msg = (0, utils_js_1.ensureBytes)(msg); // ZIP215 compliant, which means not fully RFC8032 compliant.
|
|
364
|
+
if (preHash)
|
|
365
|
+
msg = preHash(msg); // for ed25519ph, etc
|
|
366
|
+
const A = Point.fromHex(publicKey, false); // Check for s bounds, hex validity
|
|
367
|
+
const R = Point.fromHex(sig.slice(0, len), false); // 0 <= R < 2^256: ZIP215 R can be >= P
|
|
368
|
+
const s = (0, utils_js_1.bytesToNumberLE)(sig.slice(len, 2 * len)); // 0 <= s < l
|
|
369
|
+
const SB = G.multiplyUnsafe(s);
|
|
370
|
+
const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
|
|
371
|
+
const RkA = R.add(A.multiplyUnsafe(k));
|
|
554
372
|
// [8][S]B = [8]R + [8][k]A'
|
|
555
|
-
return RkA.subtract(SB).
|
|
373
|
+
return RkA.subtract(SB).clearCofactor().equals(Point.ZERO);
|
|
556
374
|
}
|
|
557
|
-
// Enable precomputes. Slows down first publicKey computation by 20ms.
|
|
558
|
-
Point.BASE._setWindowSize(8);
|
|
375
|
+
G._setWindowSize(8); // Enable precomputes. Slows down first publicKey computation by 20ms.
|
|
559
376
|
const utils = {
|
|
560
377
|
getExtendedPublicKey,
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
/**
|
|
564
|
-
* Not needed for ed25519 private keys. Needed if you use scalars directly (rare).
|
|
565
|
-
*/
|
|
566
|
-
hashToPrivateScalar: (hash) => (0, utils_js_1.hashToPrivateScalar)(hash, CURVE_ORDER, true),
|
|
567
|
-
/**
|
|
568
|
-
* ed25519 private keys are uniform 32-bit strings. We do not need to check for
|
|
569
|
-
* modulo bias like we do in secp256k1 randomPrivateKey()
|
|
570
|
-
*/
|
|
571
|
-
randomPrivateKey: () => randomBytes(fieldLen),
|
|
378
|
+
// ed25519 private keys are uniform 32b. No need to check for modulo bias, like in secp256k1.
|
|
379
|
+
randomPrivateKey: () => randomBytes(Fp.BYTES),
|
|
572
380
|
/**
|
|
573
381
|
* We're doing scalar multiplication (used in getPublicKey etc) with precomputed BASE_POINT
|
|
574
382
|
* values. This slows down first getPublicKey() by milliseconds (see Speed section),
|
|
@@ -576,10 +384,9 @@ function twistedEdwards(curveDef) {
|
|
|
576
384
|
* @param windowSize 2, 4, 8, 16
|
|
577
385
|
*/
|
|
578
386
|
precompute(windowSize = 8, point = Point.BASE) {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
return cached;
|
|
387
|
+
point._setWindowSize(windowSize);
|
|
388
|
+
point.multiply(BigInt(3));
|
|
389
|
+
return point;
|
|
583
390
|
},
|
|
584
391
|
};
|
|
585
392
|
return {
|
|
@@ -587,9 +394,7 @@ function twistedEdwards(curveDef) {
|
|
|
587
394
|
getPublicKey,
|
|
588
395
|
sign,
|
|
589
396
|
verify,
|
|
590
|
-
ExtendedPoint,
|
|
591
|
-
Point,
|
|
592
|
-
Signature,
|
|
397
|
+
ExtendedPoint: Point,
|
|
593
398
|
utils,
|
|
594
399
|
};
|
|
595
400
|
}
|