@theqrl/dilithium5 0.1.0 → 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.
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ var sha3 = require('@noble/hashes/sha3');
3
4
  var pkg = require('randombytes');
4
- var sha3 = require('sha3');
5
5
 
6
6
  const Shake128Rate = 168;
7
7
  const Shake256Rate = 136;
@@ -10,6 +10,7 @@ const Stream256BlockBytes = Shake256Rate;
10
10
 
11
11
  const SeedBytes = 32;
12
12
  const CRHBytes = 64;
13
+ const TRBytes = 64;
13
14
  const N = 256;
14
15
  const Q = 8380417;
15
16
  const QInv = 58728449;
@@ -33,7 +34,7 @@ const PolyW1PackedBytes = 128;
33
34
 
34
35
  const CryptoPublicKeyBytes = SeedBytes + K * PolyT1PackedBytes;
35
36
  const CryptoSecretKeyBytes =
36
- 3 * SeedBytes + L * PolyETAPackedBytes + K * PolyETAPackedBytes + K * PolyT0PackedBytes;
37
+ 2 * SeedBytes + TRBytes + L * PolyETAPackedBytes + K * PolyETAPackedBytes + K * PolyT0PackedBytes;
37
38
  const CryptoBytes = SeedBytes + L * PolyZPackedBytes + PolyVecHPackedBytes;
38
39
 
39
40
  const PolyUniformNBlocks = Math.floor((768 + Stream128BlockBytes - 1) / Stream128BlockBytes);
@@ -64,452 +65,65 @@ const zetas = [
64
65
  -1362209, 3937738, 1400424, -846154, 1976782,
65
66
  ];
66
67
 
67
- const NRounds = 24;
68
-
69
- const KeccakFRoundConstants = BigUint64Array.from([
70
- 0x0000000000000001n,
71
- 0x0000000000008082n,
72
- 0x800000000000808an,
73
- 0x8000000080008000n,
74
- 0x000000000000808bn,
75
- 0x0000000080000001n,
76
- 0x8000000080008081n,
77
- 0x8000000000008009n,
78
- 0x000000000000008an,
79
- 0x0000000000000088n,
80
- 0x0000000080008009n,
81
- 0x000000008000000an,
82
- 0x000000008000808bn,
83
- 0x800000000000008bn,
84
- 0x8000000000008089n,
85
- 0x8000000000008003n,
86
- 0x8000000000008002n,
87
- 0x8000000000000080n,
88
- 0x000000000000800an,
89
- 0x800000008000000an,
90
- 0x8000000080008081n,
91
- 0x8000000000008080n,
92
- 0x0000000080000001n,
93
- 0x8000000080008008n,
94
- ]);
68
+ /**
69
+ * FIPS 202 SHAKE functions using @noble/hashes
70
+ * Provides streaming XOF (extendable output function) interface
71
+ */
95
72
 
73
+
74
+ /**
75
+ * Keccak state wrapper for @noble/hashes
76
+ * Maintains hasher instance for streaming operations
77
+ */
96
78
  class KeccakState {
97
79
  constructor() {
98
- this.s = new BigUint64Array(25);
99
- this.pos = 0;
100
- }
101
- }
102
-
103
- function ROL(a, offset) {
104
- return BigInt.asUintN(64, BigInt.asUintN(64, a << offset) ^ (a >> (64n - offset)));
105
- }
106
-
107
- function load64(x, xOffset) {
108
- let r = BigInt(0);
109
-
110
- for (let i = 0; i < 8; i++) r = BigInt.asUintN(64, r | BigInt.asUintN(64, BigInt(x[xOffset + i]) << BigInt(8 * i)));
111
-
112
- return r;
113
- }
114
-
115
- function store64(xP, xOffset, u) {
116
- const x = xP;
117
- for (let i = 0; i < 8; i++) x[xOffset + i] = Number((u >> BigInt(8 * i)) & 0xffn);
118
- }
119
-
120
- function KeccakF1600StatePermute(stateP) {
121
- const state = stateP;
122
- // copyFromState(A, state)
123
- let Aba = state[0];
124
- let Abe = state[1];
125
- let Abi = state[2];
126
- let Abo = state[3];
127
- let Abu = state[4];
128
- let Aga = state[5];
129
- let Age = state[6];
130
- let Agi = state[7];
131
- let Ago = state[8];
132
- let Agu = state[9];
133
- let Aka = state[10];
134
- let Ake = state[11];
135
- let Aki = state[12];
136
- let Ako = state[13];
137
- let Aku = state[14];
138
- let Ama = state[15];
139
- let Ame = state[16];
140
- let Ami = state[17];
141
- let Amo = state[18];
142
- let Amu = state[19];
143
- let Asa = state[20];
144
- let Ase = state[21];
145
- let Asi = state[22];
146
- let Aso = state[23];
147
- let Asu = state[24];
148
-
149
- for (let round = 0; round < NRounds; round += 2) {
150
- // prepareTheta
151
- let BCa = BigInt.asUintN(64, Aba ^ Aga ^ Aka ^ Ama ^ Asa);
152
- let BCe = BigInt.asUintN(64, Abe ^ Age ^ Ake ^ Ame ^ Ase);
153
- let BCi = BigInt.asUintN(64, Abi ^ Agi ^ Aki ^ Ami ^ Asi);
154
- let BCo = BigInt.asUintN(64, Abo ^ Ago ^ Ako ^ Amo ^ Aso);
155
- let BCu = BigInt.asUintN(64, Abu ^ Agu ^ Aku ^ Amu ^ Asu);
156
-
157
- // thetaRhoPiChiIotaPrepareTheta(round, A, E)
158
- let Da = BigInt.asUintN(64, BCu ^ ROL(BCe, 1n));
159
- let De = BigInt.asUintN(64, BCa ^ ROL(BCi, 1n));
160
- let Di = BigInt.asUintN(64, BCe ^ ROL(BCo, 1n));
161
- let Do = BigInt.asUintN(64, BCi ^ ROL(BCu, 1n));
162
- let Du = BigInt.asUintN(64, BCo ^ ROL(BCa, 1n));
163
-
164
- Aba = BigInt.asUintN(64, Aba ^ Da);
165
- BCa = Aba;
166
- Age = BigInt.asUintN(64, Age ^ De);
167
- BCe = ROL(Age, 44n);
168
- Aki = BigInt.asUintN(64, Aki ^ Di);
169
- BCi = ROL(Aki, 43n);
170
- Amo = BigInt.asUintN(64, Amo ^ Do);
171
- BCo = ROL(Amo, 21n);
172
- Asu = BigInt.asUintN(64, Asu ^ Du);
173
- BCu = ROL(Asu, 14n);
174
- let Eba = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
175
- Eba = BigInt.asUintN(64, Eba ^ KeccakFRoundConstants[round]);
176
- let Ebe = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
177
- let Ebi = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
178
- let Ebo = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
179
- let Ebu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
180
-
181
- Abo = BigInt.asUintN(64, Abo ^ Do);
182
- BCa = ROL(Abo, 28n);
183
- Agu = BigInt.asUintN(64, Agu ^ Du);
184
- BCe = ROL(Agu, 20n);
185
- Aka = BigInt.asUintN(64, Aka ^ Da);
186
- BCi = ROL(Aka, 3n);
187
- Ame = BigInt.asUintN(64, Ame ^ De);
188
- BCo = ROL(Ame, 45n);
189
- Asi = BigInt.asUintN(64, Asi ^ Di);
190
- BCu = ROL(Asi, 61n);
191
- let Ega = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
192
- let Ege = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
193
- let Egi = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
194
- let Ego = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
195
- let Egu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
196
-
197
- Abe = BigInt.asUintN(64, Abe ^ De);
198
- BCa = ROL(Abe, 1n);
199
- Agi = BigInt.asUintN(64, Agi ^ Di);
200
- BCe = ROL(Agi, 6n);
201
- Ako = BigInt.asUintN(64, Ako ^ Do);
202
- BCi = ROL(Ako, 25n);
203
- Amu = BigInt.asUintN(64, Amu ^ Du);
204
- BCo = ROL(Amu, 8n);
205
- Asa = BigInt.asUintN(64, Asa ^ Da);
206
- BCu = ROL(Asa, 18n);
207
- let Eka = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
208
- let Eke = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
209
- let Eki = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
210
- let Eko = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
211
- let Eku = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
212
-
213
- Abu = BigInt.asUintN(64, Abu ^ Du);
214
- BCa = ROL(Abu, 27n);
215
- Aga = BigInt.asUintN(64, Aga ^ Da);
216
- BCe = ROL(Aga, 36n);
217
- Ake = BigInt.asUintN(64, Ake ^ De);
218
- BCi = ROL(Ake, 10n);
219
- Ami = BigInt.asUintN(64, Ami ^ Di);
220
- BCo = ROL(Ami, 15n);
221
- Aso = BigInt.asUintN(64, Aso ^ Do);
222
- BCu = ROL(Aso, 56n);
223
- let Ema = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
224
- let Eme = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
225
- let Emi = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
226
- let Emo = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
227
- let Emu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
228
-
229
- Abi = BigInt.asUintN(64, Abi ^ Di);
230
- BCa = ROL(Abi, 62n);
231
- Ago = BigInt.asUintN(64, Ago ^ Do);
232
- BCe = ROL(Ago, 55n);
233
- Aku = BigInt.asUintN(64, Aku ^ Du);
234
- BCi = ROL(Aku, 39n);
235
- Ama = BigInt.asUintN(64, Ama ^ Da);
236
- BCo = ROL(Ama, 41n);
237
- Ase = BigInt.asUintN(64, Ase ^ De);
238
- BCu = ROL(Ase, 2n);
239
- let Esa = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
240
- let Ese = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
241
- let Esi = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
242
- let Eso = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
243
- let Esu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
244
-
245
- // prepareTheta
246
- BCa = BigInt.asUintN(64, Eba ^ Ega ^ Eka ^ Ema ^ Esa);
247
- BCe = BigInt.asUintN(64, Ebe ^ Ege ^ Eke ^ Eme ^ Ese);
248
- BCi = BigInt.asUintN(64, Ebi ^ Egi ^ Eki ^ Emi ^ Esi);
249
- BCo = BigInt.asUintN(64, Ebo ^ Ego ^ Eko ^ Emo ^ Eso);
250
- BCu = BigInt.asUintN(64, Ebu ^ Egu ^ Eku ^ Emu ^ Esu);
251
-
252
- // thetaRhoPiChiIotaPrepareTheta(round+1, E, A)
253
- Da = BigInt.asUintN(64, BCu ^ ROL(BCe, 1n));
254
- De = BigInt.asUintN(64, BCa ^ ROL(BCi, 1n));
255
- Di = BigInt.asUintN(64, BCe ^ ROL(BCo, 1n));
256
- Do = BigInt.asUintN(64, BCi ^ ROL(BCu, 1n));
257
- Du = BigInt.asUintN(64, BCo ^ ROL(BCa, 1n));
258
-
259
- Eba = BigInt.asUintN(64, Eba ^ Da);
260
- BCa = Eba;
261
- Ege = BigInt.asUintN(64, Ege ^ De);
262
- BCe = ROL(Ege, 44n);
263
- Eki = BigInt.asUintN(64, Eki ^ Di);
264
- BCi = ROL(Eki, 43n);
265
- Emo = BigInt.asUintN(64, Emo ^ Do);
266
- BCo = ROL(Emo, 21n);
267
- Esu = BigInt.asUintN(64, Esu ^ Du);
268
- BCu = ROL(Esu, 14n);
269
- Aba = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
270
- Aba = BigInt.asUintN(64, Aba ^ KeccakFRoundConstants[round + 1]);
271
- Abe = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
272
- Abi = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
273
- Abo = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
274
- Abu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
275
-
276
- Ebo = BigInt.asUintN(64, Ebo ^ Do);
277
- BCa = ROL(Ebo, 28n);
278
- Egu = BigInt.asUintN(64, Egu ^ Du);
279
- BCe = ROL(Egu, 20n);
280
- Eka = BigInt.asUintN(64, Eka ^ Da);
281
- BCi = ROL(Eka, 3n);
282
- Eme = BigInt.asUintN(64, Eme ^ De);
283
- BCo = ROL(Eme, 45n);
284
- Esi = BigInt.asUintN(64, Esi ^ Di);
285
- BCu = ROL(Esi, 61n);
286
- Aga = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
287
- Age = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
288
- Agi = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
289
- Ago = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
290
- Agu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
291
-
292
- Ebe = BigInt.asUintN(64, Ebe ^ De);
293
- BCa = ROL(Ebe, 1n);
294
- Egi = BigInt.asUintN(64, Egi ^ Di);
295
- BCe = ROL(Egi, 6n);
296
- Eko = BigInt.asUintN(64, Eko ^ Do);
297
- BCi = ROL(Eko, 25n);
298
- Emu = BigInt.asUintN(64, Emu ^ Du);
299
- BCo = ROL(Emu, 8n);
300
- Esa = BigInt.asUintN(64, Esa ^ Da);
301
- BCu = ROL(Esa, 18n);
302
- Aka = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
303
- Ake = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
304
- Aki = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
305
- Ako = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
306
- Aku = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
307
-
308
- Ebu = BigInt.asUintN(64, Ebu ^ Du);
309
- BCa = ROL(Ebu, 27n);
310
- Ega = BigInt.asUintN(64, Ega ^ Da);
311
- BCe = ROL(Ega, 36n);
312
- Eke = BigInt.asUintN(64, Eke ^ De);
313
- BCi = ROL(Eke, 10n);
314
- Emi = BigInt.asUintN(64, Emi ^ Di);
315
- BCo = ROL(Emi, 15n);
316
- Eso = BigInt.asUintN(64, Eso ^ Do);
317
- BCu = ROL(Eso, 56n);
318
- Ama = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
319
- Ame = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
320
- Ami = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
321
- Amo = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
322
- Amu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
323
-
324
- Ebi = BigInt.asUintN(64, Ebi ^ Di);
325
- BCa = ROL(Ebi, 62n);
326
- Ego = BigInt.asUintN(64, Ego ^ Do);
327
- BCe = ROL(Ego, 55n);
328
- Eku = BigInt.asUintN(64, Eku ^ Du);
329
- BCi = ROL(Eku, 39n);
330
- Ema = BigInt.asUintN(64, Ema ^ Da);
331
- BCo = ROL(Ema, 41n);
332
- Ese = BigInt.asUintN(64, Ese ^ De);
333
- BCu = ROL(Ese, 2n);
334
- Asa = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
335
- Ase = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
336
- Asi = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
337
- Aso = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
338
- Asu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
339
- }
340
-
341
- state[0] = Aba;
342
- state[1] = Abe;
343
- state[2] = Abi;
344
- state[3] = Abo;
345
- state[4] = Abu;
346
- state[5] = Aga;
347
- state[6] = Age;
348
- state[7] = Agi;
349
- state[8] = Ago;
350
- state[9] = Agu;
351
- state[10] = Aka;
352
- state[11] = Ake;
353
- state[12] = Aki;
354
- state[13] = Ako;
355
- state[14] = Aku;
356
- state[15] = Ama;
357
- state[16] = Ame;
358
- state[17] = Ami;
359
- state[18] = Amo;
360
- state[19] = Amu;
361
- state[20] = Asa;
362
- state[21] = Ase;
363
- state[22] = Asi;
364
- state[23] = Aso;
365
- state[24] = Asu;
366
- }
367
-
368
- function keccakInit(sP) {
369
- const s = sP;
370
- for (let i = 0; i < 25; i++) s[i] = 0n;
371
- }
372
-
373
- function keccakAbsorb(sP, posP, r, input) {
374
- const s = sP;
375
- let pos = posP;
376
- let inLen = input.length;
377
- let i;
378
- let inputOffset = 0;
379
- while (pos + inLen >= r) {
380
- for (i = pos; i < r; i++)
381
- s[Math.floor(i / 8)] = BigInt.asUintN(
382
- 64,
383
- s[Math.floor(i / 8)] ^ (BigInt(input[inputOffset++]) << BigInt(8 * (i % 8)))
384
- );
385
- inLen -= r - pos;
386
- KeccakF1600StatePermute(s);
387
- pos = 0;
388
- }
389
-
390
- for (i = pos; i < pos + inLen; i++) {
391
- s[Math.floor(i / 8)] = BigInt.asUintN(
392
- 64,
393
- s[Math.floor(i / 8)] ^ (BigInt(input[inputOffset++]) << BigInt(8 * (i % 8)))
394
- );
80
+ this.hasher = null;
81
+ this.finalized = false;
395
82
  }
396
-
397
- return i;
398
83
  }
399
84
 
400
- function keccakFinalize(sP, pos, r, p) {
401
- const s = sP;
402
- s[Math.floor(pos / 8)] = BigInt.asUintN(64, s[Math.floor(pos / 8)] ^ (BigInt(p) << BigInt(8 * (pos % 8))));
403
- s[Math.floor(r / 8) - 1] = BigInt.asUintN(64, s[Math.floor(r / 8) - 1] ^ (1n << 63n));
404
- }
85
+ // SHAKE-128 functions
405
86
 
406
- function keccakSqueeze(outP, s, posP, r) {
407
- let pos = posP;
408
- const out = outP;
409
- let outLen = out.length;
410
- let outputOffset = 0;
411
- let i = 0;
412
-
413
- while (outLen) {
414
- if (pos === r) {
415
- KeccakF1600StatePermute(s);
416
- pos = 0;
417
- }
418
- for (i = pos; i < r && i < pos + outLen; i++) out[outputOffset++] = s[Math.floor(i / 8)] >> BigInt(8 * (i % 8));
419
- outLen -= i - pos;
420
- pos = i;
421
- }
422
-
423
- return pos;
424
- }
425
-
426
- function keccakAbsorbOnce(sP, r, input, p) {
427
- const s = sP;
428
- let inLen = input.length;
429
- let inputOffset = 0;
430
- let i;
431
-
432
- for (i = 0; i < 25; i++) s[i] = 0;
433
-
434
- while (inLen >= r) {
435
- for (i = 0; i < Math.floor(r / 8); i++) s[i] = BigInt.asUintN(64, s[i] ^ load64(input, inputOffset + 8 * i));
436
- inputOffset += r;
437
- inLen -= r;
438
- KeccakF1600StatePermute(s);
439
- }
440
-
441
- for (i = 0; i < inLen; i++)
442
- s[Math.floor(i / 8)] = BigInt.asUintN(
443
- 64,
444
- s[Math.floor(i / 8)] ^ (BigInt(input[inputOffset + i]) << BigInt(8 * (i % 8)))
445
- );
446
-
447
- s[Math.floor(i / 8)] = BigInt.asUintN(64, s[Math.floor(i / 8)] ^ (BigInt(p) << BigInt(8 * (i % 8))));
448
- s[Math.floor((r - 1) / 8)] = BigInt.asUintN(64, s[Math.floor((r - 1) / 8)] ^ (1n << 63n));
449
- }
450
-
451
- function keccakSqueezeBlocks(output, outputOffsetP, nBlocksP, s, r) {
452
- let nBlocks = nBlocksP;
453
- let outputOffset = outputOffsetP;
454
- while (nBlocks) {
455
- KeccakF1600StatePermute(s);
456
- for (let i = 0; i < Math.floor(r / 8); i++) store64(output, outputOffset + 8 * i, s[i]);
457
- outputOffset += r;
458
- nBlocks -= 1;
459
- }
87
+ function shake128Init(state) {
88
+ state.hasher = sha3.shake128.create({});
89
+ state.finalized = false;
460
90
  }
461
91
 
462
- function shake128Init(stateP) {
463
- const state = stateP;
464
- keccakInit(state.s);
465
- state.pos = 0;
92
+ function shake128Absorb(state, input) {
93
+ state.hasher.update(input);
466
94
  }
467
95
 
468
- function shake128Absorb(stateP, input) {
469
- const state = stateP;
470
- state.pos = keccakAbsorb(state.s, state.pos, Shake128Rate, input);
471
- }
472
-
473
- function shake128Finalize(stateP) {
474
- const state = stateP;
475
- keccakFinalize(state.s, state.pos, Shake128Rate, 0x1f);
476
- state.pos = Shake128Rate;
477
- }
478
-
479
- function shake128Squeeze(out, stateP) {
480
- const state = stateP;
481
- state.pos = keccakSqueeze(out, state.s, state.pos, Shake128Rate);
482
- }
483
-
484
- function shake128AbsorbOnce(stateP, input) {
485
- const state = stateP;
486
- keccakAbsorbOnce(state.s, Shake128Rate, input, 0x1f);
487
- state.pos = Shake128Rate;
96
+ function shake128Finalize(state) {
97
+ // Mark as finalized - actual finalization happens on first xofInto call
98
+ state.finalized = true;
488
99
  }
489
100
 
490
101
  function shake128SqueezeBlocks(out, outputOffset, nBlocks, state) {
491
- keccakSqueezeBlocks(out, outputOffset, nBlocks, state.s, Shake128Rate);
102
+ const len = nBlocks * Shake128Rate;
103
+ const output = out.subarray(outputOffset, outputOffset + len);
104
+ state.hasher.xofInto(output);
492
105
  }
493
106
 
494
- function shake256Init(stateP) {
495
- const state = stateP;
496
- keccakInit(state.s);
497
- state.pos = 0;
107
+ // SHAKE-256 functions
108
+
109
+ function shake256Init(state) {
110
+ state.hasher = sha3.shake256.create({});
111
+ state.finalized = false;
498
112
  }
499
113
 
500
- function shake256Absorb(stateP, input) {
501
- const state = stateP;
502
- state.pos = keccakAbsorb(state.s, state.pos, Shake256Rate, input);
114
+ function shake256Absorb(state, input) {
115
+ state.hasher.update(input);
503
116
  }
504
117
 
505
- function shake256Finalize(stateP) {
506
- const state = stateP;
507
- keccakFinalize(state.s, state.pos, Shake256Rate, 0x1f);
508
- state.pos = Shake256Rate;
118
+ function shake256Finalize(state) {
119
+ // Mark as finalized - actual finalization happens on first xofInto call
120
+ state.finalized = true;
509
121
  }
510
122
 
511
123
  function shake256SqueezeBlocks(out, outputOffset, nBlocks, state) {
512
- keccakSqueezeBlocks(out, outputOffset, nBlocks, state.s, Shake256Rate);
124
+ const len = nBlocks * Shake256Rate;
125
+ const output = out.subarray(outputOffset, outputOffset + len);
126
+ state.hasher.xofInto(output);
513
127
  }
514
128
 
515
129
  function dilithiumShake128StreamInit(state, seed, nonce) {
@@ -567,9 +181,8 @@ function ntt(a) {
567
181
  const zeta = zetas[++k];
568
182
  for (j = start; j < start + len; ++j) {
569
183
  const t = Number(montgomeryReduce(BigInt.asIntN(64, BigInt(zeta) * BigInt(a[j + len]))));
570
- a[j + len] = a[j] - t; // eslint-disable-line no-param-reassign
571
- // eslint-disable-next-line
572
- a[j] = a[j] + t;
184
+ a[j + len] = a[j] - t;
185
+ a[j] += t;
573
186
  }
574
187
  }
575
188
  }
@@ -585,15 +198,14 @@ function invNTTToMont(a) {
585
198
  const zeta = BigInt.asIntN(32, BigInt(-zetas[--k]));
586
199
  for (j = start; j < start + len; ++j) {
587
200
  const t = a[j];
588
- a[j] = t + a[j + len]; // eslint-disable-line no-param-reassign
589
- a[j + len] = t - a[j + len]; // eslint-disable-line no-param-reassign
590
- a[j + len] = Number(montgomeryReduce(BigInt.asIntN(64, zeta * BigInt(a[j + len])))); // eslint-disable-line no-param-reassign
201
+ a[j] = t + a[j + len];
202
+ a[j + len] = t - a[j + len];
203
+ a[j + len] = Number(montgomeryReduce(BigInt.asIntN(64, zeta * BigInt(a[j + len]))));
591
204
  }
592
205
  }
593
206
  }
594
- // eslint-disable-next-line no-shadow
595
207
  for (let j = 0; j < N; ++j) {
596
- a[j] = Number(montgomeryReduce(BigInt.asIntN(64, f * BigInt(a[j])))); // eslint-disable-line no-param-reassign
208
+ a[j] = Number(montgomeryReduce(BigInt.asIntN(64, f * BigInt(a[j]))));
597
209
  }
598
210
  }
599
211
 
@@ -946,7 +558,7 @@ function polyT0Pack(rP, rOffset, a) {
946
558
  t[6] = (1 << (D - 1)) - a.coeffs[8 * i + 6];
947
559
  t[7] = (1 << (D - 1)) - a.coeffs[8 * i + 7];
948
560
 
949
- r[rOffset + 13 * i] = t[0]; // eslint-disable-line prefer-destructuring
561
+ r[rOffset + 13 * i] = t[0];
950
562
  r[rOffset + 13 * i + 1] = t[0] >> 8;
951
563
  r[rOffset + 13 * i + 1] |= t[1] << 5;
952
564
  r[rOffset + 13 * i + 2] = t[1] >> 3;
@@ -1026,7 +638,7 @@ function polyZPack(rP, rOffset, a) {
1026
638
  t[0] = GAMMA1 - a.coeffs[2 * i];
1027
639
  t[1] = GAMMA1 - a.coeffs[2 * i + 1];
1028
640
 
1029
- r[rOffset + 5 * i] = t[0]; // eslint-disable-line prefer-destructuring
641
+ r[rOffset + 5 * i] = t[0];
1030
642
  r[rOffset + 5 * i + 1] = t[0] >> 8;
1031
643
  r[rOffset + 5 * i + 2] = t[0] >> 16;
1032
644
  r[rOffset + 5 * i + 2] |= t[1] << 4;
@@ -1073,7 +685,7 @@ function polyVecMatrixExpand(mat, rho) {
1073
685
 
1074
686
  function polyVecMatrixPointWiseMontgomery(t, mat, v) {
1075
687
  for (let i = 0; i < K; ++i) {
1076
- polyVecLPointWiseAccMontgomery(t.vec[i], mat[i], v); // eslint-disable-line no-use-before-define
688
+ polyVecLPointWiseAccMontgomery(t.vec[i], mat[i], v);
1077
689
  }
1078
690
  }
1079
691
 
@@ -1274,10 +886,10 @@ function packSk(skp, rho, tr, key, t0, s1, s2) {
1274
886
  }
1275
887
  skOffset += SeedBytes;
1276
888
 
1277
- for (let i = 0; i < SeedBytes; ++i) {
889
+ for (let i = 0; i < TRBytes; ++i) {
1278
890
  sk[skOffset + i] = tr[i];
1279
891
  }
1280
- skOffset += SeedBytes;
892
+ skOffset += TRBytes;
1281
893
 
1282
894
  for (let i = 0; i < L; ++i) {
1283
895
  polyEtaPack(sk, skOffset + i * PolyETAPackedBytes, s1.vec[i]);
@@ -1309,10 +921,10 @@ function unpackSk(rhoP, trP, keyP, t0, s1, s2, sk) {
1309
921
  }
1310
922
  skOffset += SeedBytes;
1311
923
 
1312
- for (let i = 0; i < SeedBytes; ++i) {
924
+ for (let i = 0; i < TRBytes; ++i) {
1313
925
  tr[i] = sk[skOffset + i];
1314
926
  }
1315
- skOffset += SeedBytes;
927
+ skOffset += TRBytes;
1316
928
 
1317
929
  for (let i = 0; i < L; ++i) {
1318
930
  polyEtaUnpack(s1.vec[i], sk, skOffset + i * PolyETAPackedBytes);
@@ -1406,6 +1018,36 @@ function unpackSig(cP, z, hP, sig) {
1406
1018
 
1407
1019
  const randomBytes = pkg;
1408
1020
 
1021
+ /**
1022
+ * Convert hex string to Uint8Array
1023
+ * @param {string} hex - Hex-encoded string
1024
+ * @returns {Uint8Array} Decoded bytes
1025
+ * @private
1026
+ */
1027
+ function hexToBytes(hex) {
1028
+ const len = hex.length / 2;
1029
+ const result = new Uint8Array(len);
1030
+ for (let i = 0; i < len; i++) {
1031
+ result[i] = parseInt(hex.substr(i * 2, 2), 16);
1032
+ }
1033
+ return result;
1034
+ }
1035
+
1036
+ /**
1037
+ * Generate a Dilithium-5 key pair.
1038
+ *
1039
+ * @param {Uint8Array|null} passedSeed - Optional 32-byte seed for deterministic key generation.
1040
+ * Pass null for random key generation.
1041
+ * @param {Uint8Array} pk - Output buffer for public key (must be CryptoPublicKeyBytes = 2592 bytes)
1042
+ * @param {Uint8Array} sk - Output buffer for secret key (must be CryptoSecretKeyBytes = 4896 bytes)
1043
+ * @returns {Uint8Array} The seed used for key generation (useful when passedSeed is null)
1044
+ * @throws {Error} If pk/sk buffers are null or wrong size, or if seed is wrong size
1045
+ *
1046
+ * @example
1047
+ * const pk = new Uint8Array(CryptoPublicKeyBytes);
1048
+ * const sk = new Uint8Array(CryptoSecretKeyBytes);
1049
+ * const seed = cryptoSignKeypair(null, pk, sk);
1050
+ */
1409
1051
  function cryptoSignKeypair(passedSeed, pk, sk) {
1410
1052
  try {
1411
1053
  if (pk.length !== CryptoPublicKeyBytes) {
@@ -1421,8 +1063,15 @@ function cryptoSignKeypair(passedSeed, pk, sk) {
1421
1063
  throw new Error(`${e.message}`);
1422
1064
  }
1423
1065
  }
1424
- // eslint-disable-next-line no-unused-vars
1425
- const mat = new Array(K).fill().map((_) => new PolyVecL());
1066
+
1067
+ // Validate seed length if provided
1068
+ if (passedSeed !== null && passedSeed !== undefined) {
1069
+ if (passedSeed.length !== SeedBytes) {
1070
+ throw new Error(`invalid seed length ${passedSeed.length} | Expected length ${SeedBytes}`);
1071
+ }
1072
+ }
1073
+
1074
+ const mat = new Array(K).fill().map(() => new PolyVecL());
1426
1075
  const s1 = new PolyVecL();
1427
1076
  const s2 = new PolyVecK();
1428
1077
  const t1 = new PolyVecK();
@@ -1431,10 +1080,8 @@ function cryptoSignKeypair(passedSeed, pk, sk) {
1431
1080
  // Get randomness for rho, rhoPrime and key
1432
1081
  const seed = passedSeed || randomBytes(SeedBytes);
1433
1082
 
1434
- const state = new sha3.SHAKE(256);
1435
- let outputLength = 2 * SeedBytes + CRHBytes;
1436
- state.update(seed);
1437
- const seedBuf = state.digest({ buffer: Buffer.alloc(outputLength) });
1083
+ const outputLength = 2 * SeedBytes + CRHBytes;
1084
+ const seedBuf = sha3.shake256.create({}).update(seed).xof(outputLength);
1438
1085
  const rho = seedBuf.slice(0, SeedBytes);
1439
1086
  const rhoPrime = seedBuf.slice(SeedBytes, SeedBytes + CRHBytes);
1440
1087
  const key = seedBuf.slice(SeedBytes + CRHBytes);
@@ -1463,30 +1110,42 @@ function cryptoSignKeypair(passedSeed, pk, sk) {
1463
1110
  packPk(pk, rho, t1);
1464
1111
 
1465
1112
  // Compute H(rho, t1) and write secret key
1466
- const hasher = new sha3.SHAKE(256);
1467
- outputLength = SeedBytes;
1468
- hasher.update(Buffer.from(pk, 'hex'));
1469
- const tr = new Uint8Array(hasher.digest());
1113
+ const tr = sha3.shake256.create({}).update(pk).xof(TRBytes);
1470
1114
  packSk(sk, rho, tr, key, t0, s1, s2);
1471
1115
 
1472
1116
  return seed;
1473
1117
  }
1474
1118
 
1119
+ /**
1120
+ * Create a detached signature for a message.
1121
+ *
1122
+ * Uses the Dilithium-5 (Round 3) signing algorithm with rejection sampling.
1123
+ *
1124
+ * @param {Uint8Array} sig - Output buffer for signature (must be at least CryptoBytes = 4595 bytes)
1125
+ * @param {string|Uint8Array} m - Message to sign (hex string or Uint8Array)
1126
+ * @param {Uint8Array} sk - Secret key (must be CryptoSecretKeyBytes = 4896 bytes)
1127
+ * @param {boolean} randomizedSigning - If true, use random nonce for hedged signing.
1128
+ * If false, use deterministic nonce derived from message and key.
1129
+ * @returns {number} 0 on success
1130
+ * @throws {Error} If sk is wrong size
1131
+ *
1132
+ * @example
1133
+ * const sig = new Uint8Array(CryptoBytes);
1134
+ * cryptoSignSignature(sig, message, sk, false);
1135
+ */
1475
1136
  function cryptoSignSignature(sig, m, sk, randomizedSigning) {
1476
1137
  if (sk.length !== CryptoSecretKeyBytes) {
1477
1138
  throw new Error(`invalid sk length ${sk.length} | Expected length ${CryptoSecretKeyBytes}`);
1478
1139
  }
1479
1140
 
1480
1141
  const rho = new Uint8Array(SeedBytes);
1481
- const tr = new Uint8Array(SeedBytes);
1142
+ const tr = new Uint8Array(TRBytes);
1482
1143
  const key = new Uint8Array(SeedBytes);
1483
1144
  let rhoPrime = new Uint8Array(CRHBytes);
1484
1145
  let nonce = 0;
1485
- let state = null;
1486
1146
  const mat = Array(K)
1487
1147
  .fill()
1488
- // eslint-disable-next-line no-unused-vars
1489
- .map((_) => new PolyVecL());
1148
+ .map(() => new PolyVecL());
1490
1149
  const s1 = new PolyVecL();
1491
1150
  const y = new PolyVecL();
1492
1151
  const z = new PolyVecL();
@@ -1499,19 +1158,14 @@ function cryptoSignSignature(sig, m, sk, randomizedSigning) {
1499
1158
 
1500
1159
  unpackSk(rho, tr, key, t0, s1, s2, sk);
1501
1160
 
1502
- state = new sha3.SHAKE(256);
1503
- let outputLength = CRHBytes;
1504
- state.update(Buffer.from(tr, 'hex'));
1505
- state.update(Buffer.from(m, 'hex'));
1506
- const mu = new Uint8Array(state.digest({ buffer: Buffer.alloc(outputLength) }));
1161
+ // Convert hex message to bytes
1162
+ const mBytes = typeof m === 'string' ? hexToBytes(m) : m;
1163
+ const mu = sha3.shake256.create({}).update(tr).update(mBytes).xof(CRHBytes);
1507
1164
 
1508
- if (randomizedSigning) rhoPrime = new Uint8Array(randomBytes(CRHBytes));
1509
- else {
1510
- state = new sha3.SHAKE(256);
1511
- outputLength = CRHBytes;
1512
- state.update(Buffer.from(key, 'hex'));
1513
- state.update(Buffer.from(mu, 'hex'));
1514
- rhoPrime.set(state.digest({ buffer: Buffer.alloc(outputLength) }));
1165
+ if (randomizedSigning) {
1166
+ rhoPrime = new Uint8Array(randomBytes(CRHBytes));
1167
+ } else {
1168
+ rhoPrime = sha3.shake256.create({}).update(key).update(mu).xof(CRHBytes);
1515
1169
  }
1516
1170
 
1517
1171
  polyVecMatrixExpand(mat, rho);
@@ -1519,7 +1173,6 @@ function cryptoSignSignature(sig, m, sk, randomizedSigning) {
1519
1173
  polyVecKNTT(s2);
1520
1174
  polyVecKNTT(t0);
1521
1175
 
1522
- // eslint-disable-next-line no-constant-condition
1523
1176
  while (true) {
1524
1177
  polyVecLUniformGamma1(y, rhoPrime, nonce++);
1525
1178
  // Matrix-vector multiplication
@@ -1534,11 +1187,12 @@ function cryptoSignSignature(sig, m, sk, randomizedSigning) {
1534
1187
  polyVecKDecompose(w1, w0, w1);
1535
1188
  polyVecKPackW1(sig, w1);
1536
1189
 
1537
- state = new sha3.SHAKE(256);
1538
- outputLength = SeedBytes;
1539
- state.update(Buffer.from(mu, 'hex'));
1540
- state.update(Buffer.from(sig.slice(0, K * PolyW1PackedBytes)), 'hex');
1541
- sig.set(state.digest({ buffer: Buffer.alloc(outputLength) }));
1190
+ const cHash = sha3.shake256
1191
+ .create({})
1192
+ .update(mu)
1193
+ .update(sig.slice(0, K * PolyW1PackedBytes))
1194
+ .xof(SeedBytes);
1195
+ sig.set(cHash);
1542
1196
 
1543
1197
  polyChallenge(cp, sig);
1544
1198
  polyNTT(cp);
@@ -1549,7 +1203,7 @@ function cryptoSignSignature(sig, m, sk, randomizedSigning) {
1549
1203
  polyVecLAdd(z, z, y);
1550
1204
  polyVecLReduce(z);
1551
1205
  if (polyVecLChkNorm(z, GAMMA1 - BETA) !== 0) {
1552
- continue; // eslint-disable-line no-continue
1206
+ continue;
1553
1207
  }
1554
1208
 
1555
1209
  polyVecKPointWisePolyMontgomery(h, cp, s2);
@@ -1557,20 +1211,20 @@ function cryptoSignSignature(sig, m, sk, randomizedSigning) {
1557
1211
  polyVecKSub(w0, w0, h);
1558
1212
  polyVecKReduce(w0);
1559
1213
  if (polyVecKChkNorm(w0, GAMMA2 - BETA) !== 0) {
1560
- continue; // eslint-disable-line no-continue
1214
+ continue;
1561
1215
  }
1562
1216
 
1563
1217
  polyVecKPointWisePolyMontgomery(h, cp, t0);
1564
1218
  polyVecKInvNTTToMont(h);
1565
1219
  polyVecKReduce(h);
1566
1220
  if (polyVecKChkNorm(h, GAMMA2) !== 0) {
1567
- continue; // eslint-disable-line no-continue
1221
+ continue;
1568
1222
  }
1569
1223
 
1570
1224
  polyVecKAdd(w0, w0, h);
1571
1225
  const n = polyVecKMakeHint(h, w0, w1);
1572
1226
  if (n > OMEGA) {
1573
- continue; // eslint-disable-line no-continue
1227
+ continue;
1574
1228
  }
1575
1229
 
1576
1230
  packSig(sig, sig, z, h);
@@ -1578,6 +1232,22 @@ function cryptoSignSignature(sig, m, sk, randomizedSigning) {
1578
1232
  }
1579
1233
  }
1580
1234
 
1235
+ /**
1236
+ * Sign a message, returning signature concatenated with message.
1237
+ *
1238
+ * This is the combined sign operation that produces a "signed message" containing
1239
+ * both the signature and the original message (signature || message).
1240
+ *
1241
+ * @param {Uint8Array} msg - Message to sign
1242
+ * @param {Uint8Array} sk - Secret key (must be CryptoSecretKeyBytes = 4896 bytes)
1243
+ * @param {boolean} randomizedSigning - If true, use random nonce; if false, deterministic
1244
+ * @returns {Uint8Array} Signed message (CryptoBytes + msg.length bytes)
1245
+ * @throws {Error} If signing fails
1246
+ *
1247
+ * @example
1248
+ * const signedMsg = cryptoSign(message, sk, false);
1249
+ * // signedMsg contains: signature (4595 bytes) || message
1250
+ */
1581
1251
  function cryptoSign(msg, sk, randomizedSigning) {
1582
1252
  const sm = new Uint8Array(CryptoBytes + msg.length);
1583
1253
  const mLen = msg.length;
@@ -1592,6 +1262,22 @@ function cryptoSign(msg, sk, randomizedSigning) {
1592
1262
  return sm;
1593
1263
  }
1594
1264
 
1265
+ /**
1266
+ * Verify a detached signature.
1267
+ *
1268
+ * Performs constant-time verification to prevent timing side-channel attacks.
1269
+ *
1270
+ * @param {Uint8Array} sig - Signature to verify (must be CryptoBytes = 4595 bytes)
1271
+ * @param {string|Uint8Array} m - Message that was signed (hex string or Uint8Array)
1272
+ * @param {Uint8Array} pk - Public key (must be CryptoPublicKeyBytes = 2592 bytes)
1273
+ * @returns {boolean} true if signature is valid, false otherwise
1274
+ *
1275
+ * @example
1276
+ * const isValid = cryptoSignVerify(signature, message, pk);
1277
+ * if (!isValid) {
1278
+ * throw new Error('Invalid signature');
1279
+ * }
1280
+ */
1595
1281
  function cryptoSignVerify(sig, m, pk) {
1596
1282
  let i;
1597
1283
  const buf = new Uint8Array(K * PolyW1PackedBytes);
@@ -1600,8 +1286,7 @@ function cryptoSignVerify(sig, m, pk) {
1600
1286
  const c = new Uint8Array(SeedBytes);
1601
1287
  const c2 = new Uint8Array(SeedBytes);
1602
1288
  const cp = new Poly();
1603
- // eslint-disable-next-line no-unused-vars
1604
- const mat = new Array(K).fill().map((_) => new PolyVecL());
1289
+ const mat = new Array(K).fill().map(() => new PolyVecL());
1605
1290
  const z = new PolyVecL();
1606
1291
  const t1 = new PolyVecK();
1607
1292
  const w1 = new PolyVecK();
@@ -1623,16 +1308,13 @@ function cryptoSignVerify(sig, m, pk) {
1623
1308
  }
1624
1309
 
1625
1310
  /* Compute CRH(H(rho, t1), msg) */
1626
- let state = new sha3.SHAKE(256);
1627
- let outputLength = SeedBytes;
1628
- state.update(pk.slice(0, CryptoPublicKeyBytes));
1629
- mu.set(state.digest({ buffer: Buffer.alloc(outputLength) }));
1311
+ const tr = sha3.shake256.create({}).update(pk).xof(TRBytes);
1312
+ mu.set(tr);
1630
1313
 
1631
- state = new sha3.SHAKE(256);
1632
- outputLength = CRHBytes;
1633
- state.update(Buffer.from(mu.slice(0, SeedBytes), 'hex'));
1634
- state.update(Buffer.from(m, 'hex'));
1635
- mu.set(state.digest({ buffer: Buffer.alloc(outputLength) }));
1314
+ // Convert hex message to bytes
1315
+ const mBytes = typeof m === 'string' ? hexToBytes(m) : m;
1316
+ const muFull = sha3.shake256.create({}).update(mu.slice(0, TRBytes)).update(mBytes).xof(CRHBytes);
1317
+ mu.set(muFull);
1636
1318
 
1637
1319
  /* Matrix-vector multiplication; compute Az - c2^dt1 */
1638
1320
  polyChallenge(cp, c);
@@ -1656,16 +1338,33 @@ function cryptoSignVerify(sig, m, pk) {
1656
1338
  polyVecKPackW1(buf, w1);
1657
1339
 
1658
1340
  /* Call random oracle and verify challenge */
1659
- state = new sha3.SHAKE(256);
1660
- outputLength = SeedBytes;
1661
- state.update(Buffer.from(mu, 'hex'));
1662
- state.update(Buffer.from(buf, 'hex'));
1663
- c2.set(state.digest({ buffer: Buffer.alloc(outputLength) }));
1664
-
1665
- for (i = 0; i < SeedBytes; ++i) if (c[i] !== c2[i]) return false;
1666
- return true;
1667
- }
1668
-
1341
+ const c2Hash = sha3.shake256.create({}).update(mu).update(buf).xof(SeedBytes);
1342
+ c2.set(c2Hash);
1343
+
1344
+ // Constant-time comparison to prevent timing attacks
1345
+ let diff = 0;
1346
+ for (i = 0; i < SeedBytes; ++i) {
1347
+ diff |= c[i] ^ c2[i];
1348
+ }
1349
+ return diff === 0;
1350
+ }
1351
+
1352
+ /**
1353
+ * Open a signed message (verify and extract message).
1354
+ *
1355
+ * This is the counterpart to cryptoSign(). It verifies the signature and
1356
+ * extracts the original message from a signed message.
1357
+ *
1358
+ * @param {Uint8Array} sm - Signed message (signature || message)
1359
+ * @param {Uint8Array} pk - Public key (must be CryptoPublicKeyBytes = 2592 bytes)
1360
+ * @returns {Uint8Array|undefined} The original message if valid, undefined if verification fails
1361
+ *
1362
+ * @example
1363
+ * const message = cryptoSignOpen(signedMsg, pk);
1364
+ * if (message === undefined) {
1365
+ * throw new Error('Invalid signature');
1366
+ * }
1367
+ */
1669
1368
  function cryptoSignOpen(sm, pk) {
1670
1369
  if (sm.length < CryptoBytes) {
1671
1370
  return undefined;
@@ -1680,10 +1379,58 @@ function cryptoSignOpen(sm, pk) {
1680
1379
  return msg;
1681
1380
  }
1682
1381
 
1683
- Object.defineProperty(exports, "SHAKE", {
1684
- enumerable: true,
1685
- get: function () { return sha3.SHAKE; }
1686
- });
1382
+ /**
1383
+ * Security utilities for Dilithium5
1384
+ *
1385
+ * IMPORTANT: JavaScript cannot guarantee secure memory zeroization.
1386
+ * See SECURITY.md for details on limitations.
1387
+ */
1388
+
1389
+ /**
1390
+ * Attempts to zero out a Uint8Array buffer.
1391
+ *
1392
+ * WARNING: This is a BEST-EFFORT operation. Due to JavaScript/JIT limitations:
1393
+ * - The write may be optimized away if the buffer is unused afterward
1394
+ * - Copies may exist in garbage collector memory
1395
+ * - Data may have been swapped to disk
1396
+ *
1397
+ * For high-security applications, consider native implementations (go-qrllib)
1398
+ * or hardware security modules.
1399
+ *
1400
+ * @param {Uint8Array} buffer - The buffer to zero
1401
+ * @returns {void}
1402
+ */
1403
+ function zeroize(buffer) {
1404
+ if (!(buffer instanceof Uint8Array)) {
1405
+ throw new TypeError('zeroize requires a Uint8Array');
1406
+ }
1407
+ // Use fill(0) for zeroing - best effort
1408
+ buffer.fill(0);
1409
+ // Additional volatile-like access to discourage optimization
1410
+ // (This is a hint to the JIT, not a guarantee)
1411
+ if (buffer.length > 0 && buffer[0] !== 0) {
1412
+ throw new Error('zeroize failed'); // Should never happen
1413
+ }
1414
+ }
1415
+
1416
+ /**
1417
+ * Checks if a buffer is all zeros.
1418
+ * Uses constant-time comparison to avoid timing leaks.
1419
+ *
1420
+ * @param {Uint8Array} buffer - The buffer to check
1421
+ * @returns {boolean} True if all bytes are zero
1422
+ */
1423
+ function isZero(buffer) {
1424
+ if (!(buffer instanceof Uint8Array)) {
1425
+ throw new TypeError('isZero requires a Uint8Array');
1426
+ }
1427
+ let acc = 0;
1428
+ for (let i = 0; i < buffer.length; i++) {
1429
+ acc |= buffer[i];
1430
+ }
1431
+ return acc === 0;
1432
+ }
1433
+
1687
1434
  exports.BETA = BETA;
1688
1435
  exports.CRHBytes = CRHBytes;
1689
1436
  exports.CryptoBytes = CryptoBytes;
@@ -1694,12 +1441,9 @@ exports.ETA = ETA;
1694
1441
  exports.GAMMA1 = GAMMA1;
1695
1442
  exports.GAMMA2 = GAMMA2;
1696
1443
  exports.K = K;
1697
- exports.KeccakF1600StatePermute = KeccakF1600StatePermute;
1698
- exports.KeccakFRoundConstants = KeccakFRoundConstants;
1699
1444
  exports.KeccakState = KeccakState;
1700
1445
  exports.L = L;
1701
1446
  exports.N = N;
1702
- exports.NRounds = NRounds;
1703
1447
  exports.OMEGA = OMEGA;
1704
1448
  exports.Poly = Poly;
1705
1449
  exports.PolyETAPackedBytes = PolyETAPackedBytes;
@@ -1715,13 +1459,13 @@ exports.PolyW1PackedBytes = PolyW1PackedBytes;
1715
1459
  exports.PolyZPackedBytes = PolyZPackedBytes;
1716
1460
  exports.Q = Q;
1717
1461
  exports.QInv = QInv;
1718
- exports.ROL = ROL;
1719
1462
  exports.SeedBytes = SeedBytes;
1720
1463
  exports.Shake128Rate = Shake128Rate;
1721
1464
  exports.Shake256Rate = Shake256Rate;
1722
1465
  exports.Stream128BlockBytes = Stream128BlockBytes;
1723
1466
  exports.Stream256BlockBytes = Stream256BlockBytes;
1724
1467
  exports.TAU = TAU;
1468
+ exports.TRBytes = TRBytes;
1725
1469
  exports.cAddQ = cAddQ;
1726
1470
  exports.cryptoSign = cryptoSign;
1727
1471
  exports.cryptoSignKeypair = cryptoSignKeypair;
@@ -1732,13 +1476,7 @@ exports.decompose = decompose;
1732
1476
  exports.dilithiumShake128StreamInit = dilithiumShake128StreamInit;
1733
1477
  exports.dilithiumShake256StreamInit = dilithiumShake256StreamInit;
1734
1478
  exports.invNTTToMont = invNTTToMont;
1735
- exports.keccakAbsorb = keccakAbsorb;
1736
- exports.keccakAbsorbOnce = keccakAbsorbOnce;
1737
- exports.keccakFinalize = keccakFinalize;
1738
- exports.keccakInit = keccakInit;
1739
- exports.keccakSqueeze = keccakSqueeze;
1740
- exports.keccakSqueezeBlocks = keccakSqueezeBlocks;
1741
- exports.load64 = load64;
1479
+ exports.isZero = isZero;
1742
1480
  exports.makeHint = makeHint;
1743
1481
  exports.montgomeryReduce = montgomeryReduce;
1744
1482
  exports.ntt = ntt;
@@ -1802,24 +1540,16 @@ exports.reduce32 = reduce32;
1802
1540
  exports.rejEta = rejEta;
1803
1541
  exports.rejUniform = rejUniform;
1804
1542
  exports.shake128Absorb = shake128Absorb;
1805
- exports.shake128AbsorbOnce = shake128AbsorbOnce;
1806
1543
  exports.shake128Finalize = shake128Finalize;
1807
1544
  exports.shake128Init = shake128Init;
1808
- exports.shake128Squeeze = shake128Squeeze;
1809
1545
  exports.shake128SqueezeBlocks = shake128SqueezeBlocks;
1810
1546
  exports.shake256Absorb = shake256Absorb;
1811
1547
  exports.shake256Finalize = shake256Finalize;
1812
1548
  exports.shake256Init = shake256Init;
1813
1549
  exports.shake256SqueezeBlocks = shake256SqueezeBlocks;
1814
- exports.store64 = store64;
1815
1550
  exports.unpackPk = unpackPk;
1816
1551
  exports.unpackSig = unpackSig;
1817
1552
  exports.unpackSk = unpackSk;
1818
1553
  exports.useHint = useHint;
1554
+ exports.zeroize = zeroize;
1819
1555
  exports.zetas = zetas;
1820
- Object.keys(pkg).forEach(function (k) {
1821
- if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
1822
- enumerable: true,
1823
- get: function () { return pkg[k]; }
1824
- });
1825
- });