@hive-p2p/browser 1.0.39 → 1.0.40

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.
@@ -0,0 +1,630 @@
1
+ /*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */
2
+ /**
3
+ * 5KB JS implementation of ed25519 EdDSA signatures.
4
+ * Compliant with RFC8032, FIPS 186-5 & ZIP215.
5
+ * @module
6
+ * @example
7
+ * ```js
8
+ import * as ed from '@noble/ed25519';
9
+ (async () => {
10
+ const secretKey = ed.utils.randomSecretKey();
11
+ const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);
12
+ const pubKey = await ed.getPublicKeyAsync(secretKey); // Sync methods are also present
13
+ const signature = await ed.signAsync(message, secretKey);
14
+ const isValid = await ed.verifyAsync(signature, message, pubKey);
15
+ })();
16
+ ```
17
+ */
18
+ /**
19
+ * Curve params. ed25519 is twisted edwards curve. Equation is −x² + y² = -a + dx²y².
20
+ * * P = `2n**255n - 19n` // field over which calculations are done
21
+ * * N = `2n**252n + 27742317777372353535851937790883648493n` // group order, amount of curve points
22
+ * * h = 8 // cofactor
23
+ * * a = `Fp.create(BigInt(-1))` // equation param
24
+ * * d = -121665/121666 a.k.a. `Fp.neg(121665 * Fp.inv(121666))` // equation param
25
+ * * Gx, Gy are coordinates of Generator / base point
26
+ */
27
+ const ed25519_CURVE = {
28
+ p: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedn,
29
+ n: 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3edn,
30
+ h: 8n,
31
+ a: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffecn,
32
+ d: 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3n,
33
+ Gx: 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51an,
34
+ Gy: 0x6666666666666666666666666666666666666666666666666666666666666658n,
35
+ };
36
+ const { p: P, n: N, Gx, Gy, a: _a, d: _d, h } = ed25519_CURVE;
37
+ const L = 32; // field / group byte length
38
+ const L2 = 64;
39
+ // Helpers and Precomputes sections are reused between libraries
40
+ // ## Helpers
41
+ // ----------
42
+ const captureTrace = (...args) => {
43
+ if ('captureStackTrace' in Error && typeof Error.captureStackTrace === 'function') {
44
+ Error.captureStackTrace(...args);
45
+ }
46
+ };
47
+ const err = (message = '') => {
48
+ const e = new Error(message);
49
+ captureTrace(e, err);
50
+ throw e;
51
+ };
52
+ const isBig = (n) => typeof n === 'bigint'; // is big integer
53
+ const isStr = (s) => typeof s === 'string'; // is string
54
+ const isBytes = (a) => a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');
55
+ /** Asserts something is Uint8Array. */
56
+ const abytes = (value, length, title = '') => {
57
+ const bytes = isBytes(value);
58
+ const len = value?.length;
59
+ const needsLen = length !== undefined;
60
+ if (!bytes || (needsLen && len !== length)) {
61
+ const prefix = title && `"${title}" `;
62
+ const ofLen = needsLen ? ` of length ${length}` : '';
63
+ const got = bytes ? `length=${len}` : `type=${typeof value}`;
64
+ err(prefix + 'expected Uint8Array' + ofLen + ', got ' + got);
65
+ }
66
+ return value;
67
+ };
68
+ /** create Uint8Array */
69
+ const u8n = (len) => new Uint8Array(len);
70
+ const u8fr = (buf) => Uint8Array.from(buf);
71
+ const padh = (n, pad) => n.toString(16).padStart(pad, '0');
72
+ const bytesToHex = (b) => Array.from(abytes(b))
73
+ .map((e) => padh(e, 2))
74
+ .join('');
75
+ const C = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 }; // ASCII characters
76
+ const _ch = (ch) => {
77
+ if (ch >= C._0 && ch <= C._9)
78
+ return ch - C._0; // '2' => 50-48
79
+ if (ch >= C.A && ch <= C.F)
80
+ return ch - (C.A - 10); // 'B' => 66-(65-10)
81
+ if (ch >= C.a && ch <= C.f)
82
+ return ch - (C.a - 10); // 'b' => 98-(97-10)
83
+ return;
84
+ };
85
+ const hexToBytes = (hex) => {
86
+ const e = 'hex invalid';
87
+ if (!isStr(hex))
88
+ return err(e);
89
+ const hl = hex.length;
90
+ const al = hl / 2;
91
+ if (hl % 2)
92
+ return err(e);
93
+ const array = u8n(al);
94
+ for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
95
+ // treat each char as ASCII
96
+ const n1 = _ch(hex.charCodeAt(hi)); // parse first char, multiply it by 16
97
+ const n2 = _ch(hex.charCodeAt(hi + 1)); // parse second char
98
+ if (n1 === undefined || n2 === undefined)
99
+ return err(e);
100
+ array[ai] = n1 * 16 + n2; // example: 'A9' => 10*16 + 9
101
+ }
102
+ return array;
103
+ };
104
+ const cr = () => globalThis?.crypto; // WebCrypto is available in all modern environments
105
+ const subtle = () => cr()?.subtle ?? err('crypto.subtle must be defined, consider polyfill');
106
+ // prettier-ignore
107
+ const concatBytes = (...arrs) => {
108
+ const r = u8n(arrs.reduce((sum, a) => sum + abytes(a).length, 0)); // create u8a of summed length
109
+ let pad = 0; // walk through each array,
110
+ arrs.forEach(a => { r.set(a, pad); pad += a.length; }); // ensure they have proper type
111
+ return r;
112
+ };
113
+ /** WebCrypto OS-level CSPRNG (random number generator). Will throw when not available. */
114
+ const randomBytes = (len = L) => {
115
+ const c = cr();
116
+ return c.getRandomValues(u8n(len));
117
+ };
118
+ const big = BigInt;
119
+ const assertRange = (n, min, max, msg = 'bad number: out of range') => (isBig(n) && min <= n && n < max ? n : err(msg));
120
+ /** modular division */
121
+ const M = (a, b = P) => {
122
+ const r = a % b;
123
+ return r >= 0n ? r : b + r;
124
+ };
125
+ const modN = (a) => M(a, N);
126
+ /** Modular inversion using euclidean GCD (non-CT). No negative exponent for now. */
127
+ // prettier-ignore
128
+ const invert = (num, md) => {
129
+ if (num === 0n || md <= 0n)
130
+ err('no inverse n=' + num + ' mod=' + md);
131
+ let a = M(num, md), b = md, x = 0n, y = 1n, u = 1n, v = 0n;
132
+ while (a !== 0n) {
133
+ const q = b / a, r = b % a;
134
+ const m = x - u * q, n = y - v * q;
135
+ b = a, a = r, x = u, y = v, u = m, v = n;
136
+ }
137
+ return b === 1n ? M(x, md) : err('no inverse'); // b is gcd at this point
138
+ };
139
+ const callHash = (name) => {
140
+ // @ts-ignore
141
+ const fn = hashes[name];
142
+ if (typeof fn !== 'function')
143
+ err('hashes.' + name + ' not set');
144
+ return fn;
145
+ };
146
+ const hash = (msg) => callHash('sha512')(msg);
147
+ const apoint = (p) => (p instanceof Point ? p : err('Point expected'));
148
+ // ## End of Helpers
149
+ // -----------------
150
+ const B256 = 2n ** 256n;
151
+ /** Point in XYZT extended coordinates. */
152
+ class Point {
153
+ static BASE;
154
+ static ZERO;
155
+ X;
156
+ Y;
157
+ Z;
158
+ T;
159
+ constructor(X, Y, Z, T) {
160
+ const max = B256;
161
+ this.X = assertRange(X, 0n, max);
162
+ this.Y = assertRange(Y, 0n, max);
163
+ this.Z = assertRange(Z, 1n, max);
164
+ this.T = assertRange(T, 0n, max);
165
+ Object.freeze(this);
166
+ }
167
+ static CURVE() {
168
+ return ed25519_CURVE;
169
+ }
170
+ static fromAffine(p) {
171
+ return new Point(p.x, p.y, 1n, M(p.x * p.y));
172
+ }
173
+ /** RFC8032 5.1.3: Uint8Array to Point. */
174
+ static fromBytes(hex, zip215 = false) {
175
+ const d = _d;
176
+ // Copy array to not mess it up.
177
+ const normed = u8fr(abytes(hex, L));
178
+ // adjust first LE byte = last BE byte
179
+ const lastByte = hex[31];
180
+ normed[31] = lastByte & ~0x80;
181
+ const y = bytesToNumLE(normed);
182
+ // zip215=true: 0 <= y < 2^256
183
+ // zip215=false, RFC8032: 0 <= y < 2^255-19
184
+ const max = zip215 ? B256 : P;
185
+ assertRange(y, 0n, max);
186
+ const y2 = M(y * y); // y²
187
+ const u = M(y2 - 1n); // u=y²-1
188
+ const v = M(d * y2 + 1n); // v=dy²+1
189
+ let { isValid, value: x } = uvRatio(u, v); // (uv³)(uv⁷)^(p-5)/8; square root
190
+ if (!isValid)
191
+ err('bad point: y not sqrt'); // not square root: bad point
192
+ const isXOdd = (x & 1n) === 1n; // adjust sign of x coordinate
193
+ const isLastByteOdd = (lastByte & 0x80) !== 0; // x_0, last bit
194
+ if (!zip215 && x === 0n && isLastByteOdd)
195
+ err('bad point: x==0, isLastByteOdd'); // x=0, x_0=1
196
+ if (isLastByteOdd !== isXOdd)
197
+ x = M(-x);
198
+ return new Point(x, y, 1n, M(x * y)); // Z=1, T=xy
199
+ }
200
+ static fromHex(hex, zip215) {
201
+ return Point.fromBytes(hexToBytes(hex), zip215);
202
+ }
203
+ get x() {
204
+ return this.toAffine().x;
205
+ }
206
+ get y() {
207
+ return this.toAffine().y;
208
+ }
209
+ /** Checks if the point is valid and on-curve. */
210
+ assertValidity() {
211
+ const a = _a;
212
+ const d = _d;
213
+ const p = this;
214
+ if (p.is0())
215
+ return err('bad point: ZERO'); // TODO: optimize, with vars below?
216
+ // Equation in affine coordinates: ax² + y² = 1 + dx²y²
217
+ // Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²
218
+ const { X, Y, Z, T } = p;
219
+ const X2 = M(X * X); // X²
220
+ const Y2 = M(Y * Y); // Y²
221
+ const Z2 = M(Z * Z); // Z²
222
+ const Z4 = M(Z2 * Z2); // Z⁴
223
+ const aX2 = M(X2 * a); // aX²
224
+ const left = M(Z2 * M(aX2 + Y2)); // (aX² + Y²)Z²
225
+ const right = M(Z4 + M(d * M(X2 * Y2))); // Z⁴ + dX²Y²
226
+ if (left !== right)
227
+ return err('bad point: equation left != right (1)');
228
+ // In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T
229
+ const XY = M(X * Y);
230
+ const ZT = M(Z * T);
231
+ if (XY !== ZT)
232
+ return err('bad point: equation left != right (2)');
233
+ return this;
234
+ }
235
+ /** Equality check: compare points P&Q. */
236
+ equals(other) {
237
+ const { X: X1, Y: Y1, Z: Z1 } = this;
238
+ const { X: X2, Y: Y2, Z: Z2 } = apoint(other); // checks class equality
239
+ const X1Z2 = M(X1 * Z2);
240
+ const X2Z1 = M(X2 * Z1);
241
+ const Y1Z2 = M(Y1 * Z2);
242
+ const Y2Z1 = M(Y2 * Z1);
243
+ return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;
244
+ }
245
+ is0() {
246
+ return this.equals(I);
247
+ }
248
+ /** Flip point over y coordinate. */
249
+ negate() {
250
+ return new Point(M(-this.X), this.Y, this.Z, M(-this.T));
251
+ }
252
+ /** Point doubling. Complete formula. Cost: `4M + 4S + 1*a + 6add + 1*2`. */
253
+ double() {
254
+ const { X: X1, Y: Y1, Z: Z1 } = this;
255
+ const a = _a;
256
+ // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd
257
+ const A = M(X1 * X1);
258
+ const B = M(Y1 * Y1);
259
+ const C = M(2n * M(Z1 * Z1));
260
+ const D = M(a * A);
261
+ const x1y1 = X1 + Y1;
262
+ const E = M(M(x1y1 * x1y1) - A - B);
263
+ const G = D + B;
264
+ const F = G - C;
265
+ const H = D - B;
266
+ const X3 = M(E * F);
267
+ const Y3 = M(G * H);
268
+ const T3 = M(E * H);
269
+ const Z3 = M(F * G);
270
+ return new Point(X3, Y3, Z3, T3);
271
+ }
272
+ /** Point addition. Complete formula. Cost: `8M + 1*k + 8add + 1*2`. */
273
+ add(other) {
274
+ const { X: X1, Y: Y1, Z: Z1, T: T1 } = this;
275
+ const { X: X2, Y: Y2, Z: Z2, T: T2 } = apoint(other); // doesn't check if other on-curve
276
+ const a = _a;
277
+ const d = _d;
278
+ // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3
279
+ const A = M(X1 * X2);
280
+ const B = M(Y1 * Y2);
281
+ const C = M(T1 * d * T2);
282
+ const D = M(Z1 * Z2);
283
+ const E = M((X1 + Y1) * (X2 + Y2) - A - B);
284
+ const F = M(D - C);
285
+ const G = M(D + C);
286
+ const H = M(B - a * A);
287
+ const X3 = M(E * F);
288
+ const Y3 = M(G * H);
289
+ const T3 = M(E * H);
290
+ const Z3 = M(F * G);
291
+ return new Point(X3, Y3, Z3, T3);
292
+ }
293
+ subtract(other) {
294
+ return this.add(apoint(other).negate());
295
+ }
296
+ /**
297
+ * Point-by-scalar multiplication. Scalar must be in range 1 <= n < CURVE.n.
298
+ * Uses {@link wNAF} for base point.
299
+ * Uses fake point to mitigate side-channel leakage.
300
+ * @param n scalar by which point is multiplied
301
+ * @param safe safe mode guards against timing attacks; unsafe mode is faster
302
+ */
303
+ multiply(n, safe = true) {
304
+ if (!safe && (n === 0n || this.is0()))
305
+ return I;
306
+ assertRange(n, 1n, N);
307
+ if (n === 1n)
308
+ return this;
309
+ if (this.equals(G))
310
+ return wNAF(n).p;
311
+ // init result point & fake point
312
+ let p = I;
313
+ let f = G;
314
+ for (let d = this; n > 0n; d = d.double(), n >>= 1n) {
315
+ // if bit is present, add to point
316
+ // if not present, add to fake, for timing safety
317
+ if (n & 1n)
318
+ p = p.add(d);
319
+ else if (safe)
320
+ f = f.add(d);
321
+ }
322
+ return p;
323
+ }
324
+ multiplyUnsafe(scalar) {
325
+ return this.multiply(scalar, false);
326
+ }
327
+ /** Convert point to 2d xy affine point. (X, Y, Z) ∋ (x=X/Z, y=Y/Z) */
328
+ toAffine() {
329
+ const { X, Y, Z } = this;
330
+ // fast-paths for ZERO point OR Z=1
331
+ if (this.equals(I))
332
+ return { x: 0n, y: 1n };
333
+ const iz = invert(Z, P);
334
+ // (Z * Z^-1) must be 1, otherwise bad math
335
+ if (M(Z * iz) !== 1n)
336
+ err('invalid inverse');
337
+ // x = X*Z^-1; y = Y*Z^-1
338
+ const x = M(X * iz);
339
+ const y = M(Y * iz);
340
+ return { x, y };
341
+ }
342
+ toBytes() {
343
+ const { x, y } = this.assertValidity().toAffine();
344
+ const b = numTo32bLE(y);
345
+ // store sign in first LE byte
346
+ b[31] |= x & 1n ? 0x80 : 0;
347
+ return b;
348
+ }
349
+ toHex() {
350
+ return bytesToHex(this.toBytes());
351
+ }
352
+ clearCofactor() {
353
+ return this.multiply(big(h), false);
354
+ }
355
+ isSmallOrder() {
356
+ return this.clearCofactor().is0();
357
+ }
358
+ isTorsionFree() {
359
+ // Multiply by big number N. We can't `mul(N)` because of checks. Instead, we `mul(N/2)*2+1`
360
+ let p = this.multiply(N / 2n, false).double();
361
+ if (N % 2n)
362
+ p = p.add(this);
363
+ return p.is0();
364
+ }
365
+ }
366
+ /** Generator / base point */
367
+ const G = new Point(Gx, Gy, 1n, M(Gx * Gy));
368
+ /** Identity / zero point */
369
+ const I = new Point(0n, 1n, 1n, 0n);
370
+ // Static aliases
371
+ Point.BASE = G;
372
+ Point.ZERO = I;
373
+ const numTo32bLE = (num) => hexToBytes(padh(assertRange(num, 0n, B256), L2)).reverse();
374
+ const bytesToNumLE = (b) => big('0x' + bytesToHex(u8fr(abytes(b)).reverse()));
375
+ const pow2 = (x, power) => {
376
+ // pow2(x, 4) == x^(2^4)
377
+ let r = x;
378
+ while (power-- > 0n) {
379
+ r *= r;
380
+ r %= P;
381
+ }
382
+ return r;
383
+ };
384
+ // prettier-ignore
385
+ const pow_2_252_3 = (x) => {
386
+ const x2 = (x * x) % P; // x^2, bits 1
387
+ const b2 = (x2 * x) % P; // x^3, bits 11
388
+ const b4 = (pow2(b2, 2n) * b2) % P; // x^(2^4-1), bits 1111
389
+ const b5 = (pow2(b4, 1n) * x) % P; // x^(2^5-1), bits 11111
390
+ const b10 = (pow2(b5, 5n) * b5) % P; // x^(2^10)
391
+ const b20 = (pow2(b10, 10n) * b10) % P; // x^(2^20)
392
+ const b40 = (pow2(b20, 20n) * b20) % P; // x^(2^40)
393
+ const b80 = (pow2(b40, 40n) * b40) % P; // x^(2^80)
394
+ const b160 = (pow2(b80, 80n) * b80) % P; // x^(2^160)
395
+ const b240 = (pow2(b160, 80n) * b80) % P; // x^(2^240)
396
+ const b250 = (pow2(b240, 10n) * b10) % P; // x^(2^250)
397
+ const pow_p_5_8 = (pow2(b250, 2n) * x) % P; // < To pow to (p+3)/8, multiply it by x.
398
+ return { pow_p_5_8, b2 };
399
+ };
400
+ const RM1 = 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0n; // √-1
401
+ // for sqrt comp
402
+ // prettier-ignore
403
+ const uvRatio = (u, v) => {
404
+ const v3 = M(v * v * v); // v³
405
+ const v7 = M(v3 * v3 * v); // v⁷
406
+ const pow = pow_2_252_3(u * v7).pow_p_5_8; // (uv⁷)^(p-5)/8
407
+ let x = M(u * v3 * pow); // (uv³)(uv⁷)^(p-5)/8
408
+ const vx2 = M(v * x * x); // vx²
409
+ const root1 = x; // First root candidate
410
+ const root2 = M(x * RM1); // Second root candidate; RM1 is √-1
411
+ const useRoot1 = vx2 === u; // If vx² = u (mod p), x is a square root
412
+ const useRoot2 = vx2 === M(-u); // If vx² = -u, set x <-- x * 2^((p-1)/4)
413
+ const noRoot = vx2 === M(-u * RM1); // There is no valid root, vx² = -u√-1
414
+ if (useRoot1)
415
+ x = root1;
416
+ if (useRoot2 || noRoot)
417
+ x = root2; // We return root2 anyway, for const-time
418
+ if ((M(x) & 1n) === 1n)
419
+ x = M(-x); // edIsNegative
420
+ return { isValid: useRoot1 || useRoot2, value: x };
421
+ };
422
+ // N == L, just weird naming
423
+ const modL_LE = (hash) => modN(bytesToNumLE(hash)); // modulo L; but little-endian
424
+ /** hashes.sha512 should conform to the interface. */
425
+ // TODO: rename
426
+ const sha512a = (...m) => hashes.sha512Async(concatBytes(...m)); // Async SHA512
427
+ const sha512s = (...m) => callHash('sha512')(concatBytes(...m));
428
+ // RFC8032 5.1.5
429
+ const hash2extK = (hashed) => {
430
+ // slice creates a copy, unlike subarray
431
+ const head = hashed.slice(0, L);
432
+ head[0] &= 248; // Clamp bits: 0b1111_1000
433
+ head[31] &= 127; // 0b0111_1111
434
+ head[31] |= 64; // 0b0100_0000
435
+ const prefix = hashed.slice(L, L2); // secret key "prefix"
436
+ const scalar = modL_LE(head); // modular division over curve order
437
+ const point = G.multiply(scalar); // public key point
438
+ const pointBytes = point.toBytes(); // point serialized to Uint8Array
439
+ return { head, prefix, scalar, point, pointBytes };
440
+ };
441
+ // RFC8032 5.1.5; getPublicKey async, sync. Hash priv key and extract point.
442
+ const getExtendedPublicKeyAsync = (secretKey) => sha512a(abytes(secretKey, L)).then(hash2extK);
443
+ const getExtendedPublicKey = (secretKey) => hash2extK(sha512s(abytes(secretKey, L)));
444
+ /** Creates 32-byte ed25519 public key from 32-byte secret key. Async. */
445
+ const getPublicKeyAsync = (secretKey) => getExtendedPublicKeyAsync(secretKey).then((p) => p.pointBytes);
446
+ /** Creates 32-byte ed25519 public key from 32-byte secret key. To use, set `hashes.sha512` first. */
447
+ const getPublicKey = (priv) => getExtendedPublicKey(priv).pointBytes;
448
+ const hashFinishA = (res) => sha512a(res.hashable).then(res.finish);
449
+ const hashFinishS = (res) => res.finish(sha512s(res.hashable));
450
+ // Code, shared between sync & async sign
451
+ const _sign = (e, rBytes, msg) => {
452
+ const { pointBytes: P, scalar: s } = e;
453
+ const r = modL_LE(rBytes); // r was created outside, reduce it modulo L
454
+ const R = G.multiply(r).toBytes(); // R = [r]B
455
+ const hashable = concatBytes(R, P, msg); // dom2(F, C) || R || A || PH(M)
456
+ const finish = (hashed) => {
457
+ // k = SHA512(dom2(F, C) || R || A || PH(M))
458
+ const S = modN(r + modL_LE(hashed) * s); // S = (r + k * s) mod L; 0 <= s < l
459
+ return abytes(concatBytes(R, numTo32bLE(S)), L2); // 64-byte sig: 32b R.x + 32b LE(S)
460
+ };
461
+ return { hashable, finish };
462
+ };
463
+ /**
464
+ * Signs message using secret key. Async.
465
+ * Follows RFC8032 5.1.6.
466
+ */
467
+ const signAsync = async (message, secretKey) => {
468
+ const m = abytes(message);
469
+ const e = await getExtendedPublicKeyAsync(secretKey);
470
+ const rBytes = await sha512a(e.prefix, m); // r = SHA512(dom2(F, C) || prefix || PH(M))
471
+ return hashFinishA(_sign(e, rBytes, m)); // gen R, k, S, then 64-byte signature
472
+ };
473
+ /**
474
+ * Signs message using secret key. To use, set `hashes.sha512` first.
475
+ * Follows RFC8032 5.1.6.
476
+ */
477
+ const sign = (message, secretKey) => {
478
+ const m = abytes(message);
479
+ const e = getExtendedPublicKey(secretKey);
480
+ const rBytes = sha512s(e.prefix, m); // r = SHA512(dom2(F, C) || prefix || PH(M))
481
+ return hashFinishS(_sign(e, rBytes, m)); // gen R, k, S, then 64-byte signature
482
+ };
483
+ const defaultVerifyOpts = { zip215: true };
484
+ const _verify = (sig, msg, pub, opts = defaultVerifyOpts) => {
485
+ sig = abytes(sig, L2); // Signature hex str/Bytes, must be 64 bytes
486
+ msg = abytes(msg); // Message hex str/Bytes
487
+ pub = abytes(pub, L);
488
+ const { zip215 } = opts; // switch between zip215 and rfc8032 verif
489
+ let A;
490
+ let R;
491
+ let s;
492
+ let SB;
493
+ let hashable = Uint8Array.of();
494
+ try {
495
+ A = Point.fromBytes(pub, zip215); // public key A decoded
496
+ R = Point.fromBytes(sig.slice(0, L), zip215); // 0 <= R < 2^256: ZIP215 R can be >= P
497
+ s = bytesToNumLE(sig.slice(L, L2)); // Decode second half as an integer S
498
+ SB = G.multiply(s, false); // in the range 0 <= s < L
499
+ hashable = concatBytes(R.toBytes(), A.toBytes(), msg); // dom2(F, C) || R || A || PH(M)
500
+ }
501
+ catch (error) { }
502
+ const finish = (hashed) => {
503
+ // k = SHA512(dom2(F, C) || R || A || PH(M))
504
+ if (SB == null)
505
+ return false; // false if try-catch catched an error
506
+ if (!zip215 && A.isSmallOrder())
507
+ return false; // false for SBS: Strongly Binding Signature
508
+ const k = modL_LE(hashed); // decode in little-endian, modulo L
509
+ const RkA = R.add(A.multiply(k, false)); // [8]R + [8][k]A'
510
+ return RkA.add(SB.negate()).clearCofactor().is0(); // [8][S]B = [8]R + [8][k]A'
511
+ };
512
+ return { hashable, finish };
513
+ };
514
+ /** Verifies signature on message and public key. Async. Follows RFC8032 5.1.7. */
515
+ const verifyAsync = async (signature, message, publicKey, opts = defaultVerifyOpts) => hashFinishA(_verify(signature, message, publicKey, opts));
516
+ /** Verifies signature on message and public key. To use, set `hashes.sha512` first. Follows RFC8032 5.1.7. */
517
+ const verify = (signature, message, publicKey, opts = defaultVerifyOpts) => hashFinishS(_verify(signature, message, publicKey, opts));
518
+ /** Math, hex, byte helpers. Not in `utils` because utils share API with noble-curves. */
519
+ const etc = {
520
+ bytesToHex: bytesToHex,
521
+ hexToBytes: hexToBytes,
522
+ concatBytes: concatBytes,
523
+ mod: M,
524
+ invert: invert,
525
+ randomBytes: randomBytes,
526
+ };
527
+ const hashes = {
528
+ sha512Async: async (message) => {
529
+ const s = subtle();
530
+ const m = concatBytes(message);
531
+ return u8n(await s.digest('SHA-512', m.buffer));
532
+ },
533
+ sha512: undefined,
534
+ };
535
+ // FIPS 186 B.4.1 compliant key generation produces private keys
536
+ // with modulo bias being neglible. takes >N+16 bytes, returns (hash mod n-1)+1
537
+ const randomSecretKey = (seed = randomBytes(L)) => seed;
538
+ const keygen = (seed) => {
539
+ const secretKey = randomSecretKey(seed);
540
+ const publicKey = getPublicKey(secretKey);
541
+ return { secretKey, publicKey };
542
+ };
543
+ const keygenAsync = async (seed) => {
544
+ const secretKey = randomSecretKey(seed);
545
+ const publicKey = await getPublicKeyAsync(secretKey);
546
+ return { secretKey, publicKey };
547
+ };
548
+ /** ed25519-specific key utilities. */
549
+ const utils = {
550
+ getExtendedPublicKeyAsync: getExtendedPublicKeyAsync,
551
+ getExtendedPublicKey: getExtendedPublicKey,
552
+ randomSecretKey: randomSecretKey,
553
+ };
554
+ // ## Precomputes
555
+ // --------------
556
+ const W = 8; // W is window size
557
+ const scalarBits = 256;
558
+ const pwindows = Math.ceil(scalarBits / W) + 1; // 33 for W=8, NOT 32 - see wNAF loop
559
+ const pwindowSize = 2 ** (W - 1); // 128 for W=8
560
+ const precompute = () => {
561
+ const points = [];
562
+ let p = G;
563
+ let b = p;
564
+ for (let w = 0; w < pwindows; w++) {
565
+ b = p;
566
+ points.push(b);
567
+ for (let i = 1; i < pwindowSize; i++) {
568
+ b = b.add(p);
569
+ points.push(b);
570
+ } // i=1, bc we skip 0
571
+ p = b.double();
572
+ }
573
+ return points;
574
+ };
575
+ let Gpows = undefined; // precomputes for base point G
576
+ // const-time negate
577
+ const ctneg = (cnd, p) => {
578
+ const n = p.negate();
579
+ return cnd ? n : p;
580
+ };
581
+ /**
582
+ * Precomputes give 12x faster getPublicKey(), 10x sign(), 2x verify() by
583
+ * caching multiples of G (base point). Cache is stored in 32MB of RAM.
584
+ * Any time `G.multiply` is done, precomputes are used.
585
+ * Not used for getSharedSecret, which instead multiplies random pubkey `P.multiply`.
586
+ *
587
+ * w-ary non-adjacent form (wNAF) precomputation method is 10% slower than windowed method,
588
+ * but takes 2x less RAM. RAM reduction is possible by utilizing `.subtract`.
589
+ *
590
+ * !! Precomputes can be disabled by commenting-out call of the wNAF() inside Point#multiply().
591
+ */
592
+ const wNAF = (n) => {
593
+ const comp = Gpows || (Gpows = precompute());
594
+ let p = I;
595
+ let f = G; // f must be G, or could become I in the end
596
+ const pow_2_w = 2 ** W; // 256 for W=8
597
+ const maxNum = pow_2_w; // 256 for W=8
598
+ const mask = big(pow_2_w - 1); // 255 for W=8 == mask 0b11111111
599
+ const shiftBy = big(W); // 8 for W=8
600
+ for (let w = 0; w < pwindows; w++) {
601
+ let wbits = Number(n & mask); // extract W bits.
602
+ n >>= shiftBy; // shift number by W bits.
603
+ // We use negative indexes to reduce size of precomputed table by 2x.
604
+ // Instead of needing precomputes 0..256, we only calculate them for 0..128.
605
+ // If an index > 128 is found, we do (256-index) - where 256 is next window.
606
+ // Naive: index +127 => 127, +224 => 224
607
+ // Optimized: index +127 => 127, +224 => 256-32
608
+ if (wbits > pwindowSize) {
609
+ wbits -= maxNum;
610
+ n += 1n;
611
+ }
612
+ const off = w * pwindowSize;
613
+ const offF = off; // offsets, evaluate both
614
+ const offP = off + Math.abs(wbits) - 1;
615
+ const isEven = w % 2 !== 0; // conditions, evaluate both
616
+ const isNeg = wbits < 0;
617
+ if (wbits === 0) {
618
+ // off == I: can't add it. Adding random offF instead.
619
+ f = f.add(ctneg(isEven, comp[offF])); // bits are 0: add garbage to fake point
620
+ }
621
+ else {
622
+ p = p.add(ctneg(isNeg, comp[offP])); // bits are 1: add to result point
623
+ }
624
+ }
625
+ if (n !== 0n)
626
+ err('invalid wnaf');
627
+ return { p, f }; // return both real and fake points for JIT
628
+ };
629
+ // !! Remove the export to easily use in REPL / browser console
630
+ export { etc, getPublicKey, getPublicKeyAsync, hash, hashes, keygen, keygenAsync, Point, sign, signAsync, utils, verify, verifyAsync, };