@noble/curves 1.4.2 → 1.5.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 +135 -123
- package/_shortw_utils.d.ts.map +1 -1
- package/abstract/bls.d.ts +37 -34
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +167 -115
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +2 -1
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +22 -7
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +11 -0
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +79 -75
- package/abstract/edwards.js.map +1 -1
- package/abstract/modular.d.ts +4 -0
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +13 -2
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +4 -9
- package/abstract/montgomery.js.map +1 -1
- package/abstract/tower.d.ts +106 -0
- package/abstract/tower.d.ts.map +1 -0
- package/abstract/tower.js +497 -0
- package/abstract/tower.js.map +1 -0
- package/abstract/utils.d.ts +17 -0
- package/abstract/utils.d.ts.map +1 -1
- package/abstract/utils.js +50 -1
- package/abstract/utils.js.map +1 -1
- package/abstract/weierstrass.d.ts +7 -0
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +88 -72
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts +1 -65
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +48 -575
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +10 -6
- package/bn254.d.ts.map +1 -1
- package/bn254.js +207 -10
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +7 -4
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +3 -0
- package/ed25519.js.map +1 -1
- package/esm/_shortw_utils.d.ts.map +1 -1
- package/esm/abstract/bls.d.ts +37 -34
- package/esm/abstract/bls.d.ts.map +1 -1
- package/esm/abstract/bls.js +168 -116
- package/esm/abstract/bls.js.map +1 -1
- package/esm/abstract/curve.d.ts +2 -1
- package/esm/abstract/curve.d.ts.map +1 -1
- package/esm/abstract/curve.js +22 -7
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.d.ts +11 -0
- package/esm/abstract/edwards.d.ts.map +1 -1
- package/esm/abstract/edwards.js +80 -76
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/modular.d.ts +4 -0
- package/esm/abstract/modular.d.ts.map +1 -1
- package/esm/abstract/modular.js +12 -2
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.d.ts.map +1 -1
- package/esm/abstract/montgomery.js +5 -10
- package/esm/abstract/montgomery.js.map +1 -1
- package/esm/abstract/tower.d.ts +106 -0
- package/esm/abstract/tower.d.ts.map +1 -0
- package/esm/abstract/tower.js +493 -0
- package/esm/abstract/tower.js.map +1 -0
- package/esm/abstract/utils.d.ts +17 -0
- package/esm/abstract/utils.d.ts.map +1 -1
- package/esm/abstract/utils.js +44 -0
- package/esm/abstract/utils.js.map +1 -1
- package/esm/abstract/weierstrass.d.ts +7 -0
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +89 -73
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.d.ts +1 -65
- package/esm/bls12-381.d.ts.map +1 -1
- package/esm/bls12-381.js +50 -577
- package/esm/bls12-381.js.map +1 -1
- package/esm/bn254.d.ts +10 -6
- package/esm/bn254.d.ts.map +1 -1
- package/esm/bn254.js +206 -9
- package/esm/bn254.js.map +1 -1
- package/esm/ed25519.d.ts +7 -4
- package/esm/ed25519.d.ts.map +1 -1
- package/esm/ed25519.js +3 -0
- package/esm/ed25519.js.map +1 -1
- package/esm/p256.d.ts.map +1 -1
- package/esm/p384.d.ts.map +1 -1
- package/esm/p521.d.ts.map +1 -1
- package/esm/secp256k1.d.ts +6 -0
- package/esm/secp256k1.d.ts.map +1 -1
- package/esm/secp256k1.js +17 -13
- package/esm/secp256k1.js.map +1 -1
- package/p256.d.ts.map +1 -1
- package/p384.d.ts.map +1 -1
- package/p521.d.ts.map +1 -1
- package/package.json +2 -1
- package/secp256k1.d.ts +6 -0
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +16 -12
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +222 -168
- package/src/abstract/curve.ts +23 -7
- package/src/abstract/edwards.ts +81 -68
- package/src/abstract/modular.ts +13 -3
- package/src/abstract/montgomery.ts +11 -10
- package/src/abstract/tower.ts +604 -0
- package/src/abstract/utils.ts +49 -0
- package/src/abstract/weierstrass.ts +85 -68
- package/src/bls12-381.ts +53 -707
- package/src/bn254.ts +224 -9
- package/src/ed25519.ts +5 -2
- package/src/secp256k1.ts +24 -12
package/src/abstract/edwards.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { AffinePoint, BasicCurve, Group, GroupConstructor, validateBasic, wNAF } from './curve.js';
|
|
4
4
|
import { mod } from './modular.js';
|
|
5
5
|
import * as ut from './utils.js';
|
|
6
|
-
import { ensureBytes, FHash, Hex } from './utils.js';
|
|
6
|
+
import { ensureBytes, FHash, Hex, memoized, abool } from './utils.js';
|
|
7
7
|
|
|
8
8
|
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
|
9
9
|
// prettier-ignore
|
|
@@ -72,6 +72,10 @@ export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
|
|
|
72
72
|
fromPrivateKey(privateKey: Hex): ExtPointType;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Edwards Curve interface.
|
|
77
|
+
* Main methods: `getPublicKey(priv)`, `sign(msg, priv)`, `verify(sig, msg, pub)`.
|
|
78
|
+
*/
|
|
75
79
|
export type CurveFn = {
|
|
76
80
|
CURVE: ReturnType<typeof validateOpts>;
|
|
77
81
|
getPublicKey: (privateKey: Hex) => Uint8Array;
|
|
@@ -95,7 +99,13 @@ export type CurveFn = {
|
|
|
95
99
|
};
|
|
96
100
|
};
|
|
97
101
|
|
|
98
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Creates Twisted Edwards curve with EdDSA signatures.
|
|
104
|
+
* @example
|
|
105
|
+
* import { Field } from '@noble/curves/abstract/modular';
|
|
106
|
+
* // Before that, define BigInt-s: a, d, p, n, Gx, Gy, h
|
|
107
|
+
* const curve = twistedEdwards({ a, d, Fp: Field(p), n, Gx, Gy, h })
|
|
108
|
+
*/
|
|
99
109
|
export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
100
110
|
const CURVE = validateOpts(curveDef) as ReturnType<typeof validateOpts>;
|
|
101
111
|
const {
|
|
@@ -124,25 +134,53 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
124
134
|
const domain =
|
|
125
135
|
CURVE.domain ||
|
|
126
136
|
((data: Uint8Array, ctx: Uint8Array, phflag: boolean) => {
|
|
137
|
+
abool('phflag', phflag);
|
|
127
138
|
if (ctx.length || phflag) throw new Error('Contexts/pre-hash are not supported');
|
|
128
139
|
return data;
|
|
129
140
|
}); // NOOP
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
// n in [1..max-1]
|
|
135
|
-
if (inRange(n, max)) return n;
|
|
136
|
-
throw new Error(`Expected valid scalar < ${max}, got ${typeof n} ${n}`);
|
|
141
|
+
// 0 <= n < MASK
|
|
142
|
+
// Coordinates larger than Fp.ORDER are allowed for zip215
|
|
143
|
+
function aCoordinate(title: string, n: bigint) {
|
|
144
|
+
ut.aInRange('coordinate ' + title, n, _0n, MASK);
|
|
137
145
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return n === _0n ? n : assertInRange(n, CURVE_ORDER); // GE = prime subgroup, not full group
|
|
141
|
-
}
|
|
142
|
-
const pointPrecomputes = new Map<Point, Point[]>();
|
|
143
|
-
function isPoint(other: unknown) {
|
|
146
|
+
|
|
147
|
+
function assertPoint(other: unknown) {
|
|
144
148
|
if (!(other instanceof Point)) throw new Error('ExtendedPoint expected');
|
|
145
149
|
}
|
|
150
|
+
// Converts Extended point to default (x, y) coordinates.
|
|
151
|
+
// Can accept precomputed Z^-1 - for example, from invertBatch.
|
|
152
|
+
const toAffineMemo = memoized((p: Point, iz?: bigint): AffinePoint<bigint> => {
|
|
153
|
+
const { ex: x, ey: y, ez: z } = p;
|
|
154
|
+
const is0 = p.is0();
|
|
155
|
+
if (iz == null) iz = is0 ? _8n : (Fp.inv(z) as bigint); // 8 was chosen arbitrarily
|
|
156
|
+
const ax = modP(x * iz);
|
|
157
|
+
const ay = modP(y * iz);
|
|
158
|
+
const zz = modP(z * iz);
|
|
159
|
+
if (is0) return { x: _0n, y: _1n };
|
|
160
|
+
if (zz !== _1n) throw new Error('invZ was invalid');
|
|
161
|
+
return { x: ax, y: ay };
|
|
162
|
+
});
|
|
163
|
+
const assertValidMemo = memoized((p: Point) => {
|
|
164
|
+
const { a, d } = CURVE;
|
|
165
|
+
if (p.is0()) throw new Error('bad point: ZERO'); // TODO: optimize, with vars below?
|
|
166
|
+
// Equation in affine coordinates: ax² + y² = 1 + dx²y²
|
|
167
|
+
// Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²
|
|
168
|
+
const { ex: X, ey: Y, ez: Z, et: T } = p;
|
|
169
|
+
const X2 = modP(X * X); // X²
|
|
170
|
+
const Y2 = modP(Y * Y); // Y²
|
|
171
|
+
const Z2 = modP(Z * Z); // Z²
|
|
172
|
+
const Z4 = modP(Z2 * Z2); // Z⁴
|
|
173
|
+
const aX2 = modP(X2 * a); // aX²
|
|
174
|
+
const left = modP(Z2 * modP(aX2 + Y2)); // (aX² + Y²)Z²
|
|
175
|
+
const right = modP(Z4 + modP(d * modP(X2 * Y2))); // Z⁴ + dX²Y²
|
|
176
|
+
if (left !== right) throw new Error('bad point: equation left != right (1)');
|
|
177
|
+
// In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T
|
|
178
|
+
const XY = modP(X * Y);
|
|
179
|
+
const ZT = modP(Z * T);
|
|
180
|
+
if (XY !== ZT) throw new Error('bad point: equation left != right (2)');
|
|
181
|
+
return true;
|
|
182
|
+
});
|
|
183
|
+
|
|
146
184
|
// Extended Point works in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z, t=xy).
|
|
147
185
|
// https://en.wikipedia.org/wiki/Twisted_Edwards_curve#Extended_coordinates
|
|
148
186
|
class Point implements ExtPointType {
|
|
@@ -155,10 +193,11 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
155
193
|
readonly ez: bigint,
|
|
156
194
|
readonly et: bigint
|
|
157
195
|
) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
196
|
+
aCoordinate('x', ex);
|
|
197
|
+
aCoordinate('y', ey);
|
|
198
|
+
aCoordinate('z', ez);
|
|
199
|
+
aCoordinate('t', et);
|
|
200
|
+
Object.freeze(this);
|
|
162
201
|
}
|
|
163
202
|
|
|
164
203
|
get x(): bigint {
|
|
@@ -171,7 +210,8 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
171
210
|
static fromAffine(p: AffinePoint<bigint>): Point {
|
|
172
211
|
if (p instanceof Point) throw new Error('extended point not allowed');
|
|
173
212
|
const { x, y } = p || {};
|
|
174
|
-
|
|
213
|
+
aCoordinate('x', x);
|
|
214
|
+
aCoordinate('y', y);
|
|
175
215
|
return new Point(x, y, _1n, modP(x * y));
|
|
176
216
|
}
|
|
177
217
|
static normalizeZ(points: Point[]): Point[] {
|
|
@@ -179,41 +219,19 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
179
219
|
return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
|
|
180
220
|
}
|
|
181
221
|
|
|
182
|
-
// We calculate precomputes for elliptic curve point multiplication
|
|
183
|
-
// using windowed method. This specifies window size and
|
|
184
|
-
// stores precomputed values. Usually only base point would be precomputed.
|
|
185
|
-
_WINDOW_SIZE?: number;
|
|
186
|
-
|
|
187
222
|
// "Private method", don't use it directly
|
|
188
223
|
_setWindowSize(windowSize: number) {
|
|
189
|
-
this
|
|
190
|
-
pointPrecomputes.delete(this);
|
|
224
|
+
wnaf.setWindowSize(this, windowSize);
|
|
191
225
|
}
|
|
192
226
|
// Not required for fromHex(), which always creates valid points.
|
|
193
227
|
// Could be useful for fromAffine().
|
|
194
228
|
assertValidity(): void {
|
|
195
|
-
|
|
196
|
-
if (this.is0()) throw new Error('bad point: ZERO'); // TODO: optimize, with vars below?
|
|
197
|
-
// Equation in affine coordinates: ax² + y² = 1 + dx²y²
|
|
198
|
-
// Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²
|
|
199
|
-
const { ex: X, ey: Y, ez: Z, et: T } = this;
|
|
200
|
-
const X2 = modP(X * X); // X²
|
|
201
|
-
const Y2 = modP(Y * Y); // Y²
|
|
202
|
-
const Z2 = modP(Z * Z); // Z²
|
|
203
|
-
const Z4 = modP(Z2 * Z2); // Z⁴
|
|
204
|
-
const aX2 = modP(X2 * a); // aX²
|
|
205
|
-
const left = modP(Z2 * modP(aX2 + Y2)); // (aX² + Y²)Z²
|
|
206
|
-
const right = modP(Z4 + modP(d * modP(X2 * Y2))); // Z⁴ + dX²Y²
|
|
207
|
-
if (left !== right) throw new Error('bad point: equation left != right (1)');
|
|
208
|
-
// In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T
|
|
209
|
-
const XY = modP(X * Y);
|
|
210
|
-
const ZT = modP(Z * T);
|
|
211
|
-
if (XY !== ZT) throw new Error('bad point: equation left != right (2)');
|
|
229
|
+
assertValidMemo(this);
|
|
212
230
|
}
|
|
213
231
|
|
|
214
232
|
// Compare one point to another.
|
|
215
233
|
equals(other: Point): boolean {
|
|
216
|
-
|
|
234
|
+
assertPoint(other);
|
|
217
235
|
const { ex: X1, ey: Y1, ez: Z1 } = this;
|
|
218
236
|
const { ex: X2, ey: Y2, ez: Z2 } = other;
|
|
219
237
|
const X1Z2 = modP(X1 * Z2);
|
|
@@ -223,7 +241,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
223
241
|
return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;
|
|
224
242
|
}
|
|
225
243
|
|
|
226
|
-
|
|
244
|
+
is0(): boolean {
|
|
227
245
|
return this.equals(Point.ZERO);
|
|
228
246
|
}
|
|
229
247
|
|
|
@@ -258,7 +276,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
258
276
|
// https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-add-2008-hwcd
|
|
259
277
|
// Cost: 9M + 1*a + 1*d + 7add.
|
|
260
278
|
add(other: Point) {
|
|
261
|
-
|
|
279
|
+
assertPoint(other);
|
|
262
280
|
const { a, d } = CURVE;
|
|
263
281
|
const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this;
|
|
264
282
|
const { ex: X2, ey: Y2, ez: Z2, et: T2 } = other;
|
|
@@ -303,12 +321,14 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
303
321
|
}
|
|
304
322
|
|
|
305
323
|
private wNAF(n: bigint): { p: Point; f: Point } {
|
|
306
|
-
return wnaf.wNAFCached(this,
|
|
324
|
+
return wnaf.wNAFCached(this, n, Point.normalizeZ);
|
|
307
325
|
}
|
|
308
326
|
|
|
309
327
|
// Constant-time multiplication.
|
|
310
328
|
multiply(scalar: bigint): Point {
|
|
311
|
-
const
|
|
329
|
+
const n = scalar;
|
|
330
|
+
ut.aInRange('scalar', n, _1n, CURVE_ORDER); // 1 <= scalar < L
|
|
331
|
+
const { p, f } = this.wNAF(n);
|
|
312
332
|
return Point.normalizeZ([p, f])[0];
|
|
313
333
|
}
|
|
314
334
|
|
|
@@ -317,7 +337,8 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
317
337
|
// an exposed private key e.g. sig verification.
|
|
318
338
|
// Does NOT allow scalars higher than CURVE.n.
|
|
319
339
|
multiplyUnsafe(scalar: bigint): Point {
|
|
320
|
-
|
|
340
|
+
const n = scalar;
|
|
341
|
+
ut.aInRange('scalar', n, _0n, CURVE_ORDER); // 0 <= scalar < L
|
|
321
342
|
if (n === _0n) return I;
|
|
322
343
|
if (this.equals(I) || n === _1n) return this;
|
|
323
344
|
if (this.equals(G)) return this.wNAF(n).p;
|
|
@@ -341,15 +362,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
341
362
|
// Converts Extended point to default (x, y) coordinates.
|
|
342
363
|
// Can accept precomputed Z^-1 - for example, from invertBatch.
|
|
343
364
|
toAffine(iz?: bigint): AffinePoint<bigint> {
|
|
344
|
-
|
|
345
|
-
const is0 = this.is0();
|
|
346
|
-
if (iz == null) iz = is0 ? _8n : (Fp.inv(z) as bigint); // 8 was chosen arbitrarily
|
|
347
|
-
const ax = modP(x * iz);
|
|
348
|
-
const ay = modP(y * iz);
|
|
349
|
-
const zz = modP(z * iz);
|
|
350
|
-
if (is0) return { x: _0n, y: _1n };
|
|
351
|
-
if (zz !== _1n) throw new Error('invZ was invalid');
|
|
352
|
-
return { x: ax, y: ay };
|
|
365
|
+
return toAffineMemo(this, iz);
|
|
353
366
|
}
|
|
354
367
|
|
|
355
368
|
clearCofactor(): Point {
|
|
@@ -364,18 +377,17 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
364
377
|
const { d, a } = CURVE;
|
|
365
378
|
const len = Fp.BYTES;
|
|
366
379
|
hex = ensureBytes('pointHex', hex, len); // copy hex to a new array
|
|
380
|
+
abool('zip215', zip215);
|
|
367
381
|
const normed = hex.slice(); // copy again, we'll manipulate it
|
|
368
382
|
const lastByte = hex[len - 1]; // select last byte
|
|
369
383
|
normed[len - 1] = lastByte & ~0x80; // clear last bit
|
|
370
384
|
const y = ut.bytesToNumberLE(normed);
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
else assertInRange(y, Fp.ORDER); // zip215=false [1..MASK-1] (2^256-1 for ed25519)
|
|
378
|
-
}
|
|
385
|
+
|
|
386
|
+
// RFC8032 prohibits >= p, but ZIP215 doesn't
|
|
387
|
+
// zip215=true: 0 <= y < MASK (2^256 for ed25519)
|
|
388
|
+
// zip215=false: 0 <= y < P (2^255-19 for ed25519)
|
|
389
|
+
const max = zip215 ? MASK : Fp.ORDER;
|
|
390
|
+
ut.aInRange('pointHex.y', y, _0n, max);
|
|
379
391
|
|
|
380
392
|
// Ed25519: x² = (y²-1)/(dy²+1) mod p. Ed448: x² = (y²-1)/(dy²-1) mod p. Generic case:
|
|
381
393
|
// ax²+y²=1+dx²y² => y²-1=dx²y²-ax² => y²-1=x²(dy²-a) => x²=(y²-1)/(dy²-a)
|
|
@@ -451,7 +463,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
451
463
|
const R = G.multiply(r).toRawBytes(); // R = rG
|
|
452
464
|
const k = hashDomainToScalar(options.context, R, pointBytes, msg); // R || A || PH(M)
|
|
453
465
|
const s = modN(r + k * scalar); // S = (r + k * s) mod L
|
|
454
|
-
|
|
466
|
+
ut.aInRange('signature.s', s, _0n, CURVE_ORDER); // 0 <= s < l
|
|
455
467
|
const res = ut.concatBytes(R, ut.numberToBytesLE(s, Fp.BYTES));
|
|
456
468
|
return ensureBytes('result', res, nByteLength * 2); // 64-byte signature
|
|
457
469
|
}
|
|
@@ -462,6 +474,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
|
|
|
462
474
|
const len = Fp.BYTES; // Verifies EdDSA signature against message and public key. RFC8032 5.1.7.
|
|
463
475
|
sig = ensureBytes('signature', sig, 2 * len); // An extended group equation is checked.
|
|
464
476
|
msg = ensureBytes('message', msg);
|
|
477
|
+
if (zip215 !== undefined) abool('zip215', zip215);
|
|
465
478
|
if (prehash) msg = prehash(msg); // for ed25519ph, etc
|
|
466
479
|
|
|
467
480
|
const s = ut.bytesToNumberLE(sig.slice(len, 2 * len));
|
package/src/abstract/modular.ts
CHANGED
|
@@ -195,7 +195,6 @@ export function FpSqrt(P: bigint) {
|
|
|
195
195
|
// return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
|
|
196
196
|
// }
|
|
197
197
|
}
|
|
198
|
-
|
|
199
198
|
// Other cases: Tonelli-Shanks algorithm
|
|
200
199
|
return tonelliShanks(P);
|
|
201
200
|
}
|
|
@@ -314,11 +313,19 @@ export function FpDiv<T>(f: IField<T>, lhs: T, rhs: T | bigint): T {
|
|
|
314
313
|
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
|
|
315
314
|
}
|
|
316
315
|
|
|
316
|
+
export function FpLegendre(order: bigint) {
|
|
317
|
+
// (a | p) ≡ 1 if a is a square (mod p), quadratic residue
|
|
318
|
+
// (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue
|
|
319
|
+
// (a | p) ≡ 0 if a ≡ 0 (mod p)
|
|
320
|
+
const legendreConst = (order - _1n) / _2n; // Integer arithmetic
|
|
321
|
+
return <T>(f: IField<T>, x: T): T => f.pow(x, legendreConst);
|
|
322
|
+
}
|
|
323
|
+
|
|
317
324
|
// This function returns True whenever the value x is a square in the field F.
|
|
318
325
|
export function FpIsSquare<T>(f: IField<T>) {
|
|
319
|
-
const
|
|
326
|
+
const legendre = FpLegendre(f.ORDER);
|
|
320
327
|
return (x: T): boolean => {
|
|
321
|
-
const p = f
|
|
328
|
+
const p = legendre(f, x);
|
|
322
329
|
return f.eql(p, f.ZERO) || f.eql(p, f.ONE);
|
|
323
330
|
};
|
|
324
331
|
}
|
|
@@ -339,6 +346,9 @@ type FpField = IField<bigint> & Required<Pick<IField<bigint>, 'isOdd'>>;
|
|
|
339
346
|
* * a) denormalized operations like mulN instead of mul
|
|
340
347
|
* * b) same object shape: never add or remove keys
|
|
341
348
|
* * c) Object.freeze
|
|
349
|
+
* NOTE: operations don't check 'isValid' for all elements for performance reasons,
|
|
350
|
+
* it is caller responsibility to check this.
|
|
351
|
+
* This is low-level code, please make sure you know what you doing.
|
|
342
352
|
* @param ORDER prime positive bigint
|
|
343
353
|
* @param bitLen how many bits the field consumes
|
|
344
354
|
* @param isLE (def: false) if encoding / decoding should be in little-endian
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
2
|
import { mod, pow } from './modular.js';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
aInRange,
|
|
5
|
+
bytesToNumberLE,
|
|
6
|
+
ensureBytes,
|
|
7
|
+
numberToBytesLE,
|
|
8
|
+
validateObject,
|
|
9
|
+
} from './utils.js';
|
|
4
10
|
|
|
5
11
|
const _0n = BigInt(0);
|
|
6
12
|
const _1n = BigInt(1);
|
|
@@ -75,12 +81,6 @@ export function montgomery(curveDef: CurveType): CurveFn {
|
|
|
75
81
|
return [x_2, x_3];
|
|
76
82
|
}
|
|
77
83
|
|
|
78
|
-
// Accepts 0 as well
|
|
79
|
-
function assertFieldElement(n: bigint): bigint {
|
|
80
|
-
if (typeof n === 'bigint' && _0n <= n && n < P) return n;
|
|
81
|
-
throw new Error('Expected valid scalar 0 < scalar < CURVE.P');
|
|
82
|
-
}
|
|
83
|
-
|
|
84
84
|
// x25519 from 4
|
|
85
85
|
// The constant a24 is (486662 - 2) / 4 = 121665 for curve25519/X25519
|
|
86
86
|
const a24 = (CURVE.a - BigInt(2)) / BigInt(4);
|
|
@@ -90,11 +90,12 @@ export function montgomery(curveDef: CurveType): CurveFn {
|
|
|
90
90
|
* @param scalar by which the point would be multiplied
|
|
91
91
|
* @returns new Point on Montgomery curve
|
|
92
92
|
*/
|
|
93
|
-
function montgomeryLadder(
|
|
94
|
-
|
|
93
|
+
function montgomeryLadder(u: bigint, scalar: bigint): bigint {
|
|
94
|
+
aInRange('u', u, _0n, P);
|
|
95
|
+
aInRange('scalar', scalar, _0n, P);
|
|
95
96
|
// Section 5: Implementations MUST accept non-canonical values and process them as
|
|
96
97
|
// if they had been reduced modulo the field prime.
|
|
97
|
-
const k =
|
|
98
|
+
const k = scalar;
|
|
98
99
|
const x_1 = u;
|
|
99
100
|
let x_2 = _1n;
|
|
100
101
|
let z_2 = _0n;
|