aegis-aead 0.1.1 → 0.2.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 (48) hide show
  1. package/README.md +241 -60
  2. package/dist/aegis128l-bs.d.ts +162 -0
  3. package/dist/aegis128l-bs.d.ts.map +1 -0
  4. package/dist/aegis128l-bs.js +470 -0
  5. package/dist/aegis128l-bs.js.map +1 -0
  6. package/dist/aegis128l.d.ts +42 -5
  7. package/dist/aegis128l.d.ts.map +1 -1
  8. package/dist/aegis128l.js +79 -5
  9. package/dist/aegis128l.js.map +1 -1
  10. package/dist/aegis128x.d.ts +67 -12
  11. package/dist/aegis128x.d.ts.map +1 -1
  12. package/dist/aegis128x.js +102 -9
  13. package/dist/aegis128x.js.map +1 -1
  14. package/dist/aegis256-bs.d.ts +151 -0
  15. package/dist/aegis256-bs.d.ts.map +1 -0
  16. package/dist/aegis256-bs.js +398 -0
  17. package/dist/aegis256-bs.js.map +1 -0
  18. package/dist/aegis256.d.ts +42 -5
  19. package/dist/aegis256.d.ts.map +1 -1
  20. package/dist/aegis256.js +79 -5
  21. package/dist/aegis256.js.map +1 -1
  22. package/dist/aegis256x.d.ts +67 -12
  23. package/dist/aegis256x.d.ts.map +1 -1
  24. package/dist/aegis256x.js +102 -9
  25. package/dist/aegis256x.js.map +1 -1
  26. package/dist/aes-bs.d.ts +71 -0
  27. package/dist/aes-bs.d.ts.map +1 -0
  28. package/dist/aes-bs.js +399 -0
  29. package/dist/aes-bs.js.map +1 -0
  30. package/dist/index.d.ts +6 -4
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +6 -4
  33. package/dist/index.js.map +1 -1
  34. package/dist/random.d.ts +22 -0
  35. package/dist/random.d.ts.map +1 -0
  36. package/dist/random.js +36 -0
  37. package/dist/random.js.map +1 -0
  38. package/package.json +1 -1
  39. package/src/aegis128l-bs.ts +602 -0
  40. package/src/aegis128l.ts +112 -5
  41. package/src/aegis128x.ts +174 -15
  42. package/src/aegis256-bs.ts +518 -0
  43. package/src/aegis256.ts +112 -5
  44. package/src/aegis256x.ts +174 -15
  45. package/src/aes-bs.ts +459 -0
  46. package/src/index.ts +66 -0
  47. package/src/random.ts +41 -0
  48. package/README.md~ +0 -154
package/src/aegis256x.ts CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  xorBlocksTo,
11
11
  zeroPad,
12
12
  } from "./aes.js";
13
+ import { randomBytes } from "./random.js";
13
14
 
14
15
  /**
15
16
  * AEGIS-256X cipher state with configurable parallelism degree.
@@ -359,16 +360,16 @@ export class Aegis256XState {
359
360
  }
360
361
 
361
362
  /**
362
- * Encrypts a message using AEGIS-256X.
363
+ * Encrypts a message using AEGIS-256X (detached mode).
363
364
  * @param msg - Plaintext message
364
365
  * @param ad - Associated data (authenticated but not encrypted)
365
366
  * @param key - 32-byte encryption key
366
367
  * @param nonce - 32-byte nonce (must be unique per message with the same key)
367
368
  * @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
368
369
  * @param degree - Parallelism degree (default: 2)
369
- * @returns Object containing ciphertext and authentication tag
370
+ * @returns Object containing ciphertext and authentication tag separately
370
371
  */
371
- export function aegis256XEncrypt(
372
+ export function aegis256XEncryptDetached(
372
373
  msg: Uint8Array,
373
374
  ad: Uint8Array,
374
375
  key: Uint8Array,
@@ -406,7 +407,7 @@ export function aegis256XEncrypt(
406
407
  }
407
408
 
408
409
  /**
409
- * Decrypts a message using AEGIS-256X.
410
+ * Decrypts a message using AEGIS-256X (detached mode).
410
411
  * @param ct - Ciphertext
411
412
  * @param tag - Authentication tag (16 or 32 bytes)
412
413
  * @param ad - Associated data (must match what was used during encryption)
@@ -415,7 +416,7 @@ export function aegis256XEncrypt(
415
416
  * @param degree - Parallelism degree (default: 2)
416
417
  * @returns Decrypted plaintext, or null if authentication fails
417
418
  */
418
- export function aegis256XDecrypt(
419
+ export function aegis256XDecryptDetached(
419
420
  ct: Uint8Array,
420
421
  tag: Uint8Array,
421
422
  ad: Uint8Array,
@@ -460,41 +461,169 @@ export function aegis256XDecrypt(
460
461
  return msg;
461
462
  }
462
463
 
464
+ /** Nonce size for AEGIS-256X in bytes. */
465
+ export const AEGIS_256X_NONCE_SIZE = 32;
466
+
467
+ /** Key size for AEGIS-256X in bytes. */
468
+ export const AEGIS_256X_KEY_SIZE = 32;
469
+
470
+ /**
471
+ * Encrypts a message using AEGIS-256X.
472
+ * Returns a single buffer containing nonce || ciphertext || tag.
473
+ * @param msg - Plaintext message
474
+ * @param ad - Associated data (authenticated but not encrypted)
475
+ * @param key - 32-byte encryption key
476
+ * @param nonce - 32-byte nonce (optional, generates random nonce if not provided)
477
+ * @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
478
+ * @param degree - Parallelism degree (default: 2)
479
+ * @returns Concatenated nonce || ciphertext || tag
480
+ */
481
+ export function aegis256XEncrypt(
482
+ msg: Uint8Array,
483
+ ad: Uint8Array,
484
+ key: Uint8Array,
485
+ nonce: Uint8Array | null = null,
486
+ tagLen: 16 | 32 = 16,
487
+ degree: number = 2,
488
+ ): Uint8Array {
489
+ const actualNonce = nonce ?? randomBytes(AEGIS_256X_NONCE_SIZE);
490
+ const state = new Aegis256XState(degree);
491
+ const rateBytes = (128 * degree) / 8;
492
+
493
+ state.init(key, actualNonce);
494
+
495
+ const adPadded = zeroPad(ad, rateBytes);
496
+ for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
497
+ state.absorb(adPadded.subarray(i, i + rateBytes));
498
+ }
499
+
500
+ const nonceSize = AEGIS_256X_NONCE_SIZE;
501
+ const result = new Uint8Array(nonceSize + msg.length + tagLen);
502
+ result.set(actualNonce, 0);
503
+
504
+ const fullBlocks = Math.floor(msg.length / rateBytes) * rateBytes;
505
+ for (let i = 0; i < fullBlocks; i += rateBytes) {
506
+ state.encTo(
507
+ msg.subarray(i, i + rateBytes),
508
+ result.subarray(nonceSize + i, nonceSize + i + rateBytes),
509
+ );
510
+ }
511
+
512
+ if (msg.length > fullBlocks) {
513
+ const lastBlock = zeroPad(msg.subarray(fullBlocks), rateBytes);
514
+ const encBlock = state.enc(lastBlock);
515
+ result.set(
516
+ encBlock.subarray(0, msg.length - fullBlocks),
517
+ nonceSize + fullBlocks,
518
+ );
519
+ }
520
+
521
+ const tag = state.finalize(
522
+ BigInt(ad.length * 8),
523
+ BigInt(msg.length * 8),
524
+ tagLen,
525
+ );
526
+ result.set(tag, nonceSize + msg.length);
527
+
528
+ return result;
529
+ }
530
+
531
+ /**
532
+ * Decrypts a message using AEGIS-256X.
533
+ * Expects input as nonce || ciphertext || tag.
534
+ * @param sealed - Concatenated nonce || ciphertext || tag
535
+ * @param ad - Associated data (must match what was used during encryption)
536
+ * @param key - 32-byte encryption key
537
+ * @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
538
+ * @param degree - Parallelism degree (default: 2)
539
+ * @returns Decrypted plaintext, or null if authentication fails
540
+ */
541
+ export function aegis256XDecrypt(
542
+ sealed: Uint8Array,
543
+ ad: Uint8Array,
544
+ key: Uint8Array,
545
+ tagLen: 16 | 32 = 16,
546
+ degree: number = 2,
547
+ ): Uint8Array | null {
548
+ const nonceSize = AEGIS_256X_NONCE_SIZE;
549
+ if (sealed.length < nonceSize + tagLen) {
550
+ return null;
551
+ }
552
+ const nonce = sealed.subarray(0, nonceSize);
553
+ const ct = sealed.subarray(nonceSize, sealed.length - tagLen);
554
+ const tag = sealed.subarray(sealed.length - tagLen);
555
+ return aegis256XDecryptDetached(ct, tag, ad, key, nonce, degree);
556
+ }
557
+
558
+ /** AEGIS-256X2 encryption - detached mode (degree=2). */
559
+ export const aegis256X2EncryptDetached = (
560
+ msg: Uint8Array,
561
+ ad: Uint8Array,
562
+ key: Uint8Array,
563
+ nonce: Uint8Array,
564
+ tagLen: 16 | 32 = 16,
565
+ ) => aegis256XEncryptDetached(msg, ad, key, nonce, tagLen, 2);
566
+
567
+ /** AEGIS-256X2 decryption - detached mode (degree=2). */
568
+ export const aegis256X2DecryptDetached = (
569
+ ct: Uint8Array,
570
+ tag: Uint8Array,
571
+ ad: Uint8Array,
572
+ key: Uint8Array,
573
+ nonce: Uint8Array,
574
+ ) => aegis256XDecryptDetached(ct, tag, ad, key, nonce, 2);
575
+
576
+ /** AEGIS-256X4 encryption - detached mode (degree=4). */
577
+ export const aegis256X4EncryptDetached = (
578
+ msg: Uint8Array,
579
+ ad: Uint8Array,
580
+ key: Uint8Array,
581
+ nonce: Uint8Array,
582
+ tagLen: 16 | 32 = 16,
583
+ ) => aegis256XEncryptDetached(msg, ad, key, nonce, tagLen, 4);
584
+
585
+ /** AEGIS-256X4 decryption - detached mode (degree=4). */
586
+ export const aegis256X4DecryptDetached = (
587
+ ct: Uint8Array,
588
+ tag: Uint8Array,
589
+ ad: Uint8Array,
590
+ key: Uint8Array,
591
+ nonce: Uint8Array,
592
+ ) => aegis256XDecryptDetached(ct, tag, ad, key, nonce, 4);
593
+
463
594
  /** AEGIS-256X2 encryption (degree=2). */
464
595
  export const aegis256X2Encrypt = (
465
596
  msg: Uint8Array,
466
597
  ad: Uint8Array,
467
598
  key: Uint8Array,
468
- nonce: Uint8Array,
599
+ nonce: Uint8Array | null = null,
469
600
  tagLen: 16 | 32 = 16,
470
601
  ) => aegis256XEncrypt(msg, ad, key, nonce, tagLen, 2);
471
602
 
472
603
  /** AEGIS-256X2 decryption (degree=2). */
473
604
  export const aegis256X2Decrypt = (
474
- ct: Uint8Array,
475
- tag: Uint8Array,
605
+ sealed: Uint8Array,
476
606
  ad: Uint8Array,
477
607
  key: Uint8Array,
478
- nonce: Uint8Array,
479
- ) => aegis256XDecrypt(ct, tag, ad, key, nonce, 2);
608
+ tagLen: 16 | 32 = 16,
609
+ ) => aegis256XDecrypt(sealed, ad, key, tagLen, 2);
480
610
 
481
611
  /** AEGIS-256X4 encryption (degree=4). */
482
612
  export const aegis256X4Encrypt = (
483
613
  msg: Uint8Array,
484
614
  ad: Uint8Array,
485
615
  key: Uint8Array,
486
- nonce: Uint8Array,
616
+ nonce: Uint8Array | null = null,
487
617
  tagLen: 16 | 32 = 16,
488
618
  ) => aegis256XEncrypt(msg, ad, key, nonce, tagLen, 4);
489
619
 
490
620
  /** AEGIS-256X4 decryption (degree=4). */
491
621
  export const aegis256X4Decrypt = (
492
- ct: Uint8Array,
493
- tag: Uint8Array,
622
+ sealed: Uint8Array,
494
623
  ad: Uint8Array,
495
624
  key: Uint8Array,
496
- nonce: Uint8Array,
497
- ) => aegis256XDecrypt(ct, tag, ad, key, nonce, 4);
625
+ tagLen: 16 | 32 = 16,
626
+ ) => aegis256XDecrypt(sealed, ad, key, tagLen, 4);
498
627
 
499
628
  /**
500
629
  * Computes a MAC (Message Authentication Code) using AEGIS-256X.
@@ -577,3 +706,33 @@ export const aegis256X4MacVerify = (
577
706
  key: Uint8Array,
578
707
  nonce: Uint8Array | null = null,
579
708
  ) => aegis256XMacVerify(data, tag, key, nonce, 4);
709
+
710
+ /**
711
+ * Generates a random 32-byte key for AEGIS-256X.
712
+ * @returns 32-byte encryption key
713
+ * @throws Error if no cryptographic random source is available
714
+ */
715
+ export function aegis256XCreateKey(): Uint8Array {
716
+ return randomBytes(AEGIS_256X_KEY_SIZE);
717
+ }
718
+
719
+ /**
720
+ * Generates a random 32-byte nonce for AEGIS-256X.
721
+ * @returns 32-byte nonce
722
+ * @throws Error if no cryptographic random source is available
723
+ */
724
+ export function aegis256XCreateNonce(): Uint8Array {
725
+ return randomBytes(AEGIS_256X_NONCE_SIZE);
726
+ }
727
+
728
+ /** AEGIS-256X2 key generation (degree=2). */
729
+ export const aegis256X2CreateKey = aegis256XCreateKey;
730
+
731
+ /** AEGIS-256X2 nonce generation (degree=2). */
732
+ export const aegis256X2CreateNonce = aegis256XCreateNonce;
733
+
734
+ /** AEGIS-256X4 key generation (degree=4). */
735
+ export const aegis256X4CreateKey = aegis256XCreateKey;
736
+
737
+ /** AEGIS-256X4 nonce generation (degree=4). */
738
+ export const aegis256X4CreateNonce = aegis256XCreateNonce;
package/src/aes-bs.ts ADDED
@@ -0,0 +1,459 @@
1
+ /**
2
+ * Bitsliced AES implementation using 32-bit integers.
3
+ * Processes 8 AES blocks simultaneously for constant-time operation.
4
+ * Based on the barrel-shiftrows representation by Adomnicai and Peyrin.
5
+ */
6
+
7
+ /**
8
+ * Bitsliced representation of 8 AES blocks.
9
+ * 32 uint32 words where each bit position corresponds to one of 8 blocks.
10
+ */
11
+ export type AesBlocks = Uint32Array;
12
+
13
+ /**
14
+ * A single AES block as 4 uint32 words (little-endian).
15
+ */
16
+ export type AesBlock = Uint32Array;
17
+
18
+ /**
19
+ * Creates a new bitsliced state for 8 AES blocks.
20
+ */
21
+ export function createAesBlocks(): AesBlocks {
22
+ return new Uint32Array(32);
23
+ }
24
+
25
+ /**
26
+ * Creates a new AES block (4 uint32 words).
27
+ */
28
+ export function createAesBlock(): AesBlock {
29
+ return new Uint32Array(4);
30
+ }
31
+
32
+ /**
33
+ * Swap-move operation used in pack/unpack transformations.
34
+ * Swaps bits at positions n between a and b using a mask.
35
+ */
36
+ function swapmove(
37
+ st: Uint32Array,
38
+ aIdx: number,
39
+ bIdx: number,
40
+ mask: number,
41
+ n: number,
42
+ ): void {
43
+ const tmp = ((st[bIdx]! ^ (st[aIdx]! >>> n)) & mask) >>> 0;
44
+ st[bIdx] = (st[bIdx]! ^ tmp) >>> 0;
45
+ st[aIdx] = (st[aIdx]! ^ ((tmp << n) >>> 0)) >>> 0;
46
+ }
47
+
48
+ /**
49
+ * 32-bit left rotation.
50
+ */
51
+ function rotl32(x: number, b: number): number {
52
+ return ((x << b) | (x >>> (32 - b))) >>> 0;
53
+ }
54
+
55
+ /**
56
+ * S-box implementation using bitsliced logic gates.
57
+ * Maximov & Ekdahl circuit.
58
+ */
59
+ function sbox(st: Uint32Array, offset: number): void {
60
+ let u0 = st[offset]!;
61
+ let u1 = st[offset + 1]!;
62
+ let u2 = st[offset + 2]!;
63
+ let u3 = st[offset + 3]!;
64
+ let u4 = st[offset + 4]!;
65
+ let u5 = st[offset + 5]!;
66
+ let u6 = st[offset + 6]!;
67
+ let u7 = st[offset + 7]!;
68
+
69
+ const z24 = (u3 ^ u4) >>> 0;
70
+ const q17 = (u1 ^ u7) >>> 0;
71
+ const q16 = (u5 ^ q17) >>> 0;
72
+ const q0 = (z24 ^ q16) >>> 0;
73
+ const q7 = (z24 ^ u1 ^ u6) >>> 0;
74
+ const q2 = (u2 ^ q0) >>> 0;
75
+ const q1 = (q7 ^ q2) >>> 0;
76
+ const q3 = (u0 ^ q7) >>> 0;
77
+ const q4 = (u0 ^ q2) >>> 0;
78
+ const q5 = (u1 ^ q4) >>> 0;
79
+ const q6 = (u2 ^ u3) >>> 0;
80
+ const q10 = (q6 ^ q7) >>> 0;
81
+ const q8 = (u0 ^ q10) >>> 0;
82
+ const q9 = (q8 ^ q2) >>> 0;
83
+ const q12 = (z24 ^ q17) >>> 0;
84
+ const q15 = (u7 ^ q4) >>> 0;
85
+ const q13 = (z24 ^ q15) >>> 0;
86
+ const q14 = (q15 ^ q0) >>> 0;
87
+ const q11 = u5;
88
+
89
+ // NAND(x, y) = ~(x & y)
90
+ // NOR(x, y) = ~(x | y)
91
+ // XNOR(x, y) = ~(x ^ y)
92
+ // MUX(s, x, y) = (x & s) | (y & ~s)
93
+ const nand = (x: number, y: number) => ~(x & y) >>> 0;
94
+ const nor = (x: number, y: number) => ~(x | y) >>> 0;
95
+ const xnor = (x: number, y: number) => ~(x ^ y) >>> 0;
96
+ const mux = (s: number, x: number, y: number) =>
97
+ (((x & s) >>> 0) | ((y & ~s) >>> 0)) >>> 0;
98
+
99
+ const t20 = nand(q6, q12);
100
+ const t21 = nand(q3, q14);
101
+ const t22 = nand(q1, q16);
102
+ const x0 = (nor(q3, q14) ^ nand(q0, q7) ^ (t20 ^ t22)) >>> 0;
103
+ const x1 = (nor(q4, q13) ^ nand(q10, q11) ^ (t21 ^ t20)) >>> 0;
104
+ const x2 = (nor(q2, q17) ^ nand(q5, q9) ^ (t21 ^ t22)) >>> 0;
105
+ const x3 = (nor(q8, q15) ^ nand(q2, q17) ^ (t21 ^ nand(q4, q13))) >>> 0;
106
+
107
+ const t2 = xnor(nand(x0, x2), nor(x1, x3));
108
+ const y0 = mux(x2, t2, x3);
109
+ const y2 = mux(x0, t2, x1);
110
+ const y1 = mux(t2, x3, mux(x1, x2, 0xffffffff));
111
+ const y3 = mux(t2, x1, mux(x3, x0, 0xffffffff));
112
+ const y02 = (y2 ^ y0) >>> 0;
113
+ const y13 = (y3 ^ y1) >>> 0;
114
+ const y23 = (y3 ^ y2) >>> 0;
115
+ const y01 = (y1 ^ y0) >>> 0;
116
+ const y00 = (y02 ^ y13) >>> 0;
117
+
118
+ const n0 = nand(y01, q11);
119
+ const n1 = nand(y0, q12);
120
+ const n2 = nand(y1, q0);
121
+ const n3 = nand(y23, q17);
122
+ const n4 = nand(y2, q5);
123
+ const n5 = nand(y3, q15);
124
+ const n6 = nand(y13, q14);
125
+ const n7 = nand(y00, q16);
126
+ const n8 = nand(y02, q13);
127
+ const n9 = nand(y01, q7);
128
+ const n10 = nand(y0, q10);
129
+ const n11 = nand(y1, q6);
130
+ const n12 = nand(y23, q2);
131
+ const n13 = nand(y2, q9);
132
+ const n14 = nand(y3, q8);
133
+ const n15 = nand(y13, q3);
134
+ const n16 = nand(y00, q1);
135
+ const n17 = nand(y02, q4);
136
+
137
+ const h1 = (n4 ^ n1 ^ n5) >>> 0;
138
+ u2 = xnor(n2, h1);
139
+ const h2 = (n9 ^ n15) >>> 0;
140
+ u6 = xnor(h2, (n11 ^ n17) >>> 0);
141
+ const h4 = (n11 ^ n14) >>> 0;
142
+ const h5 = (n9 ^ n12) >>> 0;
143
+ u5 = (h4 ^ h5) >>> 0;
144
+ const h7 = (u2 ^ u6) >>> 0;
145
+ const h8 = (n10 ^ h7) >>> 0;
146
+ u7 = xnor((n16 ^ h2) >>> 0, h8);
147
+ const h9 = (n8 ^ h1) >>> 0;
148
+ const h10 = (n13 ^ h8) >>> 0;
149
+ u3 = (h5 ^ h10) >>> 0;
150
+ const h13 = (h4 ^ n7 ^ h9 ^ h10) >>> 0;
151
+ u4 = (n1 ^ h13) >>> 0;
152
+ const h14 = xnor(n0, u7);
153
+ u1 = xnor(n6, (h7 ^ h9 ^ h14) >>> 0);
154
+ u0 = (h13 ^ n3 ^ n4 ^ h14) >>> 0;
155
+
156
+ st[offset] = u0;
157
+ st[offset + 1] = u1;
158
+ st[offset + 2] = u2;
159
+ st[offset + 3] = u3;
160
+ st[offset + 4] = u4;
161
+ st[offset + 5] = u5;
162
+ st[offset + 6] = u6;
163
+ st[offset + 7] = u7;
164
+ }
165
+
166
+ /**
167
+ * Apply S-box to all 4 byte positions.
168
+ */
169
+ function sboxes(st: AesBlocks): void {
170
+ for (let i = 0; i < 4; i++) {
171
+ sbox(st, 8 * i);
172
+ }
173
+ }
174
+
175
+ /**
176
+ * ShiftRows operation in bitsliced form.
177
+ */
178
+ function shiftrows(st: AesBlocks): void {
179
+ for (let i = 8; i < 16; i++) {
180
+ st[i] = rotl32(st[i]!, 24);
181
+ }
182
+ for (let i = 16; i < 24; i++) {
183
+ st[i] = rotl32(st[i]!, 16);
184
+ }
185
+ for (let i = 24; i < 32; i++) {
186
+ st[i] = rotl32(st[i]!, 8);
187
+ }
188
+ }
189
+
190
+ /**
191
+ * MixColumns operation in bitsliced form.
192
+ */
193
+ function mixcolumns(st: AesBlocks): void {
194
+ const t2_0 = (st[0]! ^ st[8]!) >>> 0;
195
+ const t2_1 = (st[8]! ^ st[16]!) >>> 0;
196
+ const t2_2 = (st[16]! ^ st[24]!) >>> 0;
197
+ const t2_3 = (st[24]! ^ st[0]!) >>> 0;
198
+
199
+ let t0_0 = (st[7]! ^ st[15]!) >>> 0;
200
+ let t0_1 = (st[15]! ^ st[23]!) >>> 0;
201
+ let t0_2 = (st[23]! ^ st[31]!) >>> 0;
202
+ let t0_3 = (st[31]! ^ st[7]!) >>> 0;
203
+
204
+ let t = st[7]!;
205
+ st[7] = (t2_0 ^ t0_2 ^ st[15]!) >>> 0;
206
+ st[15] = (t2_1 ^ t0_2 ^ t) >>> 0;
207
+ t = st[23]!;
208
+ st[23] = (t2_2 ^ t0_0 ^ st[31]!) >>> 0;
209
+ st[31] = (t2_3 ^ t0_0 ^ t) >>> 0;
210
+
211
+ let t1_0 = (st[6]! ^ st[14]!) >>> 0;
212
+ let t1_1 = (st[14]! ^ st[22]!) >>> 0;
213
+ let t1_2 = (st[22]! ^ st[30]!) >>> 0;
214
+ let t1_3 = (st[30]! ^ st[6]!) >>> 0;
215
+
216
+ t = st[6]!;
217
+ let t_bis = st[14]!;
218
+ st[6] = (t0_0 ^ t2_0 ^ st[14]! ^ t1_2) >>> 0;
219
+ st[14] = (t0_1 ^ t2_1 ^ t1_2 ^ t) >>> 0;
220
+ t = st[22]!;
221
+ st[22] = (t0_2 ^ t2_2 ^ t1_3 ^ t_bis) >>> 0;
222
+ st[30] = (t0_3 ^ t2_3 ^ t1_0 ^ t) >>> 0;
223
+
224
+ t0_0 = (st[5]! ^ st[13]!) >>> 0;
225
+ t0_1 = (st[13]! ^ st[21]!) >>> 0;
226
+ t0_2 = (st[21]! ^ st[29]!) >>> 0;
227
+ t0_3 = (st[29]! ^ st[5]!) >>> 0;
228
+
229
+ t = st[5]!;
230
+ t_bis = st[13]!;
231
+ st[5] = (t1_0 ^ t0_1 ^ st[29]!) >>> 0;
232
+ st[13] = (t1_1 ^ t0_2 ^ t) >>> 0;
233
+ t = st[21]!;
234
+ st[21] = (t1_2 ^ t0_3 ^ t_bis) >>> 0;
235
+ st[29] = (t1_3 ^ t0_0 ^ t) >>> 0;
236
+
237
+ t1_0 = (st[4]! ^ st[12]!) >>> 0;
238
+ t1_1 = (st[12]! ^ st[20]!) >>> 0;
239
+ t1_2 = (st[20]! ^ st[28]!) >>> 0;
240
+ t1_3 = (st[28]! ^ st[4]!) >>> 0;
241
+
242
+ t = st[4]!;
243
+ t_bis = st[12]!;
244
+ st[4] = (t0_0 ^ t2_0 ^ t1_1 ^ st[28]!) >>> 0;
245
+ st[12] = (t0_1 ^ t2_1 ^ t1_2 ^ t) >>> 0;
246
+ t = st[20]!;
247
+ st[20] = (t0_2 ^ t2_2 ^ t1_3 ^ t_bis) >>> 0;
248
+ st[28] = (t0_3 ^ t2_3 ^ t1_0 ^ t) >>> 0;
249
+
250
+ t0_0 = (st[3]! ^ st[11]!) >>> 0;
251
+ t0_1 = (st[11]! ^ st[19]!) >>> 0;
252
+ t0_2 = (st[19]! ^ st[27]!) >>> 0;
253
+ t0_3 = (st[27]! ^ st[3]!) >>> 0;
254
+
255
+ t = st[3]!;
256
+ t_bis = st[11]!;
257
+ st[3] = (t1_0 ^ t2_0 ^ t0_1 ^ st[27]!) >>> 0;
258
+ st[11] = (t1_1 ^ t2_1 ^ t0_2 ^ t) >>> 0;
259
+ t = st[19]!;
260
+ st[19] = (t1_2 ^ t2_2 ^ t0_3 ^ t_bis) >>> 0;
261
+ st[27] = (t1_3 ^ t2_3 ^ t0_0 ^ t) >>> 0;
262
+
263
+ t1_0 = (st[2]! ^ st[10]!) >>> 0;
264
+ t1_1 = (st[10]! ^ st[18]!) >>> 0;
265
+ t1_2 = (st[18]! ^ st[26]!) >>> 0;
266
+ t1_3 = (st[26]! ^ st[2]!) >>> 0;
267
+
268
+ t = st[2]!;
269
+ t_bis = st[10]!;
270
+ st[2] = (t0_0 ^ t1_1 ^ st[26]!) >>> 0;
271
+ st[10] = (t0_1 ^ t1_2 ^ t) >>> 0;
272
+ t = st[18]!;
273
+ st[18] = (t0_2 ^ t1_3 ^ t_bis) >>> 0;
274
+ st[26] = (t0_3 ^ t1_0 ^ t) >>> 0;
275
+
276
+ t0_0 = (st[1]! ^ st[9]!) >>> 0;
277
+ t0_1 = (st[9]! ^ st[17]!) >>> 0;
278
+ t0_2 = (st[17]! ^ st[25]!) >>> 0;
279
+ t0_3 = (st[25]! ^ st[1]!) >>> 0;
280
+
281
+ t = st[1]!;
282
+ t_bis = st[9]!;
283
+ st[1] = (t1_0 ^ t0_1 ^ st[25]!) >>> 0;
284
+ st[9] = (t1_1 ^ t0_2 ^ t) >>> 0;
285
+ t = st[17]!;
286
+ st[17] = (t1_2 ^ t0_3 ^ t_bis) >>> 0;
287
+ st[25] = (t1_3 ^ t0_0 ^ t) >>> 0;
288
+
289
+ t = st[0]!;
290
+ t_bis = st[8]!;
291
+ st[0] = (t0_0 ^ t2_1 ^ st[24]!) >>> 0;
292
+ st[8] = (t0_1 ^ t2_2 ^ t) >>> 0;
293
+ t = st[16]!;
294
+ st[16] = (t0_2 ^ t2_3 ^ t_bis) >>> 0;
295
+ st[24] = (t0_3 ^ t2_0 ^ t) >>> 0;
296
+ }
297
+
298
+ /**
299
+ * Complete AES round (SubBytes + ShiftRows + MixColumns).
300
+ * Note: AddRoundKey is handled separately in AEGIS.
301
+ */
302
+ export function aesRound(st: AesBlocks): void {
303
+ sboxes(st);
304
+ shiftrows(st);
305
+ mixcolumns(st);
306
+ }
307
+
308
+ /**
309
+ * Pack 8 AES blocks into bitsliced representation.
310
+ */
311
+ export function pack(st: AesBlocks): void {
312
+ for (let i = 0; i < 8; i++) {
313
+ swapmove(st, i, i + 8, 0x00ff00ff, 8);
314
+ swapmove(st, i + 16, i + 24, 0x00ff00ff, 8);
315
+ }
316
+ for (let i = 0; i < 16; i++) {
317
+ swapmove(st, i, i + 16, 0x0000ffff, 16);
318
+ }
319
+ for (let i = 0; i < 32; i += 8) {
320
+ swapmove(st, i + 1, i, 0x55555555, 1);
321
+ swapmove(st, i + 3, i + 2, 0x55555555, 1);
322
+ swapmove(st, i + 5, i + 4, 0x55555555, 1);
323
+ swapmove(st, i + 7, i + 6, 0x55555555, 1);
324
+ swapmove(st, i + 2, i, 0x33333333, 2);
325
+ swapmove(st, i + 3, i + 1, 0x33333333, 2);
326
+ swapmove(st, i + 6, i + 4, 0x33333333, 2);
327
+ swapmove(st, i + 7, i + 5, 0x33333333, 2);
328
+ swapmove(st, i + 4, i, 0x0f0f0f0f, 4);
329
+ swapmove(st, i + 5, i + 1, 0x0f0f0f0f, 4);
330
+ swapmove(st, i + 6, i + 2, 0x0f0f0f0f, 4);
331
+ swapmove(st, i + 7, i + 3, 0x0f0f0f0f, 4);
332
+ }
333
+ }
334
+
335
+ /**
336
+ * Unpack bitsliced representation to 8 AES blocks.
337
+ */
338
+ export function unpack(st: AesBlocks): void {
339
+ for (let i = 0; i < 32; i += 8) {
340
+ swapmove(st, i + 1, i, 0x55555555, 1);
341
+ swapmove(st, i + 3, i + 2, 0x55555555, 1);
342
+ swapmove(st, i + 5, i + 4, 0x55555555, 1);
343
+ swapmove(st, i + 7, i + 6, 0x55555555, 1);
344
+ swapmove(st, i + 2, i, 0x33333333, 2);
345
+ swapmove(st, i + 3, i + 1, 0x33333333, 2);
346
+ swapmove(st, i + 6, i + 4, 0x33333333, 2);
347
+ swapmove(st, i + 7, i + 5, 0x33333333, 2);
348
+ swapmove(st, i + 4, i, 0x0f0f0f0f, 4);
349
+ swapmove(st, i + 5, i + 1, 0x0f0f0f0f, 4);
350
+ swapmove(st, i + 6, i + 2, 0x0f0f0f0f, 4);
351
+ swapmove(st, i + 7, i + 3, 0x0f0f0f0f, 4);
352
+ }
353
+ for (let i = 0; i < 16; i++) {
354
+ swapmove(st, i, i + 16, 0x0000ffff, 16);
355
+ }
356
+ for (let i = 0; i < 8; i++) {
357
+ swapmove(st, i, i + 8, 0x00ff00ff, 8);
358
+ swapmove(st, i + 16, i + 24, 0x00ff00ff, 8);
359
+ }
360
+ }
361
+
362
+ /**
363
+ * Pack only blocks 0 and 4 (used for constant inputs in AEGIS-128L).
364
+ */
365
+ export function pack04(st: AesBlocks): void {
366
+ swapmove(st, 0, 0 + 8, 0x00ff00ff, 8);
367
+ swapmove(st, 0 + 16, 0 + 24, 0x00ff00ff, 8);
368
+ swapmove(st, 4, 4 + 8, 0x00ff00ff, 8);
369
+ swapmove(st, 4 + 16, 4 + 24, 0x00ff00ff, 8);
370
+
371
+ swapmove(st, 0, 0 + 16, 0x0000ffff, 16);
372
+ swapmove(st, 4, 4 + 16, 0x0000ffff, 16);
373
+ swapmove(st, 8, 8 + 16, 0x0000ffff, 16);
374
+ swapmove(st, 12, 12 + 16, 0x0000ffff, 16);
375
+
376
+ for (let i = 0; i < 32; i += 8) {
377
+ swapmove(st, i + 1, i, 0x55555555, 1);
378
+ swapmove(st, i + 5, i + 4, 0x55555555, 1);
379
+ swapmove(st, i + 2, i, 0x33333333, 2);
380
+ swapmove(st, i + 3, i + 1, 0x33333333, 2);
381
+ swapmove(st, i + 6, i + 4, 0x33333333, 2);
382
+ swapmove(st, i + 7, i + 5, 0x33333333, 2);
383
+ swapmove(st, i + 4, i, 0x0f0f0f0f, 4);
384
+ swapmove(st, i + 5, i + 1, 0x0f0f0f0f, 4);
385
+ swapmove(st, i + 6, i + 2, 0x0f0f0f0f, 4);
386
+ swapmove(st, i + 7, i + 3, 0x0f0f0f0f, 4);
387
+ }
388
+ }
389
+
390
+ /**
391
+ * Computes the index into the bitsliced state array.
392
+ * @param block - Block index (0-7)
393
+ * @param word - Word index (0-3)
394
+ */
395
+ export function wordIdx(block: number, word: number): number {
396
+ return block + word * 8;
397
+ }
398
+
399
+ /**
400
+ * Rotate all blocks right by 1 position (for AEGIS state rotation).
401
+ * Performs (st[i] & 0xfefefefe) >> 1 | (st[i] & 0x01010101) << 7
402
+ */
403
+ export function blocksRotr(st: AesBlocks): void {
404
+ for (let i = 0; i < 32; i++) {
405
+ st[i] =
406
+ (((st[i]! & 0xfefefefe) >>> 1) | ((st[i]! & 0x01010101) << 7)) >>> 0;
407
+ }
408
+ }
409
+
410
+ /**
411
+ * Put a single AES block into the bitsliced state at the given block position.
412
+ */
413
+ export function blocksPut(st: AesBlocks, s: AesBlock, block: number): void {
414
+ st[wordIdx(block, 0)] = s[0]!;
415
+ st[wordIdx(block, 1)] = s[1]!;
416
+ st[wordIdx(block, 2)] = s[2]!;
417
+ st[wordIdx(block, 3)] = s[3]!;
418
+ }
419
+
420
+ /**
421
+ * Load a 16-byte buffer into an AES block (4 uint32 little-endian).
422
+ */
423
+ export function blockFromBytes(out: AesBlock, src: Uint8Array): void {
424
+ const view = new DataView(src.buffer, src.byteOffset, src.byteLength);
425
+ out[0] = view.getUint32(0, true);
426
+ out[1] = view.getUint32(4, true);
427
+ out[2] = view.getUint32(8, true);
428
+ out[3] = view.getUint32(12, true);
429
+ }
430
+
431
+ /**
432
+ * Store an AES block to a 16-byte buffer (little-endian).
433
+ */
434
+ export function blockToBytes(out: Uint8Array, src: AesBlock): void {
435
+ const view = new DataView(out.buffer, out.byteOffset, out.byteLength);
436
+ view.setUint32(0, src[0]!, true);
437
+ view.setUint32(4, src[1]!, true);
438
+ view.setUint32(8, src[2]!, true);
439
+ view.setUint32(12, src[3]!, true);
440
+ }
441
+
442
+ /**
443
+ * XOR two AES blocks: out = a ^ b
444
+ */
445
+ export function blockXor(out: AesBlock, a: AesBlock, b: AesBlock): void {
446
+ out[0] = (a[0]! ^ b[0]!) >>> 0;
447
+ out[1] = (a[1]! ^ b[1]!) >>> 0;
448
+ out[2] = (a[2]! ^ b[2]!) >>> 0;
449
+ out[3] = (a[3]! ^ b[3]!) >>> 0;
450
+ }
451
+
452
+ /**
453
+ * XOR two bitsliced states: a ^= b
454
+ */
455
+ export function blocksXor(a: AesBlocks, b: AesBlocks): void {
456
+ for (let i = 0; i < 32; i++) {
457
+ a[i] = (a[i]! ^ b[i]!) >>> 0;
458
+ }
459
+ }