aegis-aead 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +25 -20
  2. package/dist/aegis128l.d.ts +33 -33
  3. package/dist/aegis128l.js +225 -235
  4. package/dist/aegis128x.d.ts +35 -35
  5. package/dist/aegis128x.js +348 -282
  6. package/dist/aegis256.d.ts +34 -51
  7. package/dist/aegis256.js +215 -206
  8. package/dist/aegis256x.d.ts +32 -33
  9. package/dist/aegis256x.js +333 -265
  10. package/dist/aes-bs.d.ts +42 -35
  11. package/dist/aes-bs.js +2269 -401
  12. package/dist/index.d.ts +4 -7
  13. package/dist/index.js +4 -7
  14. package/dist/random.d.ts +0 -1
  15. package/dist/random.js +0 -1
  16. package/dist/utils.d.ts +14 -0
  17. package/dist/utils.js +31 -0
  18. package/package.json +5 -6
  19. package/dist/aegis128l-bs.d.ts +0 -137
  20. package/dist/aegis128l-bs.d.ts.map +0 -1
  21. package/dist/aegis128l-bs.js +0 -442
  22. package/dist/aegis128l-bs.js.map +0 -1
  23. package/dist/aegis128l.d.ts.map +0 -1
  24. package/dist/aegis128l.js.map +0 -1
  25. package/dist/aegis128x.d.ts.map +0 -1
  26. package/dist/aegis128x.js.map +0 -1
  27. package/dist/aegis256-bs.d.ts +0 -79
  28. package/dist/aegis256-bs.d.ts.map +0 -1
  29. package/dist/aegis256-bs.js +0 -366
  30. package/dist/aegis256-bs.js.map +0 -1
  31. package/dist/aegis256.d.ts.map +0 -1
  32. package/dist/aegis256.js.map +0 -1
  33. package/dist/aegis256x.d.ts.map +0 -1
  34. package/dist/aegis256x.js.map +0 -1
  35. package/dist/aes-bs.d.ts.map +0 -1
  36. package/dist/aes-bs.js.map +0 -1
  37. package/dist/aes.d.ts +0 -81
  38. package/dist/aes.d.ts.map +0 -1
  39. package/dist/aes.js +0 -232
  40. package/dist/aes.js.map +0 -1
  41. package/dist/index.d.ts.map +0 -1
  42. package/dist/index.js.map +0 -1
  43. package/dist/random.d.ts.map +0 -1
  44. package/dist/random.js.map +0 -1
  45. package/src/aegis128l-bs.ts +0 -600
  46. package/src/aegis128l.ts +0 -653
  47. package/src/aegis128x.ts +0 -932
  48. package/src/aegis256-bs.ts +0 -519
  49. package/src/aegis256.ts +0 -597
  50. package/src/aegis256x.ts +0 -893
  51. package/src/aes-bs.ts +0 -540
  52. package/src/aes.ts +0 -271
  53. package/src/index.ts +0 -126
  54. package/src/random.ts +0 -41
  55. package/src/typed-array.d.ts +0 -18
package/src/aegis256x.ts DELETED
@@ -1,893 +0,0 @@
1
- import {
2
- aesRoundTo,
3
- andBlocksTo,
4
- C0,
5
- C1,
6
- concatBytes,
7
- constantTimeEqual,
8
- le64,
9
- xorBlocks,
10
- xorBlocksTo,
11
- zeroPad,
12
- } from "./aes.js";
13
- import { randomBytes } from "./random.js";
14
-
15
- /**
16
- * AEGIS-256X cipher state with configurable parallelism degree.
17
- * Extends AEGIS-256 with parallel AES rounds for improved performance on wide SIMD architectures.
18
- */
19
- export class Aegis256XState {
20
- private v: Uint8Array[][];
21
- private d: number;
22
- private rate: number;
23
- private newV: Uint8Array[][];
24
- private tmp: Uint8Array;
25
- private z: Uint8Array;
26
- private ctxBufs: Uint8Array[];
27
-
28
- /**
29
- * Creates a new AEGIS-256X state.
30
- * @param degree - Parallelism degree (default: 2). Use 2 for AEGIS-256X2, 4 for AEGIS-256X4.
31
- */
32
- constructor(degree: number = 2) {
33
- this.d = degree;
34
- this.rate = 128 * degree;
35
- this.v = Array.from({ length: 6 }, () =>
36
- Array.from({ length: degree }, () => new Uint8Array(16)),
37
- );
38
- this.newV = Array.from({ length: 6 }, () =>
39
- Array.from({ length: degree }, () => new Uint8Array(16)),
40
- );
41
- this.tmp = new Uint8Array(16);
42
- this.z = new Uint8Array(16 * degree);
43
- this.ctxBufs = Array.from({ length: degree }, (_, i) => {
44
- const buf = new Uint8Array(16);
45
- buf[0] = i;
46
- buf[1] = degree - 1;
47
- return buf;
48
- });
49
- }
50
-
51
- /**
52
- * Initializes the state with a key and nonce.
53
- * @param key - 32-byte encryption key
54
- * @param nonce - 32-byte nonce (must be unique per message)
55
- */
56
- init(key: Uint8Array, nonce: Uint8Array): void {
57
- const k0 = key.subarray(0, 16);
58
- const k1 = key.subarray(16, 32);
59
- const n0 = nonce.subarray(0, 16);
60
- const n1 = nonce.subarray(16, 32);
61
-
62
- const k0n0 = new Uint8Array(16);
63
- const k1n1 = new Uint8Array(16);
64
- const k0c0 = new Uint8Array(16);
65
- const k1c1 = new Uint8Array(16);
66
- xorBlocksTo(k0, n0, k0n0);
67
- xorBlocksTo(k1, n1, k1n1);
68
- xorBlocksTo(k0, C0, k0c0);
69
- xorBlocksTo(k1, C1, k1c1);
70
-
71
- for (let i = 0; i < this.d; i++) {
72
- this.v[0]![i]!.set(k0n0);
73
- this.v[1]![i]!.set(k1n1);
74
- this.v[2]![i]!.set(C1);
75
- this.v[3]![i]!.set(C0);
76
- this.v[4]![i]!.set(k0c0);
77
- this.v[5]![i]!.set(k1c1);
78
- }
79
-
80
- const k0V = new Uint8Array(16 * this.d);
81
- const k1V = new Uint8Array(16 * this.d);
82
- const k0n0V = new Uint8Array(16 * this.d);
83
- const k1n1V = new Uint8Array(16 * this.d);
84
-
85
- for (let i = 0; i < this.d; i++) {
86
- k0V.set(k0, i * 16);
87
- k1V.set(k1, i * 16);
88
- k0n0V.set(k0n0, i * 16);
89
- k1n1V.set(k1n1, i * 16);
90
- }
91
-
92
- for (let round = 0; round < 4; round++) {
93
- for (let i = 0; i < this.d; i++) {
94
- const ctx = this.ctxBufs[i]!;
95
- for (let j = 0; j < 16; j++) this.v[3]![i]![j] ^= ctx[j]!;
96
- for (let j = 0; j < 16; j++) this.v[5]![i]![j] ^= ctx[j]!;
97
- }
98
- this.update(k0V);
99
-
100
- for (let i = 0; i < this.d; i++) {
101
- const ctx = this.ctxBufs[i]!;
102
- for (let j = 0; j < 16; j++) this.v[3]![i]![j] ^= ctx[j]!;
103
- for (let j = 0; j < 16; j++) this.v[5]![i]![j] ^= ctx[j]!;
104
- }
105
- this.update(k1V);
106
-
107
- for (let i = 0; i < this.d; i++) {
108
- const ctx = this.ctxBufs[i]!;
109
- for (let j = 0; j < 16; j++) this.v[3]![i]![j] ^= ctx[j]!;
110
- for (let j = 0; j < 16; j++) this.v[5]![i]![j] ^= ctx[j]!;
111
- }
112
- this.update(k0n0V);
113
-
114
- for (let i = 0; i < this.d; i++) {
115
- const ctx = this.ctxBufs[i]!;
116
- for (let j = 0; j < 16; j++) this.v[3]![i]![j] ^= ctx[j]!;
117
- for (let j = 0; j < 16; j++) this.v[5]![i]![j] ^= ctx[j]!;
118
- }
119
- this.update(k1n1V);
120
- }
121
- }
122
-
123
- /**
124
- * Updates the state with a message vector.
125
- * @param m - Message vector (16*degree bytes)
126
- */
127
- update(m: Uint8Array): void {
128
- const newV = this.newV;
129
- const tmp = this.tmp;
130
-
131
- for (let i = 0; i < this.d; i++) {
132
- const mi = m.subarray(i * 16, (i + 1) * 16);
133
- xorBlocksTo(this.v[0]![i]!, mi, tmp);
134
- aesRoundTo(this.v[5]![i]!, tmp, newV[0]![i]!);
135
- aesRoundTo(this.v[0]![i]!, this.v[1]![i]!, newV[1]![i]!);
136
- aesRoundTo(this.v[1]![i]!, this.v[2]![i]!, newV[2]![i]!);
137
- aesRoundTo(this.v[2]![i]!, this.v[3]![i]!, newV[3]![i]!);
138
- aesRoundTo(this.v[3]![i]!, this.v[4]![i]!, newV[4]![i]!);
139
- aesRoundTo(this.v[4]![i]!, this.v[5]![i]!, newV[5]![i]!);
140
- }
141
-
142
- for (let j = 0; j < 6; j++) {
143
- for (let i = 0; i < this.d; i++) {
144
- this.v[j]![i]!.set(newV[j]![i]!);
145
- }
146
- }
147
- }
148
-
149
- /**
150
- * Absorbs an associated data block into the state.
151
- * @param ai - Associated data block (16*degree bytes)
152
- */
153
- absorb(ai: Uint8Array): void {
154
- this.update(ai);
155
- }
156
-
157
- private computeZ(): void {
158
- const z = this.z;
159
- const tmp = this.tmp;
160
-
161
- for (let i = 0; i < this.d; i++) {
162
- const off = i * 16;
163
- xorBlocksTo(this.v[1]![i]!, this.v[4]![i]!, z.subarray(off, off + 16));
164
- for (let j = 0; j < 16; j++) z[off + j] ^= this.v[5]![i]![j]!;
165
- andBlocksTo(this.v[2]![i]!, this.v[3]![i]!, tmp);
166
- for (let j = 0; j < 16; j++) z[off + j] ^= tmp[j]!;
167
- }
168
- }
169
-
170
- /**
171
- * Encrypts a plaintext block and writes to output buffer.
172
- * @param xi - Plaintext block (16*degree bytes)
173
- * @param out - Output buffer (16*degree bytes)
174
- */
175
- encTo(xi: Uint8Array, out: Uint8Array): void {
176
- this.computeZ();
177
- const z = this.z;
178
- const rateBytes = this.rate / 8;
179
-
180
- this.update(xi);
181
-
182
- for (let i = 0; i < rateBytes; i++) out[i] = xi[i]! ^ z[i]!;
183
- }
184
-
185
- /**
186
- * Encrypts a plaintext block.
187
- * @param xi - Plaintext block (16*degree bytes)
188
- * @returns Ciphertext block of the same size
189
- */
190
- enc(xi: Uint8Array): Uint8Array {
191
- const rateBytes = this.rate / 8;
192
- const out = new Uint8Array(rateBytes);
193
- this.encTo(xi, out);
194
- return out;
195
- }
196
-
197
- /**
198
- * Decrypts a ciphertext block and writes to output buffer.
199
- * @param ci - Ciphertext block (16*degree bytes)
200
- * @param out - Output buffer (16*degree bytes)
201
- */
202
- decTo(ci: Uint8Array, out: Uint8Array): void {
203
- this.computeZ();
204
- const z = this.z;
205
- const rateBytes = this.rate / 8;
206
-
207
- for (let i = 0; i < rateBytes; i++) out[i] = ci[i]! ^ z[i]!;
208
- this.update(out);
209
- }
210
-
211
- /**
212
- * Decrypts a ciphertext block.
213
- * @param ci - Ciphertext block (16*degree bytes)
214
- * @returns Plaintext block of the same size
215
- */
216
- dec(ci: Uint8Array): Uint8Array {
217
- const rateBytes = this.rate / 8;
218
- const out = new Uint8Array(rateBytes);
219
- this.decTo(ci, out);
220
- return out;
221
- }
222
-
223
- /**
224
- * Encrypts a plaintext block in-place.
225
- * @param block - Buffer (plaintext in, ciphertext out), size 16*degree bytes
226
- */
227
- encInPlace(block: Uint8Array): void {
228
- this.encTo(block, block);
229
- }
230
-
231
- /**
232
- * Decrypts a ciphertext block in-place.
233
- * @param block - Buffer (ciphertext in, plaintext out), size 16*degree bytes
234
- */
235
- decInPlace(block: Uint8Array): void {
236
- this.decTo(block, block);
237
- }
238
-
239
- /**
240
- * Decrypts a partial (final) ciphertext block.
241
- * @param cn - Partial ciphertext block (smaller than 16*degree bytes)
242
- * @returns Decrypted plaintext of the same length
243
- */
244
- decPartial(cn: Uint8Array): Uint8Array {
245
- this.computeZ();
246
- const z = this.z;
247
-
248
- const rateBytes = this.rate / 8;
249
- const t = zeroPad(cn, rateBytes);
250
- const out = new Uint8Array(rateBytes);
251
- for (let i = 0; i < rateBytes; i++) out[i] = t[i]! ^ z[i]!;
252
- const xn = new Uint8Array(out.subarray(0, cn.length));
253
-
254
- const v = zeroPad(xn, 16 * this.d);
255
- this.update(v);
256
-
257
- return xn;
258
- }
259
-
260
- /**
261
- * Finalizes encryption/decryption and produces an authentication tag.
262
- * @param adLenBits - Associated data length in bits
263
- * @param msgLenBits - Message length in bits
264
- * @param tagLen - Tag length (16 or 32 bytes)
265
- * @returns Authentication tag
266
- */
267
- finalize(
268
- adLenBits: bigint,
269
- msgLenBits: bigint,
270
- tagLen: 16 | 32 = 16,
271
- ): Uint8Array {
272
- let t = new Uint8Array(0);
273
- const u = concatBytes(le64(adLenBits), le64(msgLenBits));
274
-
275
- for (let i = 0; i < this.d; i++) {
276
- t = concatBytes(t, xorBlocks(this.v[3]![i]!, u));
277
- }
278
-
279
- for (let round = 0; round < 7; round++) {
280
- this.update(t);
281
- }
282
-
283
- if (tagLen === 16) {
284
- let tag = new Uint8Array(16);
285
- for (let i = 0; i < this.d; i++) {
286
- let ti = xorBlocks(this.v[0]![i]!, this.v[1]![i]!);
287
- ti = xorBlocks(ti, this.v[2]![i]!);
288
- ti = xorBlocks(ti, this.v[3]![i]!);
289
- ti = xorBlocks(ti, this.v[4]![i]!);
290
- ti = xorBlocks(ti, this.v[5]![i]!);
291
- tag = xorBlocks(tag, ti);
292
- }
293
- return tag;
294
- } else {
295
- let ti0 = new Uint8Array(16);
296
- let ti1 = new Uint8Array(16);
297
- for (let i = 0; i < this.d; i++) {
298
- ti0 = xorBlocks(ti0, this.v[0]![i]!);
299
- ti0 = xorBlocks(ti0, this.v[1]![i]!);
300
- ti0 = xorBlocks(ti0, this.v[2]![i]!);
301
- ti1 = xorBlocks(ti1, this.v[3]![i]!);
302
- ti1 = xorBlocks(ti1, this.v[4]![i]!);
303
- ti1 = xorBlocks(ti1, this.v[5]![i]!);
304
- }
305
- return concatBytes(ti0, ti1);
306
- }
307
- }
308
-
309
- /**
310
- * Finalizes MAC computation and produces an authentication tag.
311
- * Uses a different finalization procedure than encryption/decryption.
312
- * @param dataLenBits - Data length in bits
313
- * @param tagLen - Tag length (16 or 32 bytes)
314
- * @returns Authentication tag
315
- */
316
- finalizeMac(dataLenBits: bigint, tagLen: 16 | 32 = 16): Uint8Array {
317
- let t = new Uint8Array(0);
318
- const u = concatBytes(le64(dataLenBits), le64(BigInt(tagLen * 8)));
319
-
320
- for (let i = 0; i < this.d; i++) {
321
- t = concatBytes(t, xorBlocks(this.v[3]![i]!, u));
322
- }
323
-
324
- for (let round = 0; round < 7; round++) {
325
- this.update(t);
326
- }
327
-
328
- let tags = new Uint8Array(0);
329
- if (tagLen === 16) {
330
- for (let i = 1; i < this.d; i++) {
331
- let ti = xorBlocks(this.v[0]![i]!, this.v[1]![i]!);
332
- ti = xorBlocks(ti, this.v[2]![i]!);
333
- ti = xorBlocks(ti, this.v[3]![i]!);
334
- ti = xorBlocks(ti, this.v[4]![i]!);
335
- ti = xorBlocks(ti, this.v[5]![i]!);
336
- tags = concatBytes(tags, ti);
337
- }
338
- } else {
339
- for (let i = 1; i < this.d; i++) {
340
- let ti0 = xorBlocks(this.v[0]![i]!, this.v[1]![i]!);
341
- ti0 = xorBlocks(ti0, this.v[2]![i]!);
342
- let ti1 = xorBlocks(this.v[3]![i]!, this.v[4]![i]!);
343
- ti1 = xorBlocks(ti1, this.v[5]![i]!);
344
- tags = concatBytes(tags, ti0, ti1);
345
- }
346
- }
347
-
348
- if (this.d > 1) {
349
- for (let i = 0; i + 16 <= tags.length; i += 16) {
350
- const v = zeroPad(tags.subarray(i, i + 16), 16 * this.d);
351
- this.absorb(v);
352
- }
353
-
354
- const u2 = concatBytes(le64(BigInt(this.d)), le64(BigInt(tagLen * 8)));
355
- const t2 = zeroPad(xorBlocks(this.v[3]![0]!, u2), this.rate / 8);
356
- for (let round = 0; round < 7; round++) {
357
- this.update(t2);
358
- }
359
- }
360
-
361
- if (tagLen === 16) {
362
- let tag = xorBlocks(this.v[0]![0]!, this.v[1]![0]!);
363
- tag = xorBlocks(tag, this.v[2]![0]!);
364
- tag = xorBlocks(tag, this.v[3]![0]!);
365
- tag = xorBlocks(tag, this.v[4]![0]!);
366
- tag = xorBlocks(tag, this.v[5]![0]!);
367
- return tag;
368
- } else {
369
- let t0 = xorBlocks(this.v[0]![0]!, this.v[1]![0]!);
370
- t0 = xorBlocks(t0, this.v[2]![0]!);
371
- let t1 = xorBlocks(this.v[3]![0]!, this.v[4]![0]!);
372
- t1 = xorBlocks(t1, this.v[5]![0]!);
373
- return concatBytes(t0, t1);
374
- }
375
- }
376
- }
377
-
378
- /**
379
- * Encrypts a message using AEGIS-256X (detached mode).
380
- * @param msg - Plaintext message
381
- * @param ad - Associated data (authenticated but not encrypted)
382
- * @param key - 32-byte encryption key
383
- * @param nonce - 32-byte nonce (must be unique per message with the same key)
384
- * @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
385
- * @param degree - Parallelism degree (default: 2)
386
- * @returns Object containing ciphertext and authentication tag separately
387
- */
388
- export function aegis256XEncryptDetached(
389
- msg: Uint8Array,
390
- ad: Uint8Array,
391
- key: Uint8Array,
392
- nonce: Uint8Array,
393
- tagLen: 16 | 32 = 16,
394
- degree: number = 2,
395
- ): { ciphertext: Uint8Array; tag: Uint8Array } {
396
- const state = new Aegis256XState(degree);
397
- const rateBytes = (128 * degree) / 8;
398
-
399
- state.init(key, nonce);
400
-
401
- const adPadded = zeroPad(ad, rateBytes);
402
- for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
403
- state.absorb(adPadded.subarray(i, i + rateBytes));
404
- }
405
-
406
- const msgPadded = zeroPad(msg, rateBytes);
407
- const ct = new Uint8Array(msgPadded.length);
408
- for (let i = 0; i + rateBytes <= msgPadded.length; i += rateBytes) {
409
- state.encTo(
410
- msgPadded.subarray(i, i + rateBytes),
411
- ct.subarray(i, i + rateBytes),
412
- );
413
- }
414
-
415
- const tag = state.finalize(
416
- BigInt(ad.length * 8),
417
- BigInt(msg.length * 8),
418
- tagLen,
419
- );
420
- const ciphertext = new Uint8Array(ct.subarray(0, msg.length));
421
-
422
- return { ciphertext, tag };
423
- }
424
-
425
- /**
426
- * Decrypts a message using AEGIS-256X (detached mode).
427
- * @param ct - Ciphertext
428
- * @param tag - Authentication tag (16 or 32 bytes)
429
- * @param ad - Associated data (must match what was used during encryption)
430
- * @param key - 32-byte encryption key
431
- * @param nonce - 32-byte nonce (must match what was used during encryption)
432
- * @param degree - Parallelism degree (default: 2)
433
- * @returns Decrypted plaintext, or null if authentication fails
434
- */
435
- export function aegis256XDecryptDetached(
436
- ct: Uint8Array,
437
- tag: Uint8Array,
438
- ad: Uint8Array,
439
- key: Uint8Array,
440
- nonce: Uint8Array,
441
- degree: number = 2,
442
- ): Uint8Array | null {
443
- const tagLen = tag.length as 16 | 32;
444
- const state = new Aegis256XState(degree);
445
- const rateBytes = (128 * degree) / 8;
446
-
447
- state.init(key, nonce);
448
-
449
- const adPadded = zeroPad(ad, rateBytes);
450
- for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
451
- state.absorb(adPadded.subarray(i, i + rateBytes));
452
- }
453
-
454
- const fullBlocksLen = Math.floor(ct.length / rateBytes) * rateBytes;
455
- const cn = ct.subarray(fullBlocksLen);
456
-
457
- const msg = new Uint8Array(fullBlocksLen + (cn.length > 0 ? cn.length : 0));
458
- for (let i = 0; i + rateBytes <= ct.length; i += rateBytes) {
459
- state.decTo(ct.subarray(i, i + rateBytes), msg.subarray(i, i + rateBytes));
460
- }
461
-
462
- if (cn.length > 0) {
463
- msg.set(state.decPartial(cn), fullBlocksLen);
464
- }
465
-
466
- const expectedTag = state.finalize(
467
- BigInt(ad.length * 8),
468
- BigInt(msg.length * 8),
469
- tagLen,
470
- );
471
-
472
- if (!constantTimeEqual(tag, expectedTag)) {
473
- msg.fill(0);
474
- return null;
475
- }
476
-
477
- return msg;
478
- }
479
-
480
- /**
481
- * Encrypts a message in-place using AEGIS-256X (detached mode).
482
- * The input buffer is modified to contain the ciphertext.
483
- * @param data - Buffer containing plaintext (will be overwritten with ciphertext)
484
- * @param ad - Associated data (authenticated but not encrypted)
485
- * @param key - 32-byte encryption key
486
- * @param nonce - 32-byte nonce (must be unique per message with the same key)
487
- * @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
488
- * @param degree - Parallelism degree (default: 2)
489
- * @returns Authentication tag
490
- */
491
- export function aegis256XEncryptDetachedInPlace(
492
- data: Uint8Array,
493
- ad: Uint8Array,
494
- key: Uint8Array,
495
- nonce: Uint8Array,
496
- tagLen: 16 | 32 = 16,
497
- degree: number = 2,
498
- ): Uint8Array {
499
- const state = new Aegis256XState(degree);
500
- const rateBytes = (128 * degree) / 8;
501
-
502
- state.init(key, nonce);
503
-
504
- const adPadded = zeroPad(ad, rateBytes);
505
- for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
506
- state.absorb(adPadded.subarray(i, i + rateBytes));
507
- }
508
-
509
- const msgLen = data.length;
510
- const fullBlocksLen = Math.floor(msgLen / rateBytes) * rateBytes;
511
-
512
- for (let i = 0; i < fullBlocksLen; i += rateBytes) {
513
- state.encInPlace(data.subarray(i, i + rateBytes));
514
- }
515
-
516
- if (msgLen > fullBlocksLen) {
517
- const lastPartial = data.subarray(fullBlocksLen);
518
- const lastBlock = zeroPad(lastPartial, rateBytes);
519
- const encBlock = state.enc(lastBlock);
520
- lastPartial.set(encBlock.subarray(0, lastPartial.length));
521
- }
522
-
523
- return state.finalize(BigInt(ad.length * 8), BigInt(msgLen * 8), tagLen);
524
- }
525
-
526
- /**
527
- * Decrypts a message in-place using AEGIS-256X (detached mode).
528
- * The input buffer is modified to contain the plaintext (or zeroed on failure).
529
- * @param data - Buffer containing ciphertext (will be overwritten with plaintext)
530
- * @param tag - Authentication tag (16 or 32 bytes)
531
- * @param ad - Associated data (must match what was used during encryption)
532
- * @param key - 32-byte encryption key
533
- * @param nonce - 32-byte nonce (must match what was used during encryption)
534
- * @param degree - Parallelism degree (default: 2)
535
- * @returns True if authentication succeeds, false otherwise
536
- */
537
- export function aegis256XDecryptDetachedInPlace(
538
- data: Uint8Array,
539
- tag: Uint8Array,
540
- ad: Uint8Array,
541
- key: Uint8Array,
542
- nonce: Uint8Array,
543
- degree: number = 2,
544
- ): boolean {
545
- const tagLen = tag.length as 16 | 32;
546
- const state = new Aegis256XState(degree);
547
- const rateBytes = (128 * degree) / 8;
548
-
549
- state.init(key, nonce);
550
-
551
- const adPadded = zeroPad(ad, rateBytes);
552
- for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
553
- state.absorb(adPadded.subarray(i, i + rateBytes));
554
- }
555
-
556
- const msgLen = data.length;
557
- const fullBlocksLen = Math.floor(msgLen / rateBytes) * rateBytes;
558
-
559
- for (let i = 0; i < fullBlocksLen; i += rateBytes) {
560
- state.decInPlace(data.subarray(i, i + rateBytes));
561
- }
562
-
563
- if (msgLen > fullBlocksLen) {
564
- const lastPartial = data.subarray(fullBlocksLen);
565
- const decrypted = state.decPartial(lastPartial);
566
- lastPartial.set(decrypted);
567
- }
568
-
569
- const expectedTag = state.finalize(
570
- BigInt(ad.length * 8),
571
- BigInt(msgLen * 8),
572
- tagLen,
573
- );
574
-
575
- if (!constantTimeEqual(tag, expectedTag)) {
576
- data.fill(0);
577
- return false;
578
- }
579
-
580
- return true;
581
- }
582
-
583
- /** AEGIS-256X2 in-place encryption - detached mode (degree=2). */
584
- export const aegis256X2EncryptDetachedInPlace = (
585
- data: Uint8Array,
586
- ad: Uint8Array,
587
- key: Uint8Array,
588
- nonce: Uint8Array,
589
- tagLen: 16 | 32 = 16,
590
- ) => aegis256XEncryptDetachedInPlace(data, ad, key, nonce, tagLen, 2);
591
-
592
- /** AEGIS-256X2 in-place decryption - detached mode (degree=2). */
593
- export const aegis256X2DecryptDetachedInPlace = (
594
- data: Uint8Array,
595
- tag: Uint8Array,
596
- ad: Uint8Array,
597
- key: Uint8Array,
598
- nonce: Uint8Array,
599
- ) => aegis256XDecryptDetachedInPlace(data, tag, ad, key, nonce, 2);
600
-
601
- /** AEGIS-256X4 in-place encryption - detached mode (degree=4). */
602
- export const aegis256X4EncryptDetachedInPlace = (
603
- data: Uint8Array,
604
- ad: Uint8Array,
605
- key: Uint8Array,
606
- nonce: Uint8Array,
607
- tagLen: 16 | 32 = 16,
608
- ) => aegis256XEncryptDetachedInPlace(data, ad, key, nonce, tagLen, 4);
609
-
610
- /** AEGIS-256X4 in-place decryption - detached mode (degree=4). */
611
- export const aegis256X4DecryptDetachedInPlace = (
612
- data: Uint8Array,
613
- tag: Uint8Array,
614
- ad: Uint8Array,
615
- key: Uint8Array,
616
- nonce: Uint8Array,
617
- ) => aegis256XDecryptDetachedInPlace(data, tag, ad, key, nonce, 4);
618
-
619
- /** Nonce size for AEGIS-256X in bytes. */
620
- export const AEGIS_256X_NONCE_SIZE = 32;
621
-
622
- /** Key size for AEGIS-256X in bytes. */
623
- export const AEGIS_256X_KEY_SIZE = 32;
624
-
625
- /**
626
- * Encrypts a message using AEGIS-256X.
627
- * Returns a single buffer containing nonce || ciphertext || tag.
628
- * @param msg - Plaintext message
629
- * @param ad - Associated data (authenticated but not encrypted)
630
- * @param key - 32-byte encryption key
631
- * @param nonce - 32-byte nonce (optional, generates random nonce if not provided)
632
- * @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
633
- * @param degree - Parallelism degree (default: 2)
634
- * @returns Concatenated nonce || ciphertext || tag
635
- */
636
- export function aegis256XEncrypt(
637
- msg: Uint8Array,
638
- ad: Uint8Array,
639
- key: Uint8Array,
640
- nonce: Uint8Array | null = null,
641
- tagLen: 16 | 32 = 16,
642
- degree: number = 2,
643
- ): Uint8Array {
644
- const actualNonce = nonce ?? randomBytes(AEGIS_256X_NONCE_SIZE);
645
- const state = new Aegis256XState(degree);
646
- const rateBytes = (128 * degree) / 8;
647
-
648
- state.init(key, actualNonce);
649
-
650
- const adPadded = zeroPad(ad, rateBytes);
651
- for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
652
- state.absorb(adPadded.subarray(i, i + rateBytes));
653
- }
654
-
655
- const nonceSize = AEGIS_256X_NONCE_SIZE;
656
- const result = new Uint8Array(nonceSize + msg.length + tagLen);
657
- result.set(actualNonce, 0);
658
-
659
- const fullBlocks = Math.floor(msg.length / rateBytes) * rateBytes;
660
- for (let i = 0; i < fullBlocks; i += rateBytes) {
661
- state.encTo(
662
- msg.subarray(i, i + rateBytes),
663
- result.subarray(nonceSize + i, nonceSize + i + rateBytes),
664
- );
665
- }
666
-
667
- if (msg.length > fullBlocks) {
668
- const lastBlock = zeroPad(msg.subarray(fullBlocks), rateBytes);
669
- const encBlock = state.enc(lastBlock);
670
- result.set(
671
- encBlock.subarray(0, msg.length - fullBlocks),
672
- nonceSize + fullBlocks,
673
- );
674
- }
675
-
676
- const tag = state.finalize(
677
- BigInt(ad.length * 8),
678
- BigInt(msg.length * 8),
679
- tagLen,
680
- );
681
- result.set(tag, nonceSize + msg.length);
682
-
683
- return result;
684
- }
685
-
686
- /**
687
- * Decrypts a message using AEGIS-256X.
688
- * Expects input as nonce || ciphertext || tag.
689
- * @param sealed - Concatenated nonce || ciphertext || tag
690
- * @param ad - Associated data (must match what was used during encryption)
691
- * @param key - 32-byte encryption key
692
- * @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
693
- * @param degree - Parallelism degree (default: 2)
694
- * @returns Decrypted plaintext, or null if authentication fails
695
- */
696
- export function aegis256XDecrypt(
697
- sealed: Uint8Array,
698
- ad: Uint8Array,
699
- key: Uint8Array,
700
- tagLen: 16 | 32 = 16,
701
- degree: number = 2,
702
- ): Uint8Array | null {
703
- const nonceSize = AEGIS_256X_NONCE_SIZE;
704
- if (sealed.length < nonceSize + tagLen) {
705
- return null;
706
- }
707
- const nonce = sealed.subarray(0, nonceSize);
708
- const ct = sealed.subarray(nonceSize, sealed.length - tagLen);
709
- const tag = sealed.subarray(sealed.length - tagLen);
710
- return aegis256XDecryptDetached(ct, tag, ad, key, nonce, degree);
711
- }
712
-
713
- /** AEGIS-256X2 encryption - detached mode (degree=2). */
714
- export const aegis256X2EncryptDetached = (
715
- msg: Uint8Array,
716
- ad: Uint8Array,
717
- key: Uint8Array,
718
- nonce: Uint8Array,
719
- tagLen: 16 | 32 = 16,
720
- ) => aegis256XEncryptDetached(msg, ad, key, nonce, tagLen, 2);
721
-
722
- /** AEGIS-256X2 decryption - detached mode (degree=2). */
723
- export const aegis256X2DecryptDetached = (
724
- ct: Uint8Array,
725
- tag: Uint8Array,
726
- ad: Uint8Array,
727
- key: Uint8Array,
728
- nonce: Uint8Array,
729
- ) => aegis256XDecryptDetached(ct, tag, ad, key, nonce, 2);
730
-
731
- /** AEGIS-256X4 encryption - detached mode (degree=4). */
732
- export const aegis256X4EncryptDetached = (
733
- msg: Uint8Array,
734
- ad: Uint8Array,
735
- key: Uint8Array,
736
- nonce: Uint8Array,
737
- tagLen: 16 | 32 = 16,
738
- ) => aegis256XEncryptDetached(msg, ad, key, nonce, tagLen, 4);
739
-
740
- /** AEGIS-256X4 decryption - detached mode (degree=4). */
741
- export const aegis256X4DecryptDetached = (
742
- ct: Uint8Array,
743
- tag: Uint8Array,
744
- ad: Uint8Array,
745
- key: Uint8Array,
746
- nonce: Uint8Array,
747
- ) => aegis256XDecryptDetached(ct, tag, ad, key, nonce, 4);
748
-
749
- /** AEGIS-256X2 encryption (degree=2). */
750
- export const aegis256X2Encrypt = (
751
- msg: Uint8Array,
752
- ad: Uint8Array,
753
- key: Uint8Array,
754
- nonce: Uint8Array | null = null,
755
- tagLen: 16 | 32 = 16,
756
- ) => aegis256XEncrypt(msg, ad, key, nonce, tagLen, 2);
757
-
758
- /** AEGIS-256X2 decryption (degree=2). */
759
- export const aegis256X2Decrypt = (
760
- sealed: Uint8Array,
761
- ad: Uint8Array,
762
- key: Uint8Array,
763
- tagLen: 16 | 32 = 16,
764
- ) => aegis256XDecrypt(sealed, ad, key, tagLen, 2);
765
-
766
- /** AEGIS-256X4 encryption (degree=4). */
767
- export const aegis256X4Encrypt = (
768
- msg: Uint8Array,
769
- ad: Uint8Array,
770
- key: Uint8Array,
771
- nonce: Uint8Array | null = null,
772
- tagLen: 16 | 32 = 16,
773
- ) => aegis256XEncrypt(msg, ad, key, nonce, tagLen, 4);
774
-
775
- /** AEGIS-256X4 decryption (degree=4). */
776
- export const aegis256X4Decrypt = (
777
- sealed: Uint8Array,
778
- ad: Uint8Array,
779
- key: Uint8Array,
780
- tagLen: 16 | 32 = 16,
781
- ) => aegis256XDecrypt(sealed, ad, key, tagLen, 4);
782
-
783
- /**
784
- * Computes a MAC (Message Authentication Code) using AEGIS-256X.
785
- * @param data - Data to authenticate
786
- * @param key - 32-byte key
787
- * @param nonce - 32-byte nonce (optional, uses zero nonce if null)
788
- * @param tagLen - Tag length: 16 or 32 bytes (default: 16)
789
- * @param degree - Parallelism degree (default: 2)
790
- * @returns Authentication tag
791
- */
792
- export function aegis256XMac(
793
- data: Uint8Array,
794
- key: Uint8Array,
795
- nonce: Uint8Array | null = null,
796
- tagLen: 16 | 32 = 16,
797
- degree: number = 2,
798
- ): Uint8Array {
799
- const state = new Aegis256XState(degree);
800
- const rateBytes = (128 * degree) / 8;
801
-
802
- state.init(key, nonce ?? new Uint8Array(32));
803
-
804
- const dataPadded = zeroPad(data, rateBytes);
805
- for (let i = 0; i + rateBytes <= dataPadded.length; i += rateBytes) {
806
- state.absorb(dataPadded.subarray(i, i + rateBytes));
807
- }
808
-
809
- return state.finalizeMac(BigInt(data.length * 8), tagLen);
810
- }
811
-
812
- /**
813
- * Verifies a MAC computed using AEGIS-256X.
814
- * @param data - Data to verify
815
- * @param tag - Expected authentication tag (16 or 32 bytes)
816
- * @param key - 32-byte key
817
- * @param nonce - 32-byte nonce (optional, uses zero nonce if null)
818
- * @param degree - Parallelism degree (default: 2)
819
- * @returns True if the tag is valid, false otherwise
820
- */
821
- export function aegis256XMacVerify(
822
- data: Uint8Array,
823
- tag: Uint8Array,
824
- key: Uint8Array,
825
- nonce: Uint8Array | null = null,
826
- degree: number = 2,
827
- ): boolean {
828
- const tagLen = tag.length as 16 | 32;
829
- const expectedTag = aegis256XMac(data, key, nonce, tagLen, degree);
830
- return constantTimeEqual(tag, expectedTag);
831
- }
832
-
833
- /** AEGIS-256X2 MAC computation (degree=2). */
834
- export const aegis256X2Mac = (
835
- data: Uint8Array,
836
- key: Uint8Array,
837
- nonce: Uint8Array | null = null,
838
- tagLen: 16 | 32 = 16,
839
- ) => aegis256XMac(data, key, nonce, tagLen, 2);
840
-
841
- /** AEGIS-256X2 MAC verification (degree=2). */
842
- export const aegis256X2MacVerify = (
843
- data: Uint8Array,
844
- tag: Uint8Array,
845
- key: Uint8Array,
846
- nonce: Uint8Array | null = null,
847
- ) => aegis256XMacVerify(data, tag, key, nonce, 2);
848
-
849
- /** AEGIS-256X4 MAC computation (degree=4). */
850
- export const aegis256X4Mac = (
851
- data: Uint8Array,
852
- key: Uint8Array,
853
- nonce: Uint8Array | null = null,
854
- tagLen: 16 | 32 = 16,
855
- ) => aegis256XMac(data, key, nonce, tagLen, 4);
856
-
857
- /** AEGIS-256X4 MAC verification (degree=4). */
858
- export const aegis256X4MacVerify = (
859
- data: Uint8Array,
860
- tag: Uint8Array,
861
- key: Uint8Array,
862
- nonce: Uint8Array | null = null,
863
- ) => aegis256XMacVerify(data, tag, key, nonce, 4);
864
-
865
- /**
866
- * Generates a random 32-byte key for AEGIS-256X.
867
- * @returns 32-byte encryption key
868
- * @throws Error if no cryptographic random source is available
869
- */
870
- export function aegis256XCreateKey(): Uint8Array {
871
- return randomBytes(AEGIS_256X_KEY_SIZE);
872
- }
873
-
874
- /**
875
- * Generates a random 32-byte nonce for AEGIS-256X.
876
- * @returns 32-byte nonce
877
- * @throws Error if no cryptographic random source is available
878
- */
879
- export function aegis256XCreateNonce(): Uint8Array {
880
- return randomBytes(AEGIS_256X_NONCE_SIZE);
881
- }
882
-
883
- /** AEGIS-256X2 key generation (degree=2). */
884
- export const aegis256X2CreateKey = aegis256XCreateKey;
885
-
886
- /** AEGIS-256X2 nonce generation (degree=2). */
887
- export const aegis256X2CreateNonce = aegis256XCreateNonce;
888
-
889
- /** AEGIS-256X4 key generation (degree=4). */
890
- export const aegis256X4CreateKey = aegis256XCreateKey;
891
-
892
- /** AEGIS-256X4 nonce generation (degree=4). */
893
- export const aegis256X4CreateNonce = aegis256XCreateNonce;