@noble/curves 0.4.0 → 0.5.1
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 +254 -162
- package/lib/_shortw_utils.d.ts +75 -0
- package/lib/_shortw_utils.js +20 -0
- package/lib/{bls.d.ts → abstract/bls.d.ts} +2 -1
- package/lib/{bls.js → abstract/bls.js} +28 -27
- package/lib/{edwards.d.ts → abstract/edwards.d.ts} +17 -0
- package/lib/{edwards.js → abstract/edwards.js} +45 -4
- package/lib/{group.d.ts → abstract/group.d.ts} +2 -1
- package/lib/{group.js → abstract/group.js} +4 -3
- package/lib/abstract/hash-to-curve.d.ts +28 -0
- package/lib/{hashToCurve.js → abstract/hash-to-curve.js} +46 -11
- package/lib/{modular.d.ts → abstract/modular.d.ts} +13 -16
- package/lib/abstract/modular.js +337 -0
- package/lib/{montgomery.d.ts → abstract/montgomery.d.ts} +2 -1
- package/lib/{montgomery.js → abstract/montgomery.js} +17 -8
- package/lib/{utils.d.ts → abstract/utils.d.ts} +4 -2
- package/lib/{utils.js → abstract/utils.js} +1 -1
- package/lib/{weierstrass.d.ts → abstract/weierstrass.d.ts} +28 -16
- package/lib/{weierstrass.js → abstract/weierstrass.js} +261 -127
- package/lib/bls12-381.d.ts +66 -0
- package/lib/bls12-381.js +1132 -0
- package/lib/bn.d.ts +7 -0
- package/lib/bn.js +24 -0
- package/lib/ed25519.d.ts +48 -0
- package/lib/ed25519.js +385 -0
- package/lib/ed448.d.ts +3 -0
- package/lib/ed448.js +211 -0
- package/lib/esm/_shortw_utils.js +15 -0
- package/lib/esm/{bls.js → abstract/bls.js} +25 -24
- package/lib/esm/{edwards.js → abstract/edwards.js} +45 -4
- package/lib/esm/{group.js → abstract/group.js} +4 -3
- package/lib/esm/{hashToCurve.js → abstract/hash-to-curve.js} +43 -10
- package/lib/esm/abstract/modular.js +319 -0
- package/lib/esm/{montgomery.js → abstract/montgomery.js} +17 -8
- package/lib/esm/{utils.js → abstract/utils.js} +1 -1
- package/lib/esm/{weierstrass.js → abstract/weierstrass.js} +255 -123
- package/lib/esm/bls12-381.js +1129 -0
- package/lib/esm/bn.js +21 -0
- package/lib/esm/ed25519.js +381 -0
- package/lib/esm/ed448.js +208 -0
- package/lib/esm/index.js +2 -0
- package/lib/esm/jubjub.js +52 -0
- package/lib/esm/p192.js +21 -0
- package/lib/esm/p224.js +21 -0
- package/lib/esm/p256.js +39 -0
- package/lib/esm/p384.js +44 -0
- package/lib/esm/p521.js +58 -0
- package/lib/esm/pasta.js +29 -0
- package/lib/esm/secp256k1.js +293 -0
- package/lib/esm/stark.js +224 -0
- package/lib/index.d.ts +0 -0
- package/lib/index.js +2 -0
- package/lib/jubjub.d.ts +7 -0
- package/lib/jubjub.js +57 -0
- package/lib/p192.d.ts +130 -0
- package/lib/p192.js +24 -0
- package/lib/p224.d.ts +130 -0
- package/lib/p224.js +24 -0
- package/lib/p256.d.ts +130 -0
- package/lib/p256.js +42 -0
- package/lib/p384.d.ts +130 -0
- package/lib/p384.js +47 -0
- package/lib/p521.d.ts +131 -0
- package/lib/p521.js +61 -0
- package/lib/pasta.d.ts +4 -0
- package/lib/pasta.js +32 -0
- package/lib/secp256k1.d.ts +96 -0
- package/lib/secp256k1.js +297 -0
- package/lib/stark.d.ts +72 -0
- package/lib/stark.js +245 -0
- package/package.json +146 -50
- package/index.js +0 -1
- package/lib/esm/modular.js +0 -252
- package/lib/hashToCurve.d.ts +0 -13
- package/lib/modular.js +0 -267
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
1
2
|
import * as mod from './modular.js';
|
|
2
3
|
import * as utils from './utils.js';
|
|
3
4
|
import { Hex, PrivKey } from './utils.js';
|
|
4
|
-
import { htfOpts, stringToBytes, hash_to_field, expand_message_xmd } from './
|
|
5
|
+
import { htfOpts, stringToBytes, hash_to_field, expand_message_xmd } from './hash-to-curve.js';
|
|
5
6
|
import { CurvePointsType, PointType, CurvePointsRes } from './weierstrass.js';
|
|
6
7
|
declare type Fp = bigint;
|
|
7
8
|
export declare type SignatureCoder<Fp2> = {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.bls = void 0;
|
|
4
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
4
5
|
// Barreto-Lynn-Scott Curves. A family of pairing friendly curves, with embedding degree = 12 or 24
|
|
5
6
|
// NOTE: only 12 supported for now
|
|
6
7
|
// Constructed from pair of weierstrass curves, based pairing logic
|
|
@@ -8,7 +9,7 @@ const mod = require("./modular.js");
|
|
|
8
9
|
const utils_js_1 = require("./utils.js");
|
|
9
10
|
// Types
|
|
10
11
|
const utils_js_2 = require("./utils.js");
|
|
11
|
-
const
|
|
12
|
+
const hash_to_curve_js_1 = require("./hash-to-curve.js");
|
|
12
13
|
const weierstrass_js_1 = require("./weierstrass.js");
|
|
13
14
|
function bls(CURVE) {
|
|
14
15
|
// Fields looks pretty specific for curve, so for now we need to pass them with options
|
|
@@ -30,33 +31,33 @@ function bls(CURVE) {
|
|
|
30
31
|
// Double
|
|
31
32
|
let t0 = Fp2.square(Ry); // Ry²
|
|
32
33
|
let t1 = Fp2.square(Rz); // Rz²
|
|
33
|
-
let t2 = Fp2.multiplyByB(Fp2.
|
|
34
|
-
let t3 = Fp2.
|
|
35
|
-
let t4 = Fp2.
|
|
34
|
+
let t2 = Fp2.multiplyByB(Fp2.mul(t1, 3n)); // 3 * T1 * B
|
|
35
|
+
let t3 = Fp2.mul(t2, 3n); // 3 * T2
|
|
36
|
+
let t4 = Fp2.sub(Fp2.sub(Fp2.square(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
|
|
36
37
|
ell_coeff.push([
|
|
37
|
-
Fp2.
|
|
38
|
-
Fp2.
|
|
38
|
+
Fp2.sub(t2, t0),
|
|
39
|
+
Fp2.mul(Fp2.square(Rx), 3n),
|
|
39
40
|
Fp2.negate(t4), // -T4
|
|
40
41
|
]);
|
|
41
|
-
Rx = Fp2.div(Fp2.
|
|
42
|
-
Ry = Fp2.
|
|
43
|
-
Rz = Fp2.
|
|
42
|
+
Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), 2n); // ((T0 - T3) * Rx * Ry) / 2
|
|
43
|
+
Ry = Fp2.sub(Fp2.square(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.square(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
|
|
44
|
+
Rz = Fp2.mul(t0, t4); // T0 * T4
|
|
44
45
|
if ((0, utils_js_1.bitGet)(CURVE.x, i)) {
|
|
45
46
|
// Addition
|
|
46
|
-
let t0 = Fp2.
|
|
47
|
-
let t1 = Fp2.
|
|
47
|
+
let t0 = Fp2.sub(Ry, Fp2.mul(Qy, Rz)); // Ry - Qy * Rz
|
|
48
|
+
let t1 = Fp2.sub(Rx, Fp2.mul(Qx, Rz)); // Rx - Qx * Rz
|
|
48
49
|
ell_coeff.push([
|
|
49
|
-
Fp2.
|
|
50
|
+
Fp2.sub(Fp2.mul(t0, Qx), Fp2.mul(t1, Qy)),
|
|
50
51
|
Fp2.negate(t0),
|
|
51
52
|
t1, // T1
|
|
52
53
|
]);
|
|
53
54
|
let t2 = Fp2.square(t1); // T1²
|
|
54
|
-
let t3 = Fp2.
|
|
55
|
-
let t4 = Fp2.
|
|
56
|
-
let t5 = Fp2.add(Fp2.
|
|
57
|
-
Rx = Fp2.
|
|
58
|
-
Ry = Fp2.
|
|
59
|
-
Rz = Fp2.
|
|
55
|
+
let t3 = Fp2.mul(t2, t1); // T2 * T1
|
|
56
|
+
let t4 = Fp2.mul(t2, Rx); // T2 * Rx
|
|
57
|
+
let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.square(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
|
|
58
|
+
Rx = Fp2.mul(t1, t5); // T1 * T5
|
|
59
|
+
Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry
|
|
60
|
+
Rz = Fp2.mul(Rz, t3); // Rz * T3
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
return ell_coeff;
|
|
@@ -67,11 +68,11 @@ function bls(CURVE) {
|
|
|
67
68
|
let f12 = Fp12.ONE;
|
|
68
69
|
for (let j = 0, i = BLS_X_LEN - 2; i >= 0; i--, j++) {
|
|
69
70
|
const E = ell[j];
|
|
70
|
-
f12 = Fp12.multiplyBy014(f12, E[0], Fp2.
|
|
71
|
+
f12 = Fp12.multiplyBy014(f12, E[0], Fp2.mul(E[1], Px), Fp2.mul(E[2], Py));
|
|
71
72
|
if ((0, utils_js_1.bitGet)(CURVE.x, i)) {
|
|
72
73
|
j += 1;
|
|
73
74
|
const F = ell[j];
|
|
74
|
-
f12 = Fp12.multiplyBy014(f12, F[0], Fp2.
|
|
75
|
+
f12 = Fp12.multiplyBy014(f12, F[0], Fp2.mul(F[1], Px), Fp2.mul(F[2], Py));
|
|
75
76
|
}
|
|
76
77
|
if (i !== 0)
|
|
77
78
|
f12 = Fp12.square(f12);
|
|
@@ -97,10 +98,10 @@ function bls(CURVE) {
|
|
|
97
98
|
hexToBytes: utils_js_2.hexToBytes,
|
|
98
99
|
bytesToHex: utils_js_2.bytesToHex,
|
|
99
100
|
mod: mod.mod,
|
|
100
|
-
stringToBytes:
|
|
101
|
+
stringToBytes: hash_to_curve_js_1.stringToBytes,
|
|
101
102
|
// TODO: do we need to export it here?
|
|
102
|
-
hashToField: (msg, count, options = {}) => (0,
|
|
103
|
-
expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => (0,
|
|
103
|
+
hashToField: (msg, count, options = {}) => (0, hash_to_curve_js_1.hash_to_field)(msg, count, { ...CURVE.htfDefaults, ...options }),
|
|
104
|
+
expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => (0, hash_to_curve_js_1.expand_message_xmd)(msg, DST, lenInBytes, H),
|
|
104
105
|
/**
|
|
105
106
|
* Can take 40 or more bytes of uniform input e.g. from CSPRNG or KDF
|
|
106
107
|
* and convert them into private key, with the modulo bias being negligible.
|
|
@@ -220,7 +221,7 @@ function bls(CURVE) {
|
|
|
220
221
|
// and do one exp after multiplying 2 points.
|
|
221
222
|
const ePHm = pairing(P.negate(), Hm, false);
|
|
222
223
|
const eGS = pairing(G, S, false);
|
|
223
|
-
const exp = Fp12.finalExponentiate(Fp12.
|
|
224
|
+
const exp = Fp12.finalExponentiate(Fp12.mul(eGS, ePHm));
|
|
224
225
|
return Fp12.equals(exp, Fp12.ONE);
|
|
225
226
|
}
|
|
226
227
|
function aggregatePublicKeys(publicKeys) {
|
|
@@ -228,7 +229,7 @@ function bls(CURVE) {
|
|
|
228
229
|
throw new Error('Expected non-empty array');
|
|
229
230
|
const agg = publicKeys
|
|
230
231
|
.map(normP1)
|
|
231
|
-
.reduce((sum, p) => sum.add(G1.
|
|
232
|
+
.reduce((sum, p) => sum.add(G1.ProjectivePoint.fromAffine(p)), G1.ProjectivePoint.ZERO);
|
|
232
233
|
const aggAffine = agg.toAffine();
|
|
233
234
|
if (publicKeys[0] instanceof G1.Point) {
|
|
234
235
|
aggAffine.assertValidity();
|
|
@@ -242,7 +243,7 @@ function bls(CURVE) {
|
|
|
242
243
|
throw new Error('Expected non-empty array');
|
|
243
244
|
const agg = signatures
|
|
244
245
|
.map(normP2)
|
|
245
|
-
.reduce((sum, s) => sum.add(G2.
|
|
246
|
+
.reduce((sum, s) => sum.add(G2.ProjectivePoint.fromAffine(s)), G2.ProjectivePoint.ZERO);
|
|
246
247
|
const aggAffine = agg.toAffine();
|
|
247
248
|
if (signatures[0] instanceof G2.Point) {
|
|
248
249
|
aggAffine.assertValidity();
|
|
@@ -269,7 +270,7 @@ function bls(CURVE) {
|
|
|
269
270
|
paired.push(pairing(groupPublicKey, message, false));
|
|
270
271
|
}
|
|
271
272
|
paired.push(pairing(G1.Point.BASE.negate(), sig, false));
|
|
272
|
-
const product = paired.reduce((a, b) => Fp12.
|
|
273
|
+
const product = paired.reduce((a, b) => Fp12.mul(a, b), Fp12.ONE);
|
|
273
274
|
const exp = Fp12.finalExponentiate(product);
|
|
274
275
|
return Fp12.equals(exp, Fp12.ONE);
|
|
275
276
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import * as mod from './modular.js';
|
|
3
3
|
import { BasicCurve, Hex, PrivKey } from './utils.js';
|
|
4
4
|
import { Group, GroupConstructor } from './group.js';
|
|
5
|
+
import { htfOpts } from './hash-to-curve.js';
|
|
5
6
|
export declare type CHash = {
|
|
6
7
|
(message: Uint8Array | string): Uint8Array;
|
|
7
8
|
blockLen: number;
|
|
@@ -20,6 +21,12 @@ export declare type CurveType = BasicCurve<bigint> & {
|
|
|
20
21
|
value: bigint;
|
|
21
22
|
};
|
|
22
23
|
preHash?: CHash;
|
|
24
|
+
clearCofactor?: (c: ExtendedPointConstructor, point: ExtendedPointType) => ExtendedPointType;
|
|
25
|
+
htfDefaults?: htfOpts;
|
|
26
|
+
mapToCurve?: (scalar: bigint[]) => {
|
|
27
|
+
x: bigint;
|
|
28
|
+
y: bigint;
|
|
29
|
+
};
|
|
23
30
|
};
|
|
24
31
|
declare function validateOpts(curve: CurveType): Readonly<{
|
|
25
32
|
readonly nBitLength: number;
|
|
@@ -43,6 +50,12 @@ declare function validateOpts(curve: CurveType): Readonly<{
|
|
|
43
50
|
value: bigint;
|
|
44
51
|
}) | undefined;
|
|
45
52
|
readonly preHash?: CHash | undefined;
|
|
53
|
+
readonly clearCofactor?: ((c: ExtendedPointConstructor, point: ExtendedPointType) => ExtendedPointType) | undefined;
|
|
54
|
+
readonly htfDefaults?: htfOpts | undefined;
|
|
55
|
+
readonly mapToCurve?: ((scalar: bigint[]) => {
|
|
56
|
+
x: bigint;
|
|
57
|
+
y: bigint;
|
|
58
|
+
}) | undefined;
|
|
46
59
|
}>;
|
|
47
60
|
export interface SignatureType {
|
|
48
61
|
readonly r: PointType;
|
|
@@ -65,6 +78,7 @@ export interface ExtendedPointType extends Group<ExtendedPointType> {
|
|
|
65
78
|
isSmallOrder(): boolean;
|
|
66
79
|
isTorsionFree(): boolean;
|
|
67
80
|
toAffine(invZ?: bigint): PointType;
|
|
81
|
+
clearCofactor(): ExtendedPointType;
|
|
68
82
|
}
|
|
69
83
|
export interface ExtendedPointConstructor extends GroupConstructor<ExtendedPointType> {
|
|
70
84
|
new (x: bigint, y: bigint, z: bigint, t: bigint): ExtendedPointType;
|
|
@@ -79,11 +93,14 @@ export interface PointType extends Group<PointType> {
|
|
|
79
93
|
toRawBytes(isCompressed?: boolean): Uint8Array;
|
|
80
94
|
toHex(isCompressed?: boolean): string;
|
|
81
95
|
isTorsionFree(): boolean;
|
|
96
|
+
clearCofactor(): PointType;
|
|
82
97
|
}
|
|
83
98
|
export interface PointConstructor extends GroupConstructor<PointType> {
|
|
84
99
|
new (x: bigint, y: bigint): PointType;
|
|
85
100
|
fromHex(hex: Hex): PointType;
|
|
86
101
|
fromPrivateKey(privateKey: PrivKey): PointType;
|
|
102
|
+
hashToCurve(msg: Hex, options?: Partial<htfOpts>): PointType;
|
|
103
|
+
encodeToCurve(msg: Hex, options?: Partial<htfOpts>): PointType;
|
|
87
104
|
}
|
|
88
105
|
export declare type PubKey = Hex | PointType;
|
|
89
106
|
export declare type SigType = Hex | SignatureType;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
3
|
-
//
|
|
3
|
+
// Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.twistedEdwards = void 0;
|
|
6
6
|
// Differences from @noble/ed25519 1.7:
|
|
@@ -13,6 +13,7 @@ exports.twistedEdwards = void 0;
|
|
|
13
13
|
const mod = require("./modular.js");
|
|
14
14
|
const utils_js_1 = require("./utils.js"); // TODO: import * as u from './utils.js'?
|
|
15
15
|
const group_js_1 = require("./group.js");
|
|
16
|
+
const hash_to_curve_js_1 = require("./hash-to-curve.js");
|
|
16
17
|
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
|
|
17
18
|
const _0n = BigInt(0);
|
|
18
19
|
const _1n = BigInt(1);
|
|
@@ -31,12 +32,20 @@ function validateOpts(curve) {
|
|
|
31
32
|
if (typeof opts[fn] !== 'function')
|
|
32
33
|
throw new Error(`Invalid ${fn} function`);
|
|
33
34
|
}
|
|
34
|
-
for (const fn of [
|
|
35
|
+
for (const fn of [
|
|
36
|
+
'adjustScalarBytes',
|
|
37
|
+
'domain',
|
|
38
|
+
'uvRatio',
|
|
39
|
+
'mapToCurve',
|
|
40
|
+
'clearCofactor',
|
|
41
|
+
]) {
|
|
35
42
|
if (opts[fn] === undefined)
|
|
36
43
|
continue; // Optional
|
|
37
44
|
if (typeof opts[fn] !== 'function')
|
|
38
45
|
throw new Error(`Invalid ${fn} function`);
|
|
39
46
|
}
|
|
47
|
+
if (opts.htfDefaults !== undefined)
|
|
48
|
+
(0, hash_to_curve_js_1.validateHTFOpts)(opts.htfDefaults);
|
|
40
49
|
// Set defaults
|
|
41
50
|
return Object.freeze({ ...opts });
|
|
42
51
|
}
|
|
@@ -156,7 +165,7 @@ function twistedEdwards(curveDef) {
|
|
|
156
165
|
const B = modP((Y1 + X1) * (Y2 - X2));
|
|
157
166
|
const F = modP(B - A);
|
|
158
167
|
if (F === _0n)
|
|
159
|
-
return this.double(); // Same point.
|
|
168
|
+
return this.double(); // Same point. Tests say it doesn't affect timing
|
|
160
169
|
const C = modP(Z1 * _2n * T2);
|
|
161
170
|
const D = modP(T1 * _2n * Z2);
|
|
162
171
|
const E = D + C;
|
|
@@ -173,7 +182,6 @@ function twistedEdwards(curveDef) {
|
|
|
173
182
|
const C = modP(T1 * d * T2); // C = T1*d*T2
|
|
174
183
|
const D = modP(Z1 * Z2); // D = Z1*Z2
|
|
175
184
|
const E = modP((X1 + Y1) * (X2 + Y2) - A - B); // E = (X1+Y1)*(X2+Y2)-A-B
|
|
176
|
-
// TODO: do we need to check for same point here? Looks like working without it
|
|
177
185
|
const F = D - C; // F = D-C
|
|
178
186
|
const G = D + C; // G = D+C
|
|
179
187
|
const H = modP(B - a * A); // H = B-a*A
|
|
@@ -247,6 +255,15 @@ function twistedEdwards(curveDef) {
|
|
|
247
255
|
throw new Error('invZ was invalid');
|
|
248
256
|
return new Point(ax, ay);
|
|
249
257
|
}
|
|
258
|
+
clearCofactor() {
|
|
259
|
+
if (CURVE.h === _1n)
|
|
260
|
+
return this; // Fast-path
|
|
261
|
+
// clear_cofactor(P) := h_eff * P
|
|
262
|
+
// hEff = h for ed25519/ed448. Maybe worth moving to params?
|
|
263
|
+
if (CURVE.clearCofactor)
|
|
264
|
+
return CURVE.clearCofactor(ExtendedPoint, this);
|
|
265
|
+
return this.multiplyUnsafe(CURVE.h);
|
|
266
|
+
}
|
|
250
267
|
}
|
|
251
268
|
ExtendedPoint.BASE = new ExtendedPoint(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
|
|
252
269
|
ExtendedPoint.ZERO = new ExtendedPoint(_0n, _1n, _1n, _0n);
|
|
@@ -355,6 +372,30 @@ function twistedEdwards(curveDef) {
|
|
|
355
372
|
multiply(scalar) {
|
|
356
373
|
return ExtendedPoint.fromAffine(this).multiply(scalar, this).toAffine();
|
|
357
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();
|
|
398
|
+
}
|
|
358
399
|
}
|
|
359
400
|
// Base point aka generator
|
|
360
401
|
// public_key = Point.BASE * private_key
|
|
@@ -22,8 +22,9 @@ export declare function wNAF<T extends Group<T>>(c: GroupConstructor<T>, bits: n
|
|
|
22
22
|
precomputeWindow(elm: T, W: number): Group<T>[];
|
|
23
23
|
/**
|
|
24
24
|
* Implements w-ary non-adjacent form for calculating ec multiplication.
|
|
25
|
-
* @param
|
|
25
|
+
* @param W window size
|
|
26
26
|
* @param affinePoint optional 2d point to save cached precompute windows on it.
|
|
27
|
+
* @param n bits
|
|
27
28
|
* @returns real and fake (for const-time) points
|
|
28
29
|
*/
|
|
29
30
|
wNAF(W: number, precomputes: T[], n: bigint): {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.wNAF = void 0;
|
|
4
|
-
/*!
|
|
5
|
-
//
|
|
4
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
5
|
+
// Abelian group utilities
|
|
6
6
|
const _0n = BigInt(0);
|
|
7
7
|
const _1n = BigInt(1);
|
|
8
8
|
// Not big, but pretty complex and it is easy to break stuff. To avoid too much copy paste
|
|
@@ -55,8 +55,9 @@ function wNAF(c, bits) {
|
|
|
55
55
|
},
|
|
56
56
|
/**
|
|
57
57
|
* Implements w-ary non-adjacent form for calculating ec multiplication.
|
|
58
|
-
* @param
|
|
58
|
+
* @param W window size
|
|
59
59
|
* @param affinePoint optional 2d point to save cached precompute windows on it.
|
|
60
|
+
* @param n bits
|
|
60
61
|
* @returns real and fake (for const-time) points
|
|
61
62
|
*/
|
|
62
63
|
wNAF(W, precomputes, n) {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
+
import { CHash } from './utils.js';
|
|
3
|
+
import * as mod from './modular.js';
|
|
4
|
+
export declare type htfOpts = {
|
|
5
|
+
DST: string;
|
|
6
|
+
p: bigint;
|
|
7
|
+
m: number;
|
|
8
|
+
k: number;
|
|
9
|
+
expand?: 'xmd' | 'xof';
|
|
10
|
+
hash: CHash;
|
|
11
|
+
};
|
|
12
|
+
export declare function validateHTFOpts(opts: htfOpts): void;
|
|
13
|
+
export declare function stringToBytes(str: string): Uint8Array;
|
|
14
|
+
export declare function expand_message_xmd(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, H: CHash): Uint8Array;
|
|
15
|
+
export declare function expand_message_xof(msg: Uint8Array, DST: Uint8Array, lenInBytes: number, k: number, H: CHash): Uint8Array;
|
|
16
|
+
/**
|
|
17
|
+
* Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
|
|
18
|
+
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
|
19
|
+
* @param msg a byte string containing the message to hash
|
|
20
|
+
* @param count the number of elements of F to output
|
|
21
|
+
* @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`
|
|
22
|
+
* @returns [u_0, ..., u_(count - 1)], a list of field elements.
|
|
23
|
+
*/
|
|
24
|
+
export declare function hash_to_field(msg: Uint8Array, count: number, options: htfOpts): bigint[][];
|
|
25
|
+
export declare function isogenyMap<T, F extends mod.Field<T>>(field: F, map: [T[], T[], T[], T[]]): (x: T, y: T) => {
|
|
26
|
+
x: T;
|
|
27
|
+
y: T;
|
|
28
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.hash_to_field = exports.expand_message_xmd = exports.stringToBytes = exports.validateHTFOpts = void 0;
|
|
3
|
+
exports.isogenyMap = exports.hash_to_field = exports.expand_message_xof = exports.expand_message_xmd = exports.stringToBytes = exports.validateHTFOpts = void 0;
|
|
4
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
4
5
|
const utils_js_1 = require("./utils.js");
|
|
5
6
|
const mod = require("./modular.js");
|
|
6
7
|
function validateHTFOpts(opts) {
|
|
@@ -12,13 +13,14 @@ function validateHTFOpts(opts) {
|
|
|
12
13
|
throw new Error('Invalid htf/m');
|
|
13
14
|
if (typeof opts.k !== 'number')
|
|
14
15
|
throw new Error('Invalid htf/k');
|
|
15
|
-
if (
|
|
16
|
+
if (opts.expand !== 'xmd' && opts.expand !== 'xof' && opts.expand !== undefined)
|
|
16
17
|
throw new Error('Invalid htf/expand');
|
|
17
18
|
if (typeof opts.hash !== 'function' || !Number.isSafeInteger(opts.hash.outputLen))
|
|
18
19
|
throw new Error('Invalid htf/hash function');
|
|
19
20
|
}
|
|
20
21
|
exports.validateHTFOpts = validateHTFOpts;
|
|
21
22
|
// UTF8 to ui8a
|
|
23
|
+
// TODO: looks broken, ASCII only, why not TextEncoder/TextDecoder? it is in hashes anyway
|
|
22
24
|
function stringToBytes(str) {
|
|
23
25
|
const bytes = new Uint8Array(str.length);
|
|
24
26
|
for (let i = 0; i < str.length; i++)
|
|
@@ -61,7 +63,7 @@ function expand_message_xmd(msg, DST, lenInBytes, H) {
|
|
|
61
63
|
if (DST.length > 255)
|
|
62
64
|
DST = H((0, utils_js_1.concatBytes)(stringToBytes('H2C-OVERSIZE-DST-'), DST));
|
|
63
65
|
const b_in_bytes = H.outputLen;
|
|
64
|
-
const r_in_bytes =
|
|
66
|
+
const r_in_bytes = H.blockLen;
|
|
65
67
|
const ell = Math.ceil(lenInBytes / b_in_bytes);
|
|
66
68
|
if (ell > 255)
|
|
67
69
|
throw new Error('Invalid xmd length');
|
|
@@ -79,13 +81,32 @@ function expand_message_xmd(msg, DST, lenInBytes, H) {
|
|
|
79
81
|
return pseudo_random_bytes.slice(0, lenInBytes);
|
|
80
82
|
}
|
|
81
83
|
exports.expand_message_xmd = expand_message_xmd;
|
|
82
|
-
|
|
83
|
-
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
function expand_message_xof(msg, DST, lenInBytes, k, H) {
|
|
85
|
+
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-5.3.3
|
|
86
|
+
// DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8));
|
|
87
|
+
if (DST.length > 255) {
|
|
88
|
+
const dkLen = Math.ceil((2 * k) / 8);
|
|
89
|
+
DST = H.create({ dkLen }).update(stringToBytes('H2C-OVERSIZE-DST-')).update(DST).digest();
|
|
90
|
+
}
|
|
91
|
+
if (lenInBytes > 65535 || DST.length > 255)
|
|
92
|
+
throw new Error('expand_message_xof: invalid lenInBytes');
|
|
93
|
+
return (H.create({ dkLen: lenInBytes })
|
|
94
|
+
.update(msg)
|
|
95
|
+
.update(i2osp(lenInBytes, 2))
|
|
96
|
+
// 2. DST_prime = DST || I2OSP(len(DST), 1)
|
|
97
|
+
.update(DST)
|
|
98
|
+
.update(i2osp(DST.length, 1))
|
|
99
|
+
.digest());
|
|
100
|
+
}
|
|
101
|
+
exports.expand_message_xof = expand_message_xof;
|
|
102
|
+
/**
|
|
103
|
+
* Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
|
|
104
|
+
* https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
|
105
|
+
* @param msg a byte string containing the message to hash
|
|
106
|
+
* @param count the number of elements of F to output
|
|
107
|
+
* @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`
|
|
108
|
+
* @returns [u_0, ..., u_(count - 1)], a list of field elements.
|
|
109
|
+
*/
|
|
89
110
|
function hash_to_field(msg, count, options) {
|
|
90
111
|
// if options is provided but incomplete, fill any missing fields with the
|
|
91
112
|
// value in hftDefaults (ie hash to G2).
|
|
@@ -94,9 +115,12 @@ function hash_to_field(msg, count, options) {
|
|
|
94
115
|
const len_in_bytes = count * options.m * L;
|
|
95
116
|
const DST = stringToBytes(options.DST);
|
|
96
117
|
let pseudo_random_bytes = msg;
|
|
97
|
-
if (options.expand) {
|
|
118
|
+
if (options.expand === 'xmd') {
|
|
98
119
|
pseudo_random_bytes = expand_message_xmd(msg, DST, len_in_bytes, options.hash);
|
|
99
120
|
}
|
|
121
|
+
else if (options.expand === 'xof') {
|
|
122
|
+
pseudo_random_bytes = expand_message_xof(msg, DST, len_in_bytes, options.k, options.hash);
|
|
123
|
+
}
|
|
100
124
|
const u = new Array(count);
|
|
101
125
|
for (let i = 0; i < count; i++) {
|
|
102
126
|
const e = new Array(options.m);
|
|
@@ -110,3 +134,14 @@ function hash_to_field(msg, count, options) {
|
|
|
110
134
|
return u;
|
|
111
135
|
}
|
|
112
136
|
exports.hash_to_field = hash_to_field;
|
|
137
|
+
function isogenyMap(field, map) {
|
|
138
|
+
// Make same order as in spec
|
|
139
|
+
const COEFF = map.map((i) => Array.from(i).reverse());
|
|
140
|
+
return (x, y) => {
|
|
141
|
+
const [xNum, xDen, yNum, yDen] = COEFF.map((val) => val.reduce((acc, i) => field.add(field.mul(acc, x), i)));
|
|
142
|
+
x = field.div(xNum, xDen); // xNum / xDen
|
|
143
|
+
y = field.mul(y, field.div(yNum, yDen)); // y * (yNum / yDev)
|
|
144
|
+
return { x, y };
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
exports.isogenyMap = isogenyMap;
|
|
@@ -8,17 +8,8 @@ export declare function mod(a: bigint, b: bigint): bigint;
|
|
|
8
8
|
export declare function pow(num: bigint, power: bigint, modulo: bigint): bigint;
|
|
9
9
|
export declare function pow2(x: bigint, power: bigint, modulo: bigint): bigint;
|
|
10
10
|
export declare function invert(number: bigint, modulo: bigint): bigint;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* * (a | p) ≡ 1 if a is a square (mod p)
|
|
14
|
-
* * (a | p) ≡ -1 if a is not a square (mod p)
|
|
15
|
-
* * (a | p) ≡ 0 if a ≡ 0 (mod p)
|
|
16
|
-
*/
|
|
17
|
-
export declare function legendre(num: bigint, fieldPrime: bigint): bigint;
|
|
18
|
-
/**
|
|
19
|
-
* Calculates square root of a number in a finite field.
|
|
20
|
-
*/
|
|
21
|
-
export declare function sqrt(number: bigint, modulo: bigint): bigint;
|
|
11
|
+
export declare function tonelliShanks(P: bigint): <T>(Fp: Field<T>, n: T) => T;
|
|
12
|
+
export declare function FpSqrt(P: bigint): <T>(Fp: Field<T>, n: T) => T;
|
|
22
13
|
export declare const isNegativeLE: (num: bigint, modulo: bigint) => boolean;
|
|
23
14
|
export interface Field<T> {
|
|
24
15
|
ORDER: bigint;
|
|
@@ -36,13 +27,13 @@ export interface Field<T> {
|
|
|
36
27
|
square(num: T): T;
|
|
37
28
|
equals(lhs: T, rhs: T): boolean;
|
|
38
29
|
add(lhs: T, rhs: T): T;
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
sub(lhs: T, rhs: T): T;
|
|
31
|
+
mul(lhs: T, rhs: T | bigint): T;
|
|
41
32
|
pow(lhs: T, power: bigint): T;
|
|
42
33
|
div(lhs: T, rhs: T | bigint): T;
|
|
43
34
|
addN(lhs: T, rhs: T): T;
|
|
44
|
-
|
|
45
|
-
|
|
35
|
+
subN(lhs: T, rhs: T): T;
|
|
36
|
+
mulN(lhs: T, rhs: T | bigint): T;
|
|
46
37
|
squareN(num: T): T;
|
|
47
38
|
isOdd?(num: T): boolean;
|
|
48
39
|
legendre?(num: T): T;
|
|
@@ -50,9 +41,15 @@ export interface Field<T> {
|
|
|
50
41
|
invertBatch: (lst: T[]) => T[];
|
|
51
42
|
toBytes(num: T): Uint8Array;
|
|
52
43
|
fromBytes(bytes: Uint8Array): T;
|
|
44
|
+
cmov(a: T, b: T, c: boolean): T;
|
|
53
45
|
}
|
|
54
46
|
export declare function validateField<T>(field: Field<T>): void;
|
|
55
47
|
export declare function FpPow<T>(f: Field<T>, num: T, power: bigint): T;
|
|
56
48
|
export declare function FpInvertBatch<T>(f: Field<T>, nums: T[]): T[];
|
|
57
49
|
export declare function FpDiv<T>(f: Field<T>, lhs: T, rhs: T | bigint): T;
|
|
58
|
-
export declare function
|
|
50
|
+
export declare function FpIsSquare<T>(f: Field<T>): (x: T) => boolean;
|
|
51
|
+
declare type FpField = Field<bigint> & Required<Pick<Field<bigint>, 'isOdd'>>;
|
|
52
|
+
export declare function Fp(ORDER: bigint, bitLen?: number, isLE?: boolean, redef?: Partial<Field<bigint>>): Readonly<FpField>;
|
|
53
|
+
export declare function FpSqrtOdd<T>(Fp: Field<T>, elm: T): T;
|
|
54
|
+
export declare function FpSqrtEven<T>(Fp: Field<T>, elm: T): T;
|
|
55
|
+
export {};
|