@frequency-chain/ethereum-utils 1.17.2 → 1.17.3
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/browser/frequency-ethereum-utils.esm.min.js +812 -627
- package/browser/frequency-ethereum-utils.umd.min.js +811 -626
- package/cjs/signature.js +14 -0
- package/esm/signature.js +14 -0
- package/package.json +4 -4
- package/signature.d.ts +10 -0
|
@@ -3539,7 +3539,7 @@ const REGEX_HEX_NOPREFIX = /^[\da-fA-F]+$/;
|
|
|
3539
3539
|
function isHex(value, bitLength = -1, ignoreLength) {
|
|
3540
3540
|
return (typeof value === 'string' && (value === '0x' ||
|
|
3541
3541
|
REGEX_HEX_PREFIXED.test(value))) && (bitLength === -1
|
|
3542
|
-
? ((value.length % 2 === 0))
|
|
3542
|
+
? (ignoreLength || (value.length % 2 === 0))
|
|
3543
3543
|
: (value.length === (2 + Math.ceil(bitLength / 4))));
|
|
3544
3544
|
}/**
|
|
3545
3545
|
* @name isObject
|
|
@@ -7545,6 +7545,11 @@ var knownSubstrate = [
|
|
|
7545
7545
|
composable: [
|
|
7546
7546
|
'0xdaab8df776eb52ec604a5df5d388bb62a050a0aaec4556a64265b9d42755552d'
|
|
7547
7547
|
],
|
|
7548
|
+
creditcoin3: [
|
|
7549
|
+
'0x4436a7d64e363df85e065a894721002a86643283f9707338bf195d360ba2ee71', // cc3 mainnet
|
|
7550
|
+
'0xfc4ec97a1c1f119c4353aecb4a17c7c0cf7b40d5d660143d8bad9117e9866572', // cc3 testnet/drynet
|
|
7551
|
+
'0xfc9df99a665f964aed6649f275055e54df5e3420489538ed31d7788f53d11ef6' // cc3 devnet
|
|
7552
|
+
],
|
|
7548
7553
|
darwinia: [
|
|
7549
7554
|
'0xe71578b37a7c799b0ab4ee87ffa6f059a6b98f71f06fb8c84a8d88013a548ad6'
|
|
7550
7555
|
],
|
|
@@ -7713,6 +7718,7 @@ var knownSubstrate = [
|
|
|
7713
7718
|
bittensor: 0x00000162,
|
|
7714
7719
|
centrifuge: 0x000002eb,
|
|
7715
7720
|
composable: 0x00000162,
|
|
7721
|
+
creditcoin3: 0x00000162,
|
|
7716
7722
|
darwinia: 0x00000162,
|
|
7717
7723
|
'dock-mainnet': 0x00000252,
|
|
7718
7724
|
edgeware: 0x0000020b,
|
|
@@ -8024,10 +8030,28 @@ hmac$1.create = (hash, key) => new HMAC$1(hash, key);/**
|
|
|
8024
8030
|
*/
|
|
8025
8031
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
8026
8032
|
const _0n$9 = /* @__PURE__ */ BigInt(0);
|
|
8027
|
-
const _1n$
|
|
8028
|
-
|
|
8029
|
-
|
|
8030
|
-
|
|
8033
|
+
const _1n$a = /* @__PURE__ */ BigInt(1);
|
|
8034
|
+
// tmp name until v2
|
|
8035
|
+
function _abool2(value, title = '') {
|
|
8036
|
+
if (typeof value !== 'boolean') {
|
|
8037
|
+
const prefix = title && `"${title}"`;
|
|
8038
|
+
throw new Error(prefix + 'expected boolean, got type=' + typeof value);
|
|
8039
|
+
}
|
|
8040
|
+
return value;
|
|
8041
|
+
}
|
|
8042
|
+
// tmp name until v2
|
|
8043
|
+
/** Asserts something is Uint8Array. */
|
|
8044
|
+
function _abytes2(value, length, title = '') {
|
|
8045
|
+
const bytes = isBytes(value);
|
|
8046
|
+
const len = value?.length;
|
|
8047
|
+
const needsLen = length !== undefined;
|
|
8048
|
+
if (!bytes || (needsLen && len !== length)) {
|
|
8049
|
+
const prefix = title && `"${title}"`;
|
|
8050
|
+
const ofLen = needsLen ? ` of length ${length}` : '';
|
|
8051
|
+
const got = bytes ? `length=${len}` : `type=${typeof value}`;
|
|
8052
|
+
throw new Error(prefix + 'expected Uint8Array' + ofLen + ', got ' + got);
|
|
8053
|
+
}
|
|
8054
|
+
return value;
|
|
8031
8055
|
}
|
|
8032
8056
|
// Used in weierstrass, der
|
|
8033
8057
|
function numberToHexUnpadded$1(num) {
|
|
@@ -8057,7 +8081,7 @@ function numberToBytesLE$1(n, len) {
|
|
|
8057
8081
|
* Takes hex string or Uint8Array, converts to Uint8Array.
|
|
8058
8082
|
* Validates output length.
|
|
8059
8083
|
* Will throw error for other types.
|
|
8060
|
-
* @param title descriptive title for an error e.g. '
|
|
8084
|
+
* @param title descriptive title for an error e.g. 'secret key'
|
|
8061
8085
|
* @param hex hex string or Uint8Array
|
|
8062
8086
|
* @param expectedLength optional, will compare to result array's length
|
|
8063
8087
|
* @returns
|
|
@@ -8080,9 +8104,7 @@ function ensureBytes$1(title, hex, expectedLength) {
|
|
|
8080
8104
|
else {
|
|
8081
8105
|
throw new Error(title + ' must be hex string or Uint8Array');
|
|
8082
8106
|
}
|
|
8083
|
-
|
|
8084
|
-
if (typeof expectedLength === 'number' && len !== expectedLength)
|
|
8085
|
-
throw new Error(title + ' of length ' + expectedLength + ' expected, got ' + len);
|
|
8107
|
+
res.length;
|
|
8086
8108
|
return res;
|
|
8087
8109
|
}
|
|
8088
8110
|
/**
|
|
@@ -8121,7 +8143,7 @@ function aInRange(title, n, min, max) {
|
|
|
8121
8143
|
*/
|
|
8122
8144
|
function bitLen$1(n) {
|
|
8123
8145
|
let len;
|
|
8124
|
-
for (len = 0; n > _0n$9; n >>= _1n$
|
|
8146
|
+
for (len = 0; n > _0n$9; n >>= _1n$a, len += 1)
|
|
8125
8147
|
;
|
|
8126
8148
|
return len;
|
|
8127
8149
|
}
|
|
@@ -8129,7 +8151,7 @@ function bitLen$1(n) {
|
|
|
8129
8151
|
* Calculate mask for N bits. Not using ** operator with bigints because of old engines.
|
|
8130
8152
|
* Same as BigInt(`0b${Array(i).fill('1').join('')}`)
|
|
8131
8153
|
*/
|
|
8132
|
-
const bitMask$1 = (n) => (_1n$
|
|
8154
|
+
const bitMask$1 = (n) => (_1n$a << BigInt(n)) - _1n$a;
|
|
8133
8155
|
/**
|
|
8134
8156
|
* Minimal HMAC-DRBG from NIST 800-90 for RFC6979 sigs.
|
|
8135
8157
|
* @returns function that will call DRBG until 2nd arg returns something meaningful
|
|
@@ -8226,10 +8248,11 @@ function memoized(fn) {
|
|
|
8226
8248
|
*/
|
|
8227
8249
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
8228
8250
|
// prettier-ignore
|
|
8229
|
-
const _0n$8 = BigInt(0), _1n$
|
|
8251
|
+
const _0n$8 = BigInt(0), _1n$9 = BigInt(1), _2n$7 = /* @__PURE__ */ BigInt(2), _3n$3 = /* @__PURE__ */ BigInt(3);
|
|
8230
8252
|
// prettier-ignore
|
|
8231
|
-
const _4n$2 = /* @__PURE__ */ BigInt(4), _5n$1 = /* @__PURE__ */ BigInt(5);
|
|
8232
|
-
|
|
8253
|
+
const _4n$2 = /* @__PURE__ */ BigInt(4), _5n$1 = /* @__PURE__ */ BigInt(5), _7n$2 = /* @__PURE__ */ BigInt(7);
|
|
8254
|
+
// prettier-ignore
|
|
8255
|
+
const _8n$1 = /* @__PURE__ */ BigInt(8), _9n = /* @__PURE__ */ BigInt(9), _16n = /* @__PURE__ */ BigInt(16);
|
|
8233
8256
|
// Calculates a modulo b
|
|
8234
8257
|
function mod$1(a, b) {
|
|
8235
8258
|
const result = a % b;
|
|
@@ -8257,7 +8280,7 @@ function invert$1(number, modulo) {
|
|
|
8257
8280
|
let a = mod$1(number, modulo);
|
|
8258
8281
|
let b = modulo;
|
|
8259
8282
|
// prettier-ignore
|
|
8260
|
-
let x = _0n$8, u = _1n$
|
|
8283
|
+
let x = _0n$8, u = _1n$9;
|
|
8261
8284
|
while (a !== _0n$8) {
|
|
8262
8285
|
// JIT applies optimization if those two lines follow each other
|
|
8263
8286
|
const q = b / a;
|
|
@@ -8267,20 +8290,22 @@ function invert$1(number, modulo) {
|
|
|
8267
8290
|
b = a, a = r, x = u, u = m;
|
|
8268
8291
|
}
|
|
8269
8292
|
const gcd = b;
|
|
8270
|
-
if (gcd !== _1n$
|
|
8293
|
+
if (gcd !== _1n$9)
|
|
8271
8294
|
throw new Error('invert: does not exist');
|
|
8272
8295
|
return mod$1(x, modulo);
|
|
8273
8296
|
}
|
|
8297
|
+
function assertIsSquare(Fp, root, n) {
|
|
8298
|
+
if (!Fp.eql(Fp.sqr(root), n))
|
|
8299
|
+
throw new Error('Cannot find square root');
|
|
8300
|
+
}
|
|
8274
8301
|
// Not all roots are possible! Example which will throw:
|
|
8275
8302
|
// const NUM =
|
|
8276
8303
|
// n = 72057594037927816n;
|
|
8277
8304
|
// Fp = Field(BigInt('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'));
|
|
8278
8305
|
function sqrt3mod4(Fp, n) {
|
|
8279
|
-
const p1div4 = (Fp.ORDER + _1n$
|
|
8306
|
+
const p1div4 = (Fp.ORDER + _1n$9) / _4n$2;
|
|
8280
8307
|
const root = Fp.pow(n, p1div4);
|
|
8281
|
-
|
|
8282
|
-
if (!Fp.eql(Fp.sqr(root), n))
|
|
8283
|
-
throw new Error('Cannot find square root');
|
|
8308
|
+
assertIsSquare(Fp, root, n);
|
|
8284
8309
|
return root;
|
|
8285
8310
|
}
|
|
8286
8311
|
function sqrt5mod8(Fp, n) {
|
|
@@ -8290,32 +8315,33 @@ function sqrt5mod8(Fp, n) {
|
|
|
8290
8315
|
const nv = Fp.mul(n, v);
|
|
8291
8316
|
const i = Fp.mul(Fp.mul(nv, _2n$7), v);
|
|
8292
8317
|
const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
|
|
8293
|
-
|
|
8294
|
-
throw new Error('Cannot find square root');
|
|
8318
|
+
assertIsSquare(Fp, root, n);
|
|
8295
8319
|
return root;
|
|
8296
8320
|
}
|
|
8297
|
-
//
|
|
8298
|
-
//
|
|
8299
|
-
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
//
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8318
|
-
|
|
8321
|
+
// Based on RFC9380, Kong algorithm
|
|
8322
|
+
// prettier-ignore
|
|
8323
|
+
function sqrt9mod16(P) {
|
|
8324
|
+
const Fp_ = Field$1(P);
|
|
8325
|
+
const tn = tonelliShanks$1(P);
|
|
8326
|
+
const c1 = tn(Fp_, Fp_.neg(Fp_.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
|
8327
|
+
const c2 = tn(Fp_, c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
|
|
8328
|
+
const c3 = tn(Fp_, Fp_.neg(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
|
|
8329
|
+
const c4 = (P + _7n$2) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
|
|
8330
|
+
return (Fp, n) => {
|
|
8331
|
+
let tv1 = Fp.pow(n, c4); // 1. tv1 = x^c4
|
|
8332
|
+
let tv2 = Fp.mul(tv1, c1); // 2. tv2 = c1 * tv1
|
|
8333
|
+
const tv3 = Fp.mul(tv1, c2); // 3. tv3 = c2 * tv1
|
|
8334
|
+
const tv4 = Fp.mul(tv1, c3); // 4. tv4 = c3 * tv1
|
|
8335
|
+
const e1 = Fp.eql(Fp.sqr(tv2), n); // 5. e1 = (tv2^2) == x
|
|
8336
|
+
const e2 = Fp.eql(Fp.sqr(tv3), n); // 6. e2 = (tv3^2) == x
|
|
8337
|
+
tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
|
|
8338
|
+
tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
|
|
8339
|
+
const e3 = Fp.eql(Fp.sqr(tv2), n); // 9. e3 = (tv2^2) == x
|
|
8340
|
+
const root = Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select sqrt from tv1 & tv2
|
|
8341
|
+
assertIsSquare(Fp, root, n);
|
|
8342
|
+
return root;
|
|
8343
|
+
};
|
|
8344
|
+
}
|
|
8319
8345
|
/**
|
|
8320
8346
|
* Tonelli-Shanks square root search algorithm.
|
|
8321
8347
|
* 1. https://eprint.iacr.org/2012/685.pdf (page 12)
|
|
@@ -8326,10 +8352,10 @@ function sqrt5mod8(Fp, n) {
|
|
|
8326
8352
|
function tonelliShanks$1(P) {
|
|
8327
8353
|
// Initialization (precomputation).
|
|
8328
8354
|
// Caching initialization could boost perf by 7%.
|
|
8329
|
-
if (P <
|
|
8355
|
+
if (P < _3n$3)
|
|
8330
8356
|
throw new Error('sqrt is not defined for small field');
|
|
8331
8357
|
// Factor P - 1 = Q * 2^S, where Q is odd
|
|
8332
|
-
let Q = P - _1n$
|
|
8358
|
+
let Q = P - _1n$9;
|
|
8333
8359
|
let S = 0;
|
|
8334
8360
|
while (Q % _2n$7 === _0n$8) {
|
|
8335
8361
|
Q /= _2n$7;
|
|
@@ -8350,7 +8376,7 @@ function tonelliShanks$1(P) {
|
|
|
8350
8376
|
// Slow-path
|
|
8351
8377
|
// TODO: test on Fp2 and others
|
|
8352
8378
|
let cc = _Fp.pow(Z, Q); // c = z^Q
|
|
8353
|
-
const Q1div2 = (Q + _1n$
|
|
8379
|
+
const Q1div2 = (Q + _1n$9) / _2n$7;
|
|
8354
8380
|
return function tonelliSlow(Fp, n) {
|
|
8355
8381
|
if (Fp.is0(n))
|
|
8356
8382
|
return n;
|
|
@@ -8377,7 +8403,7 @@ function tonelliShanks$1(P) {
|
|
|
8377
8403
|
throw new Error('Cannot find square root');
|
|
8378
8404
|
}
|
|
8379
8405
|
// Calculate the exponent for b: 2^(M - i - 1)
|
|
8380
|
-
const exponent = _1n$
|
|
8406
|
+
const exponent = _1n$9 << BigInt(M - i - 1); // bigint is important
|
|
8381
8407
|
const b = Fp.pow(c, exponent); // b = 2^(M - i - 1)
|
|
8382
8408
|
// Update variables
|
|
8383
8409
|
M = i;
|
|
@@ -8393,7 +8419,8 @@ function tonelliShanks$1(P) {
|
|
|
8393
8419
|
*
|
|
8394
8420
|
* 1. P ≡ 3 (mod 4)
|
|
8395
8421
|
* 2. P ≡ 5 (mod 8)
|
|
8396
|
-
* 3.
|
|
8422
|
+
* 3. P ≡ 9 (mod 16)
|
|
8423
|
+
* 4. Tonelli-Shanks algorithm
|
|
8397
8424
|
*
|
|
8398
8425
|
* Different algorithms can give different roots, it is up to user to decide which one they want.
|
|
8399
8426
|
* For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
|
|
@@ -8405,7 +8432,9 @@ function FpSqrt$1(P) {
|
|
|
8405
8432
|
// P ≡ 5 (mod 8) => Atkin algorithm, page 10 of https://eprint.iacr.org/2012/685.pdf
|
|
8406
8433
|
if (P % _8n$1 === _5n$1)
|
|
8407
8434
|
return sqrt5mod8;
|
|
8408
|
-
// P ≡ 9 (mod 16)
|
|
8435
|
+
// P ≡ 9 (mod 16) => Kong algorithm, page 11 of https://eprint.iacr.org/2012/685.pdf (algorithm 4)
|
|
8436
|
+
if (P % _16n === _9n)
|
|
8437
|
+
return sqrt9mod16(P);
|
|
8409
8438
|
// Tonelli-Shanks algorithm
|
|
8410
8439
|
return tonelliShanks$1(P);
|
|
8411
8440
|
}
|
|
@@ -8442,15 +8471,15 @@ function FpPow$1(Fp, num, power) {
|
|
|
8442
8471
|
throw new Error('invalid exponent, negatives unsupported');
|
|
8443
8472
|
if (power === _0n$8)
|
|
8444
8473
|
return Fp.ONE;
|
|
8445
|
-
if (power === _1n$
|
|
8474
|
+
if (power === _1n$9)
|
|
8446
8475
|
return num;
|
|
8447
8476
|
let p = Fp.ONE;
|
|
8448
8477
|
let d = num;
|
|
8449
8478
|
while (power > _0n$8) {
|
|
8450
|
-
if (power & _1n$
|
|
8479
|
+
if (power & _1n$9)
|
|
8451
8480
|
p = Fp.mul(p, d);
|
|
8452
8481
|
d = Fp.sqr(d);
|
|
8453
|
-
power >>= _1n$
|
|
8482
|
+
power >>= _1n$9;
|
|
8454
8483
|
}
|
|
8455
8484
|
return p;
|
|
8456
8485
|
}
|
|
@@ -8491,7 +8520,7 @@ function FpInvertBatch$1(Fp, nums, passZero = false) {
|
|
|
8491
8520
|
function FpLegendre(Fp, n) {
|
|
8492
8521
|
// We can use 3rd argument as optional cache of this value
|
|
8493
8522
|
// but seems unneeded for now. The operation is very fast.
|
|
8494
|
-
const p1mod2 = (Fp.ORDER - _1n$
|
|
8523
|
+
const p1mod2 = (Fp.ORDER - _1n$9) / _2n$7;
|
|
8495
8524
|
const powered = Fp.pow(n, p1mod2);
|
|
8496
8525
|
const yes = Fp.eql(powered, Fp.ONE);
|
|
8497
8526
|
const zero = Fp.eql(powered, Fp.ZERO);
|
|
@@ -8528,11 +8557,14 @@ function nLength$1(n, nBitLength) {
|
|
|
8528
8557
|
* @param isLE (default: false) if encoding / decoding should be in little-endian
|
|
8529
8558
|
* @param redef optional faster redefinitions of sqrt and other methods
|
|
8530
8559
|
*/
|
|
8531
|
-
function Field$1(ORDER, bitLenOrOpts,
|
|
8560
|
+
function Field$1(ORDER, bitLenOrOpts, // TODO: use opts only in v2?
|
|
8561
|
+
isLE = false, opts = {}) {
|
|
8532
8562
|
if (ORDER <= _0n$8)
|
|
8533
8563
|
throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);
|
|
8534
8564
|
let _nbitLength = undefined;
|
|
8535
8565
|
let _sqrt = undefined;
|
|
8566
|
+
let modFromBytes = false;
|
|
8567
|
+
let allowedLengths = undefined;
|
|
8536
8568
|
if (typeof bitLenOrOpts === 'object' && bitLenOrOpts != null) {
|
|
8537
8569
|
if (opts.sqrt || isLE)
|
|
8538
8570
|
throw new Error('cannot specify opts in two arguments');
|
|
@@ -8543,6 +8575,9 @@ function Field$1(ORDER, bitLenOrOpts, isLE = false, opts = {}) {
|
|
|
8543
8575
|
_sqrt = _opts.sqrt;
|
|
8544
8576
|
if (typeof _opts.isLE === 'boolean')
|
|
8545
8577
|
isLE = _opts.isLE;
|
|
8578
|
+
if (typeof _opts.modFromBytes === 'boolean')
|
|
8579
|
+
modFromBytes = _opts.modFromBytes;
|
|
8580
|
+
allowedLengths = _opts.allowedLengths;
|
|
8546
8581
|
}
|
|
8547
8582
|
else {
|
|
8548
8583
|
if (typeof bitLenOrOpts === 'number')
|
|
@@ -8561,7 +8596,8 @@ function Field$1(ORDER, bitLenOrOpts, isLE = false, opts = {}) {
|
|
|
8561
8596
|
BYTES,
|
|
8562
8597
|
MASK: bitMask$1(BITS),
|
|
8563
8598
|
ZERO: _0n$8,
|
|
8564
|
-
ONE: _1n$
|
|
8599
|
+
ONE: _1n$9,
|
|
8600
|
+
allowedLengths: allowedLengths,
|
|
8565
8601
|
create: (num) => mod$1(num, ORDER),
|
|
8566
8602
|
isValid: (num) => {
|
|
8567
8603
|
if (typeof num !== 'bigint')
|
|
@@ -8571,7 +8607,7 @@ function Field$1(ORDER, bitLenOrOpts, isLE = false, opts = {}) {
|
|
|
8571
8607
|
is0: (num) => num === _0n$8,
|
|
8572
8608
|
// is valid and invertible
|
|
8573
8609
|
isValidNot0: (num) => !f.is0(num) && f.isValid(num),
|
|
8574
|
-
isOdd: (num) => (num & _1n$
|
|
8610
|
+
isOdd: (num) => (num & _1n$9) === _1n$9,
|
|
8575
8611
|
neg: (num) => mod$1(-num, ORDER),
|
|
8576
8612
|
eql: (lhs, rhs) => lhs === rhs,
|
|
8577
8613
|
sqr: (num) => mod$1(num * num, ORDER),
|
|
@@ -8593,10 +8629,27 @@ function Field$1(ORDER, bitLenOrOpts, isLE = false, opts = {}) {
|
|
|
8593
8629
|
return sqrtP(f, n);
|
|
8594
8630
|
}),
|
|
8595
8631
|
toBytes: (num) => (isLE ? numberToBytesLE$1(num, BYTES) : numberToBytesBE$1(num, BYTES)),
|
|
8596
|
-
fromBytes: (bytes) => {
|
|
8632
|
+
fromBytes: (bytes, skipValidation = true) => {
|
|
8633
|
+
if (allowedLengths) {
|
|
8634
|
+
if (!allowedLengths.includes(bytes.length) || bytes.length > BYTES) {
|
|
8635
|
+
throw new Error('Field.fromBytes: expected ' + allowedLengths + ' bytes, got ' + bytes.length);
|
|
8636
|
+
}
|
|
8637
|
+
const padded = new Uint8Array(BYTES);
|
|
8638
|
+
// isLE add 0 to right, !isLE to the left.
|
|
8639
|
+
padded.set(bytes, isLE ? 0 : padded.length - bytes.length);
|
|
8640
|
+
bytes = padded;
|
|
8641
|
+
}
|
|
8597
8642
|
if (bytes.length !== BYTES)
|
|
8598
8643
|
throw new Error('Field.fromBytes: expected ' + BYTES + ' bytes, got ' + bytes.length);
|
|
8599
|
-
|
|
8644
|
+
let scalar = isLE ? bytesToNumberLE$1(bytes) : bytesToNumberBE$1(bytes);
|
|
8645
|
+
if (modFromBytes)
|
|
8646
|
+
scalar = mod$1(scalar, ORDER);
|
|
8647
|
+
if (!skipValidation)
|
|
8648
|
+
if (!f.isValid(scalar))
|
|
8649
|
+
throw new Error('invalid field element: outside of range 0..ORDER');
|
|
8650
|
+
// NOTE: we don't validate scalar here, please use isValid. This done such way because some
|
|
8651
|
+
// protocol may allow non-reduced scalar that reduced later or changed some other way.
|
|
8652
|
+
return scalar;
|
|
8600
8653
|
},
|
|
8601
8654
|
// TODO: we don't need it here, move out to separate fn
|
|
8602
8655
|
invertBatch: (lst) => FpInvertBatch$1(f, lst),
|
|
@@ -8651,16 +8704,16 @@ function mapHashToField$1(key, fieldOrder, isLE = false) {
|
|
|
8651
8704
|
throw new Error('expected ' + minLen + '-1024 bytes of input, got ' + len);
|
|
8652
8705
|
const num = isLE ? bytesToNumberLE$1(key) : bytesToNumberBE$1(key);
|
|
8653
8706
|
// `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
|
|
8654
|
-
const reduced = mod$1(num, fieldOrder - _1n$
|
|
8707
|
+
const reduced = mod$1(num, fieldOrder - _1n$9) + _1n$9;
|
|
8655
8708
|
return isLE ? numberToBytesLE$1(reduced, fieldLen) : numberToBytesBE$1(reduced, fieldLen);
|
|
8656
8709
|
}/**
|
|
8657
8710
|
* Methods for elliptic curve multiplication by scalars.
|
|
8658
|
-
* Contains wNAF, pippenger
|
|
8711
|
+
* Contains wNAF, pippenger.
|
|
8659
8712
|
* @module
|
|
8660
8713
|
*/
|
|
8661
8714
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
8662
8715
|
const _0n$7 = BigInt(0);
|
|
8663
|
-
const _1n$
|
|
8716
|
+
const _1n$8 = BigInt(1);
|
|
8664
8717
|
function negateCt(condition, item) {
|
|
8665
8718
|
const neg = item.negate();
|
|
8666
8719
|
return condition ? neg : item;
|
|
@@ -8671,12 +8724,9 @@ function negateCt(condition, item) {
|
|
|
8671
8724
|
* so this improves performance massively.
|
|
8672
8725
|
* Optimization: converts a list of projective points to a list of identical points with Z=1.
|
|
8673
8726
|
*/
|
|
8674
|
-
function normalizeZ(c,
|
|
8675
|
-
const
|
|
8676
|
-
|
|
8677
|
-
// @ts-ignore
|
|
8678
|
-
const affined = points.map((p, i) => p.toAffine(toInv[i]));
|
|
8679
|
-
return affined.map(c.fromAffine);
|
|
8727
|
+
function normalizeZ(c, points) {
|
|
8728
|
+
const invertedZs = FpInvertBatch$1(c.Fp, points.map((p) => p.Z));
|
|
8729
|
+
return points.map((p, i) => c.fromAffine(p.toAffine(invertedZs[i])));
|
|
8680
8730
|
}
|
|
8681
8731
|
function validateW(W, bits) {
|
|
8682
8732
|
if (!Number.isSafeInteger(W) || W <= 0 || W > bits)
|
|
@@ -8703,7 +8753,7 @@ function calcOffsets(n, window, wOpts) {
|
|
|
8703
8753
|
if (wbits > windowSize) {
|
|
8704
8754
|
// we skip zero, which means instead of `>= size-1`, we do `> size`
|
|
8705
8755
|
wbits -= maxNumber; // -32, can be maxNumber - wbits, but then we need to set isNeg here.
|
|
8706
|
-
nextN += _1n$
|
|
8756
|
+
nextN += _1n$8; // +256 (carry)
|
|
8707
8757
|
}
|
|
8708
8758
|
const offsetStart = window * windowSize;
|
|
8709
8759
|
const offset = offsetStart + Math.abs(wbits) - 1; // -1 because we skip zero
|
|
@@ -8735,6 +8785,8 @@ function validateMSMScalars(scalars, field) {
|
|
|
8735
8785
|
const pointPrecomputes = new WeakMap();
|
|
8736
8786
|
const pointWindowSizes = new WeakMap();
|
|
8737
8787
|
function getW(P) {
|
|
8788
|
+
// To disable precomputes:
|
|
8789
|
+
// return 1;
|
|
8738
8790
|
return pointWindowSizes.get(P) || 1;
|
|
8739
8791
|
}
|
|
8740
8792
|
function assert0(n) {
|
|
@@ -8743,6 +8795,10 @@ function assert0(n) {
|
|
|
8743
8795
|
}
|
|
8744
8796
|
/**
|
|
8745
8797
|
* Elliptic curve multiplication of Point by scalar. Fragile.
|
|
8798
|
+
* Table generation takes **30MB of ram and 10ms on high-end CPU**,
|
|
8799
|
+
* but may take much longer on slow devices. Actual generation will happen on
|
|
8800
|
+
* first call of `multiply()`. By default, `BASE` point is precomputed.
|
|
8801
|
+
*
|
|
8746
8802
|
* Scalars should always be less than curve order: this should be checked inside of a curve itself.
|
|
8747
8803
|
* Creates precomputation tables for fast multiplication:
|
|
8748
8804
|
* - private scalar is split by fixed size windows of W bits
|
|
@@ -8755,172 +8811,170 @@ function assert0(n) {
|
|
|
8755
8811
|
* @todo Research returning 2d JS array of windows, instead of a single window.
|
|
8756
8812
|
* This would allow windows to be in different memory locations
|
|
8757
8813
|
*/
|
|
8758
|
-
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
8766
|
-
|
|
8767
|
-
|
|
8768
|
-
|
|
8769
|
-
|
|
8770
|
-
|
|
8771
|
-
|
|
8772
|
-
|
|
8773
|
-
|
|
8774
|
-
}
|
|
8775
|
-
|
|
8776
|
-
|
|
8777
|
-
|
|
8778
|
-
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
|
|
8782
|
-
|
|
8783
|
-
|
|
8784
|
-
|
|
8785
|
-
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
|
|
8791
|
-
|
|
8792
|
-
|
|
8793
|
-
|
|
8814
|
+
let wNAF$1=class wNAF {
|
|
8815
|
+
// Parametrized with a given Point class (not individual point)
|
|
8816
|
+
constructor(Point, bits) {
|
|
8817
|
+
this.BASE = Point.BASE;
|
|
8818
|
+
this.ZERO = Point.ZERO;
|
|
8819
|
+
this.Fn = Point.Fn;
|
|
8820
|
+
this.bits = bits;
|
|
8821
|
+
}
|
|
8822
|
+
// non-const time multiplication ladder
|
|
8823
|
+
_unsafeLadder(elm, n, p = this.ZERO) {
|
|
8824
|
+
let d = elm;
|
|
8825
|
+
while (n > _0n$7) {
|
|
8826
|
+
if (n & _1n$8)
|
|
8827
|
+
p = p.add(d);
|
|
8828
|
+
d = d.double();
|
|
8829
|
+
n >>= _1n$8;
|
|
8830
|
+
}
|
|
8831
|
+
return p;
|
|
8832
|
+
}
|
|
8833
|
+
/**
|
|
8834
|
+
* Creates a wNAF precomputation window. Used for caching.
|
|
8835
|
+
* Default window size is set by `utils.precompute()` and is equal to 8.
|
|
8836
|
+
* Number of precomputed points depends on the curve size:
|
|
8837
|
+
* 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:
|
|
8838
|
+
* - 𝑊 is the window size
|
|
8839
|
+
* - 𝑛 is the bitlength of the curve order.
|
|
8840
|
+
* For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
|
|
8841
|
+
* @param point Point instance
|
|
8842
|
+
* @param W window size
|
|
8843
|
+
* @returns precomputed point tables flattened to a single array
|
|
8844
|
+
*/
|
|
8845
|
+
precomputeWindow(point, W) {
|
|
8846
|
+
const { windows, windowSize } = calcWOpts(W, this.bits);
|
|
8847
|
+
const points = [];
|
|
8848
|
+
let p = point;
|
|
8849
|
+
let base = p;
|
|
8850
|
+
for (let window = 0; window < windows; window++) {
|
|
8851
|
+
base = p;
|
|
8852
|
+
points.push(base);
|
|
8853
|
+
// i=1, bc we skip 0
|
|
8854
|
+
for (let i = 1; i < windowSize; i++) {
|
|
8855
|
+
base = base.add(p);
|
|
8794
8856
|
points.push(base);
|
|
8795
|
-
// i=1, bc we skip 0
|
|
8796
|
-
for (let i = 1; i < windowSize; i++) {
|
|
8797
|
-
base = base.add(p);
|
|
8798
|
-
points.push(base);
|
|
8799
|
-
}
|
|
8800
|
-
p = base.double();
|
|
8801
8857
|
}
|
|
8802
|
-
|
|
8803
|
-
}
|
|
8804
|
-
|
|
8805
|
-
|
|
8806
|
-
|
|
8807
|
-
|
|
8808
|
-
|
|
8809
|
-
|
|
8810
|
-
|
|
8811
|
-
|
|
8812
|
-
|
|
8813
|
-
|
|
8814
|
-
|
|
8815
|
-
|
|
8816
|
-
|
|
8817
|
-
|
|
8818
|
-
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
8831
|
-
|
|
8832
|
-
|
|
8833
|
-
f = f.add(negateCt(isNegF, precomputes[offsetF]));
|
|
8834
|
-
}
|
|
8835
|
-
else {
|
|
8836
|
-
// bits are 1: add to result point
|
|
8837
|
-
p = p.add(negateCt(isNeg, precomputes[offset]));
|
|
8838
|
-
}
|
|
8858
|
+
p = base.double();
|
|
8859
|
+
}
|
|
8860
|
+
return points;
|
|
8861
|
+
}
|
|
8862
|
+
/**
|
|
8863
|
+
* Implements ec multiplication using precomputed tables and w-ary non-adjacent form.
|
|
8864
|
+
* More compact implementation:
|
|
8865
|
+
* https://github.com/paulmillr/noble-secp256k1/blob/47cb1669b6e506ad66b35fe7d76132ae97465da2/index.ts#L502-L541
|
|
8866
|
+
* @returns real and fake (for const-time) points
|
|
8867
|
+
*/
|
|
8868
|
+
wNAF(W, precomputes, n) {
|
|
8869
|
+
// Scalar should be smaller than field order
|
|
8870
|
+
if (!this.Fn.isValid(n))
|
|
8871
|
+
throw new Error('invalid scalar');
|
|
8872
|
+
// Accumulators
|
|
8873
|
+
let p = this.ZERO;
|
|
8874
|
+
let f = this.BASE;
|
|
8875
|
+
// This code was first written with assumption that 'f' and 'p' will never be infinity point:
|
|
8876
|
+
// since each addition is multiplied by 2 ** W, it cannot cancel each other. However,
|
|
8877
|
+
// there is negate now: it is possible that negated element from low value
|
|
8878
|
+
// would be the same as high element, which will create carry into next window.
|
|
8879
|
+
// It's not obvious how this can fail, but still worth investigating later.
|
|
8880
|
+
const wo = calcWOpts(W, this.bits);
|
|
8881
|
+
for (let window = 0; window < wo.windows; window++) {
|
|
8882
|
+
// (n === _0n) is handled and not early-exited. isEven and offsetF are used for noise
|
|
8883
|
+
const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo);
|
|
8884
|
+
n = nextN;
|
|
8885
|
+
if (isZero) {
|
|
8886
|
+
// bits are 0: add garbage to fake point
|
|
8887
|
+
// Important part for const-time getPublicKey: add random "noise" point to f.
|
|
8888
|
+
f = f.add(negateCt(isNegF, precomputes[offsetF]));
|
|
8839
8889
|
}
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
// which makes it less const-time: around 1 bigint multiply.
|
|
8844
|
-
return { p, f };
|
|
8845
|
-
},
|
|
8846
|
-
/**
|
|
8847
|
-
* Implements ec unsafe (non const-time) multiplication using precomputed tables and w-ary non-adjacent form.
|
|
8848
|
-
* @param W window size
|
|
8849
|
-
* @param precomputes precomputed tables
|
|
8850
|
-
* @param n scalar (we don't check here, but should be less than curve order)
|
|
8851
|
-
* @param acc accumulator point to add result of multiplication
|
|
8852
|
-
* @returns point
|
|
8853
|
-
*/
|
|
8854
|
-
wNAFUnsafe(W, precomputes, n, acc = c.ZERO) {
|
|
8855
|
-
const wo = calcWOpts(W, bits);
|
|
8856
|
-
for (let window = 0; window < wo.windows; window++) {
|
|
8857
|
-
if (n === _0n$7)
|
|
8858
|
-
break; // Early-exit, skip 0 value
|
|
8859
|
-
const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo);
|
|
8860
|
-
n = nextN;
|
|
8861
|
-
if (isZero) {
|
|
8862
|
-
// Window bits are 0: skip processing.
|
|
8863
|
-
// Move to next window.
|
|
8864
|
-
continue;
|
|
8865
|
-
}
|
|
8866
|
-
else {
|
|
8867
|
-
const item = precomputes[offset];
|
|
8868
|
-
acc = acc.add(isNeg ? item.negate() : item); // Re-using acc allows to save adds in MSM
|
|
8869
|
-
}
|
|
8890
|
+
else {
|
|
8891
|
+
// bits are 1: add to result point
|
|
8892
|
+
p = p.add(negateCt(isNeg, precomputes[offset]));
|
|
8870
8893
|
}
|
|
8871
|
-
|
|
8872
|
-
|
|
8873
|
-
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
|
|
8881
|
-
|
|
8882
|
-
|
|
8883
|
-
|
|
8884
|
-
|
|
8894
|
+
}
|
|
8895
|
+
assert0(n);
|
|
8896
|
+
// Return both real and fake points: JIT won't eliminate f.
|
|
8897
|
+
// At this point there is a way to F be infinity-point even if p is not,
|
|
8898
|
+
// which makes it less const-time: around 1 bigint multiply.
|
|
8899
|
+
return { p, f };
|
|
8900
|
+
}
|
|
8901
|
+
/**
|
|
8902
|
+
* Implements ec unsafe (non const-time) multiplication using precomputed tables and w-ary non-adjacent form.
|
|
8903
|
+
* @param acc accumulator point to add result of multiplication
|
|
8904
|
+
* @returns point
|
|
8905
|
+
*/
|
|
8906
|
+
wNAFUnsafe(W, precomputes, n, acc = this.ZERO) {
|
|
8907
|
+
const wo = calcWOpts(W, this.bits);
|
|
8908
|
+
for (let window = 0; window < wo.windows; window++) {
|
|
8909
|
+
if (n === _0n$7)
|
|
8910
|
+
break; // Early-exit, skip 0 value
|
|
8911
|
+
const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo);
|
|
8912
|
+
n = nextN;
|
|
8913
|
+
if (isZero) {
|
|
8914
|
+
// Window bits are 0: skip processing.
|
|
8915
|
+
// Move to next window.
|
|
8916
|
+
continue;
|
|
8885
8917
|
}
|
|
8886
|
-
|
|
8887
|
-
|
|
8888
|
-
|
|
8889
|
-
|
|
8890
|
-
|
|
8891
|
-
|
|
8892
|
-
|
|
8893
|
-
|
|
8894
|
-
|
|
8895
|
-
|
|
8896
|
-
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
|
|
8900
|
-
|
|
8901
|
-
|
|
8902
|
-
|
|
8903
|
-
|
|
8904
|
-
|
|
8905
|
-
}
|
|
8906
|
-
|
|
8907
|
-
}
|
|
8918
|
+
else {
|
|
8919
|
+
const item = precomputes[offset];
|
|
8920
|
+
acc = acc.add(isNeg ? item.negate() : item); // Re-using acc allows to save adds in MSM
|
|
8921
|
+
}
|
|
8922
|
+
}
|
|
8923
|
+
assert0(n);
|
|
8924
|
+
return acc;
|
|
8925
|
+
}
|
|
8926
|
+
getPrecomputes(W, point, transform) {
|
|
8927
|
+
// Calculate precomputes on a first run, reuse them after
|
|
8928
|
+
let comp = pointPrecomputes.get(point);
|
|
8929
|
+
if (!comp) {
|
|
8930
|
+
comp = this.precomputeWindow(point, W);
|
|
8931
|
+
if (W !== 1) {
|
|
8932
|
+
// Doing transform outside of if brings 15% perf hit
|
|
8933
|
+
if (typeof transform === 'function')
|
|
8934
|
+
comp = transform(comp);
|
|
8935
|
+
pointPrecomputes.set(point, comp);
|
|
8936
|
+
}
|
|
8937
|
+
}
|
|
8938
|
+
return comp;
|
|
8939
|
+
}
|
|
8940
|
+
cached(point, scalar, transform) {
|
|
8941
|
+
const W = getW(point);
|
|
8942
|
+
return this.wNAF(W, this.getPrecomputes(W, point, transform), scalar);
|
|
8943
|
+
}
|
|
8944
|
+
unsafe(point, scalar, transform, prev) {
|
|
8945
|
+
const W = getW(point);
|
|
8946
|
+
if (W === 1)
|
|
8947
|
+
return this._unsafeLadder(point, scalar, prev); // For W=1 ladder is ~x2 faster
|
|
8948
|
+
return this.wNAFUnsafe(W, this.getPrecomputes(W, point, transform), scalar, prev);
|
|
8949
|
+
}
|
|
8950
|
+
// We calculate precomputes for elliptic curve point multiplication
|
|
8951
|
+
// using windowed method. This specifies window size and
|
|
8952
|
+
// stores precomputed values. Usually only base point would be precomputed.
|
|
8953
|
+
createCache(P, W) {
|
|
8954
|
+
validateW(W, this.bits);
|
|
8955
|
+
pointWindowSizes.set(P, W);
|
|
8956
|
+
pointPrecomputes.delete(P);
|
|
8957
|
+
}
|
|
8958
|
+
hasCache(elm) {
|
|
8959
|
+
return getW(elm) !== 1;
|
|
8960
|
+
}
|
|
8961
|
+
};
|
|
8908
8962
|
/**
|
|
8909
8963
|
* Endomorphism-specific multiplication for Koblitz curves.
|
|
8910
8964
|
* Cost: 128 dbl, 0-256 adds.
|
|
8911
8965
|
*/
|
|
8912
|
-
function mulEndoUnsafe(
|
|
8966
|
+
function mulEndoUnsafe(Point, point, k1, k2) {
|
|
8913
8967
|
let acc = point;
|
|
8914
|
-
let p1 =
|
|
8915
|
-
let p2 =
|
|
8968
|
+
let p1 = Point.ZERO;
|
|
8969
|
+
let p2 = Point.ZERO;
|
|
8916
8970
|
while (k1 > _0n$7 || k2 > _0n$7) {
|
|
8917
|
-
if (k1 & _1n$
|
|
8971
|
+
if (k1 & _1n$8)
|
|
8918
8972
|
p1 = p1.add(acc);
|
|
8919
|
-
if (k2 & _1n$
|
|
8973
|
+
if (k2 & _1n$8)
|
|
8920
8974
|
p2 = p2.add(acc);
|
|
8921
8975
|
acc = acc.double();
|
|
8922
|
-
k1 >>= _1n$
|
|
8923
|
-
k2 >>= _1n$
|
|
8976
|
+
k1 >>= _1n$8;
|
|
8977
|
+
k2 >>= _1n$8;
|
|
8924
8978
|
}
|
|
8925
8979
|
return { p1, p2 };
|
|
8926
8980
|
}
|
|
@@ -8932,7 +8986,7 @@ function mulEndoUnsafe(c, point, k1, k2) {
|
|
|
8932
8986
|
* @param c Curve Point constructor
|
|
8933
8987
|
* @param fieldN field over CURVE.N - important that it's not over CURVE.P
|
|
8934
8988
|
* @param points array of L curve points
|
|
8935
|
-
* @param scalars array of L scalars (aka
|
|
8989
|
+
* @param scalars array of L scalars (aka secret keys / bigints)
|
|
8936
8990
|
*/
|
|
8937
8991
|
function pippenger(c, fieldN, points, scalars) {
|
|
8938
8992
|
// If we split scalars by some window (let's say 8 bits), every chunk will only
|
|
@@ -8981,7 +9035,7 @@ function pippenger(c, fieldN, points, scalars) {
|
|
|
8981
9035
|
}
|
|
8982
9036
|
return sum;
|
|
8983
9037
|
}
|
|
8984
|
-
function createField(order, field) {
|
|
9038
|
+
function createField(order, field, isLE) {
|
|
8985
9039
|
if (field) {
|
|
8986
9040
|
if (field.ORDER !== order)
|
|
8987
9041
|
throw new Error('Field.ORDER must match order: Fp == p, Fn == n');
|
|
@@ -8989,11 +9043,13 @@ function createField(order, field) {
|
|
|
8989
9043
|
return field;
|
|
8990
9044
|
}
|
|
8991
9045
|
else {
|
|
8992
|
-
return Field$1(order);
|
|
9046
|
+
return Field$1(order, { isLE });
|
|
8993
9047
|
}
|
|
8994
9048
|
}
|
|
8995
9049
|
/** Validates CURVE opts and creates fields */
|
|
8996
|
-
function _createCurveFields(type, CURVE, curveOpts = {}) {
|
|
9050
|
+
function _createCurveFields(type, CURVE, curveOpts = {}, FpFnLE) {
|
|
9051
|
+
if (FpFnLE === undefined)
|
|
9052
|
+
FpFnLE = type === 'edwards';
|
|
8997
9053
|
if (!CURVE || typeof CURVE !== 'object')
|
|
8998
9054
|
throw new Error(`expected valid ${type} CURVE object`);
|
|
8999
9055
|
for (const p of ['p', 'n', 'h']) {
|
|
@@ -9001,8 +9057,8 @@ function _createCurveFields(type, CURVE, curveOpts = {}) {
|
|
|
9001
9057
|
if (!(typeof val === 'bigint' && val > _0n$7))
|
|
9002
9058
|
throw new Error(`CURVE.${p} must be positive bigint`);
|
|
9003
9059
|
}
|
|
9004
|
-
const Fp = createField(CURVE.p, curveOpts.Fp);
|
|
9005
|
-
const Fn = createField(CURVE.n, curveOpts.Fn);
|
|
9060
|
+
const Fp = createField(CURVE.p, curveOpts.Fp, FpFnLE);
|
|
9061
|
+
const Fn = createField(CURVE.n, curveOpts.Fn, FpFnLE);
|
|
9006
9062
|
const _b = 'b' ;
|
|
9007
9063
|
const params = ['Gx', 'Gy', 'a', _b];
|
|
9008
9064
|
for (const p of params) {
|
|
@@ -9010,7 +9066,8 @@ function _createCurveFields(type, CURVE, curveOpts = {}) {
|
|
|
9010
9066
|
if (!Fp.isValid(CURVE[p]))
|
|
9011
9067
|
throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`);
|
|
9012
9068
|
}
|
|
9013
|
-
|
|
9069
|
+
CURVE = Object.freeze(Object.assign({}, CURVE));
|
|
9070
|
+
return { CURVE, Fp, Fn };
|
|
9014
9071
|
}/**
|
|
9015
9072
|
* Short Weierstrass curve methods. The formula is: y² = x³ + ax + b.
|
|
9016
9073
|
*
|
|
@@ -9038,11 +9095,52 @@ function _createCurveFields(type, CURVE, curveOpts = {}) {
|
|
|
9038
9095
|
* @module
|
|
9039
9096
|
*/
|
|
9040
9097
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
9041
|
-
|
|
9042
|
-
|
|
9043
|
-
|
|
9044
|
-
|
|
9045
|
-
|
|
9098
|
+
// We construct basis in such way that den is always positive and equals n, but num sign depends on basis (not on secret value)
|
|
9099
|
+
const divNearest$1 = (num, den) => (num + (num >= 0 ? den : -den) / _2n$6) / den;
|
|
9100
|
+
/**
|
|
9101
|
+
* Splits scalar for GLV endomorphism.
|
|
9102
|
+
*/
|
|
9103
|
+
function _splitEndoScalar(k, basis, n) {
|
|
9104
|
+
// Split scalar into two such that part is ~half bits: `abs(part) < sqrt(N)`
|
|
9105
|
+
// Since part can be negative, we need to do this on point.
|
|
9106
|
+
// TODO: verifyScalar function which consumes lambda
|
|
9107
|
+
const [[a1, b1], [a2, b2]] = basis;
|
|
9108
|
+
const c1 = divNearest$1(b2 * k, n);
|
|
9109
|
+
const c2 = divNearest$1(-b1 * k, n);
|
|
9110
|
+
// |k1|/|k2| is < sqrt(N), but can be negative.
|
|
9111
|
+
// If we do `k1 mod N`, we'll get big scalar (`> sqrt(N)`): so, we do cheaper negation instead.
|
|
9112
|
+
let k1 = k - c1 * a1 - c2 * a2;
|
|
9113
|
+
let k2 = -c1 * b1 - c2 * b2;
|
|
9114
|
+
const k1neg = k1 < _0n$6;
|
|
9115
|
+
const k2neg = k2 < _0n$6;
|
|
9116
|
+
if (k1neg)
|
|
9117
|
+
k1 = -k1;
|
|
9118
|
+
if (k2neg)
|
|
9119
|
+
k2 = -k2;
|
|
9120
|
+
// Double check that resulting scalar less than half bits of N: otherwise wNAF will fail.
|
|
9121
|
+
// This should only happen on wrong basises. Also, math inside is too complex and I don't trust it.
|
|
9122
|
+
const MAX_NUM = bitMask$1(Math.ceil(bitLen$1(n) / 2)) + _1n$7; // Half bits of N
|
|
9123
|
+
if (k1 < _0n$6 || k1 >= MAX_NUM || k2 < _0n$6 || k2 >= MAX_NUM) {
|
|
9124
|
+
throw new Error('splitScalar (endomorphism): failed, k=' + k);
|
|
9125
|
+
}
|
|
9126
|
+
return { k1neg, k1, k2neg, k2 };
|
|
9127
|
+
}
|
|
9128
|
+
function validateSigFormat(format) {
|
|
9129
|
+
if (!['compact', 'recovered', 'der'].includes(format))
|
|
9130
|
+
throw new Error('Signature format must be "compact", "recovered", or "der"');
|
|
9131
|
+
return format;
|
|
9132
|
+
}
|
|
9133
|
+
function validateSigOpts(opts, def) {
|
|
9134
|
+
const optsn = {};
|
|
9135
|
+
for (let optName of Object.keys(def)) {
|
|
9136
|
+
// @ts-ignore
|
|
9137
|
+
optsn[optName] = opts[optName] === undefined ? def[optName] : opts[optName];
|
|
9138
|
+
}
|
|
9139
|
+
_abool2(optsn.lowS, 'lowS');
|
|
9140
|
+
_abool2(optsn.prehash, 'prehash');
|
|
9141
|
+
if (optsn.format !== undefined)
|
|
9142
|
+
validateSigFormat(optsn.format);
|
|
9143
|
+
return optsn;
|
|
9046
9144
|
}
|
|
9047
9145
|
class DERErr extends Error {
|
|
9048
9146
|
constructor(m = '') {
|
|
@@ -9162,56 +9260,49 @@ const DER$1 = {
|
|
|
9162
9260
|
};
|
|
9163
9261
|
// Be friendly to bad ECMAScript parsers by not using bigint literals
|
|
9164
9262
|
// prettier-ignore
|
|
9165
|
-
const _0n$6 = BigInt(0), _1n$
|
|
9166
|
-
|
|
9167
|
-
function _legacyHelperEquat(Fp, a, b) {
|
|
9168
|
-
/**
|
|
9169
|
-
* y² = x³ + ax + b: Short weierstrass curve formula. Takes x, returns y².
|
|
9170
|
-
* @returns y²
|
|
9171
|
-
*/
|
|
9172
|
-
function weierstrassEquation(x) {
|
|
9173
|
-
const x2 = Fp.sqr(x); // x * x
|
|
9174
|
-
const x3 = Fp.mul(x2, x); // x² * x
|
|
9175
|
-
return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x³ + a * x + b
|
|
9176
|
-
}
|
|
9177
|
-
return weierstrassEquation;
|
|
9178
|
-
}
|
|
9179
|
-
function _legacyHelperNormPriv(Fn, allowedPrivateKeyLengths, wrapPrivateKey) {
|
|
9263
|
+
const _0n$6 = BigInt(0), _1n$7 = BigInt(1), _2n$6 = BigInt(2), _3n$2 = BigInt(3), _4n$1 = BigInt(4);
|
|
9264
|
+
function _normFnElement(Fn, key) {
|
|
9180
9265
|
const { BYTES: expected } = Fn;
|
|
9181
|
-
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
|
|
9185
|
-
|
|
9266
|
+
let num;
|
|
9267
|
+
if (typeof key === 'bigint') {
|
|
9268
|
+
num = key;
|
|
9269
|
+
}
|
|
9270
|
+
else {
|
|
9271
|
+
let bytes = ensureBytes$1('private key', key);
|
|
9272
|
+
try {
|
|
9273
|
+
num = Fn.fromBytes(bytes);
|
|
9186
9274
|
}
|
|
9187
|
-
|
|
9188
|
-
|
|
9189
|
-
if (allowedPrivateKeyLengths) {
|
|
9190
|
-
if (!allowedPrivateKeyLengths.includes(bytes.length * 2))
|
|
9191
|
-
throw new Error('invalid private key');
|
|
9192
|
-
const padded = new Uint8Array(expected);
|
|
9193
|
-
padded.set(bytes, padded.length - bytes.length);
|
|
9194
|
-
bytes = padded;
|
|
9195
|
-
}
|
|
9196
|
-
try {
|
|
9197
|
-
num = Fn.fromBytes(bytes);
|
|
9198
|
-
}
|
|
9199
|
-
catch (error) {
|
|
9200
|
-
throw new Error(`invalid private key: expected ui8a of size ${expected}, got ${typeof key}`);
|
|
9201
|
-
}
|
|
9275
|
+
catch (error) {
|
|
9276
|
+
throw new Error(`invalid private key: expected ui8a of size ${expected}, got ${typeof key}`);
|
|
9202
9277
|
}
|
|
9203
|
-
if (wrapPrivateKey)
|
|
9204
|
-
num = Fn.create(num); // disabled by default, enabled for BLS
|
|
9205
|
-
if (!Fn.isValidNot0(num))
|
|
9206
|
-
throw new Error('invalid private key: out of range [1..N-1]');
|
|
9207
|
-
return num;
|
|
9208
9278
|
}
|
|
9209
|
-
|
|
9279
|
+
if (!Fn.isValidNot0(num))
|
|
9280
|
+
throw new Error('invalid private key: out of range [1..N-1]');
|
|
9281
|
+
return num;
|
|
9210
9282
|
}
|
|
9211
|
-
|
|
9212
|
-
|
|
9283
|
+
/**
|
|
9284
|
+
* Creates weierstrass Point constructor, based on specified curve options.
|
|
9285
|
+
*
|
|
9286
|
+
* @example
|
|
9287
|
+
```js
|
|
9288
|
+
const opts = {
|
|
9289
|
+
p: BigInt('0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff'),
|
|
9290
|
+
n: BigInt('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551'),
|
|
9291
|
+
h: BigInt(1),
|
|
9292
|
+
a: BigInt('0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc'),
|
|
9293
|
+
b: BigInt('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b'),
|
|
9294
|
+
Gx: BigInt('0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296'),
|
|
9295
|
+
Gy: BigInt('0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5'),
|
|
9296
|
+
};
|
|
9297
|
+
const p256_Point = weierstrass(opts);
|
|
9298
|
+
```
|
|
9299
|
+
*/
|
|
9300
|
+
function weierstrassN(params, extraOpts = {}) {
|
|
9301
|
+
const validated = _createCurveFields('weierstrass', params, extraOpts);
|
|
9302
|
+
const { Fp, Fn } = validated;
|
|
9303
|
+
let CURVE = validated.CURVE;
|
|
9213
9304
|
const { h: cofactor, n: CURVE_ORDER } = CURVE;
|
|
9214
|
-
_validateObject(
|
|
9305
|
+
_validateObject(extraOpts, {}, {
|
|
9215
9306
|
allowInfinityPoint: 'boolean',
|
|
9216
9307
|
clearCofactor: 'function',
|
|
9217
9308
|
isTorsionFree: 'function',
|
|
@@ -9220,15 +9311,14 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9220
9311
|
endo: 'object',
|
|
9221
9312
|
wrapPrivateKey: 'boolean',
|
|
9222
9313
|
});
|
|
9223
|
-
const { endo } =
|
|
9314
|
+
const { endo } = extraOpts;
|
|
9224
9315
|
if (endo) {
|
|
9225
9316
|
// validateObject(endo, { beta: 'bigint', splitScalar: 'function' });
|
|
9226
|
-
if (!Fp.is0(CURVE.a) ||
|
|
9227
|
-
|
|
9228
|
-
typeof endo.splitScalar !== 'function') {
|
|
9229
|
-
throw new Error('invalid endo: expected "beta": bigint and "splitScalar": function');
|
|
9317
|
+
if (!Fp.is0(CURVE.a) || typeof endo.beta !== 'bigint' || !Array.isArray(endo.basises)) {
|
|
9318
|
+
throw new Error('invalid endo: expected "beta": bigint and "basises": array');
|
|
9230
9319
|
}
|
|
9231
9320
|
}
|
|
9321
|
+
const lengths = getWLengths(Fp, Fn);
|
|
9232
9322
|
function assertCompressionIsSupported() {
|
|
9233
9323
|
if (!Fp.isOdd)
|
|
9234
9324
|
throw new Error('compression is not supported: Field does not have .isOdd()');
|
|
@@ -9237,7 +9327,7 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9237
9327
|
function pointToBytes(_c, point, isCompressed) {
|
|
9238
9328
|
const { x, y } = point.toAffine();
|
|
9239
9329
|
const bx = Fp.toBytes(x);
|
|
9240
|
-
|
|
9330
|
+
_abool2(isCompressed, 'isCompressed');
|
|
9241
9331
|
if (isCompressed) {
|
|
9242
9332
|
assertCompressionIsSupported();
|
|
9243
9333
|
const hasEvenY = !Fp.isOdd(y);
|
|
@@ -9248,15 +9338,13 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9248
9338
|
}
|
|
9249
9339
|
}
|
|
9250
9340
|
function pointFromBytes(bytes) {
|
|
9251
|
-
|
|
9252
|
-
const
|
|
9253
|
-
const LC = L + 1; // length compressed, e.g. 33 for 32-byte field
|
|
9254
|
-
const LU = 2 * L + 1; // length uncompressed, e.g. 65 for 32-byte field
|
|
9341
|
+
_abytes2(bytes, undefined, 'Point');
|
|
9342
|
+
const { public: comp, publicUncompressed: uncomp } = lengths; // e.g. for 32-byte: 33, 65
|
|
9255
9343
|
const length = bytes.length;
|
|
9256
9344
|
const head = bytes[0];
|
|
9257
9345
|
const tail = bytes.subarray(1);
|
|
9258
9346
|
// No actual validation is done here: use .assertValidity()
|
|
9259
|
-
if (length ===
|
|
9347
|
+
if (length === comp && (head === 0x02 || head === 0x03)) {
|
|
9260
9348
|
const x = Fp.fromBytes(tail);
|
|
9261
9349
|
if (!Fp.isValid(x))
|
|
9262
9350
|
throw new Error('bad point: is not on curve, wrong x');
|
|
@@ -9276,21 +9364,26 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9276
9364
|
y = Fp.neg(y);
|
|
9277
9365
|
return { x, y };
|
|
9278
9366
|
}
|
|
9279
|
-
else if (length ===
|
|
9367
|
+
else if (length === uncomp && head === 0x04) {
|
|
9280
9368
|
// TODO: more checks
|
|
9281
|
-
const
|
|
9282
|
-
const
|
|
9369
|
+
const L = Fp.BYTES;
|
|
9370
|
+
const x = Fp.fromBytes(tail.subarray(0, L));
|
|
9371
|
+
const y = Fp.fromBytes(tail.subarray(L, L * 2));
|
|
9283
9372
|
if (!isValidXY(x, y))
|
|
9284
9373
|
throw new Error('bad point: is not on curve');
|
|
9285
9374
|
return { x, y };
|
|
9286
9375
|
}
|
|
9287
9376
|
else {
|
|
9288
|
-
throw new Error(`bad point: got length ${length}, expected compressed=${
|
|
9377
|
+
throw new Error(`bad point: got length ${length}, expected compressed=${comp} or uncompressed=${uncomp}`);
|
|
9289
9378
|
}
|
|
9290
9379
|
}
|
|
9291
|
-
const
|
|
9292
|
-
const
|
|
9293
|
-
|
|
9380
|
+
const encodePoint = extraOpts.toBytes || pointToBytes;
|
|
9381
|
+
const decodePoint = extraOpts.fromBytes || pointFromBytes;
|
|
9382
|
+
function weierstrassEquation(x) {
|
|
9383
|
+
const x2 = Fp.sqr(x); // x * x
|
|
9384
|
+
const x3 = Fp.mul(x2, x); // x² * x
|
|
9385
|
+
return Fp.add(Fp.add(x3, Fp.mul(x, CURVE.a)), CURVE.b); // x³ + a * x + b
|
|
9386
|
+
}
|
|
9294
9387
|
// TODO: move top-level
|
|
9295
9388
|
/** Checks whether equation holds for given x, y: y² == x³ + ax + b */
|
|
9296
9389
|
function isValidXY(x, y) {
|
|
@@ -9318,28 +9411,33 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9318
9411
|
if (!(other instanceof Point))
|
|
9319
9412
|
throw new Error('ProjectivePoint expected');
|
|
9320
9413
|
}
|
|
9414
|
+
function splitEndoScalarN(k) {
|
|
9415
|
+
if (!endo || !endo.basises)
|
|
9416
|
+
throw new Error('no endo');
|
|
9417
|
+
return _splitEndoScalar(k, endo.basises, Fn.ORDER);
|
|
9418
|
+
}
|
|
9321
9419
|
// Memoized toAffine / validity check. They are heavy. Points are immutable.
|
|
9322
9420
|
// Converts Projective point to affine (x, y) coordinates.
|
|
9323
9421
|
// Can accept precomputed Z^-1 - for example, from invertBatch.
|
|
9324
9422
|
// (X, Y, Z) ∋ (x=X/Z, y=Y/Z)
|
|
9325
9423
|
const toAffineMemo = memoized((p, iz) => {
|
|
9326
|
-
const {
|
|
9424
|
+
const { X, Y, Z } = p;
|
|
9327
9425
|
// Fast-path for normalized points
|
|
9328
|
-
if (Fp.eql(
|
|
9329
|
-
return { x, y };
|
|
9426
|
+
if (Fp.eql(Z, Fp.ONE))
|
|
9427
|
+
return { x: X, y: Y };
|
|
9330
9428
|
const is0 = p.is0();
|
|
9331
9429
|
// If invZ was 0, we return zero point. However we still want to execute
|
|
9332
9430
|
// all operations, so we replace invZ with a random number, 1.
|
|
9333
9431
|
if (iz == null)
|
|
9334
|
-
iz = is0 ? Fp.ONE : Fp.inv(
|
|
9335
|
-
const
|
|
9336
|
-
const
|
|
9337
|
-
const zz = Fp.mul(
|
|
9432
|
+
iz = is0 ? Fp.ONE : Fp.inv(Z);
|
|
9433
|
+
const x = Fp.mul(X, iz);
|
|
9434
|
+
const y = Fp.mul(Y, iz);
|
|
9435
|
+
const zz = Fp.mul(Z, iz);
|
|
9338
9436
|
if (is0)
|
|
9339
9437
|
return { x: Fp.ZERO, y: Fp.ZERO };
|
|
9340
9438
|
if (!Fp.eql(zz, Fp.ONE))
|
|
9341
9439
|
throw new Error('invZ was invalid');
|
|
9342
|
-
return { x
|
|
9440
|
+
return { x, y };
|
|
9343
9441
|
});
|
|
9344
9442
|
// NOTE: on exception this will crash 'cached' and no value will be set.
|
|
9345
9443
|
// Otherwise true will be return
|
|
@@ -9348,7 +9446,7 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9348
9446
|
// (0, 1, 0) aka ZERO is invalid in most contexts.
|
|
9349
9447
|
// In BLS, ZERO can be serialized, so we allow it.
|
|
9350
9448
|
// (0, 0, 0) is invalid representation of ZERO.
|
|
9351
|
-
if (
|
|
9449
|
+
if (extraOpts.allowInfinityPoint && !Fp.is0(p.Y))
|
|
9352
9450
|
return;
|
|
9353
9451
|
throw new Error('bad point: ZERO');
|
|
9354
9452
|
}
|
|
@@ -9363,7 +9461,7 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9363
9461
|
return true;
|
|
9364
9462
|
});
|
|
9365
9463
|
function finishEndo(endoBeta, k1p, k2p, k1neg, k2neg) {
|
|
9366
|
-
k2p = new Point(Fp.mul(k2p.
|
|
9464
|
+
k2p = new Point(Fp.mul(k2p.X, endoBeta), k2p.Y, k2p.Z);
|
|
9367
9465
|
k1p = negateCt(k1neg, k1p);
|
|
9368
9466
|
k2p = negateCt(k2neg, k2p);
|
|
9369
9467
|
return k1p.add(k2p);
|
|
@@ -9375,12 +9473,15 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9375
9473
|
*/
|
|
9376
9474
|
class Point {
|
|
9377
9475
|
/** Does NOT validate if the point is valid. Use `.assertValidity()`. */
|
|
9378
|
-
constructor(
|
|
9379
|
-
this.
|
|
9380
|
-
this.
|
|
9381
|
-
this.
|
|
9476
|
+
constructor(X, Y, Z) {
|
|
9477
|
+
this.X = acoord('x', X);
|
|
9478
|
+
this.Y = acoord('y', Y, true);
|
|
9479
|
+
this.Z = acoord('z', Z);
|
|
9382
9480
|
Object.freeze(this);
|
|
9383
9481
|
}
|
|
9482
|
+
static CURVE() {
|
|
9483
|
+
return CURVE;
|
|
9484
|
+
}
|
|
9384
9485
|
/** Does NOT validate if the point is valid. Use `.assertValidity()`. */
|
|
9385
9486
|
static fromAffine(p) {
|
|
9386
9487
|
const { x, y } = p || {};
|
|
@@ -9393,33 +9494,19 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9393
9494
|
return Point.ZERO;
|
|
9394
9495
|
return new Point(x, y, Fp.ONE);
|
|
9395
9496
|
}
|
|
9396
|
-
get x() {
|
|
9397
|
-
return this.toAffine().x;
|
|
9398
|
-
}
|
|
9399
|
-
get y() {
|
|
9400
|
-
return this.toAffine().y;
|
|
9401
|
-
}
|
|
9402
|
-
static normalizeZ(points) {
|
|
9403
|
-
return normalizeZ(Point, 'pz', points);
|
|
9404
|
-
}
|
|
9405
9497
|
static fromBytes(bytes) {
|
|
9406
|
-
|
|
9407
|
-
return Point.fromHex(bytes);
|
|
9408
|
-
}
|
|
9409
|
-
/** Converts hash string or Uint8Array to Point. */
|
|
9410
|
-
static fromHex(hex) {
|
|
9411
|
-
const P = Point.fromAffine(fromBytes(ensureBytes$1('pointHex', hex)));
|
|
9498
|
+
const P = Point.fromAffine(decodePoint(_abytes2(bytes, undefined, 'point')));
|
|
9412
9499
|
P.assertValidity();
|
|
9413
9500
|
return P;
|
|
9414
9501
|
}
|
|
9415
|
-
|
|
9416
|
-
|
|
9417
|
-
const normPrivateKeyToScalar = _legacyHelperNormPriv(Fn, curveOpts.allowedPrivateKeyLengths, curveOpts.wrapPrivateKey);
|
|
9418
|
-
return Point.BASE.multiply(normPrivateKeyToScalar(privateKey));
|
|
9502
|
+
static fromHex(hex) {
|
|
9503
|
+
return Point.fromBytes(ensureBytes$1('pointHex', hex));
|
|
9419
9504
|
}
|
|
9420
|
-
|
|
9421
|
-
|
|
9422
|
-
|
|
9505
|
+
get x() {
|
|
9506
|
+
return this.toAffine().x;
|
|
9507
|
+
}
|
|
9508
|
+
get y() {
|
|
9509
|
+
return this.toAffine().y;
|
|
9423
9510
|
}
|
|
9424
9511
|
/**
|
|
9425
9512
|
*
|
|
@@ -9428,15 +9515,11 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9428
9515
|
* @returns
|
|
9429
9516
|
*/
|
|
9430
9517
|
precompute(windowSize = 8, isLazy = true) {
|
|
9431
|
-
wnaf.
|
|
9518
|
+
wnaf.createCache(this, windowSize);
|
|
9432
9519
|
if (!isLazy)
|
|
9433
9520
|
this.multiply(_3n$2); // random number
|
|
9434
9521
|
return this;
|
|
9435
9522
|
}
|
|
9436
|
-
/** "Private method", don't use it directly */
|
|
9437
|
-
_setWindowSize(windowSize) {
|
|
9438
|
-
this.precompute(windowSize);
|
|
9439
|
-
}
|
|
9440
9523
|
// TODO: return `this`
|
|
9441
9524
|
/** A point on curve is valid if it conforms to equation. */
|
|
9442
9525
|
assertValidity() {
|
|
@@ -9451,15 +9534,15 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9451
9534
|
/** Compare one point to another. */
|
|
9452
9535
|
equals(other) {
|
|
9453
9536
|
aprjpoint(other);
|
|
9454
|
-
const {
|
|
9455
|
-
const {
|
|
9537
|
+
const { X: X1, Y: Y1, Z: Z1 } = this;
|
|
9538
|
+
const { X: X2, Y: Y2, Z: Z2 } = other;
|
|
9456
9539
|
const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
|
|
9457
9540
|
const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
|
|
9458
9541
|
return U1 && U2;
|
|
9459
9542
|
}
|
|
9460
9543
|
/** Flips point to one corresponding to (x, -y) in Affine coordinates. */
|
|
9461
9544
|
negate() {
|
|
9462
|
-
return new Point(this.
|
|
9545
|
+
return new Point(this.X, Fp.neg(this.Y), this.Z);
|
|
9463
9546
|
}
|
|
9464
9547
|
// Renes-Costello-Batina exception-free doubling formula.
|
|
9465
9548
|
// There is 30% faster Jacobian formula, but it is not complete.
|
|
@@ -9468,7 +9551,7 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9468
9551
|
double() {
|
|
9469
9552
|
const { a, b } = CURVE;
|
|
9470
9553
|
const b3 = Fp.mul(b, _3n$2);
|
|
9471
|
-
const {
|
|
9554
|
+
const { X: X1, Y: Y1, Z: Z1 } = this;
|
|
9472
9555
|
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
|
|
9473
9556
|
let t0 = Fp.mul(X1, X1); // step 1
|
|
9474
9557
|
let t1 = Fp.mul(Y1, Y1);
|
|
@@ -9509,8 +9592,8 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9509
9592
|
// Cost: 12M + 0S + 3*a + 3*b3 + 23add.
|
|
9510
9593
|
add(other) {
|
|
9511
9594
|
aprjpoint(other);
|
|
9512
|
-
const {
|
|
9513
|
-
const {
|
|
9595
|
+
const { X: X1, Y: Y1, Z: Z1 } = this;
|
|
9596
|
+
const { X: X2, Y: Y2, Z: Z2 } = other;
|
|
9514
9597
|
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO; // prettier-ignore
|
|
9515
9598
|
const a = CURVE.a;
|
|
9516
9599
|
const b3 = Fp.mul(CURVE.b, _3n$2);
|
|
@@ -9572,14 +9655,14 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9572
9655
|
* @returns New point
|
|
9573
9656
|
*/
|
|
9574
9657
|
multiply(scalar) {
|
|
9575
|
-
const { endo } =
|
|
9658
|
+
const { endo } = extraOpts;
|
|
9576
9659
|
if (!Fn.isValidNot0(scalar))
|
|
9577
9660
|
throw new Error('invalid scalar: out of range'); // 0 is invalid
|
|
9578
9661
|
let point, fake; // Fake point is used to const-time mult
|
|
9579
|
-
const mul = (n) => wnaf.
|
|
9662
|
+
const mul = (n) => wnaf.cached(this, n, (p) => normalizeZ(Point, p));
|
|
9580
9663
|
/** See docs for {@link EndomorphismOpts} */
|
|
9581
9664
|
if (endo) {
|
|
9582
|
-
const { k1neg, k1, k2neg, k2 } =
|
|
9665
|
+
const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(scalar);
|
|
9583
9666
|
const { p: k1p, f: k1f } = mul(k1);
|
|
9584
9667
|
const { p: k2p, f: k2f } = mul(k2);
|
|
9585
9668
|
fake = k1f.add(k2f);
|
|
@@ -9591,32 +9674,31 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9591
9674
|
fake = f;
|
|
9592
9675
|
}
|
|
9593
9676
|
// Normalize `z` for both points, but return only real one
|
|
9594
|
-
return
|
|
9677
|
+
return normalizeZ(Point, [point, fake])[0];
|
|
9595
9678
|
}
|
|
9596
9679
|
/**
|
|
9597
9680
|
* Non-constant-time multiplication. Uses double-and-add algorithm.
|
|
9598
9681
|
* It's faster, but should only be used when you don't care about
|
|
9599
|
-
* an exposed
|
|
9682
|
+
* an exposed secret key e.g. sig verification, which works over *public* keys.
|
|
9600
9683
|
*/
|
|
9601
9684
|
multiplyUnsafe(sc) {
|
|
9602
|
-
const { endo } =
|
|
9685
|
+
const { endo } = extraOpts;
|
|
9603
9686
|
const p = this;
|
|
9604
9687
|
if (!Fn.isValid(sc))
|
|
9605
9688
|
throw new Error('invalid scalar: out of range'); // 0 is valid
|
|
9606
9689
|
if (sc === _0n$6 || p.is0())
|
|
9607
9690
|
return Point.ZERO;
|
|
9608
|
-
if (sc === _1n$
|
|
9691
|
+
if (sc === _1n$7)
|
|
9609
9692
|
return p; // fast-path
|
|
9610
|
-
if (wnaf.
|
|
9693
|
+
if (wnaf.hasCache(this))
|
|
9611
9694
|
return this.multiply(sc);
|
|
9612
9695
|
if (endo) {
|
|
9613
|
-
const { k1neg, k1, k2neg, k2 } =
|
|
9614
|
-
|
|
9615
|
-
const { p1, p2 } = mulEndoUnsafe(Point, p, k1, k2);
|
|
9696
|
+
const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(sc);
|
|
9697
|
+
const { p1, p2 } = mulEndoUnsafe(Point, p, k1, k2); // 30% faster vs wnaf.unsafe
|
|
9616
9698
|
return finishEndo(endo.beta, p1, p2, k1neg, k2neg);
|
|
9617
9699
|
}
|
|
9618
9700
|
else {
|
|
9619
|
-
return wnaf.
|
|
9701
|
+
return wnaf.unsafe(p, sc);
|
|
9620
9702
|
}
|
|
9621
9703
|
}
|
|
9622
9704
|
multiplyAndAddUnsafe(Q, a, b) {
|
|
@@ -9635,29 +9717,29 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9635
9717
|
* Always torsion-free for cofactor=1 curves.
|
|
9636
9718
|
*/
|
|
9637
9719
|
isTorsionFree() {
|
|
9638
|
-
const { isTorsionFree } =
|
|
9639
|
-
if (cofactor === _1n$
|
|
9720
|
+
const { isTorsionFree } = extraOpts;
|
|
9721
|
+
if (cofactor === _1n$7)
|
|
9640
9722
|
return true;
|
|
9641
9723
|
if (isTorsionFree)
|
|
9642
9724
|
return isTorsionFree(Point, this);
|
|
9643
|
-
return wnaf.
|
|
9725
|
+
return wnaf.unsafe(this, CURVE_ORDER).is0();
|
|
9644
9726
|
}
|
|
9645
9727
|
clearCofactor() {
|
|
9646
|
-
const { clearCofactor } =
|
|
9647
|
-
if (cofactor === _1n$
|
|
9728
|
+
const { clearCofactor } = extraOpts;
|
|
9729
|
+
if (cofactor === _1n$7)
|
|
9648
9730
|
return this; // Fast-path
|
|
9649
9731
|
if (clearCofactor)
|
|
9650
9732
|
return clearCofactor(Point, this);
|
|
9651
9733
|
return this.multiplyUnsafe(cofactor);
|
|
9652
9734
|
}
|
|
9735
|
+
isSmallOrder() {
|
|
9736
|
+
// can we use this.clearCofactor()?
|
|
9737
|
+
return this.multiplyUnsafe(cofactor).is0();
|
|
9738
|
+
}
|
|
9653
9739
|
toBytes(isCompressed = true) {
|
|
9654
|
-
|
|
9740
|
+
_abool2(isCompressed, 'isCompressed');
|
|
9655
9741
|
this.assertValidity();
|
|
9656
|
-
return
|
|
9657
|
-
}
|
|
9658
|
-
/** @deprecated use `toBytes` */
|
|
9659
|
-
toRawBytes(isCompressed = true) {
|
|
9660
|
-
return this.toBytes(isCompressed);
|
|
9742
|
+
return encodePoint(Point, this, isCompressed);
|
|
9661
9743
|
}
|
|
9662
9744
|
toHex(isCompressed = true) {
|
|
9663
9745
|
return bytesToHex$1(this.toBytes(isCompressed));
|
|
@@ -9665,24 +9747,168 @@ function weierstrassN(CURVE, curveOpts = {}) {
|
|
|
9665
9747
|
toString() {
|
|
9666
9748
|
return `<Point ${this.is0() ? 'ZERO' : this.toHex()}>`;
|
|
9667
9749
|
}
|
|
9750
|
+
// TODO: remove
|
|
9751
|
+
get px() {
|
|
9752
|
+
return this.X;
|
|
9753
|
+
}
|
|
9754
|
+
get py() {
|
|
9755
|
+
return this.X;
|
|
9756
|
+
}
|
|
9757
|
+
get pz() {
|
|
9758
|
+
return this.Z;
|
|
9759
|
+
}
|
|
9760
|
+
toRawBytes(isCompressed = true) {
|
|
9761
|
+
return this.toBytes(isCompressed);
|
|
9762
|
+
}
|
|
9763
|
+
_setWindowSize(windowSize) {
|
|
9764
|
+
this.precompute(windowSize);
|
|
9765
|
+
}
|
|
9766
|
+
static normalizeZ(points) {
|
|
9767
|
+
return normalizeZ(Point, points);
|
|
9768
|
+
}
|
|
9769
|
+
static msm(points, scalars) {
|
|
9770
|
+
return pippenger(Point, Fn, points, scalars);
|
|
9771
|
+
}
|
|
9772
|
+
static fromPrivateKey(privateKey) {
|
|
9773
|
+
return Point.BASE.multiply(_normFnElement(Fn, privateKey));
|
|
9774
|
+
}
|
|
9668
9775
|
}
|
|
9669
9776
|
// base / generator point
|
|
9670
9777
|
Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
|
|
9671
9778
|
// zero / infinity / identity point
|
|
9672
9779
|
Point.ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO); // 0, 1, 0
|
|
9673
|
-
//
|
|
9780
|
+
// math field
|
|
9674
9781
|
Point.Fp = Fp;
|
|
9782
|
+
// scalar field
|
|
9675
9783
|
Point.Fn = Fn;
|
|
9676
9784
|
const bits = Fn.BITS;
|
|
9677
|
-
const wnaf = wNAF$1(Point,
|
|
9785
|
+
const wnaf = new wNAF$1(Point, extraOpts.endo ? Math.ceil(bits / 2) : bits);
|
|
9678
9786
|
return Point;
|
|
9679
9787
|
}
|
|
9680
9788
|
// Points start with byte 0x02 when y is even; otherwise 0x03
|
|
9681
9789
|
function pprefix(hasEvenY) {
|
|
9682
9790
|
return Uint8Array.of(hasEvenY ? 0x02 : 0x03);
|
|
9683
9791
|
}
|
|
9684
|
-
function
|
|
9685
|
-
|
|
9792
|
+
function getWLengths(Fp, Fn) {
|
|
9793
|
+
return {
|
|
9794
|
+
secret: Fn.BYTES,
|
|
9795
|
+
public: 1 + Fp.BYTES,
|
|
9796
|
+
publicUncompressed: 1 + 2 * Fp.BYTES,
|
|
9797
|
+
publicKeyHasPrefix: true,
|
|
9798
|
+
signature: 2 * Fn.BYTES,
|
|
9799
|
+
};
|
|
9800
|
+
}
|
|
9801
|
+
/**
|
|
9802
|
+
* Sometimes users only need getPublicKey, getSharedSecret, and secret key handling.
|
|
9803
|
+
* This helper ensures no signature functionality is present. Less code, smaller bundle size.
|
|
9804
|
+
*/
|
|
9805
|
+
function ecdh(Point, ecdhOpts = {}) {
|
|
9806
|
+
const { Fn } = Point;
|
|
9807
|
+
const randomBytes_ = ecdhOpts.randomBytes || randomBytes$3;
|
|
9808
|
+
const lengths = Object.assign(getWLengths(Point.Fp, Fn), { seed: getMinHashLength$1(Fn.ORDER) });
|
|
9809
|
+
function isValidSecretKey(secretKey) {
|
|
9810
|
+
try {
|
|
9811
|
+
return !!_normFnElement(Fn, secretKey);
|
|
9812
|
+
}
|
|
9813
|
+
catch (error) {
|
|
9814
|
+
return false;
|
|
9815
|
+
}
|
|
9816
|
+
}
|
|
9817
|
+
function isValidPublicKey(publicKey, isCompressed) {
|
|
9818
|
+
const { public: comp, publicUncompressed } = lengths;
|
|
9819
|
+
try {
|
|
9820
|
+
const l = publicKey.length;
|
|
9821
|
+
if (isCompressed === true && l !== comp)
|
|
9822
|
+
return false;
|
|
9823
|
+
if (isCompressed === false && l !== publicUncompressed)
|
|
9824
|
+
return false;
|
|
9825
|
+
return !!Point.fromBytes(publicKey);
|
|
9826
|
+
}
|
|
9827
|
+
catch (error) {
|
|
9828
|
+
return false;
|
|
9829
|
+
}
|
|
9830
|
+
}
|
|
9831
|
+
/**
|
|
9832
|
+
* Produces cryptographically secure secret key from random of size
|
|
9833
|
+
* (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
|
|
9834
|
+
*/
|
|
9835
|
+
function randomSecretKey(seed = randomBytes_(lengths.seed)) {
|
|
9836
|
+
return mapHashToField$1(_abytes2(seed, lengths.seed, 'seed'), Fn.ORDER);
|
|
9837
|
+
}
|
|
9838
|
+
/**
|
|
9839
|
+
* Computes public key for a secret key. Checks for validity of the secret key.
|
|
9840
|
+
* @param isCompressed whether to return compact (default), or full key
|
|
9841
|
+
* @returns Public key, full when isCompressed=false; short when isCompressed=true
|
|
9842
|
+
*/
|
|
9843
|
+
function getPublicKey(secretKey, isCompressed = true) {
|
|
9844
|
+
return Point.BASE.multiply(_normFnElement(Fn, secretKey)).toBytes(isCompressed);
|
|
9845
|
+
}
|
|
9846
|
+
function keygen(seed) {
|
|
9847
|
+
const secretKey = randomSecretKey(seed);
|
|
9848
|
+
return { secretKey, publicKey: getPublicKey(secretKey) };
|
|
9849
|
+
}
|
|
9850
|
+
/**
|
|
9851
|
+
* Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
|
|
9852
|
+
*/
|
|
9853
|
+
function isProbPub(item) {
|
|
9854
|
+
if (typeof item === 'bigint')
|
|
9855
|
+
return false;
|
|
9856
|
+
if (item instanceof Point)
|
|
9857
|
+
return true;
|
|
9858
|
+
if (Fn.allowedLengths || lengths.secret === lengths.public)
|
|
9859
|
+
return undefined;
|
|
9860
|
+
const l = ensureBytes$1('key', item).length;
|
|
9861
|
+
return l === lengths.public || l === lengths.publicUncompressed;
|
|
9862
|
+
}
|
|
9863
|
+
/**
|
|
9864
|
+
* ECDH (Elliptic Curve Diffie Hellman).
|
|
9865
|
+
* Computes shared public key from secret key A and public key B.
|
|
9866
|
+
* Checks: 1) secret key validity 2) shared key is on-curve.
|
|
9867
|
+
* Does NOT hash the result.
|
|
9868
|
+
* @param isCompressed whether to return compact (default), or full key
|
|
9869
|
+
* @returns shared public key
|
|
9870
|
+
*/
|
|
9871
|
+
function getSharedSecret(secretKeyA, publicKeyB, isCompressed = true) {
|
|
9872
|
+
if (isProbPub(secretKeyA) === true)
|
|
9873
|
+
throw new Error('first arg must be private key');
|
|
9874
|
+
if (isProbPub(publicKeyB) === false)
|
|
9875
|
+
throw new Error('second arg must be public key');
|
|
9876
|
+
const s = _normFnElement(Fn, secretKeyA);
|
|
9877
|
+
const b = Point.fromHex(publicKeyB); // checks for being on-curve
|
|
9878
|
+
return b.multiply(s).toBytes(isCompressed);
|
|
9879
|
+
}
|
|
9880
|
+
const utils = {
|
|
9881
|
+
isValidSecretKey,
|
|
9882
|
+
isValidPublicKey,
|
|
9883
|
+
randomSecretKey,
|
|
9884
|
+
// TODO: remove
|
|
9885
|
+
isValidPrivateKey: isValidSecretKey,
|
|
9886
|
+
randomPrivateKey: randomSecretKey,
|
|
9887
|
+
normPrivateKeyToScalar: (key) => _normFnElement(Fn, key),
|
|
9888
|
+
precompute(windowSize = 8, point = Point.BASE) {
|
|
9889
|
+
return point.precompute(windowSize, false);
|
|
9890
|
+
},
|
|
9891
|
+
};
|
|
9892
|
+
return Object.freeze({ getPublicKey, getSharedSecret, keygen, Point, utils, lengths });
|
|
9893
|
+
}
|
|
9894
|
+
/**
|
|
9895
|
+
* Creates ECDSA signing interface for given elliptic curve `Point` and `hash` function.
|
|
9896
|
+
* We need `hash` for 2 features:
|
|
9897
|
+
* 1. Message prehash-ing. NOT used if `sign` / `verify` are called with `prehash: false`
|
|
9898
|
+
* 2. k generation in `sign`, using HMAC-drbg(hash)
|
|
9899
|
+
*
|
|
9900
|
+
* ECDSAOpts are only rarely needed.
|
|
9901
|
+
*
|
|
9902
|
+
* @example
|
|
9903
|
+
* ```js
|
|
9904
|
+
* const p256_Point = weierstrass(...);
|
|
9905
|
+
* const p256_sha256 = ecdsa(p256_Point, sha256);
|
|
9906
|
+
* const p256_sha224 = ecdsa(p256_Point, sha224);
|
|
9907
|
+
* ```
|
|
9908
|
+
*/
|
|
9909
|
+
function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
9910
|
+
ahash(hash);
|
|
9911
|
+
_validateObject(ecdsaOpts, {}, {
|
|
9686
9912
|
hmac: 'function',
|
|
9687
9913
|
lowS: 'boolean',
|
|
9688
9914
|
randomBytes: 'function',
|
|
@@ -9691,54 +9917,66 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
9691
9917
|
});
|
|
9692
9918
|
const randomBytes_ = ecdsaOpts.randomBytes || randomBytes$3;
|
|
9693
9919
|
const hmac_ = ecdsaOpts.hmac ||
|
|
9694
|
-
((key, ...msgs) => hmac$1(
|
|
9920
|
+
((key, ...msgs) => hmac$1(hash, key, concatBytes$2(...msgs)));
|
|
9695
9921
|
const { Fp, Fn } = Point;
|
|
9696
9922
|
const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
|
|
9923
|
+
const { keygen, getPublicKey, getSharedSecret, utils, lengths } = ecdh(Point, ecdsaOpts);
|
|
9924
|
+
const defaultSigOpts = {
|
|
9925
|
+
prehash: false,
|
|
9926
|
+
lowS: typeof ecdsaOpts.lowS === 'boolean' ? ecdsaOpts.lowS : false,
|
|
9927
|
+
format: undefined, //'compact' as ECDSASigFormat,
|
|
9928
|
+
extraEntropy: false,
|
|
9929
|
+
};
|
|
9930
|
+
const defaultSigOpts_format = 'compact';
|
|
9697
9931
|
function isBiggerThanHalfOrder(number) {
|
|
9698
|
-
const HALF = CURVE_ORDER >> _1n$
|
|
9932
|
+
const HALF = CURVE_ORDER >> _1n$7;
|
|
9699
9933
|
return number > HALF;
|
|
9700
9934
|
}
|
|
9701
9935
|
function normalizeS(s) {
|
|
9702
9936
|
return isBiggerThanHalfOrder(s) ? Fn.neg(s) : s;
|
|
9703
9937
|
}
|
|
9704
|
-
function
|
|
9938
|
+
function validateRS(title, num) {
|
|
9705
9939
|
if (!Fn.isValidNot0(num))
|
|
9706
|
-
throw new Error(`invalid signature ${title}: out of range 1..
|
|
9940
|
+
throw new Error(`invalid signature ${title}: out of range 1..Point.Fn.ORDER`);
|
|
9941
|
+
return num;
|
|
9707
9942
|
}
|
|
9708
9943
|
/**
|
|
9709
|
-
* ECDSA signature with its (r, s) properties. Supports
|
|
9944
|
+
* ECDSA signature with its (r, s) properties. Supports compact, recovered & DER representations.
|
|
9710
9945
|
*/
|
|
9711
9946
|
class Signature {
|
|
9712
9947
|
constructor(r, s, recovery) {
|
|
9713
|
-
|
|
9714
|
-
|
|
9715
|
-
this.r = r;
|
|
9716
|
-
this.s = s;
|
|
9948
|
+
this.r = validateRS('r', r); // r in [1..N-1];
|
|
9949
|
+
this.s = validateRS('s', s); // s in [1..N-1];
|
|
9717
9950
|
if (recovery != null)
|
|
9718
9951
|
this.recovery = recovery;
|
|
9719
9952
|
Object.freeze(this);
|
|
9720
9953
|
}
|
|
9721
|
-
|
|
9722
|
-
|
|
9723
|
-
const
|
|
9724
|
-
|
|
9725
|
-
|
|
9954
|
+
static fromBytes(bytes, format = defaultSigOpts_format) {
|
|
9955
|
+
validateSigFormat(format);
|
|
9956
|
+
const size = lengths.signature;
|
|
9957
|
+
let recid;
|
|
9958
|
+
if (format === 'der') {
|
|
9959
|
+
const { r, s } = DER$1.toSig(_abytes2(bytes));
|
|
9960
|
+
return new Signature(r, s);
|
|
9961
|
+
}
|
|
9962
|
+
if (format === 'recovered') {
|
|
9963
|
+
_abytes2(bytes, size + 1);
|
|
9964
|
+
recid = bytes[0];
|
|
9965
|
+
format = 'compact';
|
|
9966
|
+
bytes = bytes.subarray(1);
|
|
9967
|
+
}
|
|
9968
|
+
_abytes2(bytes, size);
|
|
9969
|
+
const L = size / 2;
|
|
9970
|
+
const r = bytes.subarray(0, L);
|
|
9971
|
+
const s = bytes.subarray(L, L * 2);
|
|
9972
|
+
return new Signature(Fn.fromBytes(r), Fn.fromBytes(s), recid);
|
|
9726
9973
|
}
|
|
9727
|
-
|
|
9728
|
-
|
|
9729
|
-
static fromDER(hex) {
|
|
9730
|
-
const { r, s } = DER$1.toSig(ensureBytes$1('DER', hex));
|
|
9731
|
-
return new Signature(r, s);
|
|
9974
|
+
static fromHex(hex, format) {
|
|
9975
|
+
return this.fromBytes(hexToBytes$1(hex), format);
|
|
9732
9976
|
}
|
|
9733
|
-
/**
|
|
9734
|
-
* @todo remove
|
|
9735
|
-
* @deprecated
|
|
9736
|
-
*/
|
|
9737
|
-
assertValidity() { }
|
|
9738
9977
|
addRecoveryBit(recovery) {
|
|
9739
9978
|
return new Signature(this.r, this.s, recovery);
|
|
9740
9979
|
}
|
|
9741
|
-
// ProjPointType<bigint>
|
|
9742
9980
|
recoverPublicKey(msgHash) {
|
|
9743
9981
|
const FIELD_ORDER = Fp.ORDER;
|
|
9744
9982
|
const { r, s, recovery: rec } = this;
|
|
@@ -9759,7 +9997,7 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
9759
9997
|
if (!Fp.isValid(radj))
|
|
9760
9998
|
throw new Error('recovery id 2 or 3 invalid');
|
|
9761
9999
|
const x = Fp.toBytes(radj);
|
|
9762
|
-
const R = Point.
|
|
10000
|
+
const R = Point.fromBytes(concatBytes$2(pprefix((rec & 1) === 0), x));
|
|
9763
10001
|
const ir = Fn.inv(radj); // r^-1
|
|
9764
10002
|
const h = bits2int_modN(ensureBytes$1('msgHash', msgHash)); // Truncate hash
|
|
9765
10003
|
const u1 = Fn.create(-h * ir); // -hr^-1
|
|
@@ -9775,24 +10013,39 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
9775
10013
|
hasHighS() {
|
|
9776
10014
|
return isBiggerThanHalfOrder(this.s);
|
|
9777
10015
|
}
|
|
9778
|
-
|
|
9779
|
-
|
|
9780
|
-
}
|
|
9781
|
-
toBytes(format) {
|
|
9782
|
-
if (format === 'compact')
|
|
9783
|
-
return concatBytes$2(Fn.toBytes(this.r), Fn.toBytes(this.s));
|
|
10016
|
+
toBytes(format = defaultSigOpts_format) {
|
|
10017
|
+
validateSigFormat(format);
|
|
9784
10018
|
if (format === 'der')
|
|
9785
10019
|
return hexToBytes$1(DER$1.hexFromSig(this));
|
|
9786
|
-
|
|
10020
|
+
const r = Fn.toBytes(this.r);
|
|
10021
|
+
const s = Fn.toBytes(this.s);
|
|
10022
|
+
if (format === 'recovered') {
|
|
10023
|
+
if (this.recovery == null)
|
|
10024
|
+
throw new Error('recovery bit must be present');
|
|
10025
|
+
return concatBytes$2(Uint8Array.of(this.recovery), r, s);
|
|
10026
|
+
}
|
|
10027
|
+
return concatBytes$2(r, s);
|
|
10028
|
+
}
|
|
10029
|
+
toHex(format) {
|
|
10030
|
+
return bytesToHex$1(this.toBytes(format));
|
|
10031
|
+
}
|
|
10032
|
+
// TODO: remove
|
|
10033
|
+
assertValidity() { }
|
|
10034
|
+
static fromCompact(hex) {
|
|
10035
|
+
return Signature.fromBytes(ensureBytes$1('sig', hex), 'compact');
|
|
10036
|
+
}
|
|
10037
|
+
static fromDER(hex) {
|
|
10038
|
+
return Signature.fromBytes(ensureBytes$1('sig', hex), 'der');
|
|
10039
|
+
}
|
|
10040
|
+
normalizeS() {
|
|
10041
|
+
return this.hasHighS() ? new Signature(this.r, Fn.neg(this.s), this.recovery) : this;
|
|
9787
10042
|
}
|
|
9788
|
-
// DER-encoded
|
|
9789
10043
|
toDERRawBytes() {
|
|
9790
10044
|
return this.toBytes('der');
|
|
9791
10045
|
}
|
|
9792
10046
|
toDERHex() {
|
|
9793
10047
|
return bytesToHex$1(this.toBytes('der'));
|
|
9794
10048
|
}
|
|
9795
|
-
// padded bytes of r, then padded bytes of s
|
|
9796
10049
|
toCompactRawBytes() {
|
|
9797
10050
|
return this.toBytes('compact');
|
|
9798
10051
|
}
|
|
@@ -9800,77 +10053,6 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
9800
10053
|
return bytesToHex$1(this.toBytes('compact'));
|
|
9801
10054
|
}
|
|
9802
10055
|
}
|
|
9803
|
-
const normPrivateKeyToScalar = _legacyHelperNormPriv(Fn, curveOpts.allowedPrivateKeyLengths, curveOpts.wrapPrivateKey);
|
|
9804
|
-
const utils = {
|
|
9805
|
-
isValidPrivateKey(privateKey) {
|
|
9806
|
-
try {
|
|
9807
|
-
normPrivateKeyToScalar(privateKey);
|
|
9808
|
-
return true;
|
|
9809
|
-
}
|
|
9810
|
-
catch (error) {
|
|
9811
|
-
return false;
|
|
9812
|
-
}
|
|
9813
|
-
},
|
|
9814
|
-
normPrivateKeyToScalar: normPrivateKeyToScalar,
|
|
9815
|
-
/**
|
|
9816
|
-
* Produces cryptographically secure private key from random of size
|
|
9817
|
-
* (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
|
|
9818
|
-
*/
|
|
9819
|
-
randomPrivateKey: () => {
|
|
9820
|
-
const n = CURVE_ORDER;
|
|
9821
|
-
return mapHashToField$1(randomBytes_(getMinHashLength$1(n)), n);
|
|
9822
|
-
},
|
|
9823
|
-
precompute(windowSize = 8, point = Point.BASE) {
|
|
9824
|
-
return point.precompute(windowSize, false);
|
|
9825
|
-
},
|
|
9826
|
-
};
|
|
9827
|
-
/**
|
|
9828
|
-
* Computes public key for a private key. Checks for validity of the private key.
|
|
9829
|
-
* @param privateKey private key
|
|
9830
|
-
* @param isCompressed whether to return compact (default), or full key
|
|
9831
|
-
* @returns Public key, full when isCompressed=false; short when isCompressed=true
|
|
9832
|
-
*/
|
|
9833
|
-
function getPublicKey(privateKey, isCompressed = true) {
|
|
9834
|
-
return Point.fromPrivateKey(privateKey).toBytes(isCompressed);
|
|
9835
|
-
}
|
|
9836
|
-
/**
|
|
9837
|
-
* Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
|
|
9838
|
-
*/
|
|
9839
|
-
function isProbPub(item) {
|
|
9840
|
-
if (typeof item === 'bigint')
|
|
9841
|
-
return false;
|
|
9842
|
-
if (item instanceof Point)
|
|
9843
|
-
return true;
|
|
9844
|
-
const arr = ensureBytes$1('key', item);
|
|
9845
|
-
const length = arr.length;
|
|
9846
|
-
const L = Fp.BYTES;
|
|
9847
|
-
const LC = L + 1; // e.g. 33 for 32
|
|
9848
|
-
const LU = 2 * L + 1; // e.g. 65 for 32
|
|
9849
|
-
if (curveOpts.allowedPrivateKeyLengths || Fn.BYTES === LC) {
|
|
9850
|
-
return undefined;
|
|
9851
|
-
}
|
|
9852
|
-
else {
|
|
9853
|
-
return length === LC || length === LU;
|
|
9854
|
-
}
|
|
9855
|
-
}
|
|
9856
|
-
/**
|
|
9857
|
-
* ECDH (Elliptic Curve Diffie Hellman).
|
|
9858
|
-
* Computes shared public key from private key and public key.
|
|
9859
|
-
* Checks: 1) private key validity 2) shared key is on-curve.
|
|
9860
|
-
* Does NOT hash the result.
|
|
9861
|
-
* @param privateA private key
|
|
9862
|
-
* @param publicB different public key
|
|
9863
|
-
* @param isCompressed whether to return compact (default), or full key
|
|
9864
|
-
* @returns shared public key
|
|
9865
|
-
*/
|
|
9866
|
-
function getSharedSecret(privateA, publicB, isCompressed = true) {
|
|
9867
|
-
if (isProbPub(privateA) === true)
|
|
9868
|
-
throw new Error('first arg must be private key');
|
|
9869
|
-
if (isProbPub(publicB) === false)
|
|
9870
|
-
throw new Error('second arg must be public key');
|
|
9871
|
-
const b = Point.fromHex(publicB); // check for being on-curve
|
|
9872
|
-
return b.multiply(normPrivateKeyToScalar(privateA)).toBytes(isCompressed);
|
|
9873
|
-
}
|
|
9874
10056
|
// RFC6979: ensure ECDSA msg is X bytes and < N. RFC suggests optional truncating via bits2octets.
|
|
9875
10057
|
// FIPS 186-4 4.6 suggests the leftmost min(nBitLen, outLen) bits, which matches bits2int.
|
|
9876
10058
|
// bits2int can produce res>N, we can do mod(res, N) since the bitLen is the same.
|
|
@@ -9900,55 +10082,60 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
9900
10082
|
aInRange('num < 2^' + fnBits, num, _0n$6, ORDER_MASK);
|
|
9901
10083
|
return Fn.toBytes(num);
|
|
9902
10084
|
}
|
|
9903
|
-
|
|
9904
|
-
|
|
9905
|
-
|
|
9906
|
-
|
|
9907
|
-
|
|
9908
|
-
|
|
10085
|
+
/**
|
|
10086
|
+
* Steps A, D of RFC6979 3.2.
|
|
10087
|
+
* Creates RFC6979 seed; converts msg/privKey to numbers.
|
|
10088
|
+
* Used only in sign, not in verify.
|
|
10089
|
+
*
|
|
10090
|
+
* Warning: we cannot assume here that message has same amount of bytes as curve order,
|
|
10091
|
+
* this will be invalid at least for P521. Also it can be bigger for P224 + SHA256.
|
|
10092
|
+
*/
|
|
10093
|
+
function prepSig(message, privateKey, opts) {
|
|
9909
10094
|
if (['recovered', 'canonical'].some((k) => k in opts))
|
|
9910
10095
|
throw new Error('sign() legacy options not supported');
|
|
9911
|
-
const {
|
|
9912
|
-
|
|
9913
|
-
|
|
9914
|
-
lowS = true; // RFC6979 3.2: we skip step A, because we already provide hash
|
|
9915
|
-
msgHash = ensureBytes$1('msgHash', msgHash);
|
|
9916
|
-
validateSigVerOpts(opts);
|
|
10096
|
+
const { lowS, prehash, extraEntropy } = validateSigOpts(opts, defaultSigOpts);
|
|
10097
|
+
// RFC6979 3.2: we skip step A, because we already provide hash
|
|
10098
|
+
message = _abytes2(message, undefined, 'message');
|
|
9917
10099
|
if (prehash)
|
|
9918
|
-
|
|
10100
|
+
message = _abytes2(hash(message), undefined, 'prehashed message');
|
|
9919
10101
|
// We can't later call bits2octets, since nested bits2int is broken for curves
|
|
9920
10102
|
// with fnBits % 8 !== 0. Because of that, we unwrap it here as int2octets call.
|
|
9921
10103
|
// const bits2octets = (bits) => int2octets(bits2int_modN(bits))
|
|
9922
|
-
const h1int = bits2int_modN(
|
|
9923
|
-
const d =
|
|
10104
|
+
const h1int = bits2int_modN(message);
|
|
10105
|
+
const d = _normFnElement(Fn, privateKey); // validate secret key, convert to bigint
|
|
9924
10106
|
const seedArgs = [int2octets(d), int2octets(h1int)];
|
|
9925
10107
|
// extraEntropy. RFC6979 3.6: additional k' (optional).
|
|
9926
|
-
if (
|
|
10108
|
+
if (extraEntropy != null && extraEntropy !== false) {
|
|
9927
10109
|
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
|
|
9928
|
-
|
|
10110
|
+
// gen random bytes OR pass as-is
|
|
10111
|
+
const e = extraEntropy === true ? randomBytes_(lengths.secret) : extraEntropy;
|
|
9929
10112
|
seedArgs.push(ensureBytes$1('extraEntropy', e)); // check for being bytes
|
|
9930
10113
|
}
|
|
9931
10114
|
const seed = concatBytes$2(...seedArgs); // Step D of RFC6979 3.2
|
|
9932
10115
|
const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
|
|
9933
10116
|
// Converts signature params into point w r/s, checks result for validity.
|
|
10117
|
+
// To transform k => Signature:
|
|
10118
|
+
// q = k⋅G
|
|
10119
|
+
// r = q.x mod n
|
|
10120
|
+
// s = k^-1(m + rd) mod n
|
|
9934
10121
|
// Can use scalar blinding b^-1(bm + bdr) where b ∈ [1,q−1] according to
|
|
9935
10122
|
// https://tches.iacr.org/index.php/TCHES/article/view/7337/6509. We've decided against it:
|
|
9936
10123
|
// a) dependency on CSPRNG b) 15% slowdown c) doesn't really help since bigints are not CT
|
|
9937
10124
|
function k2sig(kBytes) {
|
|
9938
10125
|
// RFC 6979 Section 3.2, step 3: k = bits2int(T)
|
|
9939
10126
|
// Important: all mod() calls here must be done over N
|
|
9940
|
-
const k = bits2int(kBytes); //
|
|
10127
|
+
const k = bits2int(kBytes); // mod n, not mod p
|
|
9941
10128
|
if (!Fn.isValidNot0(k))
|
|
9942
10129
|
return; // Valid scalars (including k) must be in 1..N-1
|
|
9943
10130
|
const ik = Fn.inv(k); // k^-1 mod n
|
|
9944
|
-
const q = Point.BASE.multiply(k).toAffine(); // q =
|
|
10131
|
+
const q = Point.BASE.multiply(k).toAffine(); // q = k⋅G
|
|
9945
10132
|
const r = Fn.create(q.x); // r = q.x mod n
|
|
9946
10133
|
if (r === _0n$6)
|
|
9947
10134
|
return;
|
|
9948
10135
|
const s = Fn.create(ik * Fn.create(m + r * d)); // Not using blinding here, see comment above
|
|
9949
10136
|
if (s === _0n$6)
|
|
9950
10137
|
return;
|
|
9951
|
-
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n$
|
|
10138
|
+
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n$7); // recovery bit (2 or 3, when q.x > n)
|
|
9952
10139
|
let normS = s;
|
|
9953
10140
|
if (lowS && isBiggerThanHalfOrder(s)) {
|
|
9954
10141
|
normS = normalizeS(s); // if lowS was passed, ensure s is always
|
|
@@ -9958,131 +10145,136 @@ function ecdsa(Point, ecdsaOpts, curveOpts = {}) {
|
|
|
9958
10145
|
}
|
|
9959
10146
|
return { seed, k2sig };
|
|
9960
10147
|
}
|
|
9961
|
-
const defaultSigOpts = { lowS: ecdsaOpts.lowS, prehash: false };
|
|
9962
|
-
const defaultVerOpts = { lowS: ecdsaOpts.lowS, prehash: false };
|
|
9963
10148
|
/**
|
|
9964
|
-
* Signs message hash with a
|
|
10149
|
+
* Signs message hash with a secret key.
|
|
10150
|
+
*
|
|
9965
10151
|
* ```
|
|
9966
|
-
* sign(m, d
|
|
10152
|
+
* sign(m, d) where
|
|
10153
|
+
* k = rfc6979_hmac_drbg(m, d)
|
|
9967
10154
|
* (x, y) = G × k
|
|
9968
10155
|
* r = x mod n
|
|
9969
|
-
* s = (m + dr)/k mod n
|
|
10156
|
+
* s = (m + dr) / k mod n
|
|
9970
10157
|
* ```
|
|
9971
|
-
* @param msgHash NOT message. msg needs to be hashed to `msgHash`, or use `prehash`.
|
|
9972
|
-
* @param privKey private key
|
|
9973
|
-
* @param opts lowS for non-malleable sigs. extraEntropy for mixing randomness into k. prehash will hash first arg.
|
|
9974
|
-
* @returns signature with recovery param
|
|
9975
10158
|
*/
|
|
9976
|
-
function sign(
|
|
9977
|
-
|
|
9978
|
-
const
|
|
9979
|
-
|
|
10159
|
+
function sign(message, secretKey, opts = {}) {
|
|
10160
|
+
message = ensureBytes$1('message', message);
|
|
10161
|
+
const { seed, k2sig } = prepSig(message, secretKey, opts); // Steps A, D of RFC6979 3.2.
|
|
10162
|
+
const drbg = createHmacDrbg$1(hash.outputLen, Fn.BYTES, hmac_);
|
|
10163
|
+
const sig = drbg(seed, k2sig); // Steps B, C, D, E, F, G
|
|
10164
|
+
return sig;
|
|
9980
10165
|
}
|
|
9981
10166
|
// Enable precomputes. Slows down first publicKey computation by 20ms.
|
|
9982
10167
|
Point.BASE.precompute(8);
|
|
9983
10168
|
/**
|
|
9984
|
-
* Verifies a signature against message
|
|
9985
|
-
* Rejects lowS signatures by default:
|
|
9986
|
-
*
|
|
10169
|
+
* Verifies a signature against message and public key.
|
|
10170
|
+
* Rejects lowS signatures by default: see {@link ECDSAVerifyOpts}.
|
|
10171
|
+
* Implements section 4.1.4 from https://www.secg.org/sec1-v2.pdf:
|
|
9987
10172
|
*
|
|
9988
10173
|
* ```
|
|
9989
10174
|
* verify(r, s, h, P) where
|
|
9990
|
-
*
|
|
9991
|
-
*
|
|
9992
|
-
* R =
|
|
10175
|
+
* u1 = hs^-1 mod n
|
|
10176
|
+
* u2 = rs^-1 mod n
|
|
10177
|
+
* R = u1⋅G + u2⋅P
|
|
9993
10178
|
* mod(R.x, n) == r
|
|
9994
10179
|
* ```
|
|
9995
10180
|
*/
|
|
9996
|
-
function verify(signature,
|
|
10181
|
+
function verify(signature, message, publicKey, opts = {}) {
|
|
9997
10182
|
const sg = signature;
|
|
9998
|
-
|
|
10183
|
+
message = ensureBytes$1('msgHash', message);
|
|
9999
10184
|
publicKey = ensureBytes$1('publicKey', publicKey);
|
|
10000
|
-
|
|
10001
|
-
validateSigVerOpts(opts);
|
|
10002
|
-
const { lowS, prehash, format } = opts;
|
|
10003
|
-
// TODO: remove
|
|
10004
|
-
if ('strict' in opts)
|
|
10005
|
-
throw new Error('options.strict was renamed to lowS');
|
|
10006
|
-
if (format !== undefined && !['compact', 'der', 'js'].includes(format))
|
|
10007
|
-
throw new Error('format must be "compact", "der" or "js"');
|
|
10008
|
-
const isHex = typeof sg === 'string' || isBytes(sg);
|
|
10009
|
-
const isObj = !isHex &&
|
|
10010
|
-
!format &&
|
|
10011
|
-
typeof sg === 'object' &&
|
|
10012
|
-
sg !== null &&
|
|
10013
|
-
typeof sg.r === 'bigint' &&
|
|
10014
|
-
typeof sg.s === 'bigint';
|
|
10015
|
-
if (!isHex && !isObj)
|
|
10016
|
-
throw new Error('invalid signature, expected Uint8Array, hex string or Signature instance');
|
|
10185
|
+
const { lowS, prehash, format } = validateSigOpts(opts, defaultSigOpts);
|
|
10017
10186
|
let _sig = undefined;
|
|
10018
10187
|
let P;
|
|
10019
|
-
|
|
10020
|
-
|
|
10021
|
-
|
|
10022
|
-
//
|
|
10023
|
-
|
|
10024
|
-
|
|
10025
|
-
|
|
10026
|
-
|
|
10027
|
-
|
|
10028
|
-
|
|
10029
|
-
|
|
10188
|
+
if ('strict' in opts)
|
|
10189
|
+
throw new Error('options.strict was renamed to lowS');
|
|
10190
|
+
if (format === undefined) {
|
|
10191
|
+
// Try to deduce format
|
|
10192
|
+
const isHex = typeof sg === 'string' || isBytes(sg);
|
|
10193
|
+
const isObj = !isHex &&
|
|
10194
|
+
sg !== null &&
|
|
10195
|
+
typeof sg === 'object' &&
|
|
10196
|
+
typeof sg.r === 'bigint' &&
|
|
10197
|
+
typeof sg.s === 'bigint';
|
|
10198
|
+
if (!isHex && !isObj)
|
|
10199
|
+
throw new Error('invalid signature, expected Uint8Array, hex string or Signature instance');
|
|
10030
10200
|
if (isObj) {
|
|
10031
|
-
|
|
10032
|
-
_sig = new Signature(sg.r, sg.s);
|
|
10033
|
-
}
|
|
10034
|
-
else {
|
|
10035
|
-
throw new Error('invalid format');
|
|
10036
|
-
}
|
|
10201
|
+
_sig = new Signature(sg.r, sg.s);
|
|
10037
10202
|
}
|
|
10038
|
-
if (isHex) {
|
|
10203
|
+
else if (isHex) {
|
|
10039
10204
|
// TODO: remove this malleable check
|
|
10040
10205
|
// Signature can be represented in 2 ways: compact (2*Fn.BYTES) & DER (variable-length).
|
|
10041
10206
|
// Since DER can also be 2*Fn.BYTES bytes, we check for it first.
|
|
10042
10207
|
try {
|
|
10043
|
-
|
|
10044
|
-
_sig = Signature.fromDER(sg);
|
|
10208
|
+
_sig = Signature.fromDER(sg);
|
|
10045
10209
|
}
|
|
10046
10210
|
catch (derError) {
|
|
10047
10211
|
if (!(derError instanceof DER$1.Err))
|
|
10048
10212
|
throw derError;
|
|
10049
10213
|
}
|
|
10050
|
-
if (!_sig
|
|
10051
|
-
|
|
10214
|
+
if (!_sig) {
|
|
10215
|
+
try {
|
|
10216
|
+
_sig = Signature.fromCompact(sg);
|
|
10217
|
+
}
|
|
10218
|
+
catch (error) {
|
|
10219
|
+
return false;
|
|
10220
|
+
}
|
|
10221
|
+
}
|
|
10052
10222
|
}
|
|
10053
|
-
P = Point.fromHex(publicKey);
|
|
10054
10223
|
}
|
|
10055
|
-
|
|
10056
|
-
|
|
10224
|
+
else {
|
|
10225
|
+
if (format === 'compact' || format === 'der') {
|
|
10226
|
+
if (typeof sg !== 'string' && !isBytes(sg))
|
|
10227
|
+
throw new Error('"der" / "compact" format expects Uint8Array signature');
|
|
10228
|
+
_sig = Signature.fromBytes(ensureBytes$1('sig', sg), format);
|
|
10229
|
+
}
|
|
10230
|
+
else {
|
|
10231
|
+
throw new Error('format must be "compact", "der" or "js"');
|
|
10232
|
+
}
|
|
10057
10233
|
}
|
|
10058
10234
|
if (!_sig)
|
|
10059
10235
|
return false;
|
|
10060
|
-
|
|
10236
|
+
try {
|
|
10237
|
+
P = Point.fromHex(publicKey);
|
|
10238
|
+
if (lowS && _sig.hasHighS())
|
|
10239
|
+
return false;
|
|
10240
|
+
// todo: optional.hash => hash
|
|
10241
|
+
if (prehash)
|
|
10242
|
+
message = hash(message);
|
|
10243
|
+
const { r, s } = _sig;
|
|
10244
|
+
const h = bits2int_modN(message); // mod n, not mod p
|
|
10245
|
+
const is = Fn.inv(s); // s^-1 mod n
|
|
10246
|
+
const u1 = Fn.create(h * is); // u1 = hs^-1 mod n
|
|
10247
|
+
const u2 = Fn.create(r * is); // u2 = rs^-1 mod n
|
|
10248
|
+
const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2)); // u1⋅G + u2⋅P
|
|
10249
|
+
if (R.is0())
|
|
10250
|
+
return false;
|
|
10251
|
+
const v = Fn.create(R.x); // v = r.x mod n
|
|
10252
|
+
return v === r;
|
|
10253
|
+
}
|
|
10254
|
+
catch (e) {
|
|
10061
10255
|
return false;
|
|
10062
|
-
|
|
10256
|
+
}
|
|
10257
|
+
}
|
|
10258
|
+
function recoverPublicKey(signature, message, opts = {}) {
|
|
10259
|
+
const prehash = opts.prehash !== undefined ? opts.prehash : defaultSigOpts.prehash;
|
|
10260
|
+
_abool2(prehash, 'prehash');
|
|
10261
|
+
message = _abytes2(message, undefined, 'message');
|
|
10063
10262
|
if (prehash)
|
|
10064
|
-
|
|
10065
|
-
|
|
10066
|
-
const h = bits2int_modN(msgHash); // Cannot use fields methods, since it is group element
|
|
10067
|
-
const is = Fn.inv(s); // s^-1
|
|
10068
|
-
const u1 = Fn.create(h * is); // u1 = hs^-1 mod n
|
|
10069
|
-
const u2 = Fn.create(r * is); // u2 = rs^-1 mod n
|
|
10070
|
-
const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2));
|
|
10071
|
-
if (R.is0())
|
|
10072
|
-
return false;
|
|
10073
|
-
const v = Fn.create(R.x); // v = r.x mod n
|
|
10074
|
-
return v === r;
|
|
10263
|
+
message = _abytes2(hash(message), undefined, 'prehashed message');
|
|
10264
|
+
return Signature.fromBytes(signature, 'recovered').recoverPublicKey(message).toBytes();
|
|
10075
10265
|
}
|
|
10076
|
-
// TODO: clarify API for cloning .clone({hash: sha512}) ? .createWith({hash: sha512})?
|
|
10077
|
-
// const clone = (hash: CHash): ECDSA => ecdsa(Point, { ...ecdsaOpts, ...getHash(hash) }, curveOpts);
|
|
10078
10266
|
return Object.freeze({
|
|
10267
|
+
keygen,
|
|
10079
10268
|
getPublicKey,
|
|
10080
10269
|
getSharedSecret,
|
|
10081
|
-
sign,
|
|
10082
|
-
verify,
|
|
10083
10270
|
utils,
|
|
10271
|
+
lengths,
|
|
10084
10272
|
Point,
|
|
10273
|
+
sign,
|
|
10274
|
+
verify,
|
|
10275
|
+
recoverPublicKey,
|
|
10085
10276
|
Signature,
|
|
10277
|
+
hash,
|
|
10086
10278
|
});
|
|
10087
10279
|
}
|
|
10088
10280
|
function _weierstrass_legacy_opts_to_new(c) {
|
|
@@ -10096,14 +10288,19 @@ function _weierstrass_legacy_opts_to_new(c) {
|
|
|
10096
10288
|
Gy: c.Gy,
|
|
10097
10289
|
};
|
|
10098
10290
|
const Fp = c.Fp;
|
|
10099
|
-
|
|
10291
|
+
let allowedLengths = c.allowedPrivateKeyLengths
|
|
10292
|
+
? Array.from(new Set(c.allowedPrivateKeyLengths.map((l) => Math.ceil(l / 2))))
|
|
10293
|
+
: undefined;
|
|
10294
|
+
const Fn = Field$1(CURVE.n, {
|
|
10295
|
+
BITS: c.nBitLength,
|
|
10296
|
+
allowedLengths: allowedLengths,
|
|
10297
|
+
modFromBytes: c.wrapPrivateKey,
|
|
10298
|
+
});
|
|
10100
10299
|
const curveOpts = {
|
|
10101
10300
|
Fp,
|
|
10102
10301
|
Fn,
|
|
10103
|
-
allowedPrivateKeyLengths: c.allowedPrivateKeyLengths,
|
|
10104
10302
|
allowInfinityPoint: c.allowInfinityPoint,
|
|
10105
10303
|
endo: c.endo,
|
|
10106
|
-
wrapPrivateKey: c.wrapPrivateKey,
|
|
10107
10304
|
isTorsionFree: c.isTorsionFree,
|
|
10108
10305
|
clearCofactor: c.clearCofactor,
|
|
10109
10306
|
fromBytes: c.fromBytes,
|
|
@@ -10114,32 +10311,33 @@ function _weierstrass_legacy_opts_to_new(c) {
|
|
|
10114
10311
|
function _ecdsa_legacy_opts_to_new(c) {
|
|
10115
10312
|
const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
|
|
10116
10313
|
const ecdsaOpts = {
|
|
10117
|
-
hash: c.hash,
|
|
10118
10314
|
hmac: c.hmac,
|
|
10119
10315
|
randomBytes: c.randomBytes,
|
|
10120
10316
|
lowS: c.lowS,
|
|
10121
10317
|
bits2int: c.bits2int,
|
|
10122
10318
|
bits2int_modN: c.bits2int_modN,
|
|
10123
10319
|
};
|
|
10124
|
-
return { CURVE, curveOpts, ecdsaOpts };
|
|
10320
|
+
return { CURVE, curveOpts, hash: c.hash, ecdsaOpts };
|
|
10125
10321
|
}
|
|
10126
|
-
function _ecdsa_new_output_to_legacy(c,
|
|
10127
|
-
|
|
10128
|
-
|
|
10129
|
-
|
|
10322
|
+
function _ecdsa_new_output_to_legacy(c, _ecdsa) {
|
|
10323
|
+
const Point = _ecdsa.Point;
|
|
10324
|
+
return Object.assign({}, _ecdsa, {
|
|
10325
|
+
ProjectivePoint: Point,
|
|
10326
|
+
CURVE: Object.assign({}, c, nLength$1(Point.Fn.ORDER, Point.Fn.BITS)),
|
|
10130
10327
|
});
|
|
10131
10328
|
}
|
|
10132
10329
|
// _ecdsa_legacy
|
|
10133
10330
|
function weierstrass$1(c) {
|
|
10134
|
-
const { CURVE, curveOpts, ecdsaOpts } = _ecdsa_legacy_opts_to_new(c);
|
|
10331
|
+
const { CURVE, curveOpts, hash, ecdsaOpts } = _ecdsa_legacy_opts_to_new(c);
|
|
10135
10332
|
const Point = weierstrassN(CURVE, curveOpts);
|
|
10136
|
-
const signs = ecdsa(Point,
|
|
10333
|
+
const signs = ecdsa(Point, hash, ecdsaOpts);
|
|
10137
10334
|
return _ecdsa_new_output_to_legacy(c, signs);
|
|
10138
10335
|
}/**
|
|
10139
10336
|
* Utilities for short weierstrass curves, combined with noble-hashes.
|
|
10140
10337
|
* @module
|
|
10141
10338
|
*/
|
|
10142
10339
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
10340
|
+
/** @deprecated use new `weierstrass()` and `ecdsa()` methods */
|
|
10143
10341
|
function createCurve$1(curveDef, defHash) {
|
|
10144
10342
|
const create = (hash) => weierstrass$1({ ...curveDef, hash: hash });
|
|
10145
10343
|
return { ...create(defHash), create };
|
|
@@ -10163,10 +10361,14 @@ const secp256k1_CURVE = {
|
|
|
10163
10361
|
Gx: BigInt('0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'),
|
|
10164
10362
|
Gy: BigInt('0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'),
|
|
10165
10363
|
};
|
|
10166
|
-
|
|
10167
|
-
|
|
10168
|
-
|
|
10169
|
-
|
|
10364
|
+
const secp256k1_ENDO = {
|
|
10365
|
+
beta: BigInt('0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee'),
|
|
10366
|
+
basises: [
|
|
10367
|
+
[BigInt('0x3086d221a7d46bcde86c90e49284eb15'), -BigInt('0xe4437ed6010e88286f547fa90abfe4c3')],
|
|
10368
|
+
[BigInt('0x114ca50f7a8e2f3f657c1108d9d44cfd8'), BigInt('0x3086d221a7d46bcde86c90e49284eb15')],
|
|
10369
|
+
],
|
|
10370
|
+
};
|
|
10371
|
+
const _2n$5 = /* @__PURE__ */ BigInt(2);
|
|
10170
10372
|
/**
|
|
10171
10373
|
* √n = n^((p+1)/4) for fields p = 3 mod 4. We unwrap the loop and multiply bit-by-bit.
|
|
10172
10374
|
* (P+1n/4n).toString(2) would produce bits [223x 1, 0, 22x 1, 4x 0, 11, 00]
|
|
@@ -10195,7 +10397,7 @@ function sqrtMod$1(y) {
|
|
|
10195
10397
|
throw new Error('Cannot find square root');
|
|
10196
10398
|
return root;
|
|
10197
10399
|
}
|
|
10198
|
-
const Fpk1 = Field$1(secp256k1_CURVE.p,
|
|
10400
|
+
const Fpk1 = Field$1(secp256k1_CURVE.p, { sqrt: sqrtMod$1 });
|
|
10199
10401
|
/**
|
|
10200
10402
|
* secp256k1 curve, ECDSA and ECDH methods.
|
|
10201
10403
|
*
|
|
@@ -10204,44 +10406,13 @@ const Fpk1 = Field$1(secp256k1_CURVE.p, undefined, undefined, { sqrt: sqrtMod$1
|
|
|
10204
10406
|
* @example
|
|
10205
10407
|
* ```js
|
|
10206
10408
|
* import { secp256k1 } from '@noble/curves/secp256k1';
|
|
10207
|
-
* const
|
|
10208
|
-
* const
|
|
10209
|
-
* const
|
|
10210
|
-
* const
|
|
10211
|
-
* const isValid = secp256k1.verify(sig, msg, pub) === true;
|
|
10409
|
+
* const { secretKey, publicKey } = secp256k1.keygen();
|
|
10410
|
+
* const msg = new TextEncoder().encode('hello');
|
|
10411
|
+
* const sig = secp256k1.sign(msg, secretKey);
|
|
10412
|
+
* const isValid = secp256k1.verify(sig, msg, publicKey) === true;
|
|
10212
10413
|
* ```
|
|
10213
10414
|
*/
|
|
10214
|
-
const secp256k1$1 = createCurve$1({
|
|
10215
|
-
...secp256k1_CURVE,
|
|
10216
|
-
Fp: Fpk1,
|
|
10217
|
-
lowS: true, // Allow only low-S signatures by default in sign() and verify()
|
|
10218
|
-
endo: {
|
|
10219
|
-
// Endomorphism, see above
|
|
10220
|
-
beta: BigInt('0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee'),
|
|
10221
|
-
splitScalar: (k) => {
|
|
10222
|
-
const n = secp256k1_CURVE.n;
|
|
10223
|
-
const a1 = BigInt('0x3086d221a7d46bcde86c90e49284eb15');
|
|
10224
|
-
const b1 = -_1n$7 * BigInt('0xe4437ed6010e88286f547fa90abfe4c3');
|
|
10225
|
-
const a2 = BigInt('0x114ca50f7a8e2f3f657c1108d9d44cfd8');
|
|
10226
|
-
const b2 = a1;
|
|
10227
|
-
const POW_2_128 = BigInt('0x100000000000000000000000000000000'); // (2n**128n).toString(16)
|
|
10228
|
-
const c1 = divNearest$1(b2 * k, n);
|
|
10229
|
-
const c2 = divNearest$1(-b1 * k, n);
|
|
10230
|
-
let k1 = mod$1(k - c1 * a1 - c2 * a2, n);
|
|
10231
|
-
let k2 = mod$1(-c1 * b1 - c2 * b2, n);
|
|
10232
|
-
const k1neg = k1 > POW_2_128;
|
|
10233
|
-
const k2neg = k2 > POW_2_128;
|
|
10234
|
-
if (k1neg)
|
|
10235
|
-
k1 = n - k1;
|
|
10236
|
-
if (k2neg)
|
|
10237
|
-
k2 = n - k2;
|
|
10238
|
-
if (k1 > POW_2_128 || k2 > POW_2_128) {
|
|
10239
|
-
throw new Error('splitScalar: Endomorphism failed, k=' + k);
|
|
10240
|
-
}
|
|
10241
|
-
return { k1neg, k1, k2neg, k2 };
|
|
10242
|
-
},
|
|
10243
|
-
},
|
|
10244
|
-
}, sha256$2);function encodeAddress(key, ss58Format = defaults.prefix) {
|
|
10415
|
+
const secp256k1$1 = createCurve$1({ ...secp256k1_CURVE, Fp: Fpk1, lowS: true, endo: secp256k1_ENDO }, sha256$2);function encodeAddress(key, ss58Format = defaults.prefix) {
|
|
10245
10416
|
// decode it, this means we can re-encode an address
|
|
10246
10417
|
const u8a = decodeAddress(key);
|
|
10247
10418
|
if ((ss58Format < 0) || (ss58Format > 16383) || [46, 47].includes(ss58Format)) {
|
|
@@ -19823,13 +19994,27 @@ function createPasskeyPublicKey(publicKey) {
|
|
|
19823
19994
|
publicKey: parsedNewPublicKey,
|
|
19824
19995
|
};
|
|
19825
19996
|
}
|
|
19997
|
+
/**
|
|
19998
|
+
* Build AddAction payload for Itemized storage.
|
|
19999
|
+
*
|
|
20000
|
+
* @param data The data to be persisted on the Frequency chain
|
|
20001
|
+
*/
|
|
19826
20002
|
function createItemizedAddAction(data) {
|
|
19827
20003
|
const parsedData = typeof data === 'object' ? u8aToHex(data) : data;
|
|
19828
20004
|
assert(isHexString(parsedData), 'itemized data should be valid hex');
|
|
20005
|
+
// since Metamask does not support union types, we have to include all fields and have to set the `index` value to zero
|
|
20006
|
+
// even though it is not used for Add action
|
|
19829
20007
|
return { actionType: 'Add', data, index: 0 };
|
|
19830
20008
|
}
|
|
20009
|
+
/**
|
|
20010
|
+
* Build DeleteAction payload for Itemized storage.
|
|
20011
|
+
*
|
|
20012
|
+
* @param index The index of the item that we want to remove from the Frequency chain
|
|
20013
|
+
*/
|
|
19831
20014
|
function createItemizedDeleteAction(index) {
|
|
19832
20015
|
assert(isValidUint16(index), 'itemized index should be a valid uint16');
|
|
20016
|
+
// since Metamask does not support union types, we have to include all fields and have to set the `data` value to 0x
|
|
20017
|
+
// even though it is not used for Delete action
|
|
19833
20018
|
return { actionType: 'Delete', data: '0x', index };
|
|
19834
20019
|
}
|
|
19835
20020
|
/**
|