@usearete/sdk 0.2.0 → 0.4.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.
Files changed (39) hide show
  1. package/README.md +118 -0
  2. package/dist/index.cjs +7393 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.ts +802 -129
  5. package/dist/index.esm.js +3447 -526
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/ssr/handlers.cjs +794 -0
  8. package/dist/ssr/handlers.cjs.map +1 -0
  9. package/dist/ssr/handlers.esm.js +523 -4
  10. package/dist/ssr/handlers.esm.js.map +1 -1
  11. package/dist/ssr/index.cjs +795 -0
  12. package/dist/ssr/index.cjs.map +1 -0
  13. package/dist/ssr/index.esm.js +523 -4
  14. package/dist/ssr/index.esm.js.map +1 -1
  15. package/dist/ssr/nextjs-app.cjs +859 -0
  16. package/dist/ssr/nextjs-app.cjs.map +1 -0
  17. package/dist/ssr/nextjs-app.esm.js +523 -4
  18. package/dist/ssr/nextjs-app.esm.js.map +1 -1
  19. package/dist/ssr/tanstack-start.cjs +881 -0
  20. package/dist/ssr/tanstack-start.cjs.map +1 -0
  21. package/dist/ssr/tanstack-start.esm.js +523 -4
  22. package/dist/ssr/tanstack-start.esm.js.map +1 -1
  23. package/dist/ssr/vite.cjs +887 -0
  24. package/dist/ssr/vite.cjs.map +1 -0
  25. package/dist/ssr/vite.esm.js +523 -4
  26. package/dist/ssr/vite.esm.js.map +1 -1
  27. package/package.json +10 -8
  28. package/dist/index.js +0 -4448
  29. package/dist/index.js.map +0 -1
  30. package/dist/ssr/handlers.js +0 -294
  31. package/dist/ssr/handlers.js.map +0 -1
  32. package/dist/ssr/index.js +0 -295
  33. package/dist/ssr/index.js.map +0 -1
  34. package/dist/ssr/nextjs-app.js +0 -359
  35. package/dist/ssr/nextjs-app.js.map +0 -1
  36. package/dist/ssr/tanstack-start.js +0 -381
  37. package/dist/ssr/tanstack-start.js.map +0 -1
  38. package/dist/ssr/vite.js +0 -387
  39. package/dist/ssr/vite.js.map +0 -1
@@ -1,4 +1,523 @@
1
- import * as ed25519 from '@noble/ed25519';
1
+ /*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */
2
+ /**
3
+ * 4KB 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 privKey = ed.utils.randomPrivateKey();
11
+ const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);
12
+ const pubKey = await ed.getPublicKeyAsync(privKey); // Sync methods are also present
13
+ const signature = await ed.signAsync(message, privKey);
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 } = ed25519_CURVE;
37
+ const h = 8n; // cofactor
38
+ const L = 32; // field / group byte length
39
+ const L2 = 64;
40
+ // Helpers and Precomputes sections are reused between libraries
41
+ // ## Helpers
42
+ // ----------
43
+ // error helper, messes-up stack trace
44
+ const err = (m = '') => {
45
+ throw new Error(m);
46
+ };
47
+ const isBig = (n) => typeof n === 'bigint'; // is big integer
48
+ const isStr = (s) => typeof s === 'string'; // is string
49
+ const isBytes = (a) => a instanceof Uint8Array || (ArrayBuffer.isView(a) && a.constructor.name === 'Uint8Array');
50
+ /** assert is Uint8Array (of specific length) */
51
+ const abytes = (a, l) => !isBytes(a) || (typeof l === 'number' && l > 0 && a.length !== l)
52
+ ? err('Uint8Array expected')
53
+ : a;
54
+ /** create Uint8Array */
55
+ const u8n = (len) => new Uint8Array(len);
56
+ const u8fr = (buf) => Uint8Array.from(buf);
57
+ const padh = (n, pad) => n.toString(16).padStart(pad, '0');
58
+ const bytesToHex = (b) => Array.from(abytes(b))
59
+ .map((e) => padh(e, 2))
60
+ .join('');
61
+ const C = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 }; // ASCII characters
62
+ const _ch = (ch) => {
63
+ if (ch >= C._0 && ch <= C._9)
64
+ return ch - C._0; // '2' => 50-48
65
+ if (ch >= C.A && ch <= C.F)
66
+ return ch - (C.A - 10); // 'B' => 66-(65-10)
67
+ if (ch >= C.a && ch <= C.f)
68
+ return ch - (C.a - 10); // 'b' => 98-(97-10)
69
+ return;
70
+ };
71
+ const hexToBytes = (hex) => {
72
+ const e = 'hex invalid';
73
+ if (!isStr(hex))
74
+ return err(e);
75
+ const hl = hex.length;
76
+ const al = hl / 2;
77
+ if (hl % 2)
78
+ return err(e);
79
+ const array = u8n(al);
80
+ for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
81
+ // treat each char as ASCII
82
+ const n1 = _ch(hex.charCodeAt(hi)); // parse first char, multiply it by 16
83
+ const n2 = _ch(hex.charCodeAt(hi + 1)); // parse second char
84
+ if (n1 === undefined || n2 === undefined)
85
+ return err(e);
86
+ array[ai] = n1 * 16 + n2; // example: 'A9' => 10*16 + 9
87
+ }
88
+ return array;
89
+ };
90
+ /** normalize hex or ui8a to ui8a */
91
+ const toU8 = (a, len) => abytes(isStr(a) ? hexToBytes(a) : u8fr(abytes(a)), len);
92
+ const cr = () => globalThis?.crypto; // WebCrypto is available in all modern environments
93
+ const subtle = () => cr()?.subtle ?? err('crypto.subtle must be defined');
94
+ // prettier-ignore
95
+ const concatBytes = (...arrs) => {
96
+ const r = u8n(arrs.reduce((sum, a) => sum + abytes(a).length, 0)); // create u8a of summed length
97
+ let pad = 0; // walk through each array,
98
+ arrs.forEach(a => { r.set(a, pad); pad += a.length; }); // ensure they have proper type
99
+ return r;
100
+ };
101
+ /** WebCrypto OS-level CSPRNG (random number generator). Will throw when not available. */
102
+ const randomBytes = (len = L) => {
103
+ const c = cr();
104
+ return c.getRandomValues(u8n(len));
105
+ };
106
+ const big = BigInt;
107
+ const arange = (n, min, max, msg = 'bad number: out of range') => isBig(n) && min <= n && n < max ? n : err(msg);
108
+ /** modular division */
109
+ const M = (a, b = P) => {
110
+ const r = a % b;
111
+ return r >= 0n ? r : b + r;
112
+ };
113
+ const modN = (a) => M(a, N);
114
+ /** Modular inversion using eucledian GCD (non-CT). No negative exponent for now. */
115
+ // prettier-ignore
116
+ const invert = (num, md) => {
117
+ if (num === 0n || md <= 0n)
118
+ err('no inverse n=' + num + ' mod=' + md);
119
+ let a = M(num, md), b = md, x = 0n, u = 1n;
120
+ while (a !== 0n) {
121
+ const q = b / a, r = b % a;
122
+ const m = x - u * q;
123
+ b = a, a = r, x = u, u = m;
124
+ }
125
+ return b === 1n ? M(x, md) : err('no inverse'); // b is gcd at this point
126
+ };
127
+ const apoint = (p) => (p instanceof Point ? p : err('Point expected'));
128
+ // ## End of Helpers
129
+ // -----------------
130
+ const B256 = 2n ** 256n;
131
+ /** Point in XYZT extended coordinates. */
132
+ class Point {
133
+ static BASE;
134
+ static ZERO;
135
+ ex;
136
+ ey;
137
+ ez;
138
+ et;
139
+ constructor(ex, ey, ez, et) {
140
+ const max = B256;
141
+ this.ex = arange(ex, 0n, max);
142
+ this.ey = arange(ey, 0n, max);
143
+ this.ez = arange(ez, 1n, max);
144
+ this.et = arange(et, 0n, max);
145
+ Object.freeze(this);
146
+ }
147
+ static fromAffine(p) {
148
+ return new Point(p.x, p.y, 1n, M(p.x * p.y));
149
+ }
150
+ /** RFC8032 5.1.3: Uint8Array to Point. */
151
+ static fromBytes(hex, zip215 = false) {
152
+ const d = _d;
153
+ // Copy array to not mess it up.
154
+ const normed = u8fr(abytes(hex, L));
155
+ // adjust first LE byte = last BE byte
156
+ const lastByte = hex[31];
157
+ normed[31] = lastByte & ~0x80;
158
+ const y = bytesToNumLE(normed);
159
+ // zip215=true: 0 <= y < 2^256
160
+ // zip215=false, RFC8032: 0 <= y < 2^255-19
161
+ const max = zip215 ? B256 : P;
162
+ arange(y, 0n, max);
163
+ const y2 = M(y * y); // y²
164
+ const u = M(y2 - 1n); // u=y²-1
165
+ const v = M(d * y2 + 1n); // v=dy²+1
166
+ let { isValid, value: x } = uvRatio(u, v); // (uv³)(uv⁷)^(p-5)/8; square root
167
+ if (!isValid)
168
+ err('bad point: y not sqrt'); // not square root: bad point
169
+ const isXOdd = (x & 1n) === 1n; // adjust sign of x coordinate
170
+ const isLastByteOdd = (lastByte & 0x80) !== 0; // x_0, last bit
171
+ if (!zip215 && x === 0n && isLastByteOdd)
172
+ err('bad point: x==0, isLastByteOdd'); // x=0, x_0=1
173
+ if (isLastByteOdd !== isXOdd)
174
+ x = M(-x);
175
+ return new Point(x, y, 1n, M(x * y)); // Z=1, T=xy
176
+ }
177
+ /** Checks if the point is valid and on-curve. */
178
+ assertValidity() {
179
+ const a = _a;
180
+ const d = _d;
181
+ const p = this;
182
+ if (p.is0())
183
+ throw new Error('bad point: ZERO'); // TODO: optimize, with vars below?
184
+ // Equation in affine coordinates: ax² + y² = 1 + dx²y²
185
+ // Equation in projective coordinates (X/Z, Y/Z, Z): (aX² + Y²)Z² = Z⁴ + dX²Y²
186
+ const { ex: X, ey: Y, ez: Z, et: T } = p;
187
+ const X2 = M(X * X); // X²
188
+ const Y2 = M(Y * Y); // Y²
189
+ const Z2 = M(Z * Z); // Z²
190
+ const Z4 = M(Z2 * Z2); // Z⁴
191
+ const aX2 = M(X2 * a); // aX²
192
+ const left = M(Z2 * M(aX2 + Y2)); // (aX² + Y²)Z²
193
+ const right = M(Z4 + M(d * M(X2 * Y2))); // Z⁴ + dX²Y²
194
+ if (left !== right)
195
+ throw new Error('bad point: equation left != right (1)');
196
+ // In Extended coordinates we also have T, which is x*y=T/Z: check X*Y == Z*T
197
+ const XY = M(X * Y);
198
+ const ZT = M(Z * T);
199
+ if (XY !== ZT)
200
+ throw new Error('bad point: equation left != right (2)');
201
+ return this;
202
+ }
203
+ /** Equality check: compare points P&Q. */
204
+ equals(other) {
205
+ const { ex: X1, ey: Y1, ez: Z1 } = this;
206
+ const { ex: X2, ey: Y2, ez: Z2 } = apoint(other); // checks class equality
207
+ const X1Z2 = M(X1 * Z2);
208
+ const X2Z1 = M(X2 * Z1);
209
+ const Y1Z2 = M(Y1 * Z2);
210
+ const Y2Z1 = M(Y2 * Z1);
211
+ return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;
212
+ }
213
+ is0() {
214
+ return this.equals(I);
215
+ }
216
+ /** Flip point over y coordinate. */
217
+ negate() {
218
+ return new Point(M(-this.ex), this.ey, this.ez, M(-this.et));
219
+ }
220
+ /** Point doubling. Complete formula. Cost: `4M + 4S + 1*a + 6add + 1*2`. */
221
+ double() {
222
+ const { ex: X1, ey: Y1, ez: Z1 } = this;
223
+ const a = _a;
224
+ // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd
225
+ const A = M(X1 * X1);
226
+ const B = M(Y1 * Y1);
227
+ const C = M(2n * M(Z1 * Z1));
228
+ const D = M(a * A);
229
+ const x1y1 = X1 + Y1;
230
+ const E = M(M(x1y1 * x1y1) - A - B);
231
+ const G = D + B;
232
+ const F = G - C;
233
+ const H = D - B;
234
+ const X3 = M(E * F);
235
+ const Y3 = M(G * H);
236
+ const T3 = M(E * H);
237
+ const Z3 = M(F * G);
238
+ return new Point(X3, Y3, Z3, T3);
239
+ }
240
+ /** Point addition. Complete formula. Cost: `8M + 1*k + 8add + 1*2`. */
241
+ add(other) {
242
+ const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this;
243
+ const { ex: X2, ey: Y2, ez: Z2, et: T2 } = apoint(other); // doesn't check if other on-curve
244
+ const a = _a;
245
+ const d = _d;
246
+ // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3
247
+ const A = M(X1 * X2);
248
+ const B = M(Y1 * Y2);
249
+ const C = M(T1 * d * T2);
250
+ const D = M(Z1 * Z2);
251
+ const E = M((X1 + Y1) * (X2 + Y2) - A - B);
252
+ const F = M(D - C);
253
+ const G = M(D + C);
254
+ const H = M(B - a * A);
255
+ const X3 = M(E * F);
256
+ const Y3 = M(G * H);
257
+ const T3 = M(E * H);
258
+ const Z3 = M(F * G);
259
+ return new Point(X3, Y3, Z3, T3);
260
+ }
261
+ /**
262
+ * Point-by-scalar multiplication. Scalar must be in range 1 <= n < CURVE.n.
263
+ * Uses {@link wNAF} for base point.
264
+ * Uses fake point to mitigate side-channel leakage.
265
+ * @param n scalar by which point is multiplied
266
+ * @param safe safe mode guards against timing attacks; unsafe mode is faster
267
+ */
268
+ multiply(n, safe = true) {
269
+ if (!safe && (n === 0n || this.is0()))
270
+ return I;
271
+ arange(n, 1n, N);
272
+ if (n === 1n)
273
+ return this;
274
+ if (this.equals(G))
275
+ return wNAF(n).p;
276
+ // init result point & fake point
277
+ let p = I;
278
+ let f = G;
279
+ for (let d = this; n > 0n; d = d.double(), n >>= 1n) {
280
+ // if bit is present, add to point
281
+ // if not present, add to fake, for timing safety
282
+ if (n & 1n)
283
+ p = p.add(d);
284
+ else if (safe)
285
+ f = f.add(d);
286
+ }
287
+ return p;
288
+ }
289
+ /** Convert point to 2d xy affine point. (X, Y, Z) ∋ (x=X/Z, y=Y/Z) */
290
+ toAffine() {
291
+ const { ex: x, ey: y, ez: z } = this;
292
+ // fast-paths for ZERO point OR Z=1
293
+ if (this.equals(I))
294
+ return { x: 0n, y: 1n };
295
+ const iz = invert(z, P);
296
+ // (Z * Z^-1) must be 1, otherwise bad math
297
+ if (M(z * iz) !== 1n)
298
+ err('invalid inverse');
299
+ // x = X*Z^-1; y = Y*Z^-1
300
+ return { x: M(x * iz), y: M(y * iz) };
301
+ }
302
+ toBytes() {
303
+ const { x, y } = this.assertValidity().toAffine();
304
+ const b = numTo32bLE(y);
305
+ // store sign in first LE byte
306
+ b[31] |= x & 1n ? 0x80 : 0;
307
+ return b;
308
+ }
309
+ toHex() {
310
+ return bytesToHex(this.toBytes());
311
+ } // encode to hex string
312
+ clearCofactor() {
313
+ return this.multiply(big(h), false);
314
+ }
315
+ isSmallOrder() {
316
+ return this.clearCofactor().is0();
317
+ }
318
+ isTorsionFree() {
319
+ // multiply by big number CURVE.n
320
+ let p = this.multiply(N / 2n, false).double(); // ensures the point is not "bad".
321
+ if (N % 2n)
322
+ p = p.add(this); // P^(N+1) // P*N == (P*(N/2))*2+P
323
+ return p.is0();
324
+ }
325
+ static fromHex(hex, zip215) {
326
+ return Point.fromBytes(toU8(hex), zip215);
327
+ }
328
+ get x() {
329
+ return this.toAffine().x;
330
+ }
331
+ get y() {
332
+ return this.toAffine().y;
333
+ }
334
+ toRawBytes() {
335
+ return this.toBytes();
336
+ }
337
+ }
338
+ /** Generator / base point */
339
+ const G = new Point(Gx, Gy, 1n, M(Gx * Gy));
340
+ /** Identity / zero point */
341
+ const I = new Point(0n, 1n, 1n, 0n);
342
+ // Static aliases
343
+ Point.BASE = G;
344
+ Point.ZERO = I;
345
+ const numTo32bLE = (num) => hexToBytes(padh(arange(num, 0n, B256), L2)).reverse();
346
+ const bytesToNumLE = (b) => big('0x' + bytesToHex(u8fr(abytes(b)).reverse()));
347
+ const pow2 = (x, power) => {
348
+ // pow2(x, 4) == x^(2^4)
349
+ let r = x;
350
+ while (power-- > 0n) {
351
+ r *= r;
352
+ r %= P;
353
+ }
354
+ return r;
355
+ };
356
+ // prettier-ignore
357
+ const pow_2_252_3 = (x) => {
358
+ const x2 = (x * x) % P; // x^2, bits 1
359
+ const b2 = (x2 * x) % P; // x^3, bits 11
360
+ const b4 = (pow2(b2, 2n) * b2) % P; // x^(2^4-1), bits 1111
361
+ const b5 = (pow2(b4, 1n) * x) % P; // x^(2^5-1), bits 11111
362
+ const b10 = (pow2(b5, 5n) * b5) % P; // x^(2^10)
363
+ const b20 = (pow2(b10, 10n) * b10) % P; // x^(2^20)
364
+ const b40 = (pow2(b20, 20n) * b20) % P; // x^(2^40)
365
+ const b80 = (pow2(b40, 40n) * b40) % P; // x^(2^80)
366
+ const b160 = (pow2(b80, 80n) * b80) % P; // x^(2^160)
367
+ const b240 = (pow2(b160, 80n) * b80) % P; // x^(2^240)
368
+ const b250 = (pow2(b240, 10n) * b10) % P; // x^(2^250)
369
+ const pow_p_5_8 = (pow2(b250, 2n) * x) % P; // < To pow to (p+3)/8, multiply it by x.
370
+ return { pow_p_5_8, b2 };
371
+ };
372
+ const RM1 = 0x2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0n; // √-1
373
+ // for sqrt comp
374
+ // prettier-ignore
375
+ const uvRatio = (u, v) => {
376
+ const v3 = M(v * v * v); // v³
377
+ const v7 = M(v3 * v3 * v); // v⁷
378
+ const pow = pow_2_252_3(u * v7).pow_p_5_8; // (uv⁷)^(p-5)/8
379
+ let x = M(u * v3 * pow); // (uv³)(uv⁷)^(p-5)/8
380
+ const vx2 = M(v * x * x); // vx²
381
+ const root1 = x; // First root candidate
382
+ const root2 = M(x * RM1); // Second root candidate; RM1 is √-1
383
+ const useRoot1 = vx2 === u; // If vx² = u (mod p), x is a square root
384
+ const useRoot2 = vx2 === M(-u); // If vx² = -u, set x <-- x * 2^((p-1)/4)
385
+ const noRoot = vx2 === M(-u * RM1); // There is no valid root, vx² = -u√-1
386
+ if (useRoot1)
387
+ x = root1;
388
+ if (useRoot2 || noRoot)
389
+ x = root2; // We return root2 anyway, for const-time
390
+ if ((M(x) & 1n) === 1n)
391
+ x = M(-x); // edIsNegative
392
+ return { isValid: useRoot1 || useRoot2, value: x };
393
+ };
394
+ // N == L, just weird naming
395
+ const modL_LE = (hash) => modN(bytesToNumLE(hash)); // modulo L; but little-endian
396
+ const sha512a = (...m) => etc.sha512Async(...m); // Async SHA512
397
+ // RFC8032 5.1.5
398
+ const hash2extK = (hashed) => {
399
+ // slice creates a copy, unlike subarray
400
+ const head = hashed.slice(0, L);
401
+ head[0] &= 248; // Clamp bits: 0b1111_1000
402
+ head[31] &= 127; // 0b0111_1111
403
+ head[31] |= 64; // 0b0100_0000
404
+ const prefix = hashed.slice(L, L2); // private key "prefix"
405
+ const scalar = modL_LE(head); // modular division over curve order
406
+ const point = G.multiply(scalar); // public key point
407
+ const pointBytes = point.toBytes(); // point serialized to Uint8Array
408
+ return { head, prefix, scalar, point, pointBytes };
409
+ };
410
+ // RFC8032 5.1.5; getPublicKey async, sync. Hash priv key and extract point.
411
+ const getExtendedPublicKeyAsync = (priv) => sha512a(toU8(priv, L)).then(hash2extK);
412
+ /** Creates 32-byte ed25519 public key from 32-byte private key. Async. */
413
+ const getPublicKeyAsync = (priv) => getExtendedPublicKeyAsync(priv).then((p) => p.pointBytes);
414
+ const hashFinishA = (res) => sha512a(res.hashable).then(res.finish);
415
+ const _sign = (e, rBytes, msg) => {
416
+ // sign() shared code
417
+ const { pointBytes: P, scalar: s } = e;
418
+ const r = modL_LE(rBytes); // r was created outside, reduce it modulo L
419
+ const R = G.multiply(r).toBytes(); // R = [r]B
420
+ const hashable = concatBytes(R, P, msg); // dom2(F, C) || R || A || PH(M)
421
+ const finish = (hashed) => {
422
+ // k = SHA512(dom2(F, C) || R || A || PH(M))
423
+ const S = modN(r + modL_LE(hashed) * s); // S = (r + k * s) mod L; 0 <= s < l
424
+ return abytes(concatBytes(R, numTo32bLE(S)), L2); // 64-byte sig: 32b R.x + 32b LE(S)
425
+ };
426
+ return { hashable, finish };
427
+ };
428
+ /**
429
+ * Signs message (NOT message hash) using private key. Async.
430
+ * Follows RFC8032 5.1.6.
431
+ */
432
+ const signAsync = async (msg, privKey) => {
433
+ const m = toU8(msg);
434
+ const e = await getExtendedPublicKeyAsync(privKey);
435
+ const rBytes = await sha512a(e.prefix, m); // r = SHA512(dom2(F, C) || prefix || PH(M))
436
+ return hashFinishA(_sign(e, rBytes, m)); // gen R, k, S, then 64-byte signature
437
+ };
438
+ /** Math, hex, byte helpers. Not in `utils` because utils share API with noble-curves. */
439
+ const etc = {
440
+ sha512Async: async (...messages) => {
441
+ const s = subtle();
442
+ const m = concatBytes(...messages);
443
+ return u8n(await s.digest('SHA-512', m.buffer));
444
+ },
445
+ sha512Sync: undefined,
446
+ bytesToHex: bytesToHex,
447
+ hexToBytes: hexToBytes,
448
+ concatBytes: concatBytes,
449
+ mod: M,
450
+ invert: invert,
451
+ randomBytes: randomBytes,
452
+ };
453
+ // ## Precomputes
454
+ // --------------
455
+ const W = 8; // W is window size
456
+ const scalarBits = 256;
457
+ const pwindows = Math.ceil(scalarBits / W) + 1; // 33 for W=8
458
+ const pwindowSize = 2 ** (W - 1); // 128 for W=8
459
+ const precompute = () => {
460
+ const points = [];
461
+ let p = G;
462
+ let b = p;
463
+ for (let w = 0; w < pwindows; w++) {
464
+ b = p;
465
+ points.push(b);
466
+ for (let i = 1; i < pwindowSize; i++) {
467
+ b = b.add(p);
468
+ points.push(b);
469
+ } // i=1, bc we skip 0
470
+ p = b.double();
471
+ }
472
+ return points;
473
+ };
474
+ let Gpows = undefined; // precomputes for base point G
475
+ // const-time negate
476
+ const ctneg = (cnd, p) => {
477
+ const n = p.negate();
478
+ return cnd ? n : p;
479
+ };
480
+ /**
481
+ * Precomputes give 12x faster getPublicKey(), 10x sign(), 2x verify() by
482
+ * caching multiples of G (base point). Cache is stored in 32MB of RAM.
483
+ * Any time `G.multiply` is done, precomputes are used.
484
+ * Not used for getSharedSecret, which instead multiplies random pubkey `P.multiply`.
485
+ *
486
+ * w-ary non-adjacent form (wNAF) precomputation method is 10% slower than windowed method,
487
+ * but takes 2x less RAM. RAM reduction is possible by utilizing `.subtract`.
488
+ *
489
+ * !! Precomputes can be disabled by commenting-out call of the wNAF() inside Point#multiply().
490
+ */
491
+ const wNAF = (n) => {
492
+ const comp = Gpows || (Gpows = precompute());
493
+ let p = I;
494
+ let f = G; // f must be G, or could become I in the end
495
+ const pow_2_w = 2 ** W; // 256 for W=8
496
+ const maxNum = pow_2_w; // 256 for W=8
497
+ const mask = big(pow_2_w - 1); // 255 for W=8 == mask 0b11111111
498
+ const shiftBy = big(W); // 8 for W=8
499
+ for (let w = 0; w < pwindows; w++) {
500
+ let wbits = Number(n & mask); // extract W bits.
501
+ n >>= shiftBy; // shift number by W bits.
502
+ if (wbits > pwindowSize) {
503
+ wbits -= maxNum;
504
+ n += 1n;
505
+ } // split if bits > max: +224 => 256-32
506
+ const off = w * pwindowSize;
507
+ const offF = off; // offsets, evaluate both
508
+ const offP = off + Math.abs(wbits) - 1;
509
+ const isEven = w % 2 !== 0; // conditions, evaluate both
510
+ const isNeg = wbits < 0;
511
+ if (wbits === 0) {
512
+ // off == I: can't add it. Adding random offF instead.
513
+ f = f.add(ctneg(isEven, comp[offF])); // bits are 0: add garbage to fake point
514
+ }
515
+ else {
516
+ p = p.add(ctneg(isNeg, comp[offP])); // bits are 1: add to result point
517
+ }
518
+ }
519
+ return { p, f }; // return both real and fake points for JIT
520
+ };
2
521
 
3
522
  /**
4
523
  * Base64URL encoding/decoding utilities
@@ -101,7 +620,7 @@ function createJwtPayload(claims) {
101
620
  */
102
621
  async function signEd25519(data, privateKey) {
103
622
  const messageBytes = new TextEncoder().encode(data);
104
- return await ed25519.signAsync(messageBytes, privateKey);
623
+ return await signAsync(messageBytes, privateKey);
105
624
  }
106
625
  /**
107
626
  * Mint a session token using Ed25519 signing
@@ -118,7 +637,7 @@ async function mintSessionToken(config, subject = 'anonymous', scope = 'read', o
118
637
  'Ed25519 signing key must be 32 bytes (base64-encoded).');
119
638
  }
120
639
  // Derive public key from private key
121
- const publicKeyBytes = await ed25519.getPublicKeyAsync(privateKeyBytes);
640
+ const publicKeyBytes = await getPublicKeyAsync(privateKeyBytes);
122
641
  const keyId = config.keyId || deriveKeyId(publicKeyBytes);
123
642
  const issuer = config.issuer || process.env.ARETE_ISSUER || 'arete';
124
643
  const audience = config.audience || process.env.ARETE_AUDIENCE || 'arete';
@@ -183,7 +702,7 @@ async function generateJwks(config) {
183
702
  if (privateKeyBytes.length !== 32) {
184
703
  throw new Error(`Invalid signing key length: expected 32 bytes, got ${privateKeyBytes.length}`);
185
704
  }
186
- publicKeyBytes = await ed25519.getPublicKeyAsync(privateKeyBytes);
705
+ publicKeyBytes = await getPublicKeyAsync(privateKeyBytes);
187
706
  }
188
707
  const keyId = config.keyId ||
189
708
  (publicKeyBase64 ? 'key-1' : deriveKeyId(publicKeyBytes));