aegis-aead 0.2.1 → 0.2.2

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.
package/README.md CHANGED
@@ -1,15 +1,17 @@
1
- # aegis-aead
1
+ # AEGIS for JavaScript
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/aegis-aead)](https://www.npmjs.com/package/aegis-aead)
4
4
  [![CI](https://github.com/jedisct1/js-aegis-aead/actions/workflows/ci.yml/badge.svg)](https://github.com/jedisct1/js-aegis-aead/actions/workflows/ci.yml)
5
5
 
6
+ [View on npm](https://www.npmjs.com/package/aegis-aead)
7
+
6
8
  A compact, zero-dependency JavaScript/TypeScript implementation of [AEGIS](https://datatracker.ietf.org/doc/draft-irtf-cfrg-aegis-aead/), a family of fast, secure authenticated encryption algorithms.
7
9
 
8
10
  AEGIS provides both encryption with authentication and standalone MAC functionality, with a simple API that makes it hard to misuse.
9
11
 
10
12
  ## Table of Contents
11
13
 
12
- - [aegis-aead](#aegis-aead)
14
+ - [AEGIS for JavaScript](#aegis-for-javascript)
13
15
  - [Table of Contents](#table-of-contents)
14
16
  - [Installation](#installation)
15
17
  - [Quick Start](#quick-start)
@@ -4,37 +4,31 @@
4
4
  */
5
5
  /**
6
6
  * Bitsliced AEGIS-128L cipher state.
7
- * Uses 8 AES blocks (128 bytes) stored in bitsliced form (32 uint32 words).
7
+ * The state is kept in packed bitsliced form between operations so that
8
+ * pack/unpack does not need to be applied at every round.
8
9
  */
9
10
  export declare class Aegis128LBsState {
10
11
  private st;
11
12
  private st1;
13
+ private constantInput;
12
14
  private tmp0;
13
15
  private tmp1;
14
16
  private z0;
15
17
  private z1;
16
18
  constructor();
17
- /**
18
- * AEGIS round function: applies AES round to all blocks and rotates.
19
- * st[i] = AES(st[i]) ^ st[(i-1) mod 8]
20
- */
21
- private aegisRound;
22
- /**
23
- * AEGIS round function with constant input (used in packed mode).
24
- */
25
19
  private aegisRoundPacked;
26
- /**
27
- * Pack constant input for blocks 0 and 4.
28
- */
29
20
  private packConstantInput;
30
21
  /**
31
- * Absorb rate: XOR message blocks into state positions 0 and 4.
32
- */
33
- private absorbRate;
34
- /**
35
- * Update state with two message blocks.
22
+ * Extract the keystream blocks z0 and z1 directly from the packed state.
23
+ *
24
+ * z0 = S6 ^ S1 ^ (S2 & S3)
25
+ * z1 = S2 ^ S5 ^ (S6 & S7)
26
+ *
27
+ * The formula is evaluated lane-wise on the packed state, the result is
28
+ * placed in positions 0 (z0) and 4 (z1), then unpack04 extracts the two
29
+ * AES blocks.
36
30
  */
37
- private update;
31
+ private keystreamPacked;
38
32
  /**
39
33
  * Initializes the state with a key and nonce.
40
34
  * @param key - 16-byte encryption key
@@ -70,15 +64,7 @@ export declare class Aegis128LBsState {
70
64
  * @returns 32-byte plaintext block
71
65
  */
72
66
  dec(ci: Uint8Array): Uint8Array;
73
- /**
74
- * Encrypts a 32-byte plaintext block in-place.
75
- * @param block - 32-byte buffer (plaintext in, ciphertext out)
76
- */
77
67
  encInPlace(block: Uint8Array): void;
78
- /**
79
- * Decrypts a 32-byte ciphertext block in-place.
80
- * @param block - 32-byte buffer (ciphertext in, plaintext out)
81
- */
82
68
  decInPlace(block: Uint8Array): void;
83
69
  /**
84
70
  * Decrypts a partial (final) ciphertext block smaller than 32 bytes.
@@ -120,24 +106,10 @@ export declare function aegis128LBsEncryptDetached(msg: Uint8Array, ad: Uint8Arr
120
106
  export declare function aegis128LBsDecryptDetached(ct: Uint8Array, tag: Uint8Array, ad: Uint8Array, key: Uint8Array, nonce: Uint8Array): Uint8Array | null;
121
107
  /**
122
108
  * Encrypts a message in-place using bitsliced AEGIS-128L (detached mode).
123
- * The input buffer is modified to contain the ciphertext.
124
- * @param data - Buffer containing plaintext (will be overwritten with ciphertext)
125
- * @param ad - Associated data (authenticated but not encrypted)
126
- * @param key - 16-byte encryption key
127
- * @param nonce - 16-byte nonce (must be unique per message with the same key)
128
- * @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
129
- * @returns Authentication tag
130
109
  */
131
110
  export declare function aegis128LBsEncryptDetachedInPlace(data: Uint8Array, ad: Uint8Array, key: Uint8Array, nonce: Uint8Array, tagLen?: 16 | 32): Uint8Array;
132
111
  /**
133
112
  * Decrypts a message in-place using bitsliced AEGIS-128L (detached mode).
134
- * The input buffer is modified to contain the plaintext (or zeroed on failure).
135
- * @param data - Buffer containing ciphertext (will be overwritten with plaintext)
136
- * @param tag - Authentication tag (16 or 32 bytes)
137
- * @param ad - Associated data (must match what was used during encryption)
138
- * @param key - 16-byte encryption key
139
- * @param nonce - 16-byte nonce (must match what was used during encryption)
140
- * @returns True if authentication succeeds, false otherwise
141
113
  */
142
114
  export declare function aegis128LBsDecryptDetachedInPlace(data: Uint8Array, tag: Uint8Array, ad: Uint8Array, key: Uint8Array, nonce: Uint8Array): boolean;
143
115
  export declare const AEGIS_128L_BS_NONCE_SIZE = 16;
@@ -145,50 +117,21 @@ export declare const AEGIS_128L_BS_KEY_SIZE = 16;
145
117
  /**
146
118
  * Encrypts a message using bitsliced AEGIS-128L.
147
119
  * Returns a single buffer containing nonce || ciphertext || tag.
148
- * @param msg - Plaintext message
149
- * @param ad - Associated data (authenticated but not encrypted)
150
- * @param key - 16-byte encryption key
151
- * @param nonce - 16-byte nonce (optional, generates random nonce if not provided)
152
- * @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
153
- * @returns Concatenated nonce || ciphertext || tag
154
120
  */
155
121
  export declare function aegis128LBsEncrypt(msg: Uint8Array, ad: Uint8Array, key: Uint8Array, nonce?: Uint8Array | null, tagLen?: 16 | 32): Uint8Array;
156
122
  /**
157
123
  * Decrypts a message using bitsliced AEGIS-128L.
158
124
  * Expects input as nonce || ciphertext || tag.
159
- * @param sealed - Concatenated nonce || ciphertext || tag
160
- * @param ad - Associated data (must match what was used during encryption)
161
- * @param key - 16-byte encryption key
162
- * @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
163
- * @returns Decrypted plaintext, or null if authentication fails
164
125
  */
165
126
  export declare function aegis128LBsDecrypt(sealed: Uint8Array, ad: Uint8Array, key: Uint8Array, tagLen?: 16 | 32): Uint8Array | null;
166
127
  /**
167
- * Computes a MAC (Message Authentication Code) using bitsliced AEGIS-128L.
168
- * @param data - Data to authenticate
169
- * @param key - 16-byte key
170
- * @param nonce - 16-byte nonce (optional, uses zero nonce if null)
171
- * @param tagLen - Tag length: 16 or 32 bytes (default: 16)
172
- * @returns Authentication tag
128
+ * Computes a MAC using bitsliced AEGIS-128L.
173
129
  */
174
130
  export declare function aegis128LBsMac(data: Uint8Array, key: Uint8Array, nonce?: Uint8Array | null, tagLen?: 16 | 32): Uint8Array;
175
131
  /**
176
132
  * Verifies a MAC computed using bitsliced AEGIS-128L.
177
- * @param data - Data to verify
178
- * @param tag - Expected authentication tag (16 or 32 bytes)
179
- * @param key - 16-byte key
180
- * @param nonce - 16-byte nonce (optional, uses zero nonce if null)
181
- * @returns True if the tag is valid, false otherwise
182
133
  */
183
134
  export declare function aegis128LBsMacVerify(data: Uint8Array, tag: Uint8Array, key: Uint8Array, nonce?: Uint8Array | null): boolean;
184
- /**
185
- * Generates a random 16-byte key for bitsliced AEGIS-128L.
186
- * @returns 16-byte encryption key
187
- */
188
135
  export declare function aegis128LBsCreateKey(): Uint8Array;
189
- /**
190
- * Generates a random 16-byte nonce for bitsliced AEGIS-128L.
191
- * @returns 16-byte nonce
192
- */
193
136
  export declare function aegis128LBsCreateNonce(): Uint8Array;
194
137
  //# sourceMappingURL=aegis128l-bs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"aegis128l-bs.d.ts","sourceRoot":"","sources":["../src/aegis128l-bs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"aegis128l-bs.d.ts","sourceRoot":"","sources":["../src/aegis128l-bs.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@
3
3
  * Provides constant-time operation by processing all 8 state blocks simultaneously.
4
4
  */
5
5
  import { constantTimeEqual, zeroPad } from "./aes.js";
6
- import { aesRound, blockFromBytes, blocksPut, blocksRotr, blocksXor, blockToBytes, blockXor, createAesBlock, createAesBlocks, pack, pack04, unpack, wordIdx, } from "./aes-bs.js";
6
+ import { aesRound, blockFromBytes, blocksPut, blocksRotr, blocksXor, blockToBytes, blockXor, createAesBlock, createAesBlocks, pack, pack04, unpack, unpack04, wordIdx, } from "./aes-bs.js";
7
7
  import { randomBytes } from "./random.js";
8
8
  const RATE = 32;
9
9
  const C0 = new Uint32Array([
@@ -14,77 +14,65 @@ const C1 = new Uint32Array([
14
14
  ]);
15
15
  /**
16
16
  * Bitsliced AEGIS-128L cipher state.
17
- * Uses 8 AES blocks (128 bytes) stored in bitsliced form (32 uint32 words).
17
+ * The state is kept in packed bitsliced form between operations so that
18
+ * pack/unpack does not need to be applied at every round.
18
19
  */
19
20
  export class Aegis128LBsState {
20
21
  constructor() {
21
22
  this.st = createAesBlocks();
22
23
  this.st1 = createAesBlocks();
24
+ this.constantInput = createAesBlocks();
23
25
  this.tmp0 = createAesBlock();
24
26
  this.tmp1 = createAesBlock();
25
27
  this.z0 = createAesBlock();
26
28
  this.z1 = createAesBlock();
27
29
  }
28
- /**
29
- * AEGIS round function: applies AES round to all blocks and rotates.
30
- * st[i] = AES(st[i]) ^ st[(i-1) mod 8]
31
- */
32
- aegisRound() {
33
- const st = this.st;
34
- const st1 = this.st1;
35
- st1.set(st);
36
- pack(st1);
37
- aesRound(st1);
38
- unpack(st1);
39
- for (let i = 0; i < 8; i++) {
40
- const prev = (i + 7) % 8;
41
- st[wordIdx(i, 0)] = (st[wordIdx(i, 0)] ^ st1[wordIdx(prev, 0)]) >>> 0;
42
- st[wordIdx(i, 1)] = (st[wordIdx(i, 1)] ^ st1[wordIdx(prev, 1)]) >>> 0;
43
- st[wordIdx(i, 2)] = (st[wordIdx(i, 2)] ^ st1[wordIdx(prev, 2)]) >>> 0;
44
- st[wordIdx(i, 3)] = (st[wordIdx(i, 3)] ^ st1[wordIdx(prev, 3)]) >>> 0;
45
- }
46
- }
47
- /**
48
- * AEGIS round function with constant input (used in packed mode).
49
- */
50
- aegisRoundPacked(constantInput) {
30
+ aegisRoundPacked() {
51
31
  const st = this.st;
52
32
  const st1 = this.st1;
53
33
  st1.set(st);
54
34
  aesRound(st1);
55
35
  blocksRotr(st1);
56
36
  blocksXor(st, st1);
57
- blocksXor(st, constantInput);
37
+ blocksXor(st, this.constantInput);
58
38
  }
59
- /**
60
- * Pack constant input for blocks 0 and 4.
61
- */
62
- packConstantInput(out, m0, m1) {
39
+ packConstantInput(m0, m1) {
40
+ const out = this.constantInput;
63
41
  out.fill(0);
64
42
  blocksPut(out, m0, 0);
65
43
  blocksPut(out, m1, 4);
66
44
  pack04(out);
67
45
  }
68
46
  /**
69
- * Absorb rate: XOR message blocks into state positions 0 and 4.
47
+ * Extract the keystream blocks z0 and z1 directly from the packed state.
48
+ *
49
+ * z0 = S6 ^ S1 ^ (S2 & S3)
50
+ * z1 = S2 ^ S5 ^ (S6 & S7)
51
+ *
52
+ * The formula is evaluated lane-wise on the packed state, the result is
53
+ * placed in positions 0 (z0) and 4 (z1), then unpack04 extracts the two
54
+ * AES blocks.
70
55
  */
71
- absorbRate(m0, m1) {
56
+ keystreamPacked() {
72
57
  const st = this.st;
73
- st[wordIdx(0, 0)] = (st[wordIdx(0, 0)] ^ m0[0]) >>> 0;
74
- st[wordIdx(0, 1)] = (st[wordIdx(0, 1)] ^ m0[1]) >>> 0;
75
- st[wordIdx(0, 2)] = (st[wordIdx(0, 2)] ^ m0[2]) >>> 0;
76
- st[wordIdx(0, 3)] = (st[wordIdx(0, 3)] ^ m0[3]) >>> 0;
77
- st[wordIdx(4, 0)] = (st[wordIdx(4, 0)] ^ m1[0]) >>> 0;
78
- st[wordIdx(4, 1)] = (st[wordIdx(4, 1)] ^ m1[1]) >>> 0;
79
- st[wordIdx(4, 2)] = (st[wordIdx(4, 2)] ^ m1[2]) >>> 0;
80
- st[wordIdx(4, 3)] = (st[wordIdx(4, 3)] ^ m1[3]) >>> 0;
81
- }
82
- /**
83
- * Update state with two message blocks.
84
- */
85
- update(m0, m1) {
86
- this.aegisRound();
87
- this.absorbRate(m0, m1);
58
+ const z = this.st1;
59
+ for (let i = 0; i < 32; i++) {
60
+ const x = st[i];
61
+ z[i] =
62
+ ((x & 0x02020202) << 6) ^
63
+ ((x & 0x40404040) << 1) ^
64
+ ((x & (x >>> 1) & 0x10101010) << 3) ^
65
+ ((x & 0x20202020) >>> 2) ^
66
+ ((x & 0x04040404) << 1) ^
67
+ ((x & (x >>> 1) & 0x01010101) << 3);
68
+ }
69
+ unpack04(z);
70
+ const z0 = this.z0;
71
+ const z1 = this.z1;
72
+ for (let i = 0; i < 4; i++) {
73
+ z0[i] = z[wordIdx(0, i)];
74
+ z1[i] = z[wordIdx(4, i)];
75
+ }
88
76
  }
89
77
  /**
90
78
  * Initializes the state with a key and nonce.
@@ -110,13 +98,11 @@ export class Aegis128LBsState {
110
98
  blocksPut(this.st, kc0, 5);
111
99
  blocksPut(this.st, kc1, 6);
112
100
  blocksPut(this.st, kc0, 7);
113
- const constantInput = createAesBlocks();
114
- this.packConstantInput(constantInput, n, k);
101
+ this.packConstantInput(n, k);
115
102
  pack(this.st);
116
103
  for (let i = 0; i < 10; i++) {
117
- this.aegisRoundPacked(constantInput);
104
+ this.aegisRoundPacked();
118
105
  }
119
- unpack(this.st);
120
106
  }
121
107
  /**
122
108
  * Absorbs a 32-byte associated data block into the state.
@@ -127,7 +113,8 @@ export class Aegis128LBsState {
127
113
  const msg1 = this.tmp1;
128
114
  blockFromBytes(msg0, ai.subarray(0, 16));
129
115
  blockFromBytes(msg1, ai.subarray(16, 32));
130
- this.update(msg0, msg1);
116
+ this.packConstantInput(msg0, msg1);
117
+ this.aegisRoundPacked();
131
118
  }
132
119
  /**
133
120
  * Encrypts a 32-byte plaintext block and writes to output buffer.
@@ -135,34 +122,17 @@ export class Aegis128LBsState {
135
122
  * @param out - 32-byte output buffer
136
123
  */
137
124
  encTo(xi, out) {
138
- const st = this.st;
139
- const z0 = this.z0;
140
- const z1 = this.z1;
141
125
  const t0 = this.tmp0;
142
126
  const t1 = this.tmp1;
143
- for (let i = 0; i < 4; i++) {
144
- z0[i] =
145
- (st[wordIdx(6, i)] ^
146
- st[wordIdx(1, i)] ^
147
- (st[wordIdx(2, i)] & st[wordIdx(3, i)])) >>>
148
- 0;
149
- }
150
- for (let i = 0; i < 4; i++) {
151
- z1[i] =
152
- (st[wordIdx(2, i)] ^
153
- st[wordIdx(5, i)] ^
154
- (st[wordIdx(6, i)] & st[wordIdx(7, i)])) >>>
155
- 0;
156
- }
127
+ this.keystreamPacked();
157
128
  blockFromBytes(t0, xi.subarray(0, 16));
158
129
  blockFromBytes(t1, xi.subarray(16, 32));
159
- const out0 = createAesBlock();
160
- const out1 = createAesBlock();
161
- blockXor(out0, t0, z0);
162
- blockXor(out1, t1, z1);
163
- blockToBytes(out.subarray(0, 16), out0);
164
- blockToBytes(out.subarray(16, 32), out1);
165
- this.update(t0, t1);
130
+ this.packConstantInput(t0, t1);
131
+ this.aegisRoundPacked();
132
+ blockXor(t0, t0, this.z0);
133
+ blockXor(t1, t1, this.z1);
134
+ blockToBytes(out.subarray(0, 16), t0);
135
+ blockToBytes(out.subarray(16, 32), t1);
166
136
  }
167
137
  /**
168
138
  * Encrypts a 32-byte plaintext block.
@@ -180,28 +150,15 @@ export class Aegis128LBsState {
180
150
  * @param out - 32-byte output buffer
181
151
  */
182
152
  decTo(ci, out) {
183
- const st = this.st;
184
153
  const msg0 = this.tmp0;
185
154
  const msg1 = this.tmp1;
186
155
  blockFromBytes(msg0, ci.subarray(0, 16));
187
156
  blockFromBytes(msg1, ci.subarray(16, 32));
188
- for (let i = 0; i < 4; i++) {
189
- msg0[i] =
190
- (msg0[i] ^
191
- st[wordIdx(6, i)] ^
192
- st[wordIdx(1, i)] ^
193
- (st[wordIdx(2, i)] & st[wordIdx(3, i)])) >>>
194
- 0;
195
- }
196
- for (let i = 0; i < 4; i++) {
197
- msg1[i] =
198
- (msg1[i] ^
199
- st[wordIdx(2, i)] ^
200
- st[wordIdx(5, i)] ^
201
- (st[wordIdx(6, i)] & st[wordIdx(7, i)])) >>>
202
- 0;
203
- }
204
- this.update(msg0, msg1);
157
+ this.keystreamPacked();
158
+ blockXor(msg0, msg0, this.z0);
159
+ blockXor(msg1, msg1, this.z1);
160
+ this.packConstantInput(msg0, msg1);
161
+ this.aegisRoundPacked();
205
162
  blockToBytes(out.subarray(0, 16), msg0);
206
163
  blockToBytes(out.subarray(16, 32), msg1);
207
164
  }
@@ -215,17 +172,9 @@ export class Aegis128LBsState {
215
172
  this.decTo(ci, out);
216
173
  return out;
217
174
  }
218
- /**
219
- * Encrypts a 32-byte plaintext block in-place.
220
- * @param block - 32-byte buffer (plaintext in, ciphertext out)
221
- */
222
175
  encInPlace(block) {
223
176
  this.encTo(block, block);
224
177
  }
225
- /**
226
- * Decrypts a 32-byte ciphertext block in-place.
227
- * @param block - 32-byte buffer (ciphertext in, plaintext out)
228
- */
229
178
  decInPlace(block) {
230
179
  this.decTo(block, block);
231
180
  }
@@ -235,28 +184,14 @@ export class Aegis128LBsState {
235
184
  * @returns Decrypted plaintext of the same length
236
185
  */
237
186
  decPartial(cn) {
238
- const st = this.st;
239
187
  const msg0 = this.tmp0;
240
188
  const msg1 = this.tmp1;
241
189
  const padded = zeroPad(cn, RATE);
242
190
  blockFromBytes(msg0, padded.subarray(0, 16));
243
191
  blockFromBytes(msg1, padded.subarray(16, 32));
244
- for (let i = 0; i < 4; i++) {
245
- msg0[i] =
246
- (msg0[i] ^
247
- st[wordIdx(6, i)] ^
248
- st[wordIdx(1, i)] ^
249
- (st[wordIdx(2, i)] & st[wordIdx(3, i)])) >>>
250
- 0;
251
- }
252
- for (let i = 0; i < 4; i++) {
253
- msg1[i] =
254
- (msg1[i] ^
255
- st[wordIdx(2, i)] ^
256
- st[wordIdx(5, i)] ^
257
- (st[wordIdx(6, i)] & st[wordIdx(7, i)])) >>>
258
- 0;
259
- }
192
+ this.keystreamPacked();
193
+ blockXor(msg0, msg0, this.z0);
194
+ blockXor(msg1, msg1, this.z1);
260
195
  const pad = new Uint8Array(RATE);
261
196
  blockToBytes(pad.subarray(0, 16), msg0);
262
197
  blockToBytes(pad.subarray(16, 32), msg1);
@@ -264,8 +199,8 @@ export class Aegis128LBsState {
264
199
  pad.fill(0, cn.length);
265
200
  blockFromBytes(msg0, pad.subarray(0, 16));
266
201
  blockFromBytes(msg1, pad.subarray(16, 32));
267
- this.aegisRound();
268
- this.absorbRate(msg0, msg1);
202
+ this.packConstantInput(msg0, msg1);
203
+ this.aegisRoundPacked();
269
204
  return xn;
270
205
  }
271
206
  /**
@@ -282,17 +217,18 @@ export class Aegis128LBsState {
282
217
  tmp[1] = Math.floor((adLen * 8) / 0x100000000) >>> 0;
283
218
  tmp[2] = ((msgLen * 8) & 0xffffffff) >>> 0;
284
219
  tmp[3] = Math.floor((msgLen * 8) / 0x100000000) >>> 0;
285
- tmp[0] = (tmp[0] ^ st[wordIdx(2, 0)]) >>> 0;
286
- tmp[1] = (tmp[1] ^ st[wordIdx(2, 1)]) >>> 0;
287
- tmp[2] = (tmp[2] ^ st[wordIdx(2, 2)]) >>> 0;
288
- tmp[3] = (tmp[3] ^ st[wordIdx(2, 3)]) >>> 0;
289
- const constantInput = createAesBlocks();
290
- this.packConstantInput(constantInput, tmp, tmp);
291
- pack(this.st);
220
+ const unpacked = this.st1;
221
+ unpacked.set(st);
222
+ unpack(unpacked);
223
+ tmp[0] = (tmp[0] ^ unpacked[wordIdx(2, 0)]) >>> 0;
224
+ tmp[1] = (tmp[1] ^ unpacked[wordIdx(2, 1)]) >>> 0;
225
+ tmp[2] = (tmp[2] ^ unpacked[wordIdx(2, 2)]) >>> 0;
226
+ tmp[3] = (tmp[3] ^ unpacked[wordIdx(2, 3)]) >>> 0;
227
+ this.packConstantInput(tmp, tmp);
292
228
  for (let i = 0; i < 7; i++) {
293
- this.aegisRoundPacked(constantInput);
229
+ this.aegisRoundPacked();
294
230
  }
295
- unpack(this.st);
231
+ unpack(st);
296
232
  if (tagLen === 16) {
297
233
  const tag = new Uint8Array(16);
298
234
  const tagBlock = createAesBlock();
@@ -399,13 +335,6 @@ export function aegis128LBsDecryptDetached(ct, tag, ad, key, nonce) {
399
335
  }
400
336
  /**
401
337
  * Encrypts a message in-place using bitsliced AEGIS-128L (detached mode).
402
- * The input buffer is modified to contain the ciphertext.
403
- * @param data - Buffer containing plaintext (will be overwritten with ciphertext)
404
- * @param ad - Associated data (authenticated but not encrypted)
405
- * @param key - 16-byte encryption key
406
- * @param nonce - 16-byte nonce (must be unique per message with the same key)
407
- * @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
408
- * @returns Authentication tag
409
338
  */
410
339
  export function aegis128LBsEncryptDetachedInPlace(data, ad, key, nonce, tagLen = 16) {
411
340
  const state = new Aegis128LBsState();
@@ -429,13 +358,6 @@ export function aegis128LBsEncryptDetachedInPlace(data, ad, key, nonce, tagLen =
429
358
  }
430
359
  /**
431
360
  * Decrypts a message in-place using bitsliced AEGIS-128L (detached mode).
432
- * The input buffer is modified to contain the plaintext (or zeroed on failure).
433
- * @param data - Buffer containing ciphertext (will be overwritten with plaintext)
434
- * @param tag - Authentication tag (16 or 32 bytes)
435
- * @param ad - Associated data (must match what was used during encryption)
436
- * @param key - 16-byte encryption key
437
- * @param nonce - 16-byte nonce (must match what was used during encryption)
438
- * @returns True if authentication succeeds, false otherwise
439
361
  */
440
362
  export function aegis128LBsDecryptDetachedInPlace(data, tag, ad, key, nonce) {
441
363
  const tagLen = tag.length;
@@ -467,12 +389,6 @@ export const AEGIS_128L_BS_KEY_SIZE = 16;
467
389
  /**
468
390
  * Encrypts a message using bitsliced AEGIS-128L.
469
391
  * Returns a single buffer containing nonce || ciphertext || tag.
470
- * @param msg - Plaintext message
471
- * @param ad - Associated data (authenticated but not encrypted)
472
- * @param key - 16-byte encryption key
473
- * @param nonce - 16-byte nonce (optional, generates random nonce if not provided)
474
- * @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
475
- * @returns Concatenated nonce || ciphertext || tag
476
392
  */
477
393
  export function aegis128LBsEncrypt(msg, ad, key, nonce = null, tagLen = 16) {
478
394
  const actualNonce = nonce ?? randomBytes(AEGIS_128L_BS_NONCE_SIZE);
@@ -486,11 +402,6 @@ export function aegis128LBsEncrypt(msg, ad, key, nonce = null, tagLen = 16) {
486
402
  /**
487
403
  * Decrypts a message using bitsliced AEGIS-128L.
488
404
  * Expects input as nonce || ciphertext || tag.
489
- * @param sealed - Concatenated nonce || ciphertext || tag
490
- * @param ad - Associated data (must match what was used during encryption)
491
- * @param key - 16-byte encryption key
492
- * @param tagLen - Authentication tag length: 16 or 32 bytes (default: 16)
493
- * @returns Decrypted plaintext, or null if authentication fails
494
405
  */
495
406
  export function aegis128LBsDecrypt(sealed, ad, key, tagLen = 16) {
496
407
  const nonceSize = AEGIS_128L_BS_NONCE_SIZE;
@@ -503,12 +414,7 @@ export function aegis128LBsDecrypt(sealed, ad, key, tagLen = 16) {
503
414
  return aegis128LBsDecryptDetached(ct, tag, ad, key, nonce);
504
415
  }
505
416
  /**
506
- * Computes a MAC (Message Authentication Code) using bitsliced AEGIS-128L.
507
- * @param data - Data to authenticate
508
- * @param key - 16-byte key
509
- * @param nonce - 16-byte nonce (optional, uses zero nonce if null)
510
- * @param tagLen - Tag length: 16 or 32 bytes (default: 16)
511
- * @returns Authentication tag
417
+ * Computes a MAC using bitsliced AEGIS-128L.
512
418
  */
513
419
  export function aegis128LBsMac(data, key, nonce = null, tagLen = 16) {
514
420
  const state = new Aegis128LBsState();
@@ -521,28 +427,15 @@ export function aegis128LBsMac(data, key, nonce = null, tagLen = 16) {
521
427
  }
522
428
  /**
523
429
  * Verifies a MAC computed using bitsliced AEGIS-128L.
524
- * @param data - Data to verify
525
- * @param tag - Expected authentication tag (16 or 32 bytes)
526
- * @param key - 16-byte key
527
- * @param nonce - 16-byte nonce (optional, uses zero nonce if null)
528
- * @returns True if the tag is valid, false otherwise
529
430
  */
530
431
  export function aegis128LBsMacVerify(data, tag, key, nonce = null) {
531
432
  const tagLen = tag.length;
532
433
  const expectedTag = aegis128LBsMac(data, key, nonce, tagLen);
533
434
  return constantTimeEqual(tag, expectedTag);
534
435
  }
535
- /**
536
- * Generates a random 16-byte key for bitsliced AEGIS-128L.
537
- * @returns 16-byte encryption key
538
- */
539
436
  export function aegis128LBsCreateKey() {
540
437
  return randomBytes(AEGIS_128L_BS_KEY_SIZE);
541
438
  }
542
- /**
543
- * Generates a random 16-byte nonce for bitsliced AEGIS-128L.
544
- * @returns 16-byte nonce
545
- */
546
439
  export function aegis128LBsCreateNonce() {
547
440
  return randomBytes(AEGIS_128L_BS_NONCE_SIZE);
548
441
  }