@noble/curves 0.4.0 → 0.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 +203 -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/{hashToCurve.d.ts → abstract/hash-to-curve.d.ts} +6 -0
- package/lib/{hashToCurve.js → abstract/hash-to-curve.js} +15 -2
- package/lib/{modular.d.ts → abstract/modular.d.ts} +10 -4
- package/lib/{modular.js → abstract/modular.js} +110 -19
- 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} +1 -1
- 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 +322 -0
- package/lib/ed448.d.ts +3 -0
- package/lib/ed448.js +128 -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} +13 -1
- package/lib/esm/{modular.js → abstract/modular.js} +108 -18
- 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 +318 -0
- package/lib/esm/ed448.js +125 -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 +290 -0
- package/lib/esm/stark.js +222 -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 +294 -0
- package/lib/stark.d.ts +72 -0
- package/lib/stark.js +243 -0
- package/package.json +146 -50
- package/index.js +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
-
//
|
|
2
|
+
// Twisted Edwards curve. The formula is: ax² + y² = 1 + dx²y²
|
|
3
3
|
// Differences from @noble/ed25519 1.7:
|
|
4
4
|
// 1. Different field element lengths in ed448:
|
|
5
5
|
// EDDSA (RFC8032) is 456 bits / 57 bytes, ECDH (RFC7748) is 448 bits / 56 bytes
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import * as mod from './modular.js';
|
|
11
11
|
import { bytesToHex, concatBytes, ensureBytes, numberToBytesLE, bytesToNumberLE, hashToPrivateScalar, validateOpts as utilOpts, } from './utils.js'; // TODO: import * as u from './utils.js'?
|
|
12
12
|
import { wNAF } from './group.js';
|
|
13
|
+
import { hash_to_field, validateHTFOpts } from './hash-to-curve.js';
|
|
13
14
|
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
|
|
14
15
|
const _0n = BigInt(0);
|
|
15
16
|
const _1n = BigInt(1);
|
|
@@ -28,12 +29,20 @@ function validateOpts(curve) {
|
|
|
28
29
|
if (typeof opts[fn] !== 'function')
|
|
29
30
|
throw new Error(`Invalid ${fn} function`);
|
|
30
31
|
}
|
|
31
|
-
for (const fn of [
|
|
32
|
+
for (const fn of [
|
|
33
|
+
'adjustScalarBytes',
|
|
34
|
+
'domain',
|
|
35
|
+
'uvRatio',
|
|
36
|
+
'mapToCurve',
|
|
37
|
+
'clearCofactor',
|
|
38
|
+
]) {
|
|
32
39
|
if (opts[fn] === undefined)
|
|
33
40
|
continue; // Optional
|
|
34
41
|
if (typeof opts[fn] !== 'function')
|
|
35
42
|
throw new Error(`Invalid ${fn} function`);
|
|
36
43
|
}
|
|
44
|
+
if (opts.htfDefaults !== undefined)
|
|
45
|
+
validateHTFOpts(opts.htfDefaults);
|
|
37
46
|
// Set defaults
|
|
38
47
|
return Object.freeze({ ...opts });
|
|
39
48
|
}
|
|
@@ -153,7 +162,7 @@ export function twistedEdwards(curveDef) {
|
|
|
153
162
|
const B = modP((Y1 + X1) * (Y2 - X2));
|
|
154
163
|
const F = modP(B - A);
|
|
155
164
|
if (F === _0n)
|
|
156
|
-
return this.double(); // Same point.
|
|
165
|
+
return this.double(); // Same point. Tests say it doesn't affect timing
|
|
157
166
|
const C = modP(Z1 * _2n * T2);
|
|
158
167
|
const D = modP(T1 * _2n * Z2);
|
|
159
168
|
const E = D + C;
|
|
@@ -170,7 +179,6 @@ export function twistedEdwards(curveDef) {
|
|
|
170
179
|
const C = modP(T1 * d * T2); // C = T1*d*T2
|
|
171
180
|
const D = modP(Z1 * Z2); // D = Z1*Z2
|
|
172
181
|
const E = modP((X1 + Y1) * (X2 + Y2) - A - B); // E = (X1+Y1)*(X2+Y2)-A-B
|
|
173
|
-
// TODO: do we need to check for same point here? Looks like working without it
|
|
174
182
|
const F = D - C; // F = D-C
|
|
175
183
|
const G = D + C; // G = D+C
|
|
176
184
|
const H = modP(B - a * A); // H = B-a*A
|
|
@@ -244,6 +252,15 @@ export function twistedEdwards(curveDef) {
|
|
|
244
252
|
throw new Error('invZ was invalid');
|
|
245
253
|
return new Point(ax, ay);
|
|
246
254
|
}
|
|
255
|
+
clearCofactor() {
|
|
256
|
+
if (CURVE.h === _1n)
|
|
257
|
+
return this; // Fast-path
|
|
258
|
+
// clear_cofactor(P) := h_eff * P
|
|
259
|
+
// hEff = h for ed25519/ed448. Maybe worth moving to params?
|
|
260
|
+
if (CURVE.clearCofactor)
|
|
261
|
+
return CURVE.clearCofactor(ExtendedPoint, this);
|
|
262
|
+
return this.multiplyUnsafe(CURVE.h);
|
|
263
|
+
}
|
|
247
264
|
}
|
|
248
265
|
ExtendedPoint.BASE = new ExtendedPoint(CURVE.Gx, CURVE.Gy, _1n, modP(CURVE.Gx * CURVE.Gy));
|
|
249
266
|
ExtendedPoint.ZERO = new ExtendedPoint(_0n, _1n, _1n, _0n);
|
|
@@ -352,6 +369,30 @@ export function twistedEdwards(curveDef) {
|
|
|
352
369
|
multiply(scalar) {
|
|
353
370
|
return ExtendedPoint.fromAffine(this).multiply(scalar, this).toAffine();
|
|
354
371
|
}
|
|
372
|
+
clearCofactor() {
|
|
373
|
+
return ExtendedPoint.fromAffine(this).clearCofactor().toAffine();
|
|
374
|
+
}
|
|
375
|
+
// Encodes byte string to elliptic curve
|
|
376
|
+
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
|
|
377
|
+
static hashToCurve(msg, options) {
|
|
378
|
+
if (!CURVE.mapToCurve)
|
|
379
|
+
throw new Error('No mapToCurve defined for curve');
|
|
380
|
+
msg = ensureBytes(msg);
|
|
381
|
+
const u = hash_to_field(msg, 2, { ...CURVE.htfDefaults, ...options });
|
|
382
|
+
const { x: x0, y: y0 } = CURVE.mapToCurve(u[0]);
|
|
383
|
+
const { x: x1, y: y1 } = CURVE.mapToCurve(u[1]);
|
|
384
|
+
const p = new Point(x0, y0).add(new Point(x1, y1)).clearCofactor();
|
|
385
|
+
return p;
|
|
386
|
+
}
|
|
387
|
+
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
|
|
388
|
+
static encodeToCurve(msg, options) {
|
|
389
|
+
if (!CURVE.mapToCurve)
|
|
390
|
+
throw new Error('No mapToCurve defined for curve');
|
|
391
|
+
msg = ensureBytes(msg);
|
|
392
|
+
const u = hash_to_field(msg, 1, { ...CURVE.htfDefaults, ...options });
|
|
393
|
+
const { x, y } = CURVE.mapToCurve(u[0]);
|
|
394
|
+
return new Point(x, y).clearCofactor();
|
|
395
|
+
}
|
|
355
396
|
}
|
|
356
397
|
// Base point aka generator
|
|
357
398
|
// public_key = Point.BASE * private_key
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
//
|
|
1
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
+
// Abelian group utilities
|
|
3
3
|
const _0n = BigInt(0);
|
|
4
4
|
const _1n = BigInt(1);
|
|
5
5
|
// Not big, but pretty complex and it is easy to break stuff. To avoid too much copy paste
|
|
@@ -52,8 +52,9 @@ export function wNAF(c, bits) {
|
|
|
52
52
|
},
|
|
53
53
|
/**
|
|
54
54
|
* Implements w-ary non-adjacent form for calculating ec multiplication.
|
|
55
|
-
* @param
|
|
55
|
+
* @param W window size
|
|
56
56
|
* @param affinePoint optional 2d point to save cached precompute windows on it.
|
|
57
|
+
* @param n bits
|
|
57
58
|
* @returns real and fake (for const-time) points
|
|
58
59
|
*/
|
|
59
60
|
wNAF(W, precomputes, n) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
1
2
|
import { concatBytes } from './utils.js';
|
|
2
3
|
import * as mod from './modular.js';
|
|
3
4
|
export function validateHTFOpts(opts) {
|
|
@@ -15,6 +16,7 @@ export function validateHTFOpts(opts) {
|
|
|
15
16
|
throw new Error('Invalid htf/hash function');
|
|
16
17
|
}
|
|
17
18
|
// UTF8 to ui8a
|
|
19
|
+
// TODO: looks broken, ASCII only, why not TextEncoder/TextDecoder? it is in hashes anyway
|
|
18
20
|
export function stringToBytes(str) {
|
|
19
21
|
const bytes = new Uint8Array(str.length);
|
|
20
22
|
for (let i = 0; i < str.length; i++)
|
|
@@ -56,7 +58,7 @@ export function expand_message_xmd(msg, DST, lenInBytes, H) {
|
|
|
56
58
|
if (DST.length > 255)
|
|
57
59
|
DST = H(concatBytes(stringToBytes('H2C-OVERSIZE-DST-'), DST));
|
|
58
60
|
const b_in_bytes = H.outputLen;
|
|
59
|
-
const r_in_bytes =
|
|
61
|
+
const r_in_bytes = H.blockLen;
|
|
60
62
|
const ell = Math.ceil(lenInBytes / b_in_bytes);
|
|
61
63
|
if (ell > 255)
|
|
62
64
|
throw new Error('Invalid xmd length');
|
|
@@ -103,3 +105,13 @@ export function hash_to_field(msg, count, options) {
|
|
|
103
105
|
}
|
|
104
106
|
return u;
|
|
105
107
|
}
|
|
108
|
+
export function isogenyMap(field, map) {
|
|
109
|
+
// Make same order as in spec
|
|
110
|
+
const COEFF = map.map((i) => Array.from(i).reverse());
|
|
111
|
+
return (x, y) => {
|
|
112
|
+
const [xNum, xDen, yNum, yDen] = COEFF.map((val) => val.reduce((acc, i) => field.add(field.mul(acc, x), i)));
|
|
113
|
+
x = field.div(xNum, xDen); // xNum / xDen
|
|
114
|
+
y = field.mul(y, field.div(yNum, yDen)); // y * (yNum / yDev)
|
|
115
|
+
return { x, y };
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
/*!
|
|
1
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
2
|
import * as utils from './utils.js';
|
|
3
|
-
// Utilities for modular arithmetics
|
|
4
|
-
|
|
5
|
-
const _1n = BigInt(1);
|
|
6
|
-
|
|
3
|
+
// Utilities for modular arithmetics and finite fields
|
|
4
|
+
// prettier-ignore
|
|
5
|
+
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
|
|
6
|
+
// prettier-ignore
|
|
7
|
+
const _4n = BigInt(4), _5n = BigInt(5), _7n = BigInt(7), _8n = BigInt(8);
|
|
8
|
+
// prettier-ignore
|
|
9
|
+
const _9n = BigInt(9), _16n = BigInt(16);
|
|
7
10
|
// Calculates a modulo b
|
|
8
11
|
export function mod(a, b) {
|
|
9
12
|
const result = a % b;
|
|
@@ -74,16 +77,16 @@ export function legendre(num, fieldPrime) {
|
|
|
74
77
|
}
|
|
75
78
|
/**
|
|
76
79
|
* Calculates square root of a number in a finite field.
|
|
80
|
+
* √a mod P
|
|
77
81
|
*/
|
|
78
82
|
// TODO: rewrite as generic Fp function && remove bls versions
|
|
79
83
|
export function sqrt(number, modulo) {
|
|
80
84
|
// prettier-ignore
|
|
81
|
-
const _3n = BigInt(3), _4n = BigInt(4), _5n = BigInt(5), _8n = BigInt(8);
|
|
82
85
|
const n = number;
|
|
83
86
|
const P = modulo;
|
|
84
87
|
const p1div4 = (P + _1n) / _4n;
|
|
85
88
|
// P ≡ 3 (mod 4)
|
|
86
|
-
//
|
|
89
|
+
// √n = n^((P+1)/4)
|
|
87
90
|
if (P % _4n === _3n) {
|
|
88
91
|
// Not all roots possible!
|
|
89
92
|
// const ORDER =
|
|
@@ -139,8 +142,8 @@ export const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n) === _1n;
|
|
|
139
142
|
// prettier-ignore
|
|
140
143
|
const FIELD_FIELDS = [
|
|
141
144
|
'create', 'isValid', 'isZero', 'negate', 'invert', 'sqrt', 'square',
|
|
142
|
-
'equals', 'add', '
|
|
143
|
-
'addN', '
|
|
145
|
+
'equals', 'add', 'sub', 'mul', 'pow', 'div',
|
|
146
|
+
'addN', 'subN', 'mulN', 'squareN'
|
|
144
147
|
];
|
|
145
148
|
export function validateField(field) {
|
|
146
149
|
for (const i of ['ORDER', 'MASK']) {
|
|
@@ -170,7 +173,7 @@ export function FpPow(f, num, power) {
|
|
|
170
173
|
let d = num;
|
|
171
174
|
while (power > _0n) {
|
|
172
175
|
if (power & _1n)
|
|
173
|
-
p = f.
|
|
176
|
+
p = f.mul(p, d);
|
|
174
177
|
d = f.square(d);
|
|
175
178
|
power >>= 1n;
|
|
176
179
|
}
|
|
@@ -183,7 +186,7 @@ export function FpInvertBatch(f, nums) {
|
|
|
183
186
|
if (f.isZero(num))
|
|
184
187
|
return acc;
|
|
185
188
|
tmp[i] = acc;
|
|
186
|
-
return f.
|
|
189
|
+
return f.mul(acc, num);
|
|
187
190
|
}, f.ONE);
|
|
188
191
|
// Invert last element
|
|
189
192
|
const inverted = f.invert(lastMultiplied);
|
|
@@ -191,13 +194,13 @@ export function FpInvertBatch(f, nums) {
|
|
|
191
194
|
nums.reduceRight((acc, num, i) => {
|
|
192
195
|
if (f.isZero(num))
|
|
193
196
|
return acc;
|
|
194
|
-
tmp[i] = f.
|
|
195
|
-
return f.
|
|
197
|
+
tmp[i] = f.mul(acc, tmp[i]);
|
|
198
|
+
return f.mul(acc, num);
|
|
196
199
|
}, inverted);
|
|
197
200
|
return tmp;
|
|
198
201
|
}
|
|
199
202
|
export function FpDiv(f, lhs, rhs) {
|
|
200
|
-
return f.
|
|
203
|
+
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.invert(rhs));
|
|
201
204
|
}
|
|
202
205
|
// NOTE: very fragile, always bench. Major performance points:
|
|
203
206
|
// - NonNormalized ops
|
|
@@ -229,18 +232,21 @@ export function Fp(ORDER, bitLen, isLE = false, redef = {}) {
|
|
|
229
232
|
equals: (lhs, rhs) => lhs === rhs,
|
|
230
233
|
square: (num) => mod(num * num, ORDER),
|
|
231
234
|
add: (lhs, rhs) => mod(lhs + rhs, ORDER),
|
|
232
|
-
|
|
233
|
-
|
|
235
|
+
sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
|
|
236
|
+
mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
|
|
234
237
|
pow: (num, power) => FpPow(f, num, power),
|
|
235
238
|
div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
|
|
236
239
|
// Same as above, but doesn't normalize
|
|
237
240
|
squareN: (num) => num * num,
|
|
238
241
|
addN: (lhs, rhs) => lhs + rhs,
|
|
239
|
-
|
|
240
|
-
|
|
242
|
+
subN: (lhs, rhs) => lhs - rhs,
|
|
243
|
+
mulN: (lhs, rhs) => lhs * rhs,
|
|
241
244
|
invert: (num) => invert(num, ORDER),
|
|
242
245
|
sqrt: redef.sqrt || sqrtP,
|
|
243
246
|
invertBatch: (lst) => FpInvertBatch(f, lst),
|
|
247
|
+
// TODO: do we really need constant cmov?
|
|
248
|
+
// We don't have const-time bigints anyway, so probably will be not very useful
|
|
249
|
+
cmov: (a, b, c) => (c ? b : a),
|
|
244
250
|
toBytes: (num) => isLE ? utils.numberToBytesLE(num, BYTES) : utils.numberToBytesBE(num, BYTES),
|
|
245
251
|
fromBytes: (bytes) => {
|
|
246
252
|
if (bytes.length !== BYTES)
|
|
@@ -250,3 +256,87 @@ export function Fp(ORDER, bitLen, isLE = false, redef = {}) {
|
|
|
250
256
|
});
|
|
251
257
|
return Object.freeze(f);
|
|
252
258
|
}
|
|
259
|
+
// TODO: re-use in bls/generic sqrt for field/etc?
|
|
260
|
+
// Something like sqrtUnsafe which always returns value, but sqrt throws exception if non-square
|
|
261
|
+
// From draft-irtf-cfrg-hash-to-curve-16
|
|
262
|
+
export function FpSqrt(Fp) {
|
|
263
|
+
// NOTE: it requires another sqrt for constant precomputes, but no need for roots of unity,
|
|
264
|
+
// probably we can simply bls code using it
|
|
265
|
+
const q = Fp.ORDER;
|
|
266
|
+
const squareConst = (q - _1n) / _2n;
|
|
267
|
+
// is_square(x) := { True, if x^((q - 1) / 2) is 0 or 1 in F;
|
|
268
|
+
// { False, otherwise.
|
|
269
|
+
let isSquare = (x) => {
|
|
270
|
+
const p = Fp.pow(x, squareConst);
|
|
271
|
+
return Fp.equals(p, Fp.ZERO) || Fp.equals(p, Fp.ONE);
|
|
272
|
+
};
|
|
273
|
+
// Constant-time Tonelli-Shanks algorithm
|
|
274
|
+
let l = _0n;
|
|
275
|
+
for (let o = q - _1n; o % _2n === _0n; o /= _2n)
|
|
276
|
+
l += _1n;
|
|
277
|
+
const c1 = l; // 1. c1, the largest integer such that 2^c1 divides q - 1.
|
|
278
|
+
const c2 = (q - _1n) / _2n ** c1; // 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
|
|
279
|
+
const c3 = (c2 - _1n) / _2n; // 3. c3 = (c2 - 1) / 2 # Integer arithmetic
|
|
280
|
+
// 4. c4, a non-square value in F
|
|
281
|
+
// 5. c5 = c4^c2 in F
|
|
282
|
+
let c4 = Fp.ONE;
|
|
283
|
+
while (isSquare(c4))
|
|
284
|
+
c4 = Fp.add(c4, Fp.ONE);
|
|
285
|
+
const c5 = Fp.pow(c4, c2);
|
|
286
|
+
let sqrt = (x) => {
|
|
287
|
+
let z = Fp.pow(x, c3); // 1. z = x^c3
|
|
288
|
+
let t = Fp.square(z); // 2. t = z * z
|
|
289
|
+
t = Fp.mul(t, x); // 3. t = t * x
|
|
290
|
+
z = Fp.mul(z, x); // 4. z = z * x
|
|
291
|
+
let b = t; // 5. b = t
|
|
292
|
+
let c = c5; // 6. c = c5
|
|
293
|
+
// 7. for i in (c1, c1 - 1, ..., 2):
|
|
294
|
+
for (let i = c1; i > 1; i--) {
|
|
295
|
+
// 8. for j in (1, 2, ..., i - 2):
|
|
296
|
+
// 9. b = b * b
|
|
297
|
+
for (let j = _1n; j < i - _1n; i++)
|
|
298
|
+
b = Fp.square(b);
|
|
299
|
+
const e = Fp.equals(b, Fp.ONE); // 10. e = b == 1
|
|
300
|
+
const zt = Fp.mul(z, c); // 11. zt = z * c
|
|
301
|
+
z = Fp.cmov(zt, z, e); // 12. z = CMOV(zt, z, e)
|
|
302
|
+
c = Fp.square(c); // 13. c = c * c
|
|
303
|
+
let tt = Fp.mul(t, c); // 14. tt = t * c
|
|
304
|
+
t = Fp.cmov(tt, t, e); // 15. t = CMOV(tt, t, e)
|
|
305
|
+
b = t; // 16. b = t
|
|
306
|
+
}
|
|
307
|
+
return z; // 17. return z
|
|
308
|
+
};
|
|
309
|
+
if (q % _4n === _3n) {
|
|
310
|
+
const c1 = (q + _1n) / _4n; // 1. c1 = (q + 1) / 4 # Integer arithmetic
|
|
311
|
+
sqrt = (x) => Fp.pow(x, c1);
|
|
312
|
+
}
|
|
313
|
+
else if (q % _8n === _5n) {
|
|
314
|
+
const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
|
315
|
+
const c2 = (q + _3n) / _8n; // 2. c2 = (q + 3) / 8 # Integer arithmetic
|
|
316
|
+
sqrt = (x) => {
|
|
317
|
+
let tv1 = Fp.pow(x, c2); // 1. tv1 = x^c2
|
|
318
|
+
let tv2 = Fp.mul(tv1, c1); // 2. tv2 = tv1 * c1
|
|
319
|
+
let e = Fp.equals(Fp.square(tv1), x); // 3. e = (tv1^2) == x
|
|
320
|
+
return Fp.cmov(tv2, tv1, e); // 4. z = CMOV(tv2, tv1, e)
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
else if (Fp.ORDER % _16n === _9n) {
|
|
324
|
+
const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
|
325
|
+
const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
|
|
326
|
+
const c3 = Fp.sqrt(Fp.negate(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
|
|
327
|
+
const c4 = (Fp.ORDER + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
|
|
328
|
+
sqrt = (x) => {
|
|
329
|
+
let tv1 = Fp.pow(x, c4); // 1. tv1 = x^c4
|
|
330
|
+
let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1
|
|
331
|
+
const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1
|
|
332
|
+
let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1
|
|
333
|
+
const e1 = Fp.equals(Fp.square(tv2), x); // 5. e1 = (tv2^2) == x
|
|
334
|
+
const e2 = Fp.equals(Fp.square(tv3), x); // 6. e2 = (tv3^2) == x
|
|
335
|
+
tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
|
|
336
|
+
tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
|
|
337
|
+
const e3 = Fp.equals(Fp.square(tv2), x); // 9. e3 = (tv2^2) == x
|
|
338
|
+
return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
return { sqrt, isSquare };
|
|
342
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
1
2
|
import * as mod from './modular.js';
|
|
2
3
|
import { ensureBytes, numberToBytesLE, bytesToNumberLE,
|
|
3
4
|
// nLength,
|
|
@@ -161,8 +162,14 @@ export function montgomery(curveDef) {
|
|
|
161
162
|
throw new Error(`Expected ${montgomeryBytes} or ${fieldLen} bytes, got ${bytes.length}`);
|
|
162
163
|
return bytesToNumberLE(adjustScalarBytes(bytes));
|
|
163
164
|
}
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Computes shared secret between private key "scalar" and public key's "u" (x) coordinate.
|
|
167
|
+
* We can get 'y' coordinate from 'u',
|
|
168
|
+
* but Point.fromHex also wants 'x' coordinate oddity flag,
|
|
169
|
+
* and we cannot get 'x' without knowing 'v'.
|
|
170
|
+
* Need to add generic conversion between twisted edwards and complimentary curve for JubJub.
|
|
171
|
+
*/
|
|
172
|
+
function scalarMult(scalar, u) {
|
|
166
173
|
const pointU = decodeUCoordinate(u);
|
|
167
174
|
const _scalar = decodeScalar(scalar);
|
|
168
175
|
const pu = montgomeryLadder(pointU, _scalar);
|
|
@@ -172,17 +179,19 @@ export function montgomery(curveDef) {
|
|
|
172
179
|
throw new Error('Invalid private or public key received');
|
|
173
180
|
return encodeUCoordinate(pu);
|
|
174
181
|
}
|
|
175
|
-
|
|
182
|
+
/**
|
|
183
|
+
* Computes public key from private.
|
|
184
|
+
* Executes scalar multiplication of curve's base point by scalar.
|
|
185
|
+
* @param scalar private key
|
|
186
|
+
* @returns new public key
|
|
187
|
+
*/
|
|
176
188
|
function scalarMultBase(scalar) {
|
|
177
|
-
return scalarMult(CURVE.Gu
|
|
189
|
+
return scalarMult(scalar, CURVE.Gu);
|
|
178
190
|
}
|
|
179
191
|
return {
|
|
180
|
-
// NOTE: we can get 'y' coordinate from 'u', but Point.fromHex also wants 'x' coordinate oddity flag, and we cannot get 'x' without knowing 'v'
|
|
181
|
-
// Need to add generic conversion between twisted edwards and complimentary curve for JubJub
|
|
182
192
|
scalarMult,
|
|
183
193
|
scalarMultBase,
|
|
184
|
-
|
|
185
|
-
// getSharedSecret: (privateKey: Hex, publicKey: Hex) => scalarMult(publicKey, privateKey),
|
|
194
|
+
getSharedSecret: (privateKey, publicKey) => scalarMult(privateKey, publicKey),
|
|
186
195
|
getPublicKey: (privateKey) => scalarMultBase(privateKey),
|
|
187
196
|
Gu: CURVE.Gu,
|
|
188
197
|
};
|