aegis-aead 0.2.1 → 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 +29 -22
  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 +46 -23
  11. package/dist/aes-bs.js +2273 -331
  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 +6 -6
  19. package/dist/aegis128l-bs.d.ts +0 -194
  20. package/dist/aegis128l-bs.d.ts.map +0 -1
  21. package/dist/aegis128l-bs.js +0 -549
  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 -183
  28. package/dist/aegis256-bs.d.ts.map +0 -1
  29. package/dist/aegis256-bs.js +0 -477
  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 -709
  46. package/src/aegis128l.ts +0 -653
  47. package/src/aegis128x.ts +0 -932
  48. package/src/aegis256-bs.ts +0 -625
  49. package/src/aegis256.ts +0 -597
  50. package/src/aegis256x.ts +0 -893
  51. package/src/aes-bs.ts +0 -459
  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/dist/aegis256x.js CHANGED
@@ -1,8 +1,20 @@
1
- import { aesRoundTo, andBlocksTo, C0, C1, concatBytes, constantTimeEqual, le64, xorBlocks, xorBlocksTo, zeroPad, } from "./aes.js";
1
+ /**
2
+ * AEGIS-256X implementation with configurable parallelism degree.
3
+ * Extends AEGIS-256 with parallel lanes for improved performance on wide
4
+ * SIMD architectures. Each lane is an independent AEGIS-256 state kept in
5
+ * packed bitsliced form, built on the constant-time bitsliced AES core.
6
+ */
7
+ import { aegisRound256, blockFromBytes, blocksPut, blockToBytes, blockXor, createAesBlock, createAesBlocks, keystream256, pack, packConstantInput256, unpack, wordIdx, } from "./aes-bs.js";
2
8
  import { randomBytes } from "./random.js";
9
+ import { constantTimeEqual, zeroPad } from "./utils.js";
10
+ const C0 = new Uint32Array([
11
+ 0x02010100, 0x0d080503, 0x59372215, 0x6279e990,
12
+ ]);
13
+ const C1 = new Uint32Array([
14
+ 0x55183ddb, 0xf12fc26d, 0x42311120, 0xdd28b573,
15
+ ]);
3
16
  /**
4
17
  * AEGIS-256X cipher state with configurable parallelism degree.
5
- * Extends AEGIS-256 with parallel AES rounds for improved performance on wide SIMD architectures.
6
18
  */
7
19
  export class Aegis256XState {
8
20
  /**
@@ -11,144 +23,125 @@ export class Aegis256XState {
11
23
  */
12
24
  constructor(degree = 2) {
13
25
  this.d = degree;
14
- this.rate = 128 * degree;
15
- this.v = Array.from({ length: 6 }, () => Array.from({ length: degree }, () => new Uint8Array(16)));
16
- this.newV = Array.from({ length: 6 }, () => Array.from({ length: degree }, () => new Uint8Array(16)));
17
- this.tmp = new Uint8Array(16);
18
- this.z = new Uint8Array(16 * degree);
19
- this.ctxBufs = Array.from({ length: degree }, (_, i) => {
20
- const buf = new Uint8Array(16);
21
- buf[0] = i;
22
- buf[1] = degree - 1;
23
- return buf;
24
- });
26
+ this.rateBytes = 16 * degree;
27
+ this.lanes = Array.from({ length: degree }, () => createAesBlocks());
28
+ this.ci = createAesBlocks();
29
+ this.ciZero = createAesBlocks();
30
+ this.tmp = createAesBlock();
31
+ this.z = createAesBlock();
25
32
  }
26
33
  /**
27
- * Initializes the state with a key and nonce.
28
- * @param key - 32-byte encryption key
29
- * @param nonce - 32-byte nonce (must be unique per message)
34
+ * Returns the state blocks as byte arrays indexed [block][lane] (for testing).
30
35
  */
31
- init(key, nonce) {
32
- const k0 = key.subarray(0, 16);
33
- const k1 = key.subarray(16, 32);
34
- const n0 = nonce.subarray(0, 16);
35
- const n1 = nonce.subarray(16, 32);
36
- const k0n0 = new Uint8Array(16);
37
- const k1n1 = new Uint8Array(16);
38
- const k0c0 = new Uint8Array(16);
39
- const k1c1 = new Uint8Array(16);
40
- xorBlocksTo(k0, n0, k0n0);
41
- xorBlocksTo(k1, n1, k1n1);
42
- xorBlocksTo(k0, C0, k0c0);
43
- xorBlocksTo(k1, C1, k1c1);
44
- for (let i = 0; i < this.d; i++) {
45
- this.v[0][i].set(k0n0);
46
- this.v[1][i].set(k1n1);
47
- this.v[2][i].set(C1);
48
- this.v[3][i].set(C0);
49
- this.v[4][i].set(k0c0);
50
- this.v[5][i].set(k1c1);
51
- }
52
- const k0V = new Uint8Array(16 * this.d);
53
- const k1V = new Uint8Array(16 * this.d);
54
- const k0n0V = new Uint8Array(16 * this.d);
55
- const k1n1V = new Uint8Array(16 * this.d);
36
+ get v() {
37
+ const out = Array.from({ length: 6 }, () => []);
38
+ const unpacked = createAesBlocks();
39
+ const w = createAesBlock();
56
40
  for (let i = 0; i < this.d; i++) {
57
- k0V.set(k0, i * 16);
58
- k1V.set(k1, i * 16);
59
- k0n0V.set(k0n0, i * 16);
60
- k1n1V.set(k1n1, i * 16);
61
- }
62
- for (let round = 0; round < 4; round++) {
63
- for (let i = 0; i < this.d; i++) {
64
- const ctx = this.ctxBufs[i];
65
- for (let j = 0; j < 16; j++)
66
- this.v[3][i][j] ^= ctx[j];
67
- for (let j = 0; j < 16; j++)
68
- this.v[5][i][j] ^= ctx[j];
69
- }
70
- this.update(k0V);
71
- for (let i = 0; i < this.d; i++) {
72
- const ctx = this.ctxBufs[i];
73
- for (let j = 0; j < 16; j++)
74
- this.v[3][i][j] ^= ctx[j];
75
- for (let j = 0; j < 16; j++)
76
- this.v[5][i][j] ^= ctx[j];
77
- }
78
- this.update(k1V);
79
- for (let i = 0; i < this.d; i++) {
80
- const ctx = this.ctxBufs[i];
81
- for (let j = 0; j < 16; j++)
82
- this.v[3][i][j] ^= ctx[j];
83
- for (let j = 0; j < 16; j++)
84
- this.v[5][i][j] ^= ctx[j];
41
+ unpacked.set(this.lanes[i]);
42
+ unpack(unpacked);
43
+ for (let b = 0; b < 6; b++) {
44
+ for (let j = 0; j < 4; j++)
45
+ w[j] = unpacked[wordIdx(b, j)];
46
+ const bytes = new Uint8Array(16);
47
+ blockToBytes(bytes, w);
48
+ out[b].push(bytes);
85
49
  }
86
- this.update(k0n0V);
87
- for (let i = 0; i < this.d; i++) {
88
- const ctx = this.ctxBufs[i];
89
- for (let j = 0; j < 16; j++)
90
- this.v[3][i][j] ^= ctx[j];
91
- for (let j = 0; j < 16; j++)
92
- this.v[5][i][j] ^= ctx[j];
93
- }
94
- this.update(k1n1V);
95
50
  }
51
+ return out;
96
52
  }
97
53
  /**
98
- * Updates the state with a message vector.
99
- * @param m - Message vector (16*degree bytes)
54
+ * Initializes the state with a key and nonce.
55
+ * @param key - 32-byte encryption key
56
+ * @param nonce - 32-byte nonce (must be unique per message)
100
57
  */
101
- update(m) {
102
- const newV = this.newV;
103
- const tmp = this.tmp;
58
+ init(key, nonce) {
59
+ const k0 = createAesBlock();
60
+ const k1 = createAesBlock();
61
+ const n0 = createAesBlock();
62
+ const n1 = createAesBlock();
63
+ const k0n0 = createAesBlock();
64
+ const k1n1 = createAesBlock();
65
+ const k0c0 = createAesBlock();
66
+ const k1c1 = createAesBlock();
67
+ blockFromBytes(k0, key);
68
+ blockFromBytes(k1, key, 16);
69
+ blockFromBytes(n0, nonce);
70
+ blockFromBytes(n1, nonce, 16);
71
+ blockXor(k0n0, k0, n0);
72
+ blockXor(k1n1, k1, n1);
73
+ blockXor(k0c0, k0, C0);
74
+ blockXor(k1c1, k1, C1);
75
+ const base = createAesBlocks();
76
+ blocksPut(base, k0n0, 0);
77
+ blocksPut(base, k1n1, 1);
78
+ blocksPut(base, C1, 2);
79
+ blocksPut(base, C0, 3);
80
+ blocksPut(base, k0c0, 4);
81
+ blocksPut(base, k1c1, 5);
82
+ pack(base);
83
+ const ciK0 = createAesBlocks();
84
+ const ciK1 = createAesBlocks();
85
+ const ciK0N0 = createAesBlocks();
86
+ const ciK1N1 = createAesBlocks();
87
+ packConstantInput256(ciK0, k0);
88
+ packConstantInput256(ciK1, k1);
89
+ packConstantInput256(ciK0N0, k0n0);
90
+ packConstantInput256(ciK1N1, k1n1);
91
+ const ctx = createAesBlock();
92
+ const deltas = [];
104
93
  for (let i = 0; i < this.d; i++) {
105
- const mi = m.subarray(i * 16, (i + 1) * 16);
106
- xorBlocksTo(this.v[0][i], mi, tmp);
107
- aesRoundTo(this.v[5][i], tmp, newV[0][i]);
108
- aesRoundTo(this.v[0][i], this.v[1][i], newV[1][i]);
109
- aesRoundTo(this.v[1][i], this.v[2][i], newV[2][i]);
110
- aesRoundTo(this.v[2][i], this.v[3][i], newV[3][i]);
111
- aesRoundTo(this.v[3][i], this.v[4][i], newV[4][i]);
112
- aesRoundTo(this.v[4][i], this.v[5][i], newV[5][i]);
94
+ this.lanes[i].set(base);
95
+ const delta = createAesBlocks();
96
+ ctx[0] = i | ((this.d - 1) << 8);
97
+ blocksPut(delta, ctx, 3);
98
+ blocksPut(delta, ctx, 5);
99
+ pack(delta);
100
+ deltas.push(delta);
113
101
  }
114
- for (let j = 0; j < 6; j++) {
115
- for (let i = 0; i < this.d; i++) {
116
- this.v[j][i].set(newV[j][i]);
102
+ const inputs = [ciK0, ciK1, ciK0N0, ciK1N1];
103
+ for (let round = 0; round < 4; round++) {
104
+ for (const input of inputs) {
105
+ for (let i = 0; i < this.d; i++) {
106
+ const st = this.lanes[i];
107
+ const delta = deltas[i];
108
+ for (let w = 0; w < 32; w++)
109
+ st[w] = st[w] ^ delta[w];
110
+ aegisRound256(st, input);
111
+ }
117
112
  }
118
113
  }
119
114
  }
120
115
  /**
121
116
  * Absorbs an associated data block into the state.
122
- * @param ai - Associated data block (16*degree bytes)
117
+ * @param ai - Buffer holding the 16*degree-byte associated data block
118
+ * @param off - Offset of the block within the buffer
123
119
  */
124
- absorb(ai) {
125
- this.update(ai);
126
- }
127
- computeZ() {
128
- const z = this.z;
129
- const tmp = this.tmp;
120
+ absorb(ai, off = 0) {
130
121
  for (let i = 0; i < this.d; i++) {
131
- const off = i * 16;
132
- xorBlocksTo(this.v[1][i], this.v[4][i], z.subarray(off, off + 16));
133
- for (let j = 0; j < 16; j++)
134
- z[off + j] ^= this.v[5][i][j];
135
- andBlocksTo(this.v[2][i], this.v[3][i], tmp);
136
- for (let j = 0; j < 16; j++)
137
- z[off + j] ^= tmp[j];
122
+ blockFromBytes(this.tmp, ai, off + i * 16);
123
+ packConstantInput256(this.ci, this.tmp);
124
+ aegisRound256(this.lanes[i], this.ci);
138
125
  }
139
126
  }
140
127
  /**
141
128
  * Encrypts a plaintext block and writes to output buffer.
142
- * @param xi - Plaintext block (16*degree bytes)
143
- * @param out - Output buffer (16*degree bytes)
129
+ * @param xi - Buffer holding the 16*degree-byte plaintext block
130
+ * @param out - Output buffer receiving the ciphertext block
131
+ * @param inOff - Offset of the plaintext block within xi
132
+ * @param outOff - Offset of the ciphertext block within out
144
133
  */
145
- encTo(xi, out) {
146
- this.computeZ();
147
- const z = this.z;
148
- const rateBytes = this.rate / 8;
149
- this.update(xi);
150
- for (let i = 0; i < rateBytes; i++)
151
- out[i] = xi[i] ^ z[i];
134
+ encTo(xi, out, inOff = 0, outOff = 0) {
135
+ const t = this.tmp;
136
+ for (let i = 0; i < this.d; i++) {
137
+ const st = this.lanes[i];
138
+ keystream256(st, this.z);
139
+ blockFromBytes(t, xi, inOff + i * 16);
140
+ packConstantInput256(this.ci, t);
141
+ aegisRound256(st, this.ci);
142
+ blockXor(t, t, this.z);
143
+ blockToBytes(out, t, outOff + i * 16);
144
+ }
152
145
  }
153
146
  /**
154
147
  * Encrypts a plaintext block.
@@ -156,23 +149,28 @@ export class Aegis256XState {
156
149
  * @returns Ciphertext block of the same size
157
150
  */
158
151
  enc(xi) {
159
- const rateBytes = this.rate / 8;
160
- const out = new Uint8Array(rateBytes);
152
+ const out = new Uint8Array(this.rateBytes);
161
153
  this.encTo(xi, out);
162
154
  return out;
163
155
  }
164
156
  /**
165
157
  * Decrypts a ciphertext block and writes to output buffer.
166
- * @param ci - Ciphertext block (16*degree bytes)
167
- * @param out - Output buffer (16*degree bytes)
158
+ * @param ci - Buffer holding the 16*degree-byte ciphertext block
159
+ * @param out - Output buffer receiving the plaintext block
160
+ * @param inOff - Offset of the ciphertext block within ci
161
+ * @param outOff - Offset of the plaintext block within out
168
162
  */
169
- decTo(ci, out) {
170
- this.computeZ();
171
- const z = this.z;
172
- const rateBytes = this.rate / 8;
173
- for (let i = 0; i < rateBytes; i++)
174
- out[i] = ci[i] ^ z[i];
175
- this.update(out);
163
+ decTo(ci, out, inOff = 0, outOff = 0) {
164
+ const msg = this.tmp;
165
+ for (let i = 0; i < this.d; i++) {
166
+ const st = this.lanes[i];
167
+ blockFromBytes(msg, ci, inOff + i * 16);
168
+ keystream256(st, this.z);
169
+ blockXor(msg, msg, this.z);
170
+ packConstantInput256(this.ci, msg);
171
+ aegisRound256(st, this.ci);
172
+ blockToBytes(out, msg, outOff + i * 16);
173
+ }
176
174
  }
177
175
  /**
178
176
  * Decrypts a ciphertext block.
@@ -180,22 +178,13 @@ export class Aegis256XState {
180
178
  * @returns Plaintext block of the same size
181
179
  */
182
180
  dec(ci) {
183
- const rateBytes = this.rate / 8;
184
- const out = new Uint8Array(rateBytes);
181
+ const out = new Uint8Array(this.rateBytes);
185
182
  this.decTo(ci, out);
186
183
  return out;
187
184
  }
188
- /**
189
- * Encrypts a plaintext block in-place.
190
- * @param block - Buffer (plaintext in, ciphertext out), size 16*degree bytes
191
- */
192
185
  encInPlace(block) {
193
186
  this.encTo(block, block);
194
187
  }
195
- /**
196
- * Decrypts a ciphertext block in-place.
197
- * @param block - Buffer (ciphertext in, plaintext out), size 16*degree bytes
198
- */
199
188
  decInPlace(block) {
200
189
  this.decTo(block, block);
201
190
  }
@@ -205,121 +194,214 @@ export class Aegis256XState {
205
194
  * @returns Decrypted plaintext of the same length
206
195
  */
207
196
  decPartial(cn) {
208
- this.computeZ();
209
- const z = this.z;
210
- const rateBytes = this.rate / 8;
211
- const t = zeroPad(cn, rateBytes);
212
- const out = new Uint8Array(rateBytes);
213
- for (let i = 0; i < rateBytes; i++)
214
- out[i] = t[i] ^ z[i];
197
+ const padded = zeroPad(cn, this.rateBytes);
198
+ const ks = new Uint8Array(this.rateBytes);
199
+ for (let i = 0; i < this.d; i++) {
200
+ keystream256(this.lanes[i], this.z);
201
+ blockToBytes(ks, this.z, i * 16);
202
+ }
203
+ const out = new Uint8Array(this.rateBytes);
204
+ for (let j = 0; j < this.rateBytes; j++)
205
+ out[j] = padded[j] ^ ks[j];
215
206
  const xn = new Uint8Array(out.subarray(0, cn.length));
216
- const v = zeroPad(xn, 16 * this.d);
217
- this.update(v);
207
+ out.fill(0, cn.length);
208
+ for (let i = 0; i < this.d; i++) {
209
+ blockFromBytes(this.tmp, out, i * 16);
210
+ packConstantInput256(this.ci, this.tmp);
211
+ aegisRound256(this.lanes[i], this.ci);
212
+ }
218
213
  return xn;
219
214
  }
220
215
  /**
221
216
  * Finalizes encryption/decryption and produces an authentication tag.
222
- * @param adLenBits - Associated data length in bits
223
- * @param msgLenBits - Message length in bits
217
+ * @param adLen - Associated data length in bytes
218
+ * @param msgLen - Message length in bytes
224
219
  * @param tagLen - Tag length (16 or 32 bytes)
225
220
  * @returns Authentication tag
226
221
  */
227
- finalize(adLenBits, msgLenBits, tagLen = 16) {
228
- let t = new Uint8Array(0);
229
- const u = concatBytes(le64(adLenBits), le64(msgLenBits));
222
+ finalize(adLen, msgLen, tagLen = 16) {
223
+ const u = createAesBlock();
224
+ const t = this.tmp;
225
+ u[0] = (adLen * 8) & 0xffffffff;
226
+ u[1] = Math.floor((adLen * 8) / 0x100000000);
227
+ u[2] = (msgLen * 8) & 0xffffffff;
228
+ u[3] = Math.floor((msgLen * 8) / 0x100000000);
229
+ const unpacked = createAesBlocks();
230
230
  for (let i = 0; i < this.d; i++) {
231
- t = concatBytes(t, xorBlocks(this.v[3][i], u));
232
- }
233
- for (let round = 0; round < 7; round++) {
234
- this.update(t);
231
+ const st = this.lanes[i];
232
+ unpacked.set(st);
233
+ unpack(unpacked);
234
+ for (let j = 0; j < 4; j++)
235
+ t[j] = u[j] ^ unpacked[wordIdx(3, j)];
236
+ packConstantInput256(this.ci, t);
237
+ for (let round = 0; round < 7; round++) {
238
+ aegisRound256(st, this.ci);
239
+ }
240
+ unpack(st);
235
241
  }
236
242
  if (tagLen === 16) {
237
- let tag = new Uint8Array(16);
243
+ const tagBlock = createAesBlock();
238
244
  for (let i = 0; i < this.d; i++) {
239
- let ti = xorBlocks(this.v[0][i], this.v[1][i]);
240
- ti = xorBlocks(ti, this.v[2][i]);
241
- ti = xorBlocks(ti, this.v[3][i]);
242
- ti = xorBlocks(ti, this.v[4][i]);
243
- ti = xorBlocks(ti, this.v[5][i]);
244
- tag = xorBlocks(tag, ti);
245
+ const st = this.lanes[i];
246
+ for (let j = 0; j < 4; j++) {
247
+ tagBlock[j] =
248
+ tagBlock[j] ^
249
+ st[wordIdx(0, j)] ^
250
+ st[wordIdx(1, j)] ^
251
+ st[wordIdx(2, j)] ^
252
+ st[wordIdx(3, j)] ^
253
+ st[wordIdx(4, j)] ^
254
+ st[wordIdx(5, j)];
255
+ }
245
256
  }
257
+ const tag = new Uint8Array(16);
258
+ blockToBytes(tag, tagBlock);
246
259
  return tag;
247
260
  }
248
261
  else {
249
- let ti0 = new Uint8Array(16);
250
- let ti1 = new Uint8Array(16);
262
+ const tagBlock0 = createAesBlock();
263
+ const tagBlock1 = createAesBlock();
251
264
  for (let i = 0; i < this.d; i++) {
252
- ti0 = xorBlocks(ti0, this.v[0][i]);
253
- ti0 = xorBlocks(ti0, this.v[1][i]);
254
- ti0 = xorBlocks(ti0, this.v[2][i]);
255
- ti1 = xorBlocks(ti1, this.v[3][i]);
256
- ti1 = xorBlocks(ti1, this.v[4][i]);
257
- ti1 = xorBlocks(ti1, this.v[5][i]);
265
+ const st = this.lanes[i];
266
+ for (let j = 0; j < 4; j++) {
267
+ tagBlock0[j] =
268
+ tagBlock0[j] ^
269
+ st[wordIdx(0, j)] ^
270
+ st[wordIdx(1, j)] ^
271
+ st[wordIdx(2, j)];
272
+ tagBlock1[j] =
273
+ tagBlock1[j] ^
274
+ st[wordIdx(3, j)] ^
275
+ st[wordIdx(4, j)] ^
276
+ st[wordIdx(5, j)];
277
+ }
258
278
  }
259
- return concatBytes(ti0, ti1);
279
+ const tag = new Uint8Array(32);
280
+ blockToBytes(tag, tagBlock0);
281
+ blockToBytes(tag, tagBlock1, 16);
282
+ return tag;
260
283
  }
261
284
  }
262
285
  /**
263
286
  * Finalizes MAC computation and produces an authentication tag.
264
287
  * Uses a different finalization procedure than encryption/decryption.
265
- * @param dataLenBits - Data length in bits
288
+ * @param dataLen - Data length in bytes
266
289
  * @param tagLen - Tag length (16 or 32 bytes)
267
290
  * @returns Authentication tag
268
291
  */
269
- finalizeMac(dataLenBits, tagLen = 16) {
270
- let t = new Uint8Array(0);
271
- const u = concatBytes(le64(dataLenBits), le64(BigInt(tagLen * 8)));
292
+ finalizeMac(dataLen, tagLen = 16) {
293
+ const u = createAesBlock();
294
+ const t = this.tmp;
295
+ u[0] = (dataLen * 8) & 0xffffffff;
296
+ u[1] = Math.floor((dataLen * 8) / 0x100000000);
297
+ u[2] = tagLen * 8;
298
+ u[3] = 0;
299
+ const unpacked = createAesBlocks();
272
300
  for (let i = 0; i < this.d; i++) {
273
- t = concatBytes(t, xorBlocks(this.v[3][i], u));
274
- }
275
- for (let round = 0; round < 7; round++) {
276
- this.update(t);
277
- }
278
- let tags = new Uint8Array(0);
279
- if (tagLen === 16) {
280
- for (let i = 1; i < this.d; i++) {
281
- let ti = xorBlocks(this.v[0][i], this.v[1][i]);
282
- ti = xorBlocks(ti, this.v[2][i]);
283
- ti = xorBlocks(ti, this.v[3][i]);
284
- ti = xorBlocks(ti, this.v[4][i]);
285
- ti = xorBlocks(ti, this.v[5][i]);
286
- tags = concatBytes(tags, ti);
287
- }
288
- }
289
- else {
290
- for (let i = 1; i < this.d; i++) {
291
- let ti0 = xorBlocks(this.v[0][i], this.v[1][i]);
292
- ti0 = xorBlocks(ti0, this.v[2][i]);
293
- let ti1 = xorBlocks(this.v[3][i], this.v[4][i]);
294
- ti1 = xorBlocks(ti1, this.v[5][i]);
295
- tags = concatBytes(tags, ti0, ti1);
301
+ const st = this.lanes[i];
302
+ unpacked.set(st);
303
+ unpack(unpacked);
304
+ for (let j = 0; j < 4; j++)
305
+ t[j] = u[j] ^ unpacked[wordIdx(3, j)];
306
+ packConstantInput256(this.ci, t);
307
+ for (let round = 0; round < 7; round++) {
308
+ aegisRound256(st, this.ci);
296
309
  }
297
310
  }
298
311
  if (this.d > 1) {
299
- for (let i = 0; i + 16 <= tags.length; i += 16) {
300
- const v = zeroPad(tags.subarray(i, i + 16), 16 * this.d);
301
- this.absorb(v);
312
+ let tags;
313
+ if (tagLen === 16) {
314
+ tags = new Uint8Array(16 * (this.d - 1));
315
+ const tb = createAesBlock();
316
+ for (let i = 1; i < this.d; i++) {
317
+ unpacked.set(this.lanes[i]);
318
+ unpack(unpacked);
319
+ for (let j = 0; j < 4; j++) {
320
+ tb[j] =
321
+ unpacked[wordIdx(0, j)] ^
322
+ unpacked[wordIdx(1, j)] ^
323
+ unpacked[wordIdx(2, j)] ^
324
+ unpacked[wordIdx(3, j)] ^
325
+ unpacked[wordIdx(4, j)] ^
326
+ unpacked[wordIdx(5, j)];
327
+ }
328
+ blockToBytes(tags, tb, (i - 1) * 16);
329
+ }
330
+ }
331
+ else {
332
+ tags = new Uint8Array(32 * (this.d - 1));
333
+ const tb0 = createAesBlock();
334
+ const tb1 = createAesBlock();
335
+ for (let i = 1; i < this.d; i++) {
336
+ unpacked.set(this.lanes[i]);
337
+ unpack(unpacked);
338
+ for (let j = 0; j < 4; j++) {
339
+ tb0[j] =
340
+ unpacked[wordIdx(0, j)] ^
341
+ unpacked[wordIdx(1, j)] ^
342
+ unpacked[wordIdx(2, j)];
343
+ tb1[j] =
344
+ unpacked[wordIdx(3, j)] ^
345
+ unpacked[wordIdx(4, j)] ^
346
+ unpacked[wordIdx(5, j)];
347
+ }
348
+ blockToBytes(tags, tb0, (i - 1) * 32);
349
+ blockToBytes(tags, tb1, (i - 1) * 32 + 16);
350
+ }
351
+ }
352
+ for (let off = 0; off + 16 <= tags.length; off += 16) {
353
+ blockFromBytes(this.tmp, tags, off);
354
+ packConstantInput256(this.ci, this.tmp);
355
+ aegisRound256(this.lanes[0], this.ci);
356
+ for (let i = 1; i < this.d; i++) {
357
+ aegisRound256(this.lanes[i], this.ciZero);
358
+ }
302
359
  }
303
- const u2 = concatBytes(le64(BigInt(this.d)), le64(BigInt(tagLen * 8)));
304
- const t2 = zeroPad(xorBlocks(this.v[3][0], u2), this.rate / 8);
360
+ unpacked.set(this.lanes[0]);
361
+ unpack(unpacked);
362
+ t[0] = this.d ^ unpacked[wordIdx(3, 0)];
363
+ t[1] = unpacked[wordIdx(3, 1)];
364
+ t[2] = (tagLen * 8) ^ unpacked[wordIdx(3, 2)];
365
+ t[3] = unpacked[wordIdx(3, 3)];
366
+ packConstantInput256(this.ci, t);
305
367
  for (let round = 0; round < 7; round++) {
306
- this.update(t2);
368
+ aegisRound256(this.lanes[0], this.ci);
369
+ for (let i = 1; i < this.d; i++) {
370
+ aegisRound256(this.lanes[i], this.ciZero);
371
+ }
307
372
  }
308
373
  }
374
+ const st = createAesBlocks();
375
+ st.set(this.lanes[0]);
376
+ unpack(st);
309
377
  if (tagLen === 16) {
310
- let tag = xorBlocks(this.v[0][0], this.v[1][0]);
311
- tag = xorBlocks(tag, this.v[2][0]);
312
- tag = xorBlocks(tag, this.v[3][0]);
313
- tag = xorBlocks(tag, this.v[4][0]);
314
- tag = xorBlocks(tag, this.v[5][0]);
378
+ const tag = new Uint8Array(16);
379
+ const tagBlock = createAesBlock();
380
+ for (let j = 0; j < 4; j++) {
381
+ tagBlock[j] =
382
+ st[wordIdx(0, j)] ^
383
+ st[wordIdx(1, j)] ^
384
+ st[wordIdx(2, j)] ^
385
+ st[wordIdx(3, j)] ^
386
+ st[wordIdx(4, j)] ^
387
+ st[wordIdx(5, j)];
388
+ }
389
+ blockToBytes(tag, tagBlock);
315
390
  return tag;
316
391
  }
317
392
  else {
318
- let t0 = xorBlocks(this.v[0][0], this.v[1][0]);
319
- t0 = xorBlocks(t0, this.v[2][0]);
320
- let t1 = xorBlocks(this.v[3][0], this.v[4][0]);
321
- t1 = xorBlocks(t1, this.v[5][0]);
322
- return concatBytes(t0, t1);
393
+ const tag = new Uint8Array(32);
394
+ const tagBlock0 = createAesBlock();
395
+ const tagBlock1 = createAesBlock();
396
+ for (let j = 0; j < 4; j++) {
397
+ tagBlock0[j] =
398
+ st[wordIdx(0, j)] ^ st[wordIdx(1, j)] ^ st[wordIdx(2, j)];
399
+ tagBlock1[j] =
400
+ st[wordIdx(3, j)] ^ st[wordIdx(4, j)] ^ st[wordIdx(5, j)];
401
+ }
402
+ blockToBytes(tag, tagBlock0);
403
+ blockToBytes(tag, tagBlock1, 16);
404
+ return tag;
323
405
  }
324
406
  }
325
407
  }
@@ -335,19 +417,23 @@ export class Aegis256XState {
335
417
  */
336
418
  export function aegis256XEncryptDetached(msg, ad, key, nonce, tagLen = 16, degree = 2) {
337
419
  const state = new Aegis256XState(degree);
338
- const rateBytes = (128 * degree) / 8;
420
+ const rateBytes = 16 * degree;
339
421
  state.init(key, nonce);
340
422
  const adPadded = zeroPad(ad, rateBytes);
341
423
  for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
342
- state.absorb(adPadded.subarray(i, i + rateBytes));
424
+ state.absorb(adPadded, i);
343
425
  }
344
- const msgPadded = zeroPad(msg, rateBytes);
345
- const ct = new Uint8Array(msgPadded.length);
346
- for (let i = 0; i + rateBytes <= msgPadded.length; i += rateBytes) {
347
- state.encTo(msgPadded.subarray(i, i + rateBytes), ct.subarray(i, i + rateBytes));
426
+ const ciphertext = new Uint8Array(msg.length);
427
+ const fullBlocks = Math.floor(msg.length / rateBytes) * rateBytes;
428
+ for (let i = 0; i < fullBlocks; i += rateBytes) {
429
+ state.encTo(msg, ciphertext, i, i);
430
+ }
431
+ if (msg.length > fullBlocks) {
432
+ const lastBlock = zeroPad(msg.subarray(fullBlocks), rateBytes);
433
+ const encBlock = state.enc(lastBlock);
434
+ ciphertext.set(encBlock.subarray(0, msg.length - fullBlocks), fullBlocks);
348
435
  }
349
- const tag = state.finalize(BigInt(ad.length * 8), BigInt(msg.length * 8), tagLen);
350
- const ciphertext = new Uint8Array(ct.subarray(0, msg.length));
436
+ const tag = state.finalize(ad.length, msg.length, tagLen);
351
437
  return { ciphertext, tag };
352
438
  }
353
439
  /**
@@ -363,22 +449,21 @@ export function aegis256XEncryptDetached(msg, ad, key, nonce, tagLen = 16, degre
363
449
  export function aegis256XDecryptDetached(ct, tag, ad, key, nonce, degree = 2) {
364
450
  const tagLen = tag.length;
365
451
  const state = new Aegis256XState(degree);
366
- const rateBytes = (128 * degree) / 8;
452
+ const rateBytes = 16 * degree;
367
453
  state.init(key, nonce);
368
454
  const adPadded = zeroPad(ad, rateBytes);
369
455
  for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
370
- state.absorb(adPadded.subarray(i, i + rateBytes));
456
+ state.absorb(adPadded, i);
371
457
  }
372
- const fullBlocksLen = Math.floor(ct.length / rateBytes) * rateBytes;
373
- const cn = ct.subarray(fullBlocksLen);
374
- const msg = new Uint8Array(fullBlocksLen + (cn.length > 0 ? cn.length : 0));
375
- for (let i = 0; i + rateBytes <= ct.length; i += rateBytes) {
376
- state.decTo(ct.subarray(i, i + rateBytes), msg.subarray(i, i + rateBytes));
458
+ const msg = new Uint8Array(ct.length);
459
+ const fullBlocks = Math.floor(ct.length / rateBytes) * rateBytes;
460
+ for (let i = 0; i < fullBlocks; i += rateBytes) {
461
+ state.decTo(ct, msg, i, i);
377
462
  }
378
- if (cn.length > 0) {
379
- msg.set(state.decPartial(cn), fullBlocksLen);
463
+ if (ct.length > fullBlocks) {
464
+ msg.set(state.decPartial(ct.subarray(fullBlocks)), fullBlocks);
380
465
  }
381
- const expectedTag = state.finalize(BigInt(ad.length * 8), BigInt(msg.length * 8), tagLen);
466
+ const expectedTag = state.finalize(ad.length, msg.length, tagLen);
382
467
  if (!constantTimeEqual(tag, expectedTag)) {
383
468
  msg.fill(0);
384
469
  return null;
@@ -398,16 +483,16 @@ export function aegis256XDecryptDetached(ct, tag, ad, key, nonce, degree = 2) {
398
483
  */
399
484
  export function aegis256XEncryptDetachedInPlace(data, ad, key, nonce, tagLen = 16, degree = 2) {
400
485
  const state = new Aegis256XState(degree);
401
- const rateBytes = (128 * degree) / 8;
486
+ const rateBytes = 16 * degree;
402
487
  state.init(key, nonce);
403
488
  const adPadded = zeroPad(ad, rateBytes);
404
489
  for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
405
- state.absorb(adPadded.subarray(i, i + rateBytes));
490
+ state.absorb(adPadded, i);
406
491
  }
407
492
  const msgLen = data.length;
408
493
  const fullBlocksLen = Math.floor(msgLen / rateBytes) * rateBytes;
409
494
  for (let i = 0; i < fullBlocksLen; i += rateBytes) {
410
- state.encInPlace(data.subarray(i, i + rateBytes));
495
+ state.encTo(data, data, i, i);
411
496
  }
412
497
  if (msgLen > fullBlocksLen) {
413
498
  const lastPartial = data.subarray(fullBlocksLen);
@@ -415,7 +500,7 @@ export function aegis256XEncryptDetachedInPlace(data, ad, key, nonce, tagLen = 1
415
500
  const encBlock = state.enc(lastBlock);
416
501
  lastPartial.set(encBlock.subarray(0, lastPartial.length));
417
502
  }
418
- return state.finalize(BigInt(ad.length * 8), BigInt(msgLen * 8), tagLen);
503
+ return state.finalize(ad.length, msgLen, tagLen);
419
504
  }
420
505
  /**
421
506
  * Decrypts a message in-place using AEGIS-256X (detached mode).
@@ -431,23 +516,23 @@ export function aegis256XEncryptDetachedInPlace(data, ad, key, nonce, tagLen = 1
431
516
  export function aegis256XDecryptDetachedInPlace(data, tag, ad, key, nonce, degree = 2) {
432
517
  const tagLen = tag.length;
433
518
  const state = new Aegis256XState(degree);
434
- const rateBytes = (128 * degree) / 8;
519
+ const rateBytes = 16 * degree;
435
520
  state.init(key, nonce);
436
521
  const adPadded = zeroPad(ad, rateBytes);
437
522
  for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
438
- state.absorb(adPadded.subarray(i, i + rateBytes));
523
+ state.absorb(adPadded, i);
439
524
  }
440
525
  const msgLen = data.length;
441
526
  const fullBlocksLen = Math.floor(msgLen / rateBytes) * rateBytes;
442
527
  for (let i = 0; i < fullBlocksLen; i += rateBytes) {
443
- state.decInPlace(data.subarray(i, i + rateBytes));
528
+ state.decTo(data, data, i, i);
444
529
  }
445
530
  if (msgLen > fullBlocksLen) {
446
531
  const lastPartial = data.subarray(fullBlocksLen);
447
532
  const decrypted = state.decPartial(lastPartial);
448
533
  lastPartial.set(decrypted);
449
534
  }
450
- const expectedTag = state.finalize(BigInt(ad.length * 8), BigInt(msgLen * 8), tagLen);
535
+ const expectedTag = state.finalize(ad.length, msgLen, tagLen);
451
536
  if (!constantTimeEqual(tag, expectedTag)) {
452
537
  data.fill(0);
453
538
  return false;
@@ -479,27 +564,11 @@ export const AEGIS_256X_KEY_SIZE = 32;
479
564
  */
480
565
  export function aegis256XEncrypt(msg, ad, key, nonce = null, tagLen = 16, degree = 2) {
481
566
  const actualNonce = nonce ?? randomBytes(AEGIS_256X_NONCE_SIZE);
482
- const state = new Aegis256XState(degree);
483
- const rateBytes = (128 * degree) / 8;
484
- state.init(key, actualNonce);
485
- const adPadded = zeroPad(ad, rateBytes);
486
- for (let i = 0; i + rateBytes <= adPadded.length; i += rateBytes) {
487
- state.absorb(adPadded.subarray(i, i + rateBytes));
488
- }
489
- const nonceSize = AEGIS_256X_NONCE_SIZE;
490
- const result = new Uint8Array(nonceSize + msg.length + tagLen);
567
+ const { ciphertext, tag } = aegis256XEncryptDetached(msg, ad, key, actualNonce, tagLen, degree);
568
+ const result = new Uint8Array(AEGIS_256X_NONCE_SIZE + ciphertext.length + tagLen);
491
569
  result.set(actualNonce, 0);
492
- const fullBlocks = Math.floor(msg.length / rateBytes) * rateBytes;
493
- for (let i = 0; i < fullBlocks; i += rateBytes) {
494
- state.encTo(msg.subarray(i, i + rateBytes), result.subarray(nonceSize + i, nonceSize + i + rateBytes));
495
- }
496
- if (msg.length > fullBlocks) {
497
- const lastBlock = zeroPad(msg.subarray(fullBlocks), rateBytes);
498
- const encBlock = state.enc(lastBlock);
499
- result.set(encBlock.subarray(0, msg.length - fullBlocks), nonceSize + fullBlocks);
500
- }
501
- const tag = state.finalize(BigInt(ad.length * 8), BigInt(msg.length * 8), tagLen);
502
- result.set(tag, nonceSize + msg.length);
570
+ result.set(ciphertext, AEGIS_256X_NONCE_SIZE);
571
+ result.set(tag, AEGIS_256X_NONCE_SIZE + ciphertext.length);
503
572
  return result;
504
573
  }
505
574
  /**
@@ -549,13 +618,13 @@ export const aegis256X4Decrypt = (sealed, ad, key, tagLen = 16) => aegis256XDecr
549
618
  */
550
619
  export function aegis256XMac(data, key, nonce = null, tagLen = 16, degree = 2) {
551
620
  const state = new Aegis256XState(degree);
552
- const rateBytes = (128 * degree) / 8;
621
+ const rateBytes = 16 * degree;
553
622
  state.init(key, nonce ?? new Uint8Array(32));
554
623
  const dataPadded = zeroPad(data, rateBytes);
555
624
  for (let i = 0; i + rateBytes <= dataPadded.length; i += rateBytes) {
556
- state.absorb(dataPadded.subarray(i, i + rateBytes));
625
+ state.absorb(dataPadded, i);
557
626
  }
558
- return state.finalizeMac(BigInt(data.length * 8), tagLen);
627
+ return state.finalizeMac(data.length, tagLen);
559
628
  }
560
629
  /**
561
630
  * Verifies a MAC computed using AEGIS-256X.
@@ -603,4 +672,3 @@ export const aegis256X2CreateNonce = aegis256XCreateNonce;
603
672
  export const aegis256X4CreateKey = aegis256XCreateKey;
604
673
  /** AEGIS-256X4 nonce generation (degree=4). */
605
674
  export const aegis256X4CreateNonce = aegis256XCreateNonce;
606
- //# sourceMappingURL=aegis256x.js.map