@theqrl/dilithium5 0.1.1 → 0.2.0

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