@noble/curves 1.9.4 → 1.9.5
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/abstract/curve.d.ts +47 -46
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +9 -6
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +33 -31
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +123 -122
- package/abstract/edwards.js.map +1 -1
- package/abstract/modular.d.ts +1 -1
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +4 -4
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +2 -6
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +13 -10
- package/abstract/montgomery.js.map +1 -1
- package/abstract/weierstrass.d.ts +161 -92
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +340 -267
- 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 +15 -15
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +41 -38
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +13 -13
- package/ed448.d.ts.map +1 -1
- package/ed448.js +43 -35
- package/ed448.js.map +1 -1
- package/esm/abstract/curve.d.ts +47 -46
- package/esm/abstract/curve.d.ts.map +1 -1
- package/esm/abstract/curve.js +9 -6
- package/esm/abstract/curve.js.map +1 -1
- package/esm/abstract/edwards.d.ts +33 -31
- package/esm/abstract/edwards.d.ts.map +1 -1
- package/esm/abstract/edwards.js +124 -123
- package/esm/abstract/edwards.js.map +1 -1
- package/esm/abstract/modular.d.ts +1 -1
- package/esm/abstract/modular.d.ts.map +1 -1
- package/esm/abstract/modular.js +4 -4
- package/esm/abstract/modular.js.map +1 -1
- package/esm/abstract/montgomery.d.ts +2 -6
- package/esm/abstract/montgomery.d.ts.map +1 -1
- package/esm/abstract/montgomery.js +14 -11
- package/esm/abstract/montgomery.js.map +1 -1
- package/esm/abstract/weierstrass.d.ts +161 -92
- package/esm/abstract/weierstrass.d.ts.map +1 -1
- package/esm/abstract/weierstrass.js +342 -270
- package/esm/abstract/weierstrass.js.map +1 -1
- package/esm/bls12-381.d.ts.map +1 -1
- package/esm/bls12-381.js +5 -5
- package/esm/bls12-381.js.map +1 -1
- package/esm/ed25519.d.ts +15 -15
- package/esm/ed25519.d.ts.map +1 -1
- package/esm/ed25519.js +40 -37
- package/esm/ed25519.js.map +1 -1
- package/esm/ed448.d.ts +13 -13
- package/esm/ed448.d.ts.map +1 -1
- package/esm/ed448.js +42 -34
- package/esm/ed448.js.map +1 -1
- package/esm/misc.js +2 -2
- package/esm/misc.js.map +1 -1
- package/esm/nist.d.ts +6 -0
- package/esm/nist.d.ts.map +1 -1
- package/esm/nist.js +6 -0
- package/esm/nist.js.map +1 -1
- package/esm/secp256k1.d.ts +2 -6
- package/esm/secp256k1.d.ts.map +1 -1
- package/esm/secp256k1.js +8 -11
- package/esm/secp256k1.js.map +1 -1
- package/esm/utils.d.ts +14 -0
- package/esm/utils.d.ts.map +1 -1
- package/esm/utils.js +43 -0
- package/esm/utils.js.map +1 -1
- package/misc.js +2 -2
- package/misc.js.map +1 -1
- package/nist.d.ts +6 -0
- package/nist.d.ts.map +1 -1
- package/nist.js +7 -1
- package/nist.js.map +1 -1
- package/package.json +1 -1
- package/secp256k1.d.ts +2 -6
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +7 -10
- package/secp256k1.js.map +1 -1
- package/src/abstract/curve.ts +131 -68
- package/src/abstract/edwards.ts +162 -166
- package/src/abstract/modular.ts +4 -4
- package/src/abstract/montgomery.ts +16 -16
- package/src/abstract/weierstrass.ts +510 -395
- package/src/bls12-381.ts +5 -4
- package/src/ed25519.ts +51 -46
- package/src/ed448.ts +46 -44
- package/src/misc.ts +2 -2
- package/src/nist.ts +7 -0
- package/src/secp256k1.ts +10 -12
- package/src/utils.ts +48 -0
- package/utils.d.ts +14 -0
- package/utils.d.ts.map +1 -1
- package/utils.js +47 -0
- package/utils.js.map +1 -1
package/src/abstract/edwards.ts
CHANGED
|
@@ -7,14 +7,16 @@
|
|
|
7
7
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
8
8
|
import {
|
|
9
9
|
_validateObject,
|
|
10
|
-
abool,
|
|
11
|
-
abytes,
|
|
10
|
+
_abool2 as abool,
|
|
11
|
+
_abytes2 as abytes,
|
|
12
12
|
aInRange,
|
|
13
13
|
bytesToHex,
|
|
14
14
|
bytesToNumberLE,
|
|
15
15
|
concatBytes,
|
|
16
|
+
copyBytes,
|
|
16
17
|
ensureBytes,
|
|
17
18
|
memoized,
|
|
19
|
+
notImplemented,
|
|
18
20
|
numberToBytesLE,
|
|
19
21
|
randomBytes,
|
|
20
22
|
type FHash,
|
|
@@ -27,7 +29,7 @@ import {
|
|
|
27
29
|
wNAF,
|
|
28
30
|
type AffinePoint,
|
|
29
31
|
type BasicCurve,
|
|
30
|
-
type
|
|
32
|
+
type CurveLengths,
|
|
31
33
|
type CurvePoint,
|
|
32
34
|
type CurvePointCons,
|
|
33
35
|
} from './curve.ts';
|
|
@@ -39,23 +41,6 @@ const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _8n = BigInt(8);
|
|
|
39
41
|
|
|
40
42
|
export type UVRatio = (u: bigint, v: bigint) => { isValid: boolean; value: bigint };
|
|
41
43
|
|
|
42
|
-
// TODO: remove
|
|
43
|
-
export type CurveType = BasicCurve<bigint> & {
|
|
44
|
-
a: bigint; // curve param a
|
|
45
|
-
d: bigint; // curve param d
|
|
46
|
-
/** @deprecated the property will be removed in next release */
|
|
47
|
-
hash: FHash; // Hashing
|
|
48
|
-
randomBytes?: (bytesLength?: number) => Uint8Array; // CSPRNG
|
|
49
|
-
adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array; // clears bits to get valid field elemtn
|
|
50
|
-
domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; // Used for hashing
|
|
51
|
-
uvRatio?: UVRatio; // Ratio √(u/v)
|
|
52
|
-
prehash?: FHash; // RFC 8032 pre-hashing of messages to sign() / verify()
|
|
53
|
-
mapToCurve?: (scalar: bigint[]) => AffinePoint<bigint>; // for hash-to-curve standard
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
// TODO: remove
|
|
57
|
-
export type CurveTypeWithLength = Readonly<CurveType & Partial<NLength>>;
|
|
58
|
-
|
|
59
44
|
/** Instance of Extended Point with coordinates in X, Y, Z, T. */
|
|
60
45
|
export interface EdwardsPoint extends CurvePoint<bigint, EdwardsPoint> {
|
|
61
46
|
/** extended X coordinate. Different from affine x. */
|
|
@@ -81,8 +66,9 @@ export interface EdwardsPoint extends CurvePoint<bigint, EdwardsPoint> {
|
|
|
81
66
|
readonly et: bigint;
|
|
82
67
|
}
|
|
83
68
|
/** Static methods of Extended Point with coordinates in X, Y, Z, T. */
|
|
84
|
-
export interface EdwardsPointCons extends CurvePointCons<
|
|
69
|
+
export interface EdwardsPointCons extends CurvePointCons<EdwardsPoint> {
|
|
85
70
|
new (X: bigint, Y: bigint, Z: bigint, T: bigint): EdwardsPoint;
|
|
71
|
+
CURVE(): EdwardsOpts;
|
|
86
72
|
fromBytes(bytes: Uint8Array, zip215?: boolean): EdwardsPoint;
|
|
87
73
|
fromHex(hex: Hex, zip215?: boolean): EdwardsPoint;
|
|
88
74
|
/** @deprecated use `import { pippenger } from '@noble/curves/abstract/curve.js';` */
|
|
@@ -124,6 +110,7 @@ export type EdwardsOpts = Readonly<{
|
|
|
124
110
|
export type EdwardsExtraOpts = Partial<{
|
|
125
111
|
Fp: IField<bigint>;
|
|
126
112
|
Fn: IField<bigint>;
|
|
113
|
+
FpFnLE: boolean;
|
|
127
114
|
uvRatio: (u: bigint, v: bigint) => { isValid: boolean; value: bigint };
|
|
128
115
|
}>;
|
|
129
116
|
|
|
@@ -199,24 +186,9 @@ export interface EdDSA {
|
|
|
199
186
|
/** @deprecated use `point.precompute()` */
|
|
200
187
|
precompute: (windowSize?: number, point?: EdwardsPoint) => EdwardsPoint;
|
|
201
188
|
};
|
|
202
|
-
|
|
189
|
+
lengths: CurveLengths;
|
|
203
190
|
}
|
|
204
191
|
|
|
205
|
-
// Legacy params. TODO: remove
|
|
206
|
-
export type CurveFn = {
|
|
207
|
-
/** @deprecated the property will be removed in next release */
|
|
208
|
-
CURVE: CurveType;
|
|
209
|
-
keygen: EdDSA['keygen'];
|
|
210
|
-
getPublicKey: EdDSA['getPublicKey'];
|
|
211
|
-
sign: EdDSA['sign'];
|
|
212
|
-
verify: EdDSA['verify'];
|
|
213
|
-
Point: EdwardsPointCons;
|
|
214
|
-
/** @deprecated use `Point` */
|
|
215
|
-
ExtendedPoint: EdwardsPointCons;
|
|
216
|
-
utils: EdDSA['utils'];
|
|
217
|
-
info: CurveInfo;
|
|
218
|
-
};
|
|
219
|
-
|
|
220
192
|
function isEdValidXY(Fp: IField<bigint>, CURVE: EdwardsOpts, x: bigint, y: bigint): boolean {
|
|
221
193
|
const x2 = Fp.sqr(x);
|
|
222
194
|
const y2 = Fp.sqr(y);
|
|
@@ -225,10 +197,12 @@ function isEdValidXY(Fp: IField<bigint>, CURVE: EdwardsOpts, x: bigint, y: bigin
|
|
|
225
197
|
return Fp.eql(left, right);
|
|
226
198
|
}
|
|
227
199
|
|
|
228
|
-
export function edwards(
|
|
229
|
-
const
|
|
200
|
+
export function edwards(params: EdwardsOpts, extraOpts: EdwardsExtraOpts = {}): EdwardsPointCons {
|
|
201
|
+
const validated = _createCurveFields('edwards', params, extraOpts, extraOpts.FpFnLE);
|
|
202
|
+
const { Fp, Fn } = validated;
|
|
203
|
+
let CURVE = validated.CURVE as EdwardsOpts;
|
|
230
204
|
const { h: cofactor, n: CURVE_ORDER } = CURVE;
|
|
231
|
-
_validateObject(
|
|
205
|
+
_validateObject(extraOpts, {}, { uvRatio: 'function' });
|
|
232
206
|
|
|
233
207
|
// Important:
|
|
234
208
|
// There are some places where Fp.BYTES is used instead of nByteLength.
|
|
@@ -239,7 +213,7 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
|
|
|
239
213
|
|
|
240
214
|
// sqrt(u/v)
|
|
241
215
|
const uvRatio =
|
|
242
|
-
|
|
216
|
+
extraOpts.uvRatio ||
|
|
243
217
|
((u: bigint, v: bigint) => {
|
|
244
218
|
try {
|
|
245
219
|
return { isValid: true, value: Fp.sqrt(Fp.div(u, v)) };
|
|
@@ -307,8 +281,9 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
|
|
|
307
281
|
static readonly BASE = new Point(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
|
|
308
282
|
// zero / infinity / identity point
|
|
309
283
|
static readonly ZERO = new Point(_0n, _1n, _1n, _0n); // 0, 1, 1, 0
|
|
310
|
-
//
|
|
284
|
+
// math field
|
|
311
285
|
static readonly Fp = Fp;
|
|
286
|
+
// scalar field
|
|
312
287
|
static readonly Fn = Fn;
|
|
313
288
|
|
|
314
289
|
readonly X: bigint;
|
|
@@ -324,34 +299,8 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
|
|
|
324
299
|
Object.freeze(this);
|
|
325
300
|
}
|
|
326
301
|
|
|
327
|
-
|
|
328
|
-
return
|
|
329
|
-
}
|
|
330
|
-
get y(): bigint {
|
|
331
|
-
return this.toAffine().y;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// TODO: remove
|
|
335
|
-
get ex(): bigint {
|
|
336
|
-
return this.X;
|
|
337
|
-
}
|
|
338
|
-
get ey(): bigint {
|
|
339
|
-
return this.Y;
|
|
340
|
-
}
|
|
341
|
-
get ez(): bigint {
|
|
342
|
-
return this.Z;
|
|
343
|
-
}
|
|
344
|
-
get et(): bigint {
|
|
345
|
-
return this.T;
|
|
346
|
-
}
|
|
347
|
-
static normalizeZ(points: Point[]): Point[] {
|
|
348
|
-
return normalizeZ(Point, points);
|
|
349
|
-
}
|
|
350
|
-
static msm(points: Point[], scalars: bigint[]): Point {
|
|
351
|
-
return pippenger(Point, Fn, points, scalars);
|
|
352
|
-
}
|
|
353
|
-
_setWindowSize(windowSize: number) {
|
|
354
|
-
this.precompute(windowSize);
|
|
302
|
+
static CURVE(): EdwardsOpts {
|
|
303
|
+
return CURVE as EdwardsOpts;
|
|
355
304
|
}
|
|
356
305
|
|
|
357
306
|
static fromAffine(p: AffinePoint<bigint>): Point {
|
|
@@ -362,6 +311,50 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
|
|
|
362
311
|
return new Point(x, y, _1n, modP(x * y));
|
|
363
312
|
}
|
|
364
313
|
|
|
314
|
+
// Uses algo from RFC8032 5.1.3.
|
|
315
|
+
static fromBytes(bytes: Uint8Array, zip215 = false): Point {
|
|
316
|
+
const len = Fp.BYTES;
|
|
317
|
+
const { a, d } = CURVE;
|
|
318
|
+
bytes = copyBytes(abytes(bytes, len, 'point'));
|
|
319
|
+
abool(zip215, 'zip215');
|
|
320
|
+
const normed = copyBytes(bytes); // copy again, we'll manipulate it
|
|
321
|
+
const lastByte = bytes[len - 1]; // select last byte
|
|
322
|
+
normed[len - 1] = lastByte & ~0x80; // clear last bit
|
|
323
|
+
const y = bytesToNumberLE(normed);
|
|
324
|
+
|
|
325
|
+
// zip215=true is good for consensus-critical apps. =false follows RFC8032 / NIST186-5.
|
|
326
|
+
// RFC8032 prohibits >= p, but ZIP215 doesn't
|
|
327
|
+
// zip215=true: 0 <= y < MASK (2^256 for ed25519)
|
|
328
|
+
// zip215=false: 0 <= y < P (2^255-19 for ed25519)
|
|
329
|
+
const max = zip215 ? MASK : Fp.ORDER;
|
|
330
|
+
aInRange('pointHex.y', y, _0n, max);
|
|
331
|
+
|
|
332
|
+
// Ed25519: x² = (y²-1)/(dy²+1) mod p. Ed448: x² = (y²-1)/(dy²-1) mod p. Generic case:
|
|
333
|
+
// ax²+y²=1+dx²y² => y²-1=dx²y²-ax² => y²-1=x²(dy²-a) => x²=(y²-1)/(dy²-a)
|
|
334
|
+
const y2 = modP(y * y); // denominator is always non-0 mod p.
|
|
335
|
+
const u = modP(y2 - _1n); // u = y² - 1
|
|
336
|
+
const v = modP(d * y2 - a); // v = d y² + 1.
|
|
337
|
+
let { isValid, value: x } = uvRatio(u, v); // √(u/v)
|
|
338
|
+
if (!isValid) throw new Error('Point.fromHex: invalid y coordinate');
|
|
339
|
+
const isXOdd = (x & _1n) === _1n; // There are 2 square roots. Use x_0 bit to select proper
|
|
340
|
+
const isLastByteOdd = (lastByte & 0x80) !== 0; // x_0, last bit
|
|
341
|
+
if (!zip215 && x === _0n && isLastByteOdd)
|
|
342
|
+
// if x=0 and x_0 = 1, fail
|
|
343
|
+
throw new Error('Point.fromHex: x=0 and x_0=1');
|
|
344
|
+
if (isLastByteOdd !== isXOdd) x = modP(-x); // if x_0 != x mod 2, set x = p-x
|
|
345
|
+
return Point.fromAffine({ x, y });
|
|
346
|
+
}
|
|
347
|
+
static fromHex(bytes: Uint8Array, zip215 = false): Point {
|
|
348
|
+
return Point.fromBytes(ensureBytes('point', bytes), zip215);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
get x(): bigint {
|
|
352
|
+
return this.toAffine().x;
|
|
353
|
+
}
|
|
354
|
+
get y(): bigint {
|
|
355
|
+
return this.toAffine().y;
|
|
356
|
+
}
|
|
357
|
+
|
|
365
358
|
precompute(windowSize: number = 8, isLazy = true) {
|
|
366
359
|
wnaf.createCache(this, windowSize);
|
|
367
360
|
if (!isLazy) this.multiply(_2n); // random number
|
|
@@ -489,45 +482,6 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
|
|
|
489
482
|
return this.multiplyUnsafe(cofactor);
|
|
490
483
|
}
|
|
491
484
|
|
|
492
|
-
static fromBytes(bytes: Uint8Array, zip215 = false): Point {
|
|
493
|
-
abytes(bytes);
|
|
494
|
-
return Point.fromHex(bytes, zip215);
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
// Converts hash string or Uint8Array to Point.
|
|
498
|
-
// Uses algo from RFC8032 5.1.3.
|
|
499
|
-
static fromHex(hex: Hex, zip215 = false): Point {
|
|
500
|
-
const { d, a } = CURVE;
|
|
501
|
-
const len = Fp.BYTES;
|
|
502
|
-
hex = ensureBytes('pointHex', hex, len); // copy hex to a new array
|
|
503
|
-
abool('zip215', zip215);
|
|
504
|
-
const normed = hex.slice(); // copy again, we'll manipulate it
|
|
505
|
-
const lastByte = hex[len - 1]; // select last byte
|
|
506
|
-
normed[len - 1] = lastByte & ~0x80; // clear last bit
|
|
507
|
-
const y = bytesToNumberLE(normed);
|
|
508
|
-
|
|
509
|
-
// zip215=true is good for consensus-critical apps. =false follows RFC8032 / NIST186-5.
|
|
510
|
-
// RFC8032 prohibits >= p, but ZIP215 doesn't
|
|
511
|
-
// zip215=true: 0 <= y < MASK (2^256 for ed25519)
|
|
512
|
-
// zip215=false: 0 <= y < P (2^255-19 for ed25519)
|
|
513
|
-
const max = zip215 ? MASK : Fp.ORDER;
|
|
514
|
-
aInRange('pointHex.y', y, _0n, max);
|
|
515
|
-
|
|
516
|
-
// Ed25519: x² = (y²-1)/(dy²+1) mod p. Ed448: x² = (y²-1)/(dy²-1) mod p. Generic case:
|
|
517
|
-
// ax²+y²=1+dx²y² => y²-1=dx²y²-ax² => y²-1=x²(dy²-a) => x²=(y²-1)/(dy²-a)
|
|
518
|
-
const y2 = modP(y * y); // denominator is always non-0 mod p.
|
|
519
|
-
const u = modP(y2 - _1n); // u = y² - 1
|
|
520
|
-
const v = modP(d * y2 - a); // v = d y² + 1.
|
|
521
|
-
let { isValid, value: x } = uvRatio(u, v); // √(u/v)
|
|
522
|
-
if (!isValid) throw new Error('Point.fromHex: invalid y coordinate');
|
|
523
|
-
const isXOdd = (x & _1n) === _1n; // There are 2 square roots. Use x_0 bit to select proper
|
|
524
|
-
const isLastByteOdd = (lastByte & 0x80) !== 0; // x_0, last bit
|
|
525
|
-
if (!zip215 && x === _0n && isLastByteOdd)
|
|
526
|
-
// if x=0 and x_0 = 1, fail
|
|
527
|
-
throw new Error('Point.fromHex: x=0 and x_0=1');
|
|
528
|
-
if (isLastByteOdd !== isXOdd) x = modP(-x); // if x_0 != x mod 2, set x = p-x
|
|
529
|
-
return Point.fromAffine({ x, y });
|
|
530
|
-
}
|
|
531
485
|
toBytes(): Uint8Array {
|
|
532
486
|
const { x, y } = this.toAffine();
|
|
533
487
|
const bytes = numberToBytesLE(y, Fp.BYTES); // each y has 2 x values (x, -y)
|
|
@@ -545,6 +499,29 @@ export function edwards(CURVE: EdwardsOpts, curveOpts: EdwardsExtraOpts = {}): E
|
|
|
545
499
|
toString() {
|
|
546
500
|
return `<Point ${this.is0() ? 'ZERO' : this.toHex()}>`;
|
|
547
501
|
}
|
|
502
|
+
|
|
503
|
+
// TODO: remove
|
|
504
|
+
get ex(): bigint {
|
|
505
|
+
return this.X;
|
|
506
|
+
}
|
|
507
|
+
get ey(): bigint {
|
|
508
|
+
return this.Y;
|
|
509
|
+
}
|
|
510
|
+
get ez(): bigint {
|
|
511
|
+
return this.Z;
|
|
512
|
+
}
|
|
513
|
+
get et(): bigint {
|
|
514
|
+
return this.T;
|
|
515
|
+
}
|
|
516
|
+
static normalizeZ(points: Point[]): Point[] {
|
|
517
|
+
return normalizeZ(Point, points);
|
|
518
|
+
}
|
|
519
|
+
static msm(points: Point[], scalars: bigint[]): Point {
|
|
520
|
+
return pippenger(Point, Fn, points, scalars);
|
|
521
|
+
}
|
|
522
|
+
_setWindowSize(windowSize: number) {
|
|
523
|
+
this.precompute(windowSize);
|
|
524
|
+
}
|
|
548
525
|
}
|
|
549
526
|
const wnaf = new wNAF(Point, Fn.BYTES * 8); // Fn.BITS?
|
|
550
527
|
return Point;
|
|
@@ -575,11 +552,11 @@ export abstract class PrimeEdwardsPoint<T extends PrimeEdwardsPoint<T>>
|
|
|
575
552
|
|
|
576
553
|
// Static methods that must be implemented by subclasses
|
|
577
554
|
static fromBytes(_bytes: Uint8Array): any {
|
|
578
|
-
|
|
555
|
+
notImplemented();
|
|
579
556
|
}
|
|
580
557
|
|
|
581
558
|
static fromHex(_hex: Hex): any {
|
|
582
|
-
|
|
559
|
+
notImplemented();
|
|
583
560
|
}
|
|
584
561
|
|
|
585
562
|
get x(): bigint {
|
|
@@ -663,7 +640,7 @@ export abstract class PrimeEdwardsPoint<T extends PrimeEdwardsPoint<T>>
|
|
|
663
640
|
/**
|
|
664
641
|
* Initializes EdDSA signatures over given Edwards curve.
|
|
665
642
|
*/
|
|
666
|
-
export function eddsa(Point: EdwardsPointCons, cHash: FHash, eddsaOpts: EdDSAOpts): EdDSA {
|
|
643
|
+
export function eddsa(Point: EdwardsPointCons, cHash: FHash, eddsaOpts: EdDSAOpts = {}): EdDSA {
|
|
667
644
|
if (typeof cHash !== 'function') throw new Error('"hash" function param is required');
|
|
668
645
|
_validateObject(
|
|
669
646
|
eddsaOpts,
|
|
@@ -686,7 +663,7 @@ export function eddsa(Point: EdwardsPointCons, cHash: FHash, eddsaOpts: EdDSAOpt
|
|
|
686
663
|
const domain =
|
|
687
664
|
eddsaOpts.domain ||
|
|
688
665
|
((data: Uint8Array, ctx: Uint8Array, phflag: boolean) => {
|
|
689
|
-
abool(
|
|
666
|
+
abool(phflag, 'phflag');
|
|
690
667
|
if (ctx.length || phflag) throw new Error('Contexts/pre-hash are not supported');
|
|
691
668
|
return data;
|
|
692
669
|
}); // NOOP
|
|
@@ -703,7 +680,7 @@ export function eddsa(Point: EdwardsPointCons, cHash: FHash, eddsaOpts: EdDSAOpt
|
|
|
703
680
|
|
|
704
681
|
// Get the hashed private scalar per RFC8032 5.1.5
|
|
705
682
|
function getPrivateScalar(key: Hex) {
|
|
706
|
-
const len =
|
|
683
|
+
const len = lengths.secret;
|
|
707
684
|
key = ensureBytes('private key', key, len);
|
|
708
685
|
// Hash private key with curve's hash function to produce uniformingly random input
|
|
709
686
|
// Check byte lengths: ensure(64, h(ensure(32, key)))
|
|
@@ -757,21 +734,23 @@ export function eddsa(Point: EdwardsPointCons, cHash: FHash, eddsaOpts: EdDSAOpt
|
|
|
757
734
|
*/
|
|
758
735
|
function verify(sig: Hex, msg: Hex, publicKey: Hex, options = verifyOpts): boolean {
|
|
759
736
|
const { context, zip215 } = options;
|
|
760
|
-
const len =
|
|
761
|
-
sig = ensureBytes('signature', sig,
|
|
737
|
+
const len = lengths.signature; // Verifies EdDSA signature against message and public key. RFC8032 5.1.7.
|
|
738
|
+
sig = ensureBytes('signature', sig, len); // An extended group equation is checked.
|
|
762
739
|
msg = ensureBytes('message', msg);
|
|
763
|
-
publicKey = ensureBytes('publicKey', publicKey,
|
|
764
|
-
if (zip215 !== undefined) abool(
|
|
740
|
+
publicKey = ensureBytes('publicKey', publicKey, lengths.public);
|
|
741
|
+
if (zip215 !== undefined) abool(zip215, 'zip215');
|
|
765
742
|
if (prehash) msg = prehash(msg); // for ed25519ph, etc
|
|
766
743
|
|
|
767
|
-
const
|
|
744
|
+
const mid = len / 2;
|
|
745
|
+
const r = sig.subarray(0, mid);
|
|
746
|
+
const s = bytesToNumberLE(sig.subarray(mid, len));
|
|
768
747
|
let A, R, SB;
|
|
769
748
|
try {
|
|
770
749
|
// zip215=true is good for consensus-critical apps. =false follows RFC8032 / NIST186-5.
|
|
771
750
|
// zip215=true: 0 <= y < MASK (2^256 for ed25519)
|
|
772
751
|
// zip215=false: 0 <= y < P (2^255-19 for ed25519)
|
|
773
|
-
A = Point.
|
|
774
|
-
R = Point.
|
|
752
|
+
A = Point.fromBytes(publicKey, zip215);
|
|
753
|
+
R = Point.fromBytes(r, zip215);
|
|
775
754
|
SB = G.multiplyUnsafe(s); // 0 <= s < l is done inside
|
|
776
755
|
} catch (error) {
|
|
777
756
|
return false;
|
|
@@ -787,27 +766,42 @@ export function eddsa(Point: EdwardsPointCons, cHash: FHash, eddsaOpts: EdDSAOpt
|
|
|
787
766
|
|
|
788
767
|
G.precompute(8); // Enable precomputes. Slows down first publicKey computation by 20ms.
|
|
789
768
|
|
|
790
|
-
const
|
|
769
|
+
const _size = Fp.BYTES;
|
|
791
770
|
const lengths = {
|
|
792
|
-
secret:
|
|
793
|
-
public:
|
|
794
|
-
signature: 2 *
|
|
795
|
-
seed:
|
|
771
|
+
secret: _size,
|
|
772
|
+
public: _size,
|
|
773
|
+
signature: 2 * _size,
|
|
774
|
+
seed: _size,
|
|
796
775
|
};
|
|
797
776
|
function randomSecretKey(seed = randomBytes_!(lengths.seed)): Uint8Array {
|
|
798
|
-
return seed;
|
|
777
|
+
return abytes(seed, lengths.seed, 'seed');
|
|
778
|
+
}
|
|
779
|
+
function keygen(seed?: Uint8Array) {
|
|
780
|
+
const secretKey = utils.randomSecretKey(seed);
|
|
781
|
+
return { secretKey, publicKey: getPublicKey(secretKey) };
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
function isValidSecretKey(key: Uint8Array): boolean {
|
|
785
|
+
try {
|
|
786
|
+
return !!Fn.fromBytes(key, false);
|
|
787
|
+
} catch (error) {
|
|
788
|
+
return false;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
function isValidPublicKey(key: Uint8Array, zip215?: boolean): boolean {
|
|
793
|
+
try {
|
|
794
|
+
return !!Point.fromBytes(key, zip215);
|
|
795
|
+
} catch (error) {
|
|
796
|
+
return false;
|
|
797
|
+
}
|
|
799
798
|
}
|
|
800
799
|
|
|
801
800
|
const utils = {
|
|
802
801
|
getExtendedPublicKey,
|
|
803
|
-
/** ed25519 priv keys are uniform 32b. No need to check for modulo bias, like in secp256k1. */
|
|
804
802
|
randomSecretKey,
|
|
805
|
-
|
|
806
803
|
isValidSecretKey,
|
|
807
804
|
isValidPublicKey,
|
|
808
|
-
|
|
809
|
-
randomPrivateKey: randomSecretKey,
|
|
810
|
-
|
|
811
805
|
/**
|
|
812
806
|
* Converts ed public key to x public key. Uses formula:
|
|
813
807
|
* - ed25519:
|
|
@@ -824,50 +818,28 @@ export function eddsa(Point: EdwardsPointCons, cHash: FHash, eddsaOpts: EdDSAOpt
|
|
|
824
818
|
*/
|
|
825
819
|
toMontgomery(publicKey: Uint8Array): Uint8Array {
|
|
826
820
|
const { y } = Point.fromBytes(publicKey);
|
|
821
|
+
const size = lengths.public;
|
|
827
822
|
const is25519 = size === 32;
|
|
828
823
|
if (!is25519 && size !== 57) throw new Error('only defined for 25519 and 448');
|
|
829
824
|
const u = is25519 ? Fp.div(_1n + y, _1n - y) : Fp.div(y - _1n, y + _1n);
|
|
830
825
|
return Fp.toBytes(u);
|
|
831
826
|
},
|
|
832
827
|
|
|
833
|
-
toMontgomeryPriv(
|
|
834
|
-
|
|
835
|
-
|
|
828
|
+
toMontgomeryPriv(secretKey: Uint8Array): Uint8Array {
|
|
829
|
+
const size = lengths.secret;
|
|
830
|
+
abytes(secretKey, size);
|
|
831
|
+
const hashed = cHash(secretKey.subarray(0, size));
|
|
836
832
|
return adjustScalarBytes(hashed).subarray(0, size);
|
|
837
833
|
},
|
|
838
834
|
|
|
839
|
-
/**
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
* but allows to speed-up subsequent getPublicKey() calls up to 20x.
|
|
843
|
-
* @param windowSize 2, 4, 8, 16
|
|
844
|
-
*/
|
|
835
|
+
/** @deprecated */
|
|
836
|
+
randomPrivateKey: randomSecretKey,
|
|
837
|
+
/** @deprecated */
|
|
845
838
|
precompute(windowSize = 8, point: EdwardsPoint = Point.BASE): EdwardsPoint {
|
|
846
839
|
return point.precompute(windowSize, false);
|
|
847
840
|
},
|
|
848
841
|
};
|
|
849
842
|
|
|
850
|
-
function keygen(seed?: Uint8Array) {
|
|
851
|
-
const secretKey = utils.randomSecretKey(seed);
|
|
852
|
-
return { secretKey, publicKey: getPublicKey(secretKey) };
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
function isValidSecretKey(key: Uint8Array): boolean {
|
|
856
|
-
try {
|
|
857
|
-
return !!Fn.fromBytes(key, false);
|
|
858
|
-
} catch (error) {
|
|
859
|
-
return false;
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
function isValidPublicKey(key: Uint8Array, zip215?: boolean): boolean {
|
|
864
|
-
try {
|
|
865
|
-
return !!Point.fromBytes(key, zip215);
|
|
866
|
-
} catch (error) {
|
|
867
|
-
return false;
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
|
|
871
843
|
return Object.freeze({
|
|
872
844
|
keygen,
|
|
873
845
|
getPublicKey,
|
|
@@ -875,18 +847,43 @@ export function eddsa(Point: EdwardsPointCons, cHash: FHash, eddsaOpts: EdDSAOpt
|
|
|
875
847
|
verify,
|
|
876
848
|
utils,
|
|
877
849
|
Point,
|
|
878
|
-
|
|
850
|
+
lengths,
|
|
879
851
|
});
|
|
880
852
|
}
|
|
881
853
|
|
|
882
|
-
// TODO: remove
|
|
854
|
+
// TODO: remove everything below
|
|
855
|
+
export type CurveType = BasicCurve<bigint> & {
|
|
856
|
+
a: bigint; // curve param a
|
|
857
|
+
d: bigint; // curve param d
|
|
858
|
+
/** @deprecated the property will be removed in next release */
|
|
859
|
+
hash: FHash; // Hashing
|
|
860
|
+
randomBytes?: (bytesLength?: number) => Uint8Array; // CSPRNG
|
|
861
|
+
adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array; // clears bits to get valid field elemtn
|
|
862
|
+
domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; // Used for hashing
|
|
863
|
+
uvRatio?: UVRatio; // Ratio √(u/v)
|
|
864
|
+
prehash?: FHash; // RFC 8032 pre-hashing of messages to sign() / verify()
|
|
865
|
+
mapToCurve?: (scalar: bigint[]) => AffinePoint<bigint>; // for hash-to-curve standard
|
|
866
|
+
};
|
|
867
|
+
export type CurveTypeWithLength = Readonly<CurveType & Partial<NLength>>;
|
|
868
|
+
export type CurveFn = {
|
|
869
|
+
/** @deprecated the property will be removed in next release */
|
|
870
|
+
CURVE: CurveType;
|
|
871
|
+
keygen: EdDSA['keygen'];
|
|
872
|
+
getPublicKey: EdDSA['getPublicKey'];
|
|
873
|
+
sign: EdDSA['sign'];
|
|
874
|
+
verify: EdDSA['verify'];
|
|
875
|
+
Point: EdwardsPointCons;
|
|
876
|
+
/** @deprecated use `Point` */
|
|
877
|
+
ExtendedPoint: EdwardsPointCons;
|
|
878
|
+
utils: EdDSA['utils'];
|
|
879
|
+
lengths: CurveLengths;
|
|
880
|
+
};
|
|
883
881
|
export type EdComposed = {
|
|
884
882
|
CURVE: EdwardsOpts;
|
|
885
883
|
curveOpts: EdwardsExtraOpts;
|
|
886
884
|
hash: FHash;
|
|
887
885
|
eddsaOpts: EdDSAOpts;
|
|
888
886
|
};
|
|
889
|
-
// TODO: remove
|
|
890
887
|
function _eddsa_legacy_opts_to_new(c: CurveTypeWithLength): EdComposed {
|
|
891
888
|
const CURVE: EdwardsOpts = {
|
|
892
889
|
a: c.a,
|
|
@@ -909,7 +906,6 @@ function _eddsa_legacy_opts_to_new(c: CurveTypeWithLength): EdComposed {
|
|
|
909
906
|
};
|
|
910
907
|
return { CURVE, curveOpts, hash: c.hash, eddsaOpts };
|
|
911
908
|
}
|
|
912
|
-
// TODO: remove
|
|
913
909
|
function _eddsa_new_output_to_legacy(c: CurveTypeWithLength, eddsa: EdDSA): CurveFn {
|
|
914
910
|
const legacy = Object.assign({}, eddsa, { ExtendedPoint: eddsa.Point, CURVE: c });
|
|
915
911
|
return legacy;
|
package/src/abstract/modular.ts
CHANGED
|
@@ -384,7 +384,7 @@ type FieldOpts = Partial<{
|
|
|
384
384
|
sqrt: SqrtFn;
|
|
385
385
|
isLE: boolean;
|
|
386
386
|
BITS: number;
|
|
387
|
-
|
|
387
|
+
modFromBytes: boolean; // bls12-381 requires mod(n) instead of rejecting keys >= n
|
|
388
388
|
allowedLengths?: readonly number[]; // for P521 (adds padding for smaller sizes)
|
|
389
389
|
}>;
|
|
390
390
|
/**
|
|
@@ -415,7 +415,7 @@ export function Field(
|
|
|
415
415
|
if (ORDER <= _0n) throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);
|
|
416
416
|
let _nbitLength: number | undefined = undefined;
|
|
417
417
|
let _sqrt: SqrtFn | undefined = undefined;
|
|
418
|
-
let
|
|
418
|
+
let modFromBytes: boolean = false;
|
|
419
419
|
let allowedLengths: undefined | readonly number[] = undefined;
|
|
420
420
|
if (typeof bitLenOrOpts === 'object' && bitLenOrOpts != null) {
|
|
421
421
|
if (opts.sqrt || isLE) throw new Error('cannot specify opts in two arguments');
|
|
@@ -423,7 +423,7 @@ export function Field(
|
|
|
423
423
|
if (_opts.BITS) _nbitLength = _opts.BITS;
|
|
424
424
|
if (_opts.sqrt) _sqrt = _opts.sqrt;
|
|
425
425
|
if (typeof _opts.isLE === 'boolean') isLE = _opts.isLE;
|
|
426
|
-
if (typeof _opts.
|
|
426
|
+
if (typeof _opts.modFromBytes === 'boolean') modFromBytes = _opts.modFromBytes;
|
|
427
427
|
allowedLengths = _opts.allowedLengths;
|
|
428
428
|
} else {
|
|
429
429
|
if (typeof bitLenOrOpts === 'number') _nbitLength = bitLenOrOpts;
|
|
@@ -490,7 +490,7 @@ export function Field(
|
|
|
490
490
|
if (bytes.length !== BYTES)
|
|
491
491
|
throw new Error('Field.fromBytes: expected ' + BYTES + ' bytes, got ' + bytes.length);
|
|
492
492
|
let scalar = isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
|
|
493
|
-
if (
|
|
493
|
+
if (modFromBytes) scalar = mod(scalar, ORDER);
|
|
494
494
|
if (!skipValidation)
|
|
495
495
|
if (!f.isValid(scalar)) throw new Error('invalid field element: outside of range 0..ORDER');
|
|
496
496
|
// NOTE: we don't validate scalar here, please use isValid. This done such way because some
|
|
@@ -7,13 +7,14 @@
|
|
|
7
7
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
8
8
|
import {
|
|
9
9
|
_validateObject,
|
|
10
|
+
abytes,
|
|
10
11
|
aInRange,
|
|
11
12
|
bytesToNumberLE,
|
|
12
13
|
ensureBytes,
|
|
13
14
|
numberToBytesLE,
|
|
14
15
|
randomBytes,
|
|
15
16
|
} from '../utils.ts';
|
|
16
|
-
import type {
|
|
17
|
+
import type { CurveLengths } from './curve.ts';
|
|
17
18
|
import { mod } from './modular.ts';
|
|
18
19
|
|
|
19
20
|
const _0n = BigInt(0);
|
|
@@ -40,11 +41,7 @@ export type MontgomeryECDH = {
|
|
|
40
41
|
randomPrivateKey: () => Uint8Array;
|
|
41
42
|
};
|
|
42
43
|
GuBytes: Uint8Array;
|
|
43
|
-
|
|
44
|
-
type: 'montgomery';
|
|
45
|
-
lengths: Omit<CurveInfo['lengths'], 'signature'>;
|
|
46
|
-
publicKeyHasPrefix?: boolean;
|
|
47
|
-
};
|
|
44
|
+
lengths: CurveLengths;
|
|
48
45
|
keygen: (seed?: Uint8Array) => { secretKey: Uint8Array; publicKey: Uint8Array };
|
|
49
46
|
};
|
|
50
47
|
export type CurveFn = MontgomeryECDH;
|
|
@@ -167,20 +164,23 @@ export function montgomery(curveDef: CurveType): MontgomeryECDH {
|
|
|
167
164
|
const z2 = powPminus2(z_2); // `Fp.pow(x, P - _2n)` is much slower equivalent
|
|
168
165
|
return modP(x_2 * z2); // Return x_2 * (z_2^(p - 2))
|
|
169
166
|
}
|
|
170
|
-
const randomSecretKey = (seed = randomBytes_(fieldLen)) => seed;
|
|
171
|
-
const utils = {
|
|
172
|
-
randomSecretKey,
|
|
173
|
-
randomPrivateKey: randomSecretKey,
|
|
174
|
-
};
|
|
175
|
-
function keygen(seed?: Uint8Array) {
|
|
176
|
-
const secretKey = utils.randomSecretKey(seed);
|
|
177
|
-
return { secretKey, publicKey: scalarMultBase(secretKey) };
|
|
178
|
-
}
|
|
179
167
|
const lengths = {
|
|
180
168
|
secret: fieldLen,
|
|
181
169
|
public: fieldLen,
|
|
182
170
|
seed: fieldLen,
|
|
183
171
|
};
|
|
172
|
+
const randomSecretKey = (seed = randomBytes_(fieldLen)) => {
|
|
173
|
+
abytes(seed, lengths.seed);
|
|
174
|
+
return seed;
|
|
175
|
+
};
|
|
176
|
+
function keygen(seed?: Uint8Array) {
|
|
177
|
+
const secretKey = randomSecretKey(seed);
|
|
178
|
+
return { secretKey, publicKey: scalarMultBase(secretKey) };
|
|
179
|
+
}
|
|
180
|
+
const utils = {
|
|
181
|
+
randomSecretKey,
|
|
182
|
+
randomPrivateKey: randomSecretKey,
|
|
183
|
+
};
|
|
184
184
|
return {
|
|
185
185
|
keygen,
|
|
186
186
|
getSharedSecret: (secretKey: Hex, publicKey: Hex) => scalarMult(secretKey, publicKey),
|
|
@@ -189,6 +189,6 @@ export function montgomery(curveDef: CurveType): MontgomeryECDH {
|
|
|
189
189
|
scalarMultBase,
|
|
190
190
|
utils,
|
|
191
191
|
GuBytes: GuBytes.slice(),
|
|
192
|
-
|
|
192
|
+
lengths,
|
|
193
193
|
};
|
|
194
194
|
}
|