@protontech/openpgp 6.0.0 → 6.0.2-patch.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lightweight/argon2id.min.mjs +1 -1
- package/dist/lightweight/argon2id.mjs +1 -1
- package/dist/lightweight/legacy_ciphers.min.mjs +1 -1
- package/dist/lightweight/legacy_ciphers.mjs +1 -1
- package/dist/lightweight/noble_curves.min.mjs +11 -11
- package/dist/lightweight/noble_curves.min.mjs.map +1 -1
- package/dist/lightweight/noble_curves.mjs +260 -158
- package/dist/lightweight/noble_hashes.min.mjs +2 -2
- package/dist/lightweight/noble_hashes.min.mjs.map +1 -1
- package/dist/lightweight/noble_hashes.mjs +3 -2
- package/dist/lightweight/noble_post_quantum.min.mjs +5 -0
- package/dist/lightweight/noble_post_quantum.min.mjs.map +1 -0
- package/dist/lightweight/noble_post_quantum.mjs +1002 -0
- package/dist/lightweight/openpgp.min.mjs +4 -4
- package/dist/lightweight/openpgp.min.mjs.map +1 -1
- package/dist/lightweight/openpgp.mjs +626 -111
- package/dist/lightweight/seek-bzip.min.mjs +1 -1
- package/dist/lightweight/seek-bzip.mjs +1 -1
- package/dist/lightweight/sha3.min.mjs +3 -3
- package/dist/lightweight/sha3.min.mjs.map +1 -1
- package/dist/lightweight/sha3.mjs +27 -456
- package/dist/lightweight/sha512.min.mjs +3 -0
- package/dist/lightweight/sha512.min.mjs.map +1 -0
- package/dist/lightweight/sha512.mjs +436 -0
- package/dist/node/openpgp.cjs +2247 -621
- package/dist/node/openpgp.min.cjs +16 -14
- package/dist/node/openpgp.min.cjs.map +1 -1
- package/dist/node/openpgp.min.mjs +16 -14
- package/dist/node/openpgp.min.mjs.map +1 -1
- package/dist/node/openpgp.mjs +2247 -621
- package/dist/openpgp.js +2247 -621
- package/dist/openpgp.min.js +16 -14
- package/dist/openpgp.min.js.map +1 -1
- package/dist/openpgp.min.mjs +16 -14
- package/dist/openpgp.min.mjs.map +1 -1
- package/dist/openpgp.mjs +2247 -621
- package/openpgp.d.ts +7 -11
- package/package.json +5 -4
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
/*! OpenPGP.js v6.0.0 - 2024-11-
|
|
1
|
+
/*! OpenPGP.js v6.0.2-patch.0 - 2024-11-27 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
|
|
2
2
|
const globalThis = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { s as sha256, a as sha384, b as sha512 } from './sha512.mjs';
|
|
5
|
+
import { H as Hash, a as ahash, t as toBytes, b as aexists, c as abytes$1, d as concatBytes$1, r as randomBytes, w as wrapConstructor, u as utf8ToBytes$1, s as shake256 } from './sha3.mjs';
|
|
5
6
|
|
|
6
7
|
// HMAC (RFC 2104)
|
|
7
8
|
class HMAC extends Hash {
|
|
8
|
-
constructor(hash
|
|
9
|
+
constructor(hash, _key) {
|
|
9
10
|
super();
|
|
10
11
|
this.finished = false;
|
|
11
12
|
this.destroyed = false;
|
|
12
|
-
|
|
13
|
+
ahash(hash);
|
|
13
14
|
const key = toBytes(_key);
|
|
14
|
-
this.iHash = hash
|
|
15
|
+
this.iHash = hash.create();
|
|
15
16
|
if (typeof this.iHash.update !== 'function')
|
|
16
17
|
throw new Error('Expected instance of class which extends utils.Hash');
|
|
17
18
|
this.blockLen = this.iHash.blockLen;
|
|
@@ -19,12 +20,12 @@ class HMAC extends Hash {
|
|
|
19
20
|
const blockLen = this.blockLen;
|
|
20
21
|
const pad = new Uint8Array(blockLen);
|
|
21
22
|
// blockLen can be bigger than outputLen
|
|
22
|
-
pad.set(key.length > blockLen ? hash
|
|
23
|
+
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
|
23
24
|
for (let i = 0; i < pad.length; i++)
|
|
24
25
|
pad[i] ^= 0x36;
|
|
25
26
|
this.iHash.update(pad);
|
|
26
27
|
// By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone
|
|
27
|
-
this.oHash = hash
|
|
28
|
+
this.oHash = hash.create();
|
|
28
29
|
// Undo internal XOR && apply outer XOR
|
|
29
30
|
for (let i = 0; i < pad.length; i++)
|
|
30
31
|
pad[i] ^= 0x36 ^ 0x5c;
|
|
@@ -32,13 +33,13 @@ class HMAC extends Hash {
|
|
|
32
33
|
pad.fill(0);
|
|
33
34
|
}
|
|
34
35
|
update(buf) {
|
|
35
|
-
|
|
36
|
+
aexists(this);
|
|
36
37
|
this.iHash.update(buf);
|
|
37
38
|
return this;
|
|
38
39
|
}
|
|
39
40
|
digestInto(out) {
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
aexists(this);
|
|
42
|
+
abytes$1(out, this.outputLen);
|
|
42
43
|
this.finished = true;
|
|
43
44
|
this.iHash.digestInto(out);
|
|
44
45
|
this.oHash.update(out);
|
|
@@ -91,8 +92,7 @@ const _0n$5 = /* @__PURE__ */ BigInt(0);
|
|
|
91
92
|
const _1n$7 = /* @__PURE__ */ BigInt(1);
|
|
92
93
|
const _2n$4 = /* @__PURE__ */ BigInt(2);
|
|
93
94
|
function isBytes(a) {
|
|
94
|
-
return
|
|
95
|
-
(a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array'));
|
|
95
|
+
return a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');
|
|
96
96
|
}
|
|
97
97
|
function abytes(item) {
|
|
98
98
|
if (!isBytes(item))
|
|
@@ -100,7 +100,7 @@ function abytes(item) {
|
|
|
100
100
|
}
|
|
101
101
|
function abool(title, value) {
|
|
102
102
|
if (typeof value !== 'boolean')
|
|
103
|
-
throw new Error(
|
|
103
|
+
throw new Error(title + ' boolean expected, got ' + value);
|
|
104
104
|
}
|
|
105
105
|
// Array where index 0xf0 (240) is mapped to string 'f0'
|
|
106
106
|
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
|
|
@@ -118,23 +118,22 @@ function bytesToHex(bytes) {
|
|
|
118
118
|
}
|
|
119
119
|
function numberToHexUnpadded(num) {
|
|
120
120
|
const hex = num.toString(16);
|
|
121
|
-
return hex.length & 1 ?
|
|
121
|
+
return hex.length & 1 ? '0' + hex : hex;
|
|
122
122
|
}
|
|
123
123
|
function hexToNumber(hex) {
|
|
124
124
|
if (typeof hex !== 'string')
|
|
125
125
|
throw new Error('hex string expected, got ' + typeof hex);
|
|
126
|
-
// Big Endian
|
|
127
|
-
return BigInt(hex === '' ? '0' : `0x${hex}`);
|
|
126
|
+
return hex === '' ? _0n$5 : BigInt('0x' + hex); // Big Endian
|
|
128
127
|
}
|
|
129
128
|
// We use optimized technique to convert hex string to byte array
|
|
130
|
-
const asciis = { _0: 48, _9: 57,
|
|
131
|
-
function asciiToBase16(
|
|
132
|
-
if (
|
|
133
|
-
return
|
|
134
|
-
if (
|
|
135
|
-
return
|
|
136
|
-
if (
|
|
137
|
-
return
|
|
129
|
+
const asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
|
|
130
|
+
function asciiToBase16(ch) {
|
|
131
|
+
if (ch >= asciis._0 && ch <= asciis._9)
|
|
132
|
+
return ch - asciis._0; // '2' => 50-48
|
|
133
|
+
if (ch >= asciis.A && ch <= asciis.F)
|
|
134
|
+
return ch - (asciis.A - 10); // 'B' => 66-(65-10)
|
|
135
|
+
if (ch >= asciis.a && ch <= asciis.f)
|
|
136
|
+
return ch - (asciis.a - 10); // 'b' => 98-(97-10)
|
|
138
137
|
return;
|
|
139
138
|
}
|
|
140
139
|
/**
|
|
@@ -146,7 +145,7 @@ function hexToBytes(hex) {
|
|
|
146
145
|
const hl = hex.length;
|
|
147
146
|
const al = hl / 2;
|
|
148
147
|
if (hl % 2)
|
|
149
|
-
throw new Error('
|
|
148
|
+
throw new Error('hex string expected, got unpadded hex of length ' + hl);
|
|
150
149
|
const array = new Uint8Array(al);
|
|
151
150
|
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
|
|
152
151
|
const n1 = asciiToBase16(hex.charCodeAt(hi));
|
|
@@ -155,7 +154,7 @@ function hexToBytes(hex) {
|
|
|
155
154
|
const char = hex[hi] + hex[hi + 1];
|
|
156
155
|
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
|
|
157
156
|
}
|
|
158
|
-
array[ai] = n1 * 16 + n2;
|
|
157
|
+
array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163
|
|
159
158
|
}
|
|
160
159
|
return array;
|
|
161
160
|
}
|
|
@@ -193,7 +192,7 @@ function ensureBytes(title, hex, expectedLength) {
|
|
|
193
192
|
res = hexToBytes(hex);
|
|
194
193
|
}
|
|
195
194
|
catch (e) {
|
|
196
|
-
throw new Error(
|
|
195
|
+
throw new Error(title + ' must be hex string or Uint8Array, cause: ' + e);
|
|
197
196
|
}
|
|
198
197
|
}
|
|
199
198
|
else if (isBytes(hex)) {
|
|
@@ -202,11 +201,11 @@ function ensureBytes(title, hex, expectedLength) {
|
|
|
202
201
|
res = Uint8Array.from(hex);
|
|
203
202
|
}
|
|
204
203
|
else {
|
|
205
|
-
throw new Error(
|
|
204
|
+
throw new Error(title + ' must be hex string or Uint8Array');
|
|
206
205
|
}
|
|
207
206
|
const len = res.length;
|
|
208
207
|
if (typeof expectedLength === 'number' && len !== expectedLength)
|
|
209
|
-
throw new Error(
|
|
208
|
+
throw new Error(title + ' of length ' + expectedLength + ' expected, got ' + len);
|
|
210
209
|
return res;
|
|
211
210
|
}
|
|
212
211
|
/**
|
|
@@ -241,7 +240,7 @@ function equalBytes(a, b) {
|
|
|
241
240
|
*/
|
|
242
241
|
function utf8ToBytes(str) {
|
|
243
242
|
if (typeof str !== 'string')
|
|
244
|
-
throw new Error(
|
|
243
|
+
throw new Error('string expected');
|
|
245
244
|
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
|
|
246
245
|
}
|
|
247
246
|
// Is positive bigint
|
|
@@ -261,7 +260,7 @@ function aInRange(title, n, min, max) {
|
|
|
261
260
|
// - b would commonly require subtraction: `inRange('x', x, 0n, P - 1n)`
|
|
262
261
|
// - our way is the cleanest: `inRange('x', x, 0n, P)
|
|
263
262
|
if (!inRange(n, min, max))
|
|
264
|
-
throw new Error(
|
|
263
|
+
throw new Error('expected valid ' + title + ': ' + min + ' <= n < ' + max + ', got ' + n);
|
|
265
264
|
}
|
|
266
265
|
// Bit operations
|
|
267
266
|
/**
|
|
@@ -371,12 +370,12 @@ function validateObject(object, validators, optValidators = {}) {
|
|
|
371
370
|
const checkField = (fieldName, type, isOptional) => {
|
|
372
371
|
const checkVal = validatorFns[type];
|
|
373
372
|
if (typeof checkVal !== 'function')
|
|
374
|
-
throw new Error(
|
|
373
|
+
throw new Error('invalid validator function');
|
|
375
374
|
const val = object[fieldName];
|
|
376
375
|
if (isOptional && val === undefined)
|
|
377
376
|
return;
|
|
378
377
|
if (!checkVal(val, object)) {
|
|
379
|
-
throw new Error(
|
|
378
|
+
throw new Error('param ' + String(fieldName) + ' is invalid. Expected ' + type + ', got ' + val);
|
|
380
379
|
}
|
|
381
380
|
};
|
|
382
381
|
for (const [fieldName, type] of Object.entries(validators))
|
|
@@ -448,11 +447,9 @@ var ut = /*#__PURE__*/Object.freeze({
|
|
|
448
447
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
449
448
|
// Utilities for modular arithmetics and finite fields
|
|
450
449
|
// prettier-ignore
|
|
451
|
-
const _0n$4 = BigInt(0), _1n$6 = BigInt(1), _2n$3 = BigInt(2), _3n$2 = BigInt(3);
|
|
450
|
+
const _0n$4 = BigInt(0), _1n$6 = BigInt(1), _2n$3 = /* @__PURE__ */ BigInt(2), _3n$2 = /* @__PURE__ */ BigInt(3);
|
|
452
451
|
// prettier-ignore
|
|
453
|
-
const _4n = BigInt(4), _5n = BigInt(5), _8n$1 = BigInt(8);
|
|
454
|
-
// prettier-ignore
|
|
455
|
-
BigInt(9); BigInt(16);
|
|
452
|
+
const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5), _8n$1 = /* @__PURE__ */ BigInt(8);
|
|
456
453
|
// Calculates a modulo b
|
|
457
454
|
function mod(a, b) {
|
|
458
455
|
const result = a % b;
|
|
@@ -466,8 +463,10 @@ function mod(a, b) {
|
|
|
466
463
|
*/
|
|
467
464
|
// TODO: use field version && remove
|
|
468
465
|
function pow(num, power, modulo) {
|
|
469
|
-
if (
|
|
470
|
-
throw new Error('
|
|
466
|
+
if (power < _0n$4)
|
|
467
|
+
throw new Error('invalid exponent, negatives unsupported');
|
|
468
|
+
if (modulo <= _0n$4)
|
|
469
|
+
throw new Error('invalid modulus');
|
|
471
470
|
if (modulo === _1n$6)
|
|
472
471
|
return _0n$4;
|
|
473
472
|
let res = _1n$6;
|
|
@@ -490,9 +489,10 @@ function pow2(x, power, modulo) {
|
|
|
490
489
|
}
|
|
491
490
|
// Inverses number over modulo
|
|
492
491
|
function invert(number, modulo) {
|
|
493
|
-
if (number === _0n$4
|
|
494
|
-
throw new Error(
|
|
495
|
-
|
|
492
|
+
if (number === _0n$4)
|
|
493
|
+
throw new Error('invert: expected non-zero number');
|
|
494
|
+
if (modulo <= _0n$4)
|
|
495
|
+
throw new Error('invert: expected positive modulus, got ' + modulo);
|
|
496
496
|
// Euclidean GCD https://brilliant.org/wiki/extended-euclidean-algorithm/
|
|
497
497
|
// Fermat's little theorem "CT-like" version inv(n) = n^(m-2) mod m is 30x slower.
|
|
498
498
|
let a = mod(number, modulo);
|
|
@@ -533,8 +533,11 @@ function tonelliShanks(P) {
|
|
|
533
533
|
for (Q = P - _1n$6, S = 0; Q % _2n$3 === _0n$4; Q /= _2n$3, S++)
|
|
534
534
|
;
|
|
535
535
|
// Step 2: Select a non-square z such that (z | p) ≡ -1 and set c ≡ zq
|
|
536
|
-
for (Z = _2n$3; Z < P && pow(Z, legendreC, P) !== P - _1n$6; Z++)
|
|
537
|
-
|
|
536
|
+
for (Z = _2n$3; Z < P && pow(Z, legendreC, P) !== P - _1n$6; Z++) {
|
|
537
|
+
// Crash instead of infinity loop, we cannot reasonable count until P.
|
|
538
|
+
if (Z > 1000)
|
|
539
|
+
throw new Error('Cannot find square root: likely non-prime P');
|
|
540
|
+
}
|
|
538
541
|
// Fast-path
|
|
539
542
|
if (S === 1) {
|
|
540
543
|
const p1div4 = (P + _1n$6) / _4n;
|
|
@@ -640,7 +643,7 @@ function FpPow(f, num, power) {
|
|
|
640
643
|
// Should have same speed as pow for bigints
|
|
641
644
|
// TODO: benchmark!
|
|
642
645
|
if (power < _0n$4)
|
|
643
|
-
throw new Error('
|
|
646
|
+
throw new Error('invalid exponent, negatives unsupported');
|
|
644
647
|
if (power === _0n$4)
|
|
645
648
|
return f.ONE;
|
|
646
649
|
if (power === _1n$6)
|
|
@@ -703,11 +706,11 @@ function nLength(n, nBitLength) {
|
|
|
703
706
|
*/
|
|
704
707
|
function Field(ORDER, bitLen, isLE = false, redef = {}) {
|
|
705
708
|
if (ORDER <= _0n$4)
|
|
706
|
-
throw new Error(
|
|
709
|
+
throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);
|
|
707
710
|
const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
|
|
708
711
|
if (BYTES > 2048)
|
|
709
|
-
throw new Error('
|
|
710
|
-
|
|
712
|
+
throw new Error('invalid field: expected ORDER of <= 2048 bytes');
|
|
713
|
+
let sqrtP; // cached sqrtP
|
|
711
714
|
const f = Object.freeze({
|
|
712
715
|
ORDER,
|
|
713
716
|
BITS,
|
|
@@ -718,7 +721,7 @@ function Field(ORDER, bitLen, isLE = false, redef = {}) {
|
|
|
718
721
|
create: (num) => mod(num, ORDER),
|
|
719
722
|
isValid: (num) => {
|
|
720
723
|
if (typeof num !== 'bigint')
|
|
721
|
-
throw new Error(
|
|
724
|
+
throw new Error('invalid field element: expected bigint, got ' + typeof num);
|
|
722
725
|
return _0n$4 <= num && num < ORDER; // 0 is valid element, but it's not invertible
|
|
723
726
|
},
|
|
724
727
|
is0: (num) => num === _0n$4,
|
|
@@ -737,7 +740,12 @@ function Field(ORDER, bitLen, isLE = false, redef = {}) {
|
|
|
737
740
|
subN: (lhs, rhs) => lhs - rhs,
|
|
738
741
|
mulN: (lhs, rhs) => lhs * rhs,
|
|
739
742
|
inv: (num) => invert(num, ORDER),
|
|
740
|
-
sqrt: redef.sqrt ||
|
|
743
|
+
sqrt: redef.sqrt ||
|
|
744
|
+
((n) => {
|
|
745
|
+
if (!sqrtP)
|
|
746
|
+
sqrtP = FpSqrt(ORDER);
|
|
747
|
+
return sqrtP(f, n);
|
|
748
|
+
}),
|
|
741
749
|
invertBatch: (lst) => FpInvertBatch(f, lst),
|
|
742
750
|
// TODO: do we really need constant cmov?
|
|
743
751
|
// We don't have const-time bigints anyway, so probably will be not very useful
|
|
@@ -745,7 +753,7 @@ function Field(ORDER, bitLen, isLE = false, redef = {}) {
|
|
|
745
753
|
toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES)),
|
|
746
754
|
fromBytes: (bytes) => {
|
|
747
755
|
if (bytes.length !== BYTES)
|
|
748
|
-
throw new Error(
|
|
756
|
+
throw new Error('Field.fromBytes: expected ' + BYTES + ' bytes, got ' + bytes.length);
|
|
749
757
|
return isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
|
|
750
758
|
},
|
|
751
759
|
});
|
|
@@ -793,7 +801,7 @@ function mapHashToField(key, fieldOrder, isLE = false) {
|
|
|
793
801
|
const minLen = getMinHashLength(fieldOrder);
|
|
794
802
|
// No small numbers: need to understand bias story. No huge numbers: easier to detect JS timings.
|
|
795
803
|
if (len < 16 || len < minLen || len > 1024)
|
|
796
|
-
throw new Error(
|
|
804
|
+
throw new Error('expected ' + minLen + '-1024 bytes of input, got ' + len);
|
|
797
805
|
const num = isLE ? bytesToNumberBE(key) : bytesToNumberLE(key);
|
|
798
806
|
// `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
|
|
799
807
|
const reduced = mod(num, fieldOrder - _1n$6) + _1n$6;
|
|
@@ -804,10 +812,43 @@ function mapHashToField(key, fieldOrder, isLE = false) {
|
|
|
804
812
|
// Abelian group utilities
|
|
805
813
|
const _0n$3 = BigInt(0);
|
|
806
814
|
const _1n$5 = BigInt(1);
|
|
815
|
+
function constTimeNegate(condition, item) {
|
|
816
|
+
const neg = item.negate();
|
|
817
|
+
return condition ? neg : item;
|
|
818
|
+
}
|
|
819
|
+
function validateW(W, bits) {
|
|
820
|
+
if (!Number.isSafeInteger(W) || W <= 0 || W > bits)
|
|
821
|
+
throw new Error('invalid window size, expected [1..' + bits + '], got W=' + W);
|
|
822
|
+
}
|
|
823
|
+
function calcWOpts(W, bits) {
|
|
824
|
+
validateW(W, bits);
|
|
825
|
+
const windows = Math.ceil(bits / W) + 1; // +1, because
|
|
826
|
+
const windowSize = 2 ** (W - 1); // -1 because we skip zero
|
|
827
|
+
return { windows, windowSize };
|
|
828
|
+
}
|
|
829
|
+
function validateMSMPoints(points, c) {
|
|
830
|
+
if (!Array.isArray(points))
|
|
831
|
+
throw new Error('array expected');
|
|
832
|
+
points.forEach((p, i) => {
|
|
833
|
+
if (!(p instanceof c))
|
|
834
|
+
throw new Error('invalid point at index ' + i);
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
function validateMSMScalars(scalars, field) {
|
|
838
|
+
if (!Array.isArray(scalars))
|
|
839
|
+
throw new Error('array of scalars expected');
|
|
840
|
+
scalars.forEach((s, i) => {
|
|
841
|
+
if (!field.isValid(s))
|
|
842
|
+
throw new Error('invalid scalar at index ' + i);
|
|
843
|
+
});
|
|
844
|
+
}
|
|
807
845
|
// Since points in different groups cannot be equal (different object constructor),
|
|
808
846
|
// we can have single place to store precomputes
|
|
809
847
|
const pointPrecomputes = new WeakMap();
|
|
810
848
|
const pointWindowSizes = new WeakMap(); // This allows use make points immutable (nothing changes inside)
|
|
849
|
+
function getW(P) {
|
|
850
|
+
return pointWindowSizes.get(P) || 1;
|
|
851
|
+
}
|
|
811
852
|
// Elliptic curve multiplication of Point by scalar. Fragile.
|
|
812
853
|
// Scalars should always be less than curve order: this should be checked inside of a curve itself.
|
|
813
854
|
// Creates precomputation tables for fast multiplication:
|
|
@@ -820,25 +861,13 @@ const pointWindowSizes = new WeakMap(); // This allows use make points immutable
|
|
|
820
861
|
// TODO: Research returning 2d JS array of windows, instead of a single window. This would allow
|
|
821
862
|
// windows to be in different memory locations
|
|
822
863
|
function wNAF(c, bits) {
|
|
823
|
-
const constTimeNegate = (condition, item) => {
|
|
824
|
-
const neg = item.negate();
|
|
825
|
-
return condition ? neg : item;
|
|
826
|
-
};
|
|
827
|
-
const validateW = (W) => {
|
|
828
|
-
if (!Number.isSafeInteger(W) || W <= 0 || W > bits)
|
|
829
|
-
throw new Error(`Wrong window size=${W}, should be [1..${bits}]`);
|
|
830
|
-
};
|
|
831
|
-
const opts = (W) => {
|
|
832
|
-
validateW(W);
|
|
833
|
-
const windows = Math.ceil(bits / W) + 1; // +1, because
|
|
834
|
-
const windowSize = 2 ** (W - 1); // -1 because we skip zero
|
|
835
|
-
return { windows, windowSize };
|
|
836
|
-
};
|
|
837
864
|
return {
|
|
838
865
|
constTimeNegate,
|
|
866
|
+
hasPrecomputes(elm) {
|
|
867
|
+
return getW(elm) !== 1;
|
|
868
|
+
},
|
|
839
869
|
// non-const time multiplication ladder
|
|
840
|
-
unsafeLadder(elm, n) {
|
|
841
|
-
let p = c.ZERO;
|
|
870
|
+
unsafeLadder(elm, n, p = c.ZERO) {
|
|
842
871
|
let d = elm;
|
|
843
872
|
while (n > _0n$3) {
|
|
844
873
|
if (n & _1n$5)
|
|
@@ -856,10 +885,12 @@ function wNAF(c, bits) {
|
|
|
856
885
|
* - 𝑊 is the window size
|
|
857
886
|
* - 𝑛 is the bitlength of the curve order.
|
|
858
887
|
* For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
|
|
888
|
+
* @param elm Point instance
|
|
889
|
+
* @param W window size
|
|
859
890
|
* @returns precomputed point tables flattened to a single array
|
|
860
891
|
*/
|
|
861
892
|
precomputeWindow(elm, W) {
|
|
862
|
-
const { windows, windowSize } =
|
|
893
|
+
const { windows, windowSize } = calcWOpts(W, bits);
|
|
863
894
|
const points = [];
|
|
864
895
|
let p = elm;
|
|
865
896
|
let base = p;
|
|
@@ -885,7 +916,7 @@ function wNAF(c, bits) {
|
|
|
885
916
|
wNAF(W, precomputes, n) {
|
|
886
917
|
// TODO: maybe check that scalar is less than group order? wNAF behavious is undefined otherwise
|
|
887
918
|
// But need to carefully remove other checks before wNAF. ORDER == bits here
|
|
888
|
-
const { windows, windowSize } =
|
|
919
|
+
const { windows, windowSize } = calcWOpts(W, bits);
|
|
889
920
|
let p = c.ZERO;
|
|
890
921
|
let f = c.BASE;
|
|
891
922
|
const mask = BigInt(2 ** W - 1); // Create mask with W ones: 0b1111 for W=4 etc.
|
|
@@ -929,8 +960,44 @@ function wNAF(c, bits) {
|
|
|
929
960
|
// which makes it less const-time: around 1 bigint multiply.
|
|
930
961
|
return { p, f };
|
|
931
962
|
},
|
|
932
|
-
|
|
933
|
-
|
|
963
|
+
/**
|
|
964
|
+
* Implements ec unsafe (non const-time) multiplication using precomputed tables and w-ary non-adjacent form.
|
|
965
|
+
* @param W window size
|
|
966
|
+
* @param precomputes precomputed tables
|
|
967
|
+
* @param n scalar (we don't check here, but should be less than curve order)
|
|
968
|
+
* @param acc accumulator point to add result of multiplication
|
|
969
|
+
* @returns point
|
|
970
|
+
*/
|
|
971
|
+
wNAFUnsafe(W, precomputes, n, acc = c.ZERO) {
|
|
972
|
+
const { windows, windowSize } = calcWOpts(W, bits);
|
|
973
|
+
const mask = BigInt(2 ** W - 1); // Create mask with W ones: 0b1111 for W=4 etc.
|
|
974
|
+
const maxNumber = 2 ** W;
|
|
975
|
+
const shiftBy = BigInt(W);
|
|
976
|
+
for (let window = 0; window < windows; window++) {
|
|
977
|
+
const offset = window * windowSize;
|
|
978
|
+
if (n === _0n$3)
|
|
979
|
+
break; // No need to go over empty scalar
|
|
980
|
+
// Extract W bits.
|
|
981
|
+
let wbits = Number(n & mask);
|
|
982
|
+
// Shift number by W bits.
|
|
983
|
+
n >>= shiftBy;
|
|
984
|
+
// If the bits are bigger than max size, we'll split those.
|
|
985
|
+
// +224 => 256 - 32
|
|
986
|
+
if (wbits > windowSize) {
|
|
987
|
+
wbits -= maxNumber;
|
|
988
|
+
n += _1n$5;
|
|
989
|
+
}
|
|
990
|
+
if (wbits === 0)
|
|
991
|
+
continue;
|
|
992
|
+
let curr = precomputes[offset + Math.abs(wbits) - 1]; // -1 because we skip zero
|
|
993
|
+
if (wbits < 0)
|
|
994
|
+
curr = curr.negate();
|
|
995
|
+
// NOTE: by re-using acc, we can save a lot of additions in case of MSM
|
|
996
|
+
acc = acc.add(curr);
|
|
997
|
+
}
|
|
998
|
+
return acc;
|
|
999
|
+
},
|
|
1000
|
+
getPrecomputes(W, P, transform) {
|
|
934
1001
|
// Calculate precomputes on a first run, reuse them after
|
|
935
1002
|
let comp = pointPrecomputes.get(P);
|
|
936
1003
|
if (!comp) {
|
|
@@ -938,62 +1005,66 @@ function wNAF(c, bits) {
|
|
|
938
1005
|
if (W !== 1)
|
|
939
1006
|
pointPrecomputes.set(P, transform(comp));
|
|
940
1007
|
}
|
|
941
|
-
return
|
|
1008
|
+
return comp;
|
|
1009
|
+
},
|
|
1010
|
+
wNAFCached(P, n, transform) {
|
|
1011
|
+
const W = getW(P);
|
|
1012
|
+
return this.wNAF(W, this.getPrecomputes(W, P, transform), n);
|
|
1013
|
+
},
|
|
1014
|
+
wNAFCachedUnsafe(P, n, transform, prev) {
|
|
1015
|
+
const W = getW(P);
|
|
1016
|
+
if (W === 1)
|
|
1017
|
+
return this.unsafeLadder(P, n, prev); // For W=1 ladder is ~x2 faster
|
|
1018
|
+
return this.wNAFUnsafe(W, this.getPrecomputes(W, P, transform), n, prev);
|
|
942
1019
|
},
|
|
943
1020
|
// We calculate precomputes for elliptic curve point multiplication
|
|
944
1021
|
// using windowed method. This specifies window size and
|
|
945
1022
|
// stores precomputed values. Usually only base point would be precomputed.
|
|
946
1023
|
setWindowSize(P, W) {
|
|
947
|
-
validateW(W);
|
|
1024
|
+
validateW(W, bits);
|
|
948
1025
|
pointWindowSizes.set(P, W);
|
|
949
1026
|
pointPrecomputes.delete(P);
|
|
950
1027
|
},
|
|
951
1028
|
};
|
|
952
1029
|
}
|
|
953
1030
|
/**
|
|
954
|
-
* Pippenger algorithm for multi-scalar multiplication (MSM).
|
|
955
|
-
* MSM is basically (Pa + Qb + Rc + ...).
|
|
1031
|
+
* Pippenger algorithm for multi-scalar multiplication (MSM, Pa + Qb + Rc + ...).
|
|
956
1032
|
* 30x faster vs naive addition on L=4096, 10x faster with precomputes.
|
|
957
1033
|
* For N=254bit, L=1, it does: 1024 ADD + 254 DBL. For L=5: 1536 ADD + 254 DBL.
|
|
958
1034
|
* Algorithmically constant-time (for same L), even when 1 point + scalar, or when scalar = 0.
|
|
959
1035
|
* @param c Curve Point constructor
|
|
960
|
-
* @param
|
|
1036
|
+
* @param fieldN field over CURVE.N - important that it's not over CURVE.P
|
|
961
1037
|
* @param points array of L curve points
|
|
962
1038
|
* @param scalars array of L scalars (aka private keys / bigints)
|
|
963
1039
|
*/
|
|
964
|
-
function pippenger(c,
|
|
1040
|
+
function pippenger(c, fieldN, points, scalars) {
|
|
965
1041
|
// If we split scalars by some window (let's say 8 bits), every chunk will only
|
|
966
1042
|
// take 256 buckets even if there are 4096 scalars, also re-uses double.
|
|
967
1043
|
// TODO:
|
|
968
1044
|
// - https://eprint.iacr.org/2024/750.pdf
|
|
969
1045
|
// - https://tches.iacr.org/index.php/TCHES/article/view/10287
|
|
970
1046
|
// 0 is accepted in scalars
|
|
971
|
-
|
|
1047
|
+
validateMSMPoints(points, c);
|
|
1048
|
+
validateMSMScalars(scalars, fieldN);
|
|
1049
|
+
if (points.length !== scalars.length)
|
|
972
1050
|
throw new Error('arrays of points and scalars must have equal length');
|
|
973
|
-
|
|
974
|
-
if (!field.isValid(s))
|
|
975
|
-
throw new Error(`wrong scalar at index ${i}`);
|
|
976
|
-
});
|
|
977
|
-
points.forEach((p, i) => {
|
|
978
|
-
if (!(p instanceof c))
|
|
979
|
-
throw new Error(`wrong point at index ${i}`);
|
|
980
|
-
});
|
|
1051
|
+
const zero = c.ZERO;
|
|
981
1052
|
const wbits = bitLen(BigInt(points.length));
|
|
982
1053
|
const windowSize = wbits > 12 ? wbits - 3 : wbits > 4 ? wbits - 2 : wbits ? 2 : 1; // in bits
|
|
983
1054
|
const MASK = (1 << windowSize) - 1;
|
|
984
|
-
const buckets = new Array(MASK + 1).fill(
|
|
985
|
-
const lastBits = Math.floor((
|
|
986
|
-
let sum =
|
|
1055
|
+
const buckets = new Array(MASK + 1).fill(zero); // +1 for zero array
|
|
1056
|
+
const lastBits = Math.floor((fieldN.BITS - 1) / windowSize) * windowSize;
|
|
1057
|
+
let sum = zero;
|
|
987
1058
|
for (let i = lastBits; i >= 0; i -= windowSize) {
|
|
988
|
-
buckets.fill(
|
|
1059
|
+
buckets.fill(zero);
|
|
989
1060
|
for (let j = 0; j < scalars.length; j++) {
|
|
990
1061
|
const scalar = scalars[j];
|
|
991
1062
|
const wbits = Number((scalar >> BigInt(i)) & BigInt(MASK));
|
|
992
1063
|
buckets[wbits] = buckets[wbits].add(points[j]);
|
|
993
1064
|
}
|
|
994
|
-
let resI =
|
|
1065
|
+
let resI = zero; // not using this will do small speed-up, but will lose ct
|
|
995
1066
|
// Skip first bucket, because it is zero
|
|
996
|
-
for (let j = buckets.length - 1, sumI =
|
|
1067
|
+
for (let j = buckets.length - 1, sumI = zero; j > 0; j--) {
|
|
997
1068
|
sumI = sumI.add(buckets[j]);
|
|
998
1069
|
resI = resI.add(sumI);
|
|
999
1070
|
}
|
|
@@ -1048,12 +1119,12 @@ function validatePointOpts(curve) {
|
|
|
1048
1119
|
const { endo, Fp, a } = opts;
|
|
1049
1120
|
if (endo) {
|
|
1050
1121
|
if (!Fp.eql(a, Fp.ZERO)) {
|
|
1051
|
-
throw new Error('
|
|
1122
|
+
throw new Error('invalid endomorphism, can only be defined for Koblitz curves that have a=0');
|
|
1052
1123
|
}
|
|
1053
1124
|
if (typeof endo !== 'object' ||
|
|
1054
1125
|
typeof endo.beta !== 'bigint' ||
|
|
1055
1126
|
typeof endo.splitScalar !== 'function') {
|
|
1056
|
-
throw new Error('
|
|
1127
|
+
throw new Error('invalid endomorphism, expected beta: bigint and splitScalar: function');
|
|
1057
1128
|
}
|
|
1058
1129
|
}
|
|
1059
1130
|
return Object.freeze({ ...opts });
|
|
@@ -1087,7 +1158,8 @@ const DER = {
|
|
|
1087
1158
|
throw new E('tlv.encode: long form length too big');
|
|
1088
1159
|
// length of length with long form flag
|
|
1089
1160
|
const lenLen = dataLen > 127 ? numberToHexUnpadded((len.length / 2) | 128) : '';
|
|
1090
|
-
|
|
1161
|
+
const t = numberToHexUnpadded(tag);
|
|
1162
|
+
return t + lenLen + len + data;
|
|
1091
1163
|
},
|
|
1092
1164
|
// v - value, l - left bytes (unparsed)
|
|
1093
1165
|
decode(tag, data) {
|
|
@@ -1140,15 +1212,15 @@ const DER = {
|
|
|
1140
1212
|
if (Number.parseInt(hex[0], 16) & 0b1000)
|
|
1141
1213
|
hex = '00' + hex;
|
|
1142
1214
|
if (hex.length & 1)
|
|
1143
|
-
throw new E('unexpected assertion');
|
|
1215
|
+
throw new E('unexpected DER parsing assertion: unpadded hex');
|
|
1144
1216
|
return hex;
|
|
1145
1217
|
},
|
|
1146
1218
|
decode(data) {
|
|
1147
1219
|
const { Err: E } = DER;
|
|
1148
1220
|
if (data[0] & 128)
|
|
1149
|
-
throw new E('
|
|
1221
|
+
throw new E('invalid signature integer: negative');
|
|
1150
1222
|
if (data[0] === 0x00 && !(data[1] & 128))
|
|
1151
|
-
throw new E('
|
|
1223
|
+
throw new E('invalid signature integer: unnecessary leading zero');
|
|
1152
1224
|
return b2n(data);
|
|
1153
1225
|
},
|
|
1154
1226
|
},
|
|
@@ -1159,16 +1231,18 @@ const DER = {
|
|
|
1159
1231
|
abytes(data);
|
|
1160
1232
|
const { v: seqBytes, l: seqLeftBytes } = tlv.decode(0x30, data);
|
|
1161
1233
|
if (seqLeftBytes.length)
|
|
1162
|
-
throw new E('
|
|
1234
|
+
throw new E('invalid signature: left bytes after parsing');
|
|
1163
1235
|
const { v: rBytes, l: rLeftBytes } = tlv.decode(0x02, seqBytes);
|
|
1164
1236
|
const { v: sBytes, l: sLeftBytes } = tlv.decode(0x02, rLeftBytes);
|
|
1165
1237
|
if (sLeftBytes.length)
|
|
1166
|
-
throw new E('
|
|
1238
|
+
throw new E('invalid signature: left bytes after parsing');
|
|
1167
1239
|
return { r: int.decode(rBytes), s: int.decode(sBytes) };
|
|
1168
1240
|
},
|
|
1169
1241
|
hexFromSig(sig) {
|
|
1170
1242
|
const { _tlv: tlv, _int: int } = DER;
|
|
1171
|
-
const
|
|
1243
|
+
const rs = tlv.encode(0x02, int.encode(sig.r));
|
|
1244
|
+
const ss = tlv.encode(0x02, int.encode(sig.s));
|
|
1245
|
+
const seq = rs + ss;
|
|
1172
1246
|
return tlv.encode(0x30, seq);
|
|
1173
1247
|
},
|
|
1174
1248
|
};
|
|
@@ -1222,7 +1296,7 @@ function weierstrassPoints(opts) {
|
|
|
1222
1296
|
key = bytesToHex(key);
|
|
1223
1297
|
// Normalize to hex string, pad. E.g. P521 would norm 130-132 char hex to 132-char bytes
|
|
1224
1298
|
if (typeof key !== 'string' || !lengths.includes(key.length))
|
|
1225
|
-
throw new Error('
|
|
1299
|
+
throw new Error('invalid private key');
|
|
1226
1300
|
key = key.padStart(nByteLength * 2, '0');
|
|
1227
1301
|
}
|
|
1228
1302
|
let num;
|
|
@@ -1233,7 +1307,7 @@ function weierstrassPoints(opts) {
|
|
|
1233
1307
|
: bytesToNumberBE(ensureBytes('private key', key, nByteLength));
|
|
1234
1308
|
}
|
|
1235
1309
|
catch (error) {
|
|
1236
|
-
throw new Error(
|
|
1310
|
+
throw new Error('invalid private key, expected hex or ' + nByteLength + ' bytes, got ' + typeof key);
|
|
1237
1311
|
}
|
|
1238
1312
|
if (wrapPrivateKey)
|
|
1239
1313
|
num = mod(num, N); // disabled by default, enabled for BLS
|
|
@@ -1273,7 +1347,7 @@ function weierstrassPoints(opts) {
|
|
|
1273
1347
|
if (p.is0()) {
|
|
1274
1348
|
// (0, 1, 0) aka ZERO is invalid in most contexts.
|
|
1275
1349
|
// In BLS, ZERO can be serialized, so we allow it.
|
|
1276
|
-
// (0, 0, 0) is
|
|
1350
|
+
// (0, 0, 0) is invalid representation of ZERO.
|
|
1277
1351
|
if (CURVE.allowInfinityPoint && !Fp.is0(p.py))
|
|
1278
1352
|
return;
|
|
1279
1353
|
throw new Error('bad point: ZERO');
|
|
@@ -1497,16 +1571,17 @@ function weierstrassPoints(opts) {
|
|
|
1497
1571
|
* an exposed private key e.g. sig verification, which works over *public* keys.
|
|
1498
1572
|
*/
|
|
1499
1573
|
multiplyUnsafe(sc) {
|
|
1500
|
-
|
|
1574
|
+
const { endo, n: N } = CURVE;
|
|
1575
|
+
aInRange('scalar', sc, _0n$2, N);
|
|
1501
1576
|
const I = Point.ZERO;
|
|
1502
1577
|
if (sc === _0n$2)
|
|
1503
1578
|
return I;
|
|
1504
|
-
if (sc === _1n$4)
|
|
1579
|
+
if (this.is0() || sc === _1n$4)
|
|
1505
1580
|
return this;
|
|
1506
|
-
|
|
1507
|
-
if (!endo)
|
|
1508
|
-
return wnaf.
|
|
1509
|
-
//
|
|
1581
|
+
// Case a: no endomorphism. Case b: has precomputes.
|
|
1582
|
+
if (!endo || wnaf.hasPrecomputes(this))
|
|
1583
|
+
return wnaf.wNAFCachedUnsafe(this, sc, Point.normalizeZ);
|
|
1584
|
+
// Case c: endomorphism
|
|
1510
1585
|
let { k1neg, k1, k2neg, k2 } = endo.splitScalar(sc);
|
|
1511
1586
|
let k1p = I;
|
|
1512
1587
|
let k2p = I;
|
|
@@ -1692,7 +1767,9 @@ function weierstrass(curveDef) {
|
|
|
1692
1767
|
return { x, y };
|
|
1693
1768
|
}
|
|
1694
1769
|
else {
|
|
1695
|
-
|
|
1770
|
+
const cl = compressedLen;
|
|
1771
|
+
const ul = uncompressedLen;
|
|
1772
|
+
throw new Error('invalid Point, expected length of ' + cl + ', or uncompressed ' + ul + ', got ' + len);
|
|
1696
1773
|
}
|
|
1697
1774
|
},
|
|
1698
1775
|
});
|
|
@@ -1857,6 +1934,9 @@ function weierstrass(curveDef) {
|
|
|
1857
1934
|
// int2octets can't be used; pads small msgs with 0: unacceptatble for trunc as per RFC vectors
|
|
1858
1935
|
const bits2int = CURVE.bits2int ||
|
|
1859
1936
|
function (bytes) {
|
|
1937
|
+
// Our custom check "just in case"
|
|
1938
|
+
if (bytes.length > 8192)
|
|
1939
|
+
throw new Error('input is too large');
|
|
1860
1940
|
// For curves with nBitLength % 8 !== 0: bits2octets(bits2octets(m)) !== bits2octets(m)
|
|
1861
1941
|
// for some cases, since bytes.length * 8 is not actual bitLength.
|
|
1862
1942
|
const num = bytesToNumberBE(bytes); // check for == u8 done here
|
|
@@ -1873,15 +1953,15 @@ function weierstrass(curveDef) {
|
|
|
1873
1953
|
* Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`.
|
|
1874
1954
|
*/
|
|
1875
1955
|
function int2octets(num) {
|
|
1876
|
-
aInRange(
|
|
1956
|
+
aInRange('num < 2^' + CURVE.nBitLength, num, _0n$2, ORDER_MASK);
|
|
1877
1957
|
// works with order, can have different size than numToField!
|
|
1878
1958
|
return numberToBytesBE(num, CURVE.nByteLength);
|
|
1879
1959
|
}
|
|
1880
1960
|
// Steps A, D of RFC6979 3.2
|
|
1881
1961
|
// Creates RFC6979 seed; converts msg/privKey to numbers.
|
|
1882
1962
|
// Used only in sign, not in verify.
|
|
1883
|
-
// NOTE: we cannot assume here that msgHash has same amount of bytes as curve order,
|
|
1884
|
-
// Also it can be bigger for P224 + SHA256
|
|
1963
|
+
// NOTE: we cannot assume here that msgHash has same amount of bytes as curve order,
|
|
1964
|
+
// this will be invalid at least for P521. Also it can be bigger for P224 + SHA256
|
|
1885
1965
|
function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
|
|
1886
1966
|
if (['recovered', 'canonical'].some((k) => k in opts))
|
|
1887
1967
|
throw new Error('sign() legacy options not supported');
|
|
@@ -1975,39 +2055,48 @@ function weierstrass(curveDef) {
|
|
|
1975
2055
|
const sg = signature;
|
|
1976
2056
|
msgHash = ensureBytes('msgHash', msgHash);
|
|
1977
2057
|
publicKey = ensureBytes('publicKey', publicKey);
|
|
2058
|
+
const { lowS, prehash, format } = opts;
|
|
2059
|
+
// Verify opts, deduce signature format
|
|
2060
|
+
validateSigVerOpts(opts);
|
|
1978
2061
|
if ('strict' in opts)
|
|
1979
2062
|
throw new Error('options.strict was renamed to lowS');
|
|
1980
|
-
|
|
1981
|
-
|
|
2063
|
+
if (format !== undefined && format !== 'compact' && format !== 'der')
|
|
2064
|
+
throw new Error('format must be compact or der');
|
|
2065
|
+
const isHex = typeof sg === 'string' || isBytes(sg);
|
|
2066
|
+
const isObj = !isHex &&
|
|
2067
|
+
!format &&
|
|
2068
|
+
typeof sg === 'object' &&
|
|
2069
|
+
sg !== null &&
|
|
2070
|
+
typeof sg.r === 'bigint' &&
|
|
2071
|
+
typeof sg.s === 'bigint';
|
|
2072
|
+
if (!isHex && !isObj)
|
|
2073
|
+
throw new Error('invalid signature, expected Uint8Array, hex string or Signature instance');
|
|
1982
2074
|
let _sig = undefined;
|
|
1983
2075
|
let P;
|
|
1984
2076
|
try {
|
|
1985
|
-
if (
|
|
2077
|
+
if (isObj)
|
|
2078
|
+
_sig = new Signature(sg.r, sg.s);
|
|
2079
|
+
if (isHex) {
|
|
1986
2080
|
// Signature can be represented in 2 ways: compact (2*nByteLength) & DER (variable-length).
|
|
1987
2081
|
// Since DER can also be 2*nByteLength bytes, we check for it first.
|
|
1988
2082
|
try {
|
|
1989
|
-
|
|
2083
|
+
if (format !== 'compact')
|
|
2084
|
+
_sig = Signature.fromDER(sg);
|
|
1990
2085
|
}
|
|
1991
2086
|
catch (derError) {
|
|
1992
2087
|
if (!(derError instanceof DER.Err))
|
|
1993
2088
|
throw derError;
|
|
1994
|
-
_sig = Signature.fromCompact(sg);
|
|
1995
2089
|
}
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
const { r, s } = sg;
|
|
1999
|
-
_sig = new Signature(r, s);
|
|
2000
|
-
}
|
|
2001
|
-
else {
|
|
2002
|
-
throw new Error('PARSE');
|
|
2090
|
+
if (!_sig && format !== 'der')
|
|
2091
|
+
_sig = Signature.fromCompact(sg);
|
|
2003
2092
|
}
|
|
2004
2093
|
P = Point.fromHex(publicKey);
|
|
2005
2094
|
}
|
|
2006
2095
|
catch (error) {
|
|
2007
|
-
if (error.message === 'PARSE')
|
|
2008
|
-
throw new Error(`signature must be Signature instance, Uint8Array or hex string`);
|
|
2009
2096
|
return false;
|
|
2010
2097
|
}
|
|
2098
|
+
if (!_sig)
|
|
2099
|
+
return false;
|
|
2011
2100
|
if (lowS && _sig.hasHighS())
|
|
2012
2101
|
return false;
|
|
2013
2102
|
if (prehash)
|
|
@@ -2052,14 +2141,14 @@ function createCurve(curveDef, defHash) {
|
|
|
2052
2141
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2053
2142
|
// NIST secp256r1 aka p256
|
|
2054
2143
|
// https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/nist/P-256
|
|
2055
|
-
const
|
|
2056
|
-
const CURVE_A$4 =
|
|
2144
|
+
const Fp256 = Field(BigInt('0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff'));
|
|
2145
|
+
const CURVE_A$4 = Fp256.create(BigInt('-3'));
|
|
2057
2146
|
const CURVE_B$4 = BigInt('0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b');
|
|
2058
2147
|
// prettier-ignore
|
|
2059
2148
|
const p256 = createCurve({
|
|
2060
2149
|
a: CURVE_A$4, // Equation params: a, b
|
|
2061
2150
|
b: CURVE_B$4,
|
|
2062
|
-
Fp:
|
|
2151
|
+
Fp: Fp256, // Field: 2n**224n * (2n**32n-1n) + 2n**192n + 2n**96n-1n
|
|
2063
2152
|
// Curve order, total count of valid points in the field
|
|
2064
2153
|
n: BigInt('0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551'),
|
|
2065
2154
|
// Base (generator) point (x, y)
|
|
@@ -2075,15 +2164,15 @@ const p256 = createCurve({
|
|
|
2075
2164
|
// Field over which we'll do calculations.
|
|
2076
2165
|
// prettier-ignore
|
|
2077
2166
|
const P$1 = BigInt('0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff');
|
|
2078
|
-
const
|
|
2079
|
-
const CURVE_A$3 =
|
|
2167
|
+
const Fp384 = Field(P$1);
|
|
2168
|
+
const CURVE_A$3 = Fp384.create(BigInt('-3'));
|
|
2080
2169
|
// prettier-ignore
|
|
2081
2170
|
const CURVE_B$3 = BigInt('0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef');
|
|
2082
2171
|
// prettier-ignore
|
|
2083
2172
|
const p384 = createCurve({
|
|
2084
2173
|
a: CURVE_A$3, // Equation params: a, b
|
|
2085
2174
|
b: CURVE_B$3,
|
|
2086
|
-
Fp:
|
|
2175
|
+
Fp: Fp384, // Field: 2n**384n - 2n**128n - 2n**96n + 2n**32n - 1n
|
|
2087
2176
|
// Curve order, total count of valid points in the field.
|
|
2088
2177
|
n: BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973'),
|
|
2089
2178
|
// Base (generator) point (x, y)
|
|
@@ -2100,11 +2189,11 @@ const p384 = createCurve({
|
|
|
2100
2189
|
// Field over which we'll do calculations.
|
|
2101
2190
|
// prettier-ignore
|
|
2102
2191
|
const P = BigInt('0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');
|
|
2103
|
-
const
|
|
2192
|
+
const Fp521 = Field(P);
|
|
2104
2193
|
const CURVE = {
|
|
2105
|
-
a:
|
|
2194
|
+
a: Fp521.create(BigInt('-3')),
|
|
2106
2195
|
b: BigInt('0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00'),
|
|
2107
|
-
Fp:
|
|
2196
|
+
Fp: Fp521,
|
|
2108
2197
|
n: BigInt('0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409'),
|
|
2109
2198
|
Gx: BigInt('0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66'),
|
|
2110
2199
|
Gy: BigInt('0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650'),
|
|
@@ -2114,7 +2203,7 @@ const CURVE = {
|
|
|
2114
2203
|
const p521 = createCurve({
|
|
2115
2204
|
a: CURVE.a, // Equation params: a, b
|
|
2116
2205
|
b: CURVE.b,
|
|
2117
|
-
Fp:
|
|
2206
|
+
Fp: Fp521, // Field: 2n**521n - 1n
|
|
2118
2207
|
// Curve order, total count of valid points in the field
|
|
2119
2208
|
n: CURVE.n,
|
|
2120
2209
|
Gx: CURVE.Gx, // Base point (x, y) aka generator point
|
|
@@ -2157,6 +2246,10 @@ function validateOpts$1(curve) {
|
|
|
2157
2246
|
function twistedEdwards(curveDef) {
|
|
2158
2247
|
const CURVE = validateOpts$1(curveDef);
|
|
2159
2248
|
const { Fp, n: CURVE_ORDER, prehash: prehash, hash: cHash, randomBytes, nByteLength, h: cofactor, } = CURVE;
|
|
2249
|
+
// Important:
|
|
2250
|
+
// There are some places where Fp.BYTES is used instead of nByteLength.
|
|
2251
|
+
// So far, everything has been tested with curves of Fp.BYTES == nByteLength.
|
|
2252
|
+
// TODO: test and find curves which behave otherwise.
|
|
2160
2253
|
const MASK = _2n$2 << (BigInt(nByteLength * 8) - _1n$3);
|
|
2161
2254
|
const modP = Fp.create; // Function overrides
|
|
2162
2255
|
const Fn = Field(CURVE.n, CURVE.nBitLength);
|
|
@@ -2370,16 +2463,15 @@ function twistedEdwards(curveDef) {
|
|
|
2370
2463
|
// It's faster, but should only be used when you don't care about
|
|
2371
2464
|
// an exposed private key e.g. sig verification.
|
|
2372
2465
|
// Does NOT allow scalars higher than CURVE.n.
|
|
2373
|
-
|
|
2466
|
+
// Accepts optional accumulator to merge with multiply (important for sparse scalars)
|
|
2467
|
+
multiplyUnsafe(scalar, acc = Point.ZERO) {
|
|
2374
2468
|
const n = scalar;
|
|
2375
2469
|
aInRange('scalar', n, _0n$1, CURVE_ORDER); // 0 <= scalar < L
|
|
2376
2470
|
if (n === _0n$1)
|
|
2377
2471
|
return I;
|
|
2378
|
-
if (this.
|
|
2472
|
+
if (this.is0() || n === _1n$3)
|
|
2379
2473
|
return this;
|
|
2380
|
-
|
|
2381
|
-
return this.wNAF(n).p;
|
|
2382
|
-
return wnaf.unsafeLadder(this, n);
|
|
2474
|
+
return wnaf.wNAFCachedUnsafe(this, n, Point.normalizeZ, acc);
|
|
2383
2475
|
}
|
|
2384
2476
|
// Checks if point is of small order.
|
|
2385
2477
|
// If you add something to small order point, you will have "dirty"
|
|
@@ -2415,6 +2507,7 @@ function twistedEdwards(curveDef) {
|
|
|
2415
2507
|
const lastByte = hex[len - 1]; // select last byte
|
|
2416
2508
|
normed[len - 1] = lastByte & ~0x80; // clear last bit
|
|
2417
2509
|
const y = bytesToNumberLE(normed);
|
|
2510
|
+
// zip215=true is good for consensus-critical apps. =false follows RFC8032 / NIST186-5.
|
|
2418
2511
|
// RFC8032 prohibits >= p, but ZIP215 doesn't
|
|
2419
2512
|
// zip215=true: 0 <= y < MASK (2^256 for ed25519)
|
|
2420
2513
|
// zip215=false: 0 <= y < P (2^255-19 for ed25519)
|
|
@@ -2463,7 +2556,7 @@ function twistedEdwards(curveDef) {
|
|
|
2463
2556
|
}
|
|
2464
2557
|
/** Convenience method that creates public key and other stuff. RFC8032 5.1.5 */
|
|
2465
2558
|
function getExtendedPublicKey(key) {
|
|
2466
|
-
const len =
|
|
2559
|
+
const len = Fp.BYTES;
|
|
2467
2560
|
key = ensureBytes('private key', key, len);
|
|
2468
2561
|
// Hash private key with curve's hash function to produce uniformingly random input
|
|
2469
2562
|
// Check byte lengths: ensure(64, h(ensure(32, key)))
|
|
@@ -2496,23 +2589,29 @@ function twistedEdwards(curveDef) {
|
|
|
2496
2589
|
const s = modN(r + k * scalar); // S = (r + k * s) mod L
|
|
2497
2590
|
aInRange('signature.s', s, _0n$1, CURVE_ORDER); // 0 <= s < l
|
|
2498
2591
|
const res = concatBytes(R, numberToBytesLE(s, Fp.BYTES));
|
|
2499
|
-
return ensureBytes('result', res,
|
|
2592
|
+
return ensureBytes('result', res, Fp.BYTES * 2); // 64-byte signature
|
|
2500
2593
|
}
|
|
2501
2594
|
const verifyOpts = VERIFY_DEFAULT;
|
|
2595
|
+
/**
|
|
2596
|
+
* Verifies EdDSA signature against message and public key. RFC8032 5.1.7.
|
|
2597
|
+
* An extended group equation is checked.
|
|
2598
|
+
*/
|
|
2502
2599
|
function verify(sig, msg, publicKey, options = verifyOpts) {
|
|
2503
2600
|
const { context, zip215 } = options;
|
|
2504
2601
|
const len = Fp.BYTES; // Verifies EdDSA signature against message and public key. RFC8032 5.1.7.
|
|
2505
2602
|
sig = ensureBytes('signature', sig, 2 * len); // An extended group equation is checked.
|
|
2506
2603
|
msg = ensureBytes('message', msg);
|
|
2604
|
+
publicKey = ensureBytes('publicKey', publicKey, len);
|
|
2507
2605
|
if (zip215 !== undefined)
|
|
2508
2606
|
abool('zip215', zip215);
|
|
2509
2607
|
if (prehash)
|
|
2510
2608
|
msg = prehash(msg); // for ed25519ph, etc
|
|
2511
2609
|
const s = bytesToNumberLE(sig.slice(len, 2 * len));
|
|
2512
|
-
// zip215: true is good for consensus-critical apps and allows points < 2^256
|
|
2513
|
-
// zip215: false follows RFC8032 / NIST186-5 and restricts points to CURVE.p
|
|
2514
2610
|
let A, R, SB;
|
|
2515
2611
|
try {
|
|
2612
|
+
// zip215=true is good for consensus-critical apps. =false follows RFC8032 / NIST186-5.
|
|
2613
|
+
// zip215=true: 0 <= y < MASK (2^256 for ed25519)
|
|
2614
|
+
// zip215=false: 0 <= y < P (2^255-19 for ed25519)
|
|
2516
2615
|
A = Point.fromHex(publicKey, zip215);
|
|
2517
2616
|
R = Point.fromHex(sig.slice(0, len), zip215);
|
|
2518
2617
|
SB = G.multiplyUnsafe(s); // 0 <= s < l is done inside
|
|
@@ -2524,6 +2623,7 @@ function twistedEdwards(curveDef) {
|
|
|
2524
2623
|
return false;
|
|
2525
2624
|
const k = hashDomainToScalar(context, R.toRawBytes(), A.toRawBytes(), msg);
|
|
2526
2625
|
const RkA = R.add(A.multiplyUnsafe(k));
|
|
2626
|
+
// Extended group equation
|
|
2527
2627
|
// [8][S]B = [8]R + [8][k]A'
|
|
2528
2628
|
return RkA.subtract(SB).clearCofactor().equals(Point.ZERO);
|
|
2529
2629
|
}
|
|
@@ -2673,8 +2773,10 @@ function montgomery(curveDef) {
|
|
|
2673
2773
|
function decodeScalar(n) {
|
|
2674
2774
|
const bytes = ensureBytes('scalar', n);
|
|
2675
2775
|
const len = bytes.length;
|
|
2676
|
-
if (len !== montgomeryBytes && len !== fieldLen)
|
|
2677
|
-
|
|
2776
|
+
if (len !== montgomeryBytes && len !== fieldLen) {
|
|
2777
|
+
let valid = '' + montgomeryBytes + ' or ' + fieldLen;
|
|
2778
|
+
throw new Error('invalid scalar, expected ' + valid + ' bytes, got ' + len);
|
|
2779
|
+
}
|
|
2678
2780
|
return bytesToNumberLE(adjustScalarBytes(bytes));
|
|
2679
2781
|
}
|
|
2680
2782
|
function scalarMult(scalar, u) {
|
|
@@ -2684,7 +2786,7 @@ function montgomery(curveDef) {
|
|
|
2684
2786
|
// The result was not contributory
|
|
2685
2787
|
// https://cr.yp.to/ecdh.html#validate
|
|
2686
2788
|
if (pu === _0n)
|
|
2687
|
-
throw new Error('
|
|
2789
|
+
throw new Error('invalid private or public key received');
|
|
2688
2790
|
return encodeUCoordinate(pu);
|
|
2689
2791
|
}
|
|
2690
2792
|
// Computes public key from private. By doing scalar multiplication of base point.
|
|
@@ -2767,14 +2869,14 @@ function uvRatio(u, v) {
|
|
|
2767
2869
|
// square root exists, and the decoding fails.
|
|
2768
2870
|
return { isValid: mod(x2 * v, P) === u, value: x };
|
|
2769
2871
|
}
|
|
2770
|
-
const Fp$
|
|
2872
|
+
const Fp$3 = Field(ed448P, 456, true);
|
|
2771
2873
|
const ED448_DEF = {
|
|
2772
2874
|
// Param: a
|
|
2773
2875
|
a: BigInt(1),
|
|
2774
2876
|
// -39081. Negative number is P - number
|
|
2775
2877
|
d: BigInt('726838724295606890549323807888004534353641360687318060281490199180612328166730772686396383698676545930088884461843637361053498018326358'),
|
|
2776
2878
|
// Finite field 𝔽p over which we'll do calculations; 2n**448n - 2n**224n - 1n
|
|
2777
|
-
Fp: Fp$
|
|
2879
|
+
Fp: Fp$3,
|
|
2778
2880
|
// Subgroup order: how many points curve has;
|
|
2779
2881
|
// 2n**446n - 13818066809895115352007386748515426880336692474882178609894547503885n
|
|
2780
2882
|
n: BigInt('181709681073901722637330951972001133588410340171829515070372549795146003961539585716195755291692375963310293709091662304773755859649779'),
|
|
@@ -2792,7 +2894,7 @@ const ED448_DEF = {
|
|
|
2792
2894
|
// dom4
|
|
2793
2895
|
domain: (data, ctx, phflag) => {
|
|
2794
2896
|
if (ctx.length > 255)
|
|
2795
|
-
throw new Error(
|
|
2897
|
+
throw new Error('context must be smaller than 255, got: ' + ctx.length);
|
|
2796
2898
|
return concatBytes$1(utf8ToBytes$1('SigEd448'), new Uint8Array([phflag ? 1 : 0, ctx.length]), ctx, data);
|
|
2797
2899
|
},
|
|
2798
2900
|
uvRatio,
|
|
@@ -2818,7 +2920,7 @@ const x448 = /* @__PURE__ */ (() => montgomery({
|
|
|
2818
2920
|
}))();
|
|
2819
2921
|
// TODO: add edwardsToMontgomeryPriv, similar to ed25519 version
|
|
2820
2922
|
// Hash To Curve Elligator2 Map
|
|
2821
|
-
(Fp$
|
|
2923
|
+
(Fp$3.ORDER - BigInt(3)) / BigInt(4); // 1. c1 = (q - 3) / 4 # Integer arithmetic
|
|
2822
2924
|
BigInt(156326);
|
|
2823
2925
|
// 1-d
|
|
2824
2926
|
BigInt('39082');
|
|
@@ -2860,18 +2962,18 @@ function sqrtMod(y) {
|
|
|
2860
2962
|
const t1 = (pow2(b223, _23n, P) * b22) % P;
|
|
2861
2963
|
const t2 = (pow2(t1, _6n, P) * b2) % P;
|
|
2862
2964
|
const root = pow2(t2, _2n, P);
|
|
2863
|
-
if (!
|
|
2965
|
+
if (!Fpk1.eql(Fpk1.sqr(root), y))
|
|
2864
2966
|
throw new Error('Cannot find square root');
|
|
2865
2967
|
return root;
|
|
2866
2968
|
}
|
|
2867
|
-
const
|
|
2969
|
+
const Fpk1 = Field(secp256k1P, undefined, undefined, { sqrt: sqrtMod });
|
|
2868
2970
|
/**
|
|
2869
2971
|
* secp256k1 short weierstrass curve and ECDSA signatures over it.
|
|
2870
2972
|
*/
|
|
2871
2973
|
const secp256k1 = createCurve({
|
|
2872
2974
|
a: BigInt(0), // equation params: a, b
|
|
2873
2975
|
b: BigInt(7), // Seem to be rigid: bitcointalk.org/index.php?topic=289795.msg3183975#msg3183975
|
|
2874
|
-
Fp:
|
|
2976
|
+
Fp: Fpk1, // Field's prime: 2n**256n - 2n**32n - 2n**9n - 2n**8n - 2n**7n - 2n**6n - 2n**4n - 1n
|
|
2875
2977
|
n: secp256k1N, // Curve order, total count of valid points in the field
|
|
2876
2978
|
// Base point (x, y) aka generator point
|
|
2877
2979
|
Gx: BigInt('55066263022277343669578718895168534326250603453777594175500187360389116729240'),
|