@theqrl/mldsa87 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.
@@ -0,0 +1,1596 @@
1
+ 'use strict';
2
+
3
+ var sha3 = require('@noble/hashes/sha3');
4
+ var pkg = require('randombytes');
5
+
6
+ const Shake128Rate = 168;
7
+ const Shake256Rate = 136;
8
+ const Stream128BlockBytes = Shake128Rate;
9
+ const Stream256BlockBytes = Shake256Rate;
10
+
11
+ const SeedBytes = 32;
12
+ const CRHBytes = 64;
13
+ const TRBytes = 64;
14
+ const RNDBytes = 32;
15
+ const N = 256;
16
+ const Q = 8380417;
17
+ const QInv = 58728449;
18
+ const D = 13;
19
+
20
+ const K = 8;
21
+ const L = 7;
22
+ const ETA = 2;
23
+ const TAU = 60;
24
+ const BETA = 120;
25
+ const GAMMA1 = 1 << 19;
26
+ const GAMMA2 = Math.floor((Q - 1) / 32);
27
+ const OMEGA = 75;
28
+ const CTILDEBytes = 64;
29
+
30
+ const PolyT1PackedBytes = 320;
31
+ const PolyT0PackedBytes = 416;
32
+ const PolyETAPackedBytes = 96;
33
+ const PolyZPackedBytes = 640;
34
+ const PolyVecHPackedBytes = OMEGA + K;
35
+ const PolyW1PackedBytes = 128;
36
+
37
+ const CryptoPublicKeyBytes = SeedBytes + K * PolyT1PackedBytes;
38
+ const CryptoSecretKeyBytes =
39
+ 2 * SeedBytes + TRBytes + L * PolyETAPackedBytes + K * PolyETAPackedBytes + K * PolyT0PackedBytes;
40
+ const CryptoBytes = CTILDEBytes + L * PolyZPackedBytes + PolyVecHPackedBytes;
41
+
42
+ const PolyUniformNBlocks = Math.floor((768 + Stream128BlockBytes - 1) / Stream128BlockBytes);
43
+ const PolyUniformETANBlocks = Math.floor((136 + Stream256BlockBytes - 1) / Stream256BlockBytes);
44
+ const PolyUniformGamma1NBlocks = Math.floor((PolyZPackedBytes + Stream256BlockBytes - 1) / Stream256BlockBytes);
45
+
46
+ const zetas = [
47
+ 0, 25847, -2608894, -518909, 237124, -777960, -876248, 466468, 1826347, 2353451, -359251, -2091905, 3119733, -2884855,
48
+ 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488, -1119584, 2619752, -2108549, -2118186, -3859737,
49
+ -1399561, -3277672, 1757237, -19422, 4010497, 280005, 2706023, 95776, 3077325, 3530437, -1661693, -3592148, -2537516,
50
+ 3915439, -3861115, -3043716, 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, -1643818, 3505694,
51
+ -3821735, 3507263, -2140649, -1600420, 3699596, 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, -2797779,
52
+ -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, 2176455, -1585221, -1257611, 1939314, -4083598, -1000202,
53
+ -3190144, -3157330, -3632928, 126922, 3412210, -983419, 2147896, 2715295, -2967645, -3693493, -411027, -2477047,
54
+ -671102, -1228525, -22981, -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, 508951, 3097992, 44288,
55
+ -1100098, 904516, 3958618, -3724342, -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, 189548, -3553272,
56
+ 3159746, -1851402, -2409325, -177440, 1315589, 1341330, 1285669, -1584928, -812732, -1439742, -3019102, -3881060,
57
+ -3628969, 3839961, 2091667, 3407706, 2316500, 3817976, -3342478, 2244091, -2446433, -3562462, 266997, 2434439,
58
+ -1235728, 3513181, -3520352, -3759364, -1197226, -3193378, 900702, 1859098, 909542, 819034, 495491, -1613174, -43260,
59
+ -522500, -655327, -3122442, 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, 286988, -2437823, 4108315,
60
+ 3437287, -3342277, 1735879, 203044, 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, 1595974, -3767016,
61
+ 1250494, 2635921, -3548272, -2994039, 1869119, 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100,
62
+ 1312455, 3306115, -1962642, -1279661, 1917081, -2546312, -1374803, 1500165, 777191, 2235880, 3406031, -542412,
63
+ -2831860, -1671176, -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, 2454455, -164721, 1957272,
64
+ 3369112, 185531, -1207385, -3183426, 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, -3038916, 3523897,
65
+ 3866901, 269760, 2213111, -975884, 1717735, 472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, -260646,
66
+ -3833893, -2939036, -2235985, -420899, -2286327, 183443, -976891, 1612842, -3545687, -554416, 3919660, -48306,
67
+ -1362209, 3937738, 1400424, -846154, 1976782,
68
+ ];
69
+
70
+ /**
71
+ * FIPS 202 SHAKE functions using @noble/hashes
72
+ * Provides streaming XOF (extendable output function) interface
73
+ */
74
+
75
+
76
+ /**
77
+ * Keccak state wrapper for @noble/hashes
78
+ * Maintains hasher instance for streaming operations
79
+ */
80
+ class KeccakState {
81
+ constructor() {
82
+ this.hasher = null;
83
+ this.finalized = false;
84
+ }
85
+ }
86
+
87
+ // SHAKE-128 functions
88
+
89
+ function shake128Init(state) {
90
+ state.hasher = sha3.shake128.create({});
91
+ state.finalized = false;
92
+ }
93
+
94
+ function shake128Absorb(state, input) {
95
+ state.hasher.update(input);
96
+ }
97
+
98
+ function shake128Finalize(state) {
99
+ // Mark as finalized - actual finalization happens on first xofInto call
100
+ state.finalized = true;
101
+ }
102
+
103
+ function shake128SqueezeBlocks(out, outputOffset, nBlocks, state) {
104
+ const len = nBlocks * Shake128Rate;
105
+ const output = out.subarray(outputOffset, outputOffset + len);
106
+ state.hasher.xofInto(output);
107
+ }
108
+
109
+ // SHAKE-256 functions
110
+
111
+ function shake256Init(state) {
112
+ state.hasher = sha3.shake256.create({});
113
+ state.finalized = false;
114
+ }
115
+
116
+ function shake256Absorb(state, input) {
117
+ state.hasher.update(input);
118
+ }
119
+
120
+ function shake256Finalize(state) {
121
+ // Mark as finalized - actual finalization happens on first xofInto call
122
+ state.finalized = true;
123
+ }
124
+
125
+ function shake256SqueezeBlocks(out, outputOffset, nBlocks, state) {
126
+ const len = nBlocks * Shake256Rate;
127
+ const output = out.subarray(outputOffset, outputOffset + len);
128
+ state.hasher.xofInto(output);
129
+ }
130
+
131
+ function mldsaShake128StreamInit(state, seed, nonce) {
132
+ if (seed.length !== SeedBytes) {
133
+ throw new Error(`invalid seed length ${seed.length} | expected ${SeedBytes}`);
134
+ }
135
+ const t = new Uint8Array(2);
136
+ t[0] = nonce & 0xff;
137
+ t[1] = nonce >> 8;
138
+
139
+ shake128Init(state);
140
+ shake128Absorb(state, seed);
141
+ shake128Absorb(state, t);
142
+ shake128Finalize(state);
143
+ }
144
+
145
+ function mldsaShake256StreamInit(state, seed, nonce) {
146
+ if (seed.length !== CRHBytes) {
147
+ throw new Error(`invalid seed length ${seed.length} | expected ${CRHBytes}`);
148
+ }
149
+ const t = new Uint8Array(2);
150
+ t[0] = nonce & 0xff;
151
+ t[1] = nonce >> 8;
152
+
153
+ shake256Init(state);
154
+ shake256Absorb(state, seed);
155
+ shake256Absorb(state, t);
156
+ shake256Finalize(state);
157
+ }
158
+
159
+ function montgomeryReduce(a) {
160
+ let t = BigInt.asIntN(32, BigInt.asIntN(64, BigInt.asIntN(32, a)) * BigInt(QInv));
161
+ t = BigInt.asIntN(32, (a - t * BigInt(Q)) >> 32n);
162
+ return t;
163
+ }
164
+
165
+ function reduce32(a) {
166
+ let t = (a + (1 << 22)) >> 23;
167
+ t = a - t * Q;
168
+ return t;
169
+ }
170
+
171
+ function cAddQ(a) {
172
+ let ar = a;
173
+ ar += (ar >> 31) & Q;
174
+ return ar;
175
+ }
176
+
177
+ function ntt(a) {
178
+ let k = 0;
179
+ let j = 0;
180
+
181
+ for (let len = 128; len > 0; len >>= 1) {
182
+ for (let start = 0; start < N; start = j + len) {
183
+ const zeta = zetas[++k];
184
+ for (j = start; j < start + len; ++j) {
185
+ const t = Number(montgomeryReduce(BigInt.asIntN(64, BigInt(zeta) * BigInt(a[j + len]))));
186
+ a[j + len] = a[j] - t;
187
+ a[j] += t;
188
+ }
189
+ }
190
+ }
191
+ }
192
+
193
+ function invNTTToMont(a) {
194
+ const f = 41978n; // mont^2/256
195
+ let j = 0;
196
+ let k = 256;
197
+
198
+ for (let len = 1; len < N; len <<= 1) {
199
+ for (let start = 0; start < N; start = j + len) {
200
+ const zeta = BigInt.asIntN(32, BigInt(-zetas[--k]));
201
+ for (j = start; j < start + len; ++j) {
202
+ const t = a[j];
203
+ a[j] = t + a[j + len];
204
+ a[j + len] = t - a[j + len];
205
+ a[j + len] = Number(montgomeryReduce(BigInt.asIntN(64, zeta * BigInt(a[j + len]))));
206
+ }
207
+ }
208
+ }
209
+ for (let j = 0; j < N; ++j) {
210
+ a[j] = Number(montgomeryReduce(BigInt.asIntN(64, f * BigInt(a[j]))));
211
+ }
212
+ }
213
+
214
+ function power2round(a0p, i, a) {
215
+ const a0 = a0p;
216
+ const a1 = (a + (1 << (D - 1)) - 1) >> D;
217
+ a0[i] = a - (a1 << D);
218
+ return a1;
219
+ }
220
+
221
+ function decompose(a0p, i, a) {
222
+ const a0 = a0p;
223
+ let a1 = (a + 127) >> 7;
224
+ a1 = (a1 * 1025 + (1 << 21)) >> 22;
225
+ a1 &= 15;
226
+
227
+ a0[i] = a - a1 * 2 * GAMMA2;
228
+ a0[i] -= (((Q - 1) / 2 - a0[i]) >> 31) & Q;
229
+ return a1;
230
+ }
231
+
232
+ function makeHint(a0, a1) {
233
+ if (a0 > GAMMA2 || a0 < -GAMMA2 || (a0 === -GAMMA2 && a1 !== 0)) return 1;
234
+
235
+ return 0;
236
+ }
237
+
238
+ function useHint(a, hint) {
239
+ const a0 = new Int32Array(1);
240
+ const a1 = decompose(a0, 0, a);
241
+
242
+ if (hint === 0) return a1;
243
+
244
+ if (a0[0] > 0) return (a1 + 1) & 15;
245
+ return (a1 - 1) & 15;
246
+ }
247
+
248
+ class Poly {
249
+ constructor() {
250
+ this.coeffs = new Int32Array(N);
251
+ }
252
+
253
+ copy(poly) {
254
+ for (let i = N - 1; i >= 0; i--) {
255
+ this.coeffs[i] = poly.coeffs[i];
256
+ }
257
+ }
258
+ }
259
+
260
+ function polyReduce(aP) {
261
+ const a = aP;
262
+ for (let i = 0; i < N; ++i) a.coeffs[i] = reduce32(a.coeffs[i]);
263
+ }
264
+
265
+ function polyCAddQ(aP) {
266
+ const a = aP;
267
+ for (let i = 0; i < N; ++i) a.coeffs[i] = cAddQ(a.coeffs[i]);
268
+ }
269
+
270
+ function polyAdd(cP, a, b) {
271
+ const c = cP;
272
+ for (let i = 0; i < N; ++i) c.coeffs[i] = a.coeffs[i] + b.coeffs[i];
273
+ }
274
+
275
+ function polySub(cP, a, b) {
276
+ const c = cP;
277
+ for (let i = 0; i < N; ++i) c.coeffs[i] = a.coeffs[i] - b.coeffs[i];
278
+ }
279
+
280
+ function polyShiftL(aP) {
281
+ const a = aP;
282
+ for (let i = 0; i < N; ++i) a.coeffs[i] <<= D;
283
+ }
284
+
285
+ function polyNTT(a) {
286
+ ntt(a.coeffs);
287
+ }
288
+
289
+ function polyInvNTTToMont(a) {
290
+ invNTTToMont(a.coeffs);
291
+ }
292
+
293
+ function polyPointWiseMontgomery(cP, a, b) {
294
+ const c = cP;
295
+ for (let i = 0; i < N; ++i) c.coeffs[i] = Number(montgomeryReduce(BigInt(a.coeffs[i]) * BigInt(b.coeffs[i])));
296
+ }
297
+
298
+ function polyPower2round(a1p, a0, a) {
299
+ const a1 = a1p;
300
+ for (let i = 0; i < N; ++i) a1.coeffs[i] = power2round(a0.coeffs, i, a.coeffs[i]);
301
+ }
302
+
303
+ function polyDecompose(a1p, a0, a) {
304
+ const a1 = a1p;
305
+ for (let i = 0; i < N; ++i) a1.coeffs[i] = decompose(a0.coeffs, i, a.coeffs[i]);
306
+ }
307
+
308
+ function polyMakeHint(hp, a0, a1) {
309
+ let s = 0;
310
+ const h = hp;
311
+ for (let i = 0; i < N; ++i) {
312
+ h.coeffs[i] = makeHint(a0.coeffs[i], a1.coeffs[i]);
313
+ s += h.coeffs[i];
314
+ }
315
+
316
+ return s;
317
+ }
318
+
319
+ function polyUseHint(bp, a, h) {
320
+ const b = bp;
321
+ for (let i = 0; i < N; ++i) {
322
+ b.coeffs[i] = useHint(a.coeffs[i], h.coeffs[i]);
323
+ }
324
+ }
325
+
326
+ function polyChkNorm(a, b) {
327
+ if (b > Math.floor((Q - 1) / 8)) {
328
+ return 1;
329
+ }
330
+
331
+ for (let i = 0; i < N; i++) {
332
+ let t = a.coeffs[i] >> 31;
333
+ t = a.coeffs[i] - (t & (2 * a.coeffs[i]));
334
+
335
+ if (t >= b) {
336
+ return 1;
337
+ }
338
+ }
339
+
340
+ return 0;
341
+ }
342
+
343
+ function rejUniform(ap, aOffset, len, buf, bufLen) {
344
+ let ctr = 0;
345
+ let pos = 0;
346
+ const a = ap;
347
+ while (ctr < len && pos + 3 <= bufLen) {
348
+ let t = buf[pos++];
349
+ t |= buf[pos++] << 8;
350
+ t |= buf[pos++] << 16;
351
+ t &= 0x7fffff;
352
+
353
+ if (t < Q) {
354
+ a[aOffset + ctr++] = t;
355
+ }
356
+ }
357
+
358
+ return ctr;
359
+ }
360
+
361
+ function polyUniform(a, seed, nonce) {
362
+ let off = 0;
363
+ let bufLen = PolyUniformNBlocks * Stream128BlockBytes;
364
+ const buf = new Uint8Array(PolyUniformNBlocks * Stream128BlockBytes + 2);
365
+
366
+ const state = new KeccakState();
367
+ mldsaShake128StreamInit(state, seed, nonce);
368
+ shake128SqueezeBlocks(buf, off, PolyUniformNBlocks, state);
369
+
370
+ let ctr = rejUniform(a.coeffs, 0, N, buf, bufLen);
371
+
372
+ while (ctr < N) {
373
+ off = bufLen % 3;
374
+ for (let i = 0; i < off; ++i) buf[i] = buf[bufLen - off + i];
375
+
376
+ shake128SqueezeBlocks(buf, off, 1, state);
377
+ bufLen = Stream128BlockBytes + off;
378
+ ctr += rejUniform(a.coeffs, ctr, N - ctr, buf, bufLen);
379
+ }
380
+ }
381
+
382
+ function rejEta(aP, aOffset, len, buf, bufLen) {
383
+ let ctr;
384
+ let pos;
385
+ let t0;
386
+ let t1;
387
+ const a = aP;
388
+ ctr = 0;
389
+ pos = 0;
390
+ while (ctr < len && pos < bufLen) {
391
+ t0 = buf[pos] & 0x0f;
392
+ t1 = buf[pos++] >> 4;
393
+
394
+ if (t0 < 15) {
395
+ t0 -= ((205 * t0) >> 10) * 5;
396
+ a[aOffset + ctr++] = 2 - t0;
397
+ }
398
+ if (t1 < 15 && ctr < len) {
399
+ t1 -= ((205 * t1) >> 10) * 5;
400
+ a[aOffset + ctr++] = 2 - t1;
401
+ }
402
+ }
403
+
404
+ return ctr;
405
+ }
406
+
407
+ function polyUniformEta(a, seed, nonce) {
408
+ let ctr;
409
+ const bufLen = PolyUniformETANBlocks * Stream256BlockBytes;
410
+ const buf = new Uint8Array(bufLen);
411
+
412
+ const state = new KeccakState();
413
+ mldsaShake256StreamInit(state, seed, nonce);
414
+ shake256SqueezeBlocks(buf, 0, PolyUniformETANBlocks, state);
415
+
416
+ ctr = rejEta(a.coeffs, 0, N, buf, bufLen);
417
+ while (ctr < N) {
418
+ shake256SqueezeBlocks(buf, 0, 1, state);
419
+ ctr += rejEta(a.coeffs, ctr, N - ctr, buf, Stream256BlockBytes);
420
+ }
421
+ }
422
+
423
+ function polyZUnpack(rP, a, aOffset) {
424
+ const r = rP;
425
+ for (let i = 0; i < N / 2; ++i) {
426
+ r.coeffs[2 * i] = a[aOffset + 5 * i];
427
+ r.coeffs[2 * i] |= a[aOffset + 5 * i + 1] << 8;
428
+ r.coeffs[2 * i] |= a[aOffset + 5 * i + 2] << 16;
429
+ r.coeffs[2 * i] &= 0xfffff;
430
+
431
+ r.coeffs[2 * i + 1] = a[aOffset + 5 * i + 2] >> 4;
432
+ r.coeffs[2 * i + 1] |= a[aOffset + 5 * i + 3] << 4;
433
+ r.coeffs[2 * i + 1] |= a[aOffset + 5 * i + 4] << 12;
434
+ r.coeffs[2 * i] &= 0xfffff;
435
+
436
+ r.coeffs[2 * i] = GAMMA1 - r.coeffs[2 * i];
437
+ r.coeffs[2 * i + 1] = GAMMA1 - r.coeffs[2 * i + 1];
438
+ }
439
+ }
440
+
441
+ function polyUniformGamma1(a, seed, nonce) {
442
+ const buf = new Uint8Array(PolyUniformGamma1NBlocks * Stream256BlockBytes);
443
+
444
+ const state = new KeccakState();
445
+ mldsaShake256StreamInit(state, seed, nonce);
446
+ shake256SqueezeBlocks(buf, 0, PolyUniformGamma1NBlocks, state);
447
+ polyZUnpack(a, buf, 0);
448
+ }
449
+
450
+ function polyChallenge(cP, seed) {
451
+ if (seed.length !== CTILDEBytes) throw new Error('invalid ctilde length');
452
+
453
+ let b;
454
+ let pos;
455
+ const c = cP;
456
+ const buf = new Uint8Array(Shake256Rate);
457
+
458
+ const state = new KeccakState();
459
+ shake256Init(state);
460
+ shake256Absorb(state, seed);
461
+ shake256Finalize(state);
462
+ shake256SqueezeBlocks(buf, 0, 1, state);
463
+
464
+ let signs = 0n;
465
+ for (let i = 0; i < 8; ++i) {
466
+ signs = BigInt.asUintN(64, signs | (BigInt(buf[i]) << BigInt(8 * i)));
467
+ }
468
+ pos = 8;
469
+
470
+ for (let i = 0; i < N; ++i) {
471
+ c.coeffs[i] = 0;
472
+ }
473
+ for (let i = N - TAU; i < N; ++i) {
474
+ do {
475
+ if (pos >= Shake256Rate) {
476
+ shake256SqueezeBlocks(buf, 0, 1, state);
477
+ pos = 0;
478
+ }
479
+
480
+ b = buf[pos++];
481
+ } while (b > i);
482
+
483
+ c.coeffs[i] = c.coeffs[b];
484
+ c.coeffs[b] = Number(1n - 2n * (signs & 1n));
485
+ signs >>= 1n;
486
+ }
487
+ }
488
+
489
+ function polyEtaPack(rP, rOffset, a) {
490
+ const t = new Uint8Array(8);
491
+ const r = rP;
492
+ for (let i = 0; i < N / 8; ++i) {
493
+ t[0] = ETA - a.coeffs[8 * i];
494
+ t[1] = ETA - a.coeffs[8 * i + 1];
495
+ t[2] = ETA - a.coeffs[8 * i + 2];
496
+ t[3] = ETA - a.coeffs[8 * i + 3];
497
+ t[4] = ETA - a.coeffs[8 * i + 4];
498
+ t[5] = ETA - a.coeffs[8 * i + 5];
499
+ t[6] = ETA - a.coeffs[8 * i + 6];
500
+ t[7] = ETA - a.coeffs[8 * i + 7];
501
+
502
+ r[rOffset + 3 * i] = (t[0] >> 0) | (t[1] << 3) | (t[2] << 6);
503
+ r[rOffset + 3 * i + 1] = (t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7);
504
+ r[rOffset + 3 * i + 2] = (t[5] >> 1) | (t[6] << 2) | (t[7] << 5);
505
+ }
506
+ }
507
+
508
+ function polyEtaUnpack(rP, a, aOffset) {
509
+ const r = rP;
510
+ for (let i = 0; i < N / 8; ++i) {
511
+ r.coeffs[8 * i] = (a[aOffset + 3 * i] >> 0) & 7;
512
+ r.coeffs[8 * i + 1] = (a[aOffset + 3 * i] >> 3) & 7;
513
+ r.coeffs[8 * i + 2] = ((a[aOffset + 3 * i] >> 6) | (a[aOffset + 3 * i + 1] << 2)) & 7;
514
+ r.coeffs[8 * i + 3] = (a[aOffset + 3 * i + 1] >> 1) & 7;
515
+ r.coeffs[8 * i + 4] = (a[aOffset + 3 * i + 1] >> 4) & 7;
516
+ r.coeffs[8 * i + 5] = ((a[aOffset + 3 * i + 1] >> 7) | (a[aOffset + 3 * i + 2] << 1)) & 7;
517
+ r.coeffs[8 * i + 6] = (a[aOffset + 3 * i + 2] >> 2) & 7;
518
+ r.coeffs[8 * i + 7] = (a[aOffset + 3 * i + 2] >> 5) & 7;
519
+
520
+ r.coeffs[8 * i] = ETA - r.coeffs[8 * i];
521
+ r.coeffs[8 * i + 1] = ETA - r.coeffs[8 * i + 1];
522
+ r.coeffs[8 * i + 2] = ETA - r.coeffs[8 * i + 2];
523
+ r.coeffs[8 * i + 3] = ETA - r.coeffs[8 * i + 3];
524
+ r.coeffs[8 * i + 4] = ETA - r.coeffs[8 * i + 4];
525
+ r.coeffs[8 * i + 5] = ETA - r.coeffs[8 * i + 5];
526
+ r.coeffs[8 * i + 6] = ETA - r.coeffs[8 * i + 6];
527
+ r.coeffs[8 * i + 7] = ETA - r.coeffs[8 * i + 7];
528
+ }
529
+ }
530
+
531
+ function polyT1Pack(rP, rOffset, a) {
532
+ const r = rP;
533
+ for (let i = 0; i < N / 4; ++i) {
534
+ r[rOffset + 5 * i] = a.coeffs[4 * i] >> 0;
535
+ r[rOffset + 5 * i + 1] = (a.coeffs[4 * i] >> 8) | (a.coeffs[4 * i + 1] << 2);
536
+ r[rOffset + 5 * i + 2] = (a.coeffs[4 * i + 1] >> 6) | (a.coeffs[4 * i + 2] << 4);
537
+ r[rOffset + 5 * i + 3] = (a.coeffs[4 * i + 2] >> 4) | (a.coeffs[4 * i + 3] << 6);
538
+ r[rOffset + 5 * i + 4] = a.coeffs[4 * i + 3] >> 2;
539
+ }
540
+ }
541
+
542
+ function polyT1Unpack(rP, a, aOffset) {
543
+ const r = rP;
544
+ for (let i = 0; i < N / 4; ++i) {
545
+ r.coeffs[4 * i] = ((a[aOffset + 5 * i] >> 0) | (a[aOffset + 5 * i + 1] << 8)) & 0x3ff;
546
+ r.coeffs[4 * i + 1] = ((a[aOffset + 5 * i + 1] >> 2) | (a[aOffset + 5 * i + 2] << 6)) & 0x3ff;
547
+ r.coeffs[4 * i + 2] = ((a[aOffset + 5 * i + 2] >> 4) | (a[aOffset + 5 * i + 3] << 4)) & 0x3ff;
548
+ r.coeffs[4 * i + 3] = ((a[aOffset + 5 * i + 3] >> 6) | (a[aOffset + 5 * i + 4] << 2)) & 0x3ff;
549
+ }
550
+ }
551
+
552
+ function polyT0Pack(rP, rOffset, a) {
553
+ const t = new Uint32Array(8);
554
+ const r = rP;
555
+ for (let i = 0; i < N / 8; ++i) {
556
+ t[0] = (1 << (D - 1)) - a.coeffs[8 * i];
557
+ t[1] = (1 << (D - 1)) - a.coeffs[8 * i + 1];
558
+ t[2] = (1 << (D - 1)) - a.coeffs[8 * i + 2];
559
+ t[3] = (1 << (D - 1)) - a.coeffs[8 * i + 3];
560
+ t[4] = (1 << (D - 1)) - a.coeffs[8 * i + 4];
561
+ t[5] = (1 << (D - 1)) - a.coeffs[8 * i + 5];
562
+ t[6] = (1 << (D - 1)) - a.coeffs[8 * i + 6];
563
+ t[7] = (1 << (D - 1)) - a.coeffs[8 * i + 7];
564
+
565
+ r[rOffset + 13 * i] = t[0];
566
+ r[rOffset + 13 * i + 1] = t[0] >> 8;
567
+ r[rOffset + 13 * i + 1] |= t[1] << 5;
568
+ r[rOffset + 13 * i + 2] = t[1] >> 3;
569
+ r[rOffset + 13 * i + 3] = t[1] >> 11;
570
+ r[rOffset + 13 * i + 3] |= t[2] << 2;
571
+ r[rOffset + 13 * i + 4] = t[2] >> 6;
572
+ r[rOffset + 13 * i + 4] |= t[3] << 7;
573
+ r[rOffset + 13 * i + 5] = t[3] >> 1;
574
+ r[rOffset + 13 * i + 6] = t[3] >> 9;
575
+ r[rOffset + 13 * i + 6] |= t[4] << 4;
576
+ r[rOffset + 13 * i + 7] = t[4] >> 4;
577
+ r[rOffset + 13 * i + 8] = t[4] >> 12;
578
+ r[rOffset + 13 * i + 8] |= t[5] << 1;
579
+ r[rOffset + 13 * i + 9] = t[5] >> 7;
580
+ r[rOffset + 13 * i + 9] |= t[6] << 6;
581
+ r[rOffset + 13 * i + 10] = t[6] >> 2;
582
+ r[rOffset + 13 * i + 11] = t[6] >> 10;
583
+ r[rOffset + 13 * i + 11] |= t[7] << 3;
584
+ r[rOffset + 13 * i + 12] = t[7] >> 5;
585
+ }
586
+ }
587
+
588
+ function polyT0Unpack(rP, a, aOffset) {
589
+ const r = rP;
590
+ for (let i = 0; i < N / 8; ++i) {
591
+ r.coeffs[8 * i] = a[aOffset + 13 * i];
592
+ r.coeffs[8 * i] |= a[aOffset + 13 * i + 1] << 8;
593
+ r.coeffs[8 * i] &= 0x1fff;
594
+
595
+ r.coeffs[8 * i + 1] = a[aOffset + 13 * i + 1] >> 5;
596
+ r.coeffs[8 * i + 1] |= a[aOffset + 13 * i + 2] << 3;
597
+ r.coeffs[8 * i + 1] |= a[aOffset + 13 * i + 3] << 11;
598
+ r.coeffs[8 * i + 1] &= 0x1fff;
599
+
600
+ r.coeffs[8 * i + 2] = a[aOffset + 13 * i + 3] >> 2;
601
+ r.coeffs[8 * i + 2] |= a[aOffset + 13 * i + 4] << 6;
602
+ r.coeffs[8 * i + 2] &= 0x1fff;
603
+
604
+ r.coeffs[8 * i + 3] = a[aOffset + 13 * i + 4] >> 7;
605
+ r.coeffs[8 * i + 3] |= a[aOffset + 13 * i + 5] << 1;
606
+ r.coeffs[8 * i + 3] |= a[aOffset + 13 * i + 6] << 9;
607
+ r.coeffs[8 * i + 3] &= 0x1fff;
608
+
609
+ r.coeffs[8 * i + 4] = a[aOffset + 13 * i + 6] >> 4;
610
+ r.coeffs[8 * i + 4] |= a[aOffset + 13 * i + 7] << 4;
611
+ r.coeffs[8 * i + 4] |= a[aOffset + 13 * i + 8] << 12;
612
+ r.coeffs[8 * i + 4] &= 0x1fff;
613
+
614
+ r.coeffs[8 * i + 5] = a[aOffset + 13 * i + 8] >> 1;
615
+ r.coeffs[8 * i + 5] |= a[aOffset + 13 * i + 9] << 7;
616
+ r.coeffs[8 * i + 5] &= 0x1fff;
617
+
618
+ r.coeffs[8 * i + 6] = a[aOffset + 13 * i + 9] >> 6;
619
+ r.coeffs[8 * i + 6] |= a[aOffset + 13 * i + 10] << 2;
620
+ r.coeffs[8 * i + 6] |= a[aOffset + 13 * i + 11] << 10;
621
+ r.coeffs[8 * i + 6] &= 0x1fff;
622
+
623
+ r.coeffs[8 * i + 7] = a[aOffset + 13 * i + 11] >> 3;
624
+ r.coeffs[8 * i + 7] |= a[aOffset + 13 * i + 12] << 5;
625
+ r.coeffs[8 * i + 7] &= 0x1fff;
626
+
627
+ r.coeffs[8 * i] = (1 << (D - 1)) - r.coeffs[8 * i];
628
+ r.coeffs[8 * i + 1] = (1 << (D - 1)) - r.coeffs[8 * i + 1];
629
+ r.coeffs[8 * i + 2] = (1 << (D - 1)) - r.coeffs[8 * i + 2];
630
+ r.coeffs[8 * i + 3] = (1 << (D - 1)) - r.coeffs[8 * i + 3];
631
+ r.coeffs[8 * i + 4] = (1 << (D - 1)) - r.coeffs[8 * i + 4];
632
+ r.coeffs[8 * i + 5] = (1 << (D - 1)) - r.coeffs[8 * i + 5];
633
+ r.coeffs[8 * i + 6] = (1 << (D - 1)) - r.coeffs[8 * i + 6];
634
+ r.coeffs[8 * i + 7] = (1 << (D - 1)) - r.coeffs[8 * i + 7];
635
+ }
636
+ }
637
+
638
+ function polyZPack(rP, rOffset, a) {
639
+ const t = new Uint32Array(4);
640
+ const r = rP;
641
+ for (let i = 0; i < N / 2; ++i) {
642
+ t[0] = GAMMA1 - a.coeffs[2 * i];
643
+ t[1] = GAMMA1 - a.coeffs[2 * i + 1];
644
+
645
+ r[rOffset + 5 * i] = t[0];
646
+ r[rOffset + 5 * i + 1] = t[0] >> 8;
647
+ r[rOffset + 5 * i + 2] = t[0] >> 16;
648
+ r[rOffset + 5 * i + 2] |= t[1] << 4;
649
+ r[rOffset + 5 * i + 3] = t[1] >> 4;
650
+ r[rOffset + 5 * i + 4] = t[1] >> 12;
651
+ }
652
+ }
653
+
654
+ function polyW1Pack(rP, rOffset, a) {
655
+ const r = rP;
656
+ for (let i = 0; i < N / 2; ++i) {
657
+ r[rOffset + i] = a.coeffs[2 * i] | (a.coeffs[2 * i + 1] << 4);
658
+ }
659
+ }
660
+
661
+ class PolyVecK {
662
+ constructor() {
663
+ this.vec = new Array(K).fill().map(() => new Poly());
664
+ }
665
+ }
666
+
667
+ class PolyVecL {
668
+ constructor() {
669
+ this.vec = new Array(L).fill().map(() => new Poly());
670
+ }
671
+
672
+ copy(polyVecL) {
673
+ for (let i = L - 1; i >= 0; i--) {
674
+ this.vec[i].copy(polyVecL.vec[i]);
675
+ }
676
+ }
677
+ }
678
+
679
+ function polyVecMatrixExpand(mat, rho) {
680
+ if (rho.length !== SeedBytes) {
681
+ throw new Error(`invalid rho length ${rho.length} | Expected length ${SeedBytes}`);
682
+ }
683
+ for (let i = 0; i < K; ++i) {
684
+ for (let j = 0; j < L; ++j) {
685
+ polyUniform(mat[i].vec[j], rho, (i << 8) + j);
686
+ }
687
+ }
688
+ }
689
+
690
+ function polyVecMatrixPointWiseMontgomery(t, mat, v) {
691
+ for (let i = 0; i < K; ++i) {
692
+ polyVecLPointWiseAccMontgomery(t.vec[i], mat[i], v);
693
+ }
694
+ }
695
+
696
+ function polyVecLUniformEta(v, seed, nonceP) {
697
+ let nonce = nonceP;
698
+ if (seed.length !== CRHBytes) {
699
+ throw new Error(`invalid seed length ${seed.length} | Expected length ${CRHBytes}`);
700
+ }
701
+ for (let i = 0; i < L; i++) {
702
+ polyUniformEta(v.vec[i], seed, nonce++);
703
+ }
704
+ }
705
+
706
+ function polyVecLUniformGamma1(v, seed, nonce) {
707
+ if (seed.length !== CRHBytes) {
708
+ throw new Error(`invalid seed length ${seed.length} | Expected length ${CRHBytes}`);
709
+ }
710
+ for (let i = 0; i < L; i++) {
711
+ polyUniformGamma1(v.vec[i], seed, L * nonce + i);
712
+ }
713
+ }
714
+
715
+ function polyVecLReduce(v) {
716
+ for (let i = 0; i < L; i++) {
717
+ polyReduce(v.vec[i]);
718
+ }
719
+ }
720
+
721
+ function polyVecLAdd(w, u, v) {
722
+ for (let i = 0; i < L; ++i) {
723
+ polyAdd(w.vec[i], u.vec[i], v.vec[i]);
724
+ }
725
+ }
726
+
727
+ function polyVecLNTT(v) {
728
+ for (let i = 0; i < L; ++i) {
729
+ polyNTT(v.vec[i]);
730
+ }
731
+ }
732
+
733
+ function polyVecLInvNTTToMont(v) {
734
+ for (let i = 0; i < L; ++i) {
735
+ polyInvNTTToMont(v.vec[i]);
736
+ }
737
+ }
738
+
739
+ function polyVecLPointWisePolyMontgomery(r, a, v) {
740
+ for (let i = 0; i < L; ++i) {
741
+ polyPointWiseMontgomery(r.vec[i], a, v.vec[i]);
742
+ }
743
+ }
744
+
745
+ function polyVecLPointWiseAccMontgomery(w, u, v) {
746
+ const t = new Poly();
747
+ polyPointWiseMontgomery(w, u.vec[0], v.vec[0]);
748
+ for (let i = 1; i < L; i++) {
749
+ polyPointWiseMontgomery(t, u.vec[i], v.vec[i]);
750
+ polyAdd(w, w, t);
751
+ }
752
+ }
753
+
754
+ function polyVecLChkNorm(v, bound) {
755
+ for (let i = 0; i < L; i++) {
756
+ if (polyChkNorm(v.vec[i], bound) !== 0) {
757
+ return 1;
758
+ }
759
+ }
760
+ return 0;
761
+ }
762
+
763
+ function polyVecKUniformEta(v, seed, nonceP) {
764
+ let nonce = nonceP;
765
+ for (let i = 0; i < K; ++i) {
766
+ polyUniformEta(v.vec[i], seed, nonce++);
767
+ }
768
+ }
769
+
770
+ function polyVecKReduce(v) {
771
+ for (let i = 0; i < K; ++i) {
772
+ polyReduce(v.vec[i]);
773
+ }
774
+ }
775
+
776
+ function polyVecKCAddQ(v) {
777
+ for (let i = 0; i < K; ++i) {
778
+ polyCAddQ(v.vec[i]);
779
+ }
780
+ }
781
+
782
+ function polyVecKAdd(w, u, v) {
783
+ for (let i = 0; i < K; ++i) {
784
+ polyAdd(w.vec[i], u.vec[i], v.vec[i]);
785
+ }
786
+ }
787
+
788
+ function polyVecKSub(w, u, v) {
789
+ for (let i = 0; i < K; ++i) {
790
+ polySub(w.vec[i], u.vec[i], v.vec[i]);
791
+ }
792
+ }
793
+
794
+ function polyVecKShiftL(v) {
795
+ for (let i = 0; i < K; ++i) {
796
+ polyShiftL(v.vec[i]);
797
+ }
798
+ }
799
+
800
+ function polyVecKNTT(v) {
801
+ for (let i = 0; i < K; i++) {
802
+ polyNTT(v.vec[i]);
803
+ }
804
+ }
805
+
806
+ function polyVecKInvNTTToMont(v) {
807
+ for (let i = 0; i < K; i++) {
808
+ polyInvNTTToMont(v.vec[i]);
809
+ }
810
+ }
811
+
812
+ function polyVecKPointWisePolyMontgomery(r, a, v) {
813
+ for (let i = 0; i < K; i++) {
814
+ polyPointWiseMontgomery(r.vec[i], a, v.vec[i]);
815
+ }
816
+ }
817
+
818
+ function polyVecKChkNorm(v, bound) {
819
+ for (let i = 0; i < K; i++) {
820
+ if (polyChkNorm(v.vec[i], bound) !== 0) {
821
+ return 1;
822
+ }
823
+ }
824
+ return 0;
825
+ }
826
+
827
+ function polyVecKPower2round(v1, v0, v) {
828
+ for (let i = 0; i < K; i++) {
829
+ polyPower2round(v1.vec[i], v0.vec[i], v.vec[i]);
830
+ }
831
+ }
832
+
833
+ function polyVecKDecompose(v1, v0, v) {
834
+ for (let i = 0; i < K; i++) {
835
+ polyDecompose(v1.vec[i], v0.vec[i], v.vec[i]);
836
+ }
837
+ }
838
+
839
+ function polyVecKMakeHint(h, v0, v1) {
840
+ let s = 0;
841
+ for (let i = 0; i < K; i++) {
842
+ s += polyMakeHint(h.vec[i], v0.vec[i], v1.vec[i]);
843
+ }
844
+ return s;
845
+ }
846
+
847
+ function polyVecKUseHint(w, u, h) {
848
+ for (let i = 0; i < K; ++i) {
849
+ polyUseHint(w.vec[i], u.vec[i], h.vec[i]);
850
+ }
851
+ }
852
+
853
+ function polyVecKPackW1(r, w1) {
854
+ for (let i = 0; i < K; ++i) {
855
+ polyW1Pack(r, i * PolyW1PackedBytes, w1.vec[i]);
856
+ }
857
+ }
858
+
859
+ function packPk(pkp, rho, t1) {
860
+ const pk = pkp;
861
+ for (let i = 0; i < SeedBytes; ++i) {
862
+ pk[i] = rho[i];
863
+ }
864
+ for (let i = 0; i < K; ++i) {
865
+ polyT1Pack(pk, SeedBytes + i * PolyT1PackedBytes, t1.vec[i]);
866
+ }
867
+ }
868
+
869
+ function unpackPk(rhop, t1, pk) {
870
+ const rho = rhop;
871
+ for (let i = 0; i < SeedBytes; ++i) {
872
+ rho[i] = pk[i];
873
+ }
874
+
875
+ for (let i = 0; i < K; ++i) {
876
+ polyT1Unpack(t1.vec[i], pk, SeedBytes + i * PolyT1PackedBytes);
877
+ }
878
+ }
879
+
880
+ function packSk(skp, rho, tr, key, t0, s1, s2) {
881
+ let skOffset = 0;
882
+ const sk = skp;
883
+ for (let i = 0; i < SeedBytes; ++i) {
884
+ sk[i] = rho[i];
885
+ }
886
+ skOffset += SeedBytes;
887
+
888
+ for (let i = 0; i < SeedBytes; ++i) {
889
+ sk[skOffset + i] = key[i];
890
+ }
891
+ skOffset += SeedBytes;
892
+
893
+ for (let i = 0; i < TRBytes; ++i) {
894
+ sk[skOffset + i] = tr[i];
895
+ }
896
+ skOffset += TRBytes;
897
+
898
+ for (let i = 0; i < L; ++i) {
899
+ polyEtaPack(sk, skOffset + i * PolyETAPackedBytes, s1.vec[i]);
900
+ }
901
+ skOffset += L * PolyETAPackedBytes;
902
+
903
+ for (let i = 0; i < K; ++i) {
904
+ polyEtaPack(sk, skOffset + i * PolyETAPackedBytes, s2.vec[i]);
905
+ }
906
+ skOffset += K * PolyETAPackedBytes;
907
+
908
+ for (let i = 0; i < K; ++i) {
909
+ polyT0Pack(sk, skOffset + i * PolyT0PackedBytes, t0.vec[i]);
910
+ }
911
+ }
912
+
913
+ function unpackSk(rhoP, trP, keyP, t0, s1, s2, sk) {
914
+ let skOffset = 0;
915
+ const rho = rhoP;
916
+ const tr = trP;
917
+ const key = keyP;
918
+ for (let i = 0; i < SeedBytes; ++i) {
919
+ rho[i] = sk[i];
920
+ }
921
+ skOffset += SeedBytes;
922
+
923
+ for (let i = 0; i < SeedBytes; ++i) {
924
+ key[i] = sk[skOffset + i];
925
+ }
926
+ skOffset += SeedBytes;
927
+
928
+ for (let i = 0; i < TRBytes; ++i) {
929
+ tr[i] = sk[skOffset + i];
930
+ }
931
+ skOffset += TRBytes;
932
+
933
+ for (let i = 0; i < L; ++i) {
934
+ polyEtaUnpack(s1.vec[i], sk, skOffset + i * PolyETAPackedBytes);
935
+ }
936
+ skOffset += L * PolyETAPackedBytes;
937
+
938
+ for (let i = 0; i < K; ++i) {
939
+ polyEtaUnpack(s2.vec[i], sk, skOffset + i * PolyETAPackedBytes);
940
+ }
941
+ skOffset += K * PolyETAPackedBytes;
942
+
943
+ for (let i = 0; i < K; ++i) {
944
+ polyT0Unpack(t0.vec[i], sk, skOffset + i * PolyT0PackedBytes);
945
+ }
946
+ }
947
+
948
+ function packSig(sigP, ctilde, z, h) {
949
+ let sigOffset = 0;
950
+ const sig = sigP;
951
+ for (let i = 0; i < CTILDEBytes; ++i) {
952
+ sig[i] = ctilde[i];
953
+ }
954
+ sigOffset += CTILDEBytes;
955
+
956
+ for (let i = 0; i < L; ++i) {
957
+ polyZPack(sig, sigOffset + i * PolyZPackedBytes, z.vec[i]);
958
+ }
959
+ sigOffset += L * PolyZPackedBytes;
960
+
961
+ for (let i = 0; i < OMEGA + K; ++i) {
962
+ sig[sigOffset + i] = 0;
963
+ }
964
+
965
+ let k = 0;
966
+ for (let i = 0; i < K; ++i) {
967
+ for (let j = 0; j < N; ++j) {
968
+ if (h.vec[i].coeffs[j] !== 0) {
969
+ sig[sigOffset + k++] = j;
970
+ }
971
+ }
972
+
973
+ sig[sigOffset + OMEGA + i] = k;
974
+ }
975
+ }
976
+
977
+ function unpackSig(cP, z, hP, sig) {
978
+ let sigOffset = 0;
979
+ const c = cP; // ctilde
980
+ const h = hP;
981
+ for (let i = 0; i < CTILDEBytes; ++i) {
982
+ c[i] = sig[i];
983
+ }
984
+ sigOffset += CTILDEBytes;
985
+
986
+ for (let i = 0; i < L; ++i) {
987
+ polyZUnpack(z.vec[i], sig, sigOffset + i * PolyZPackedBytes);
988
+ }
989
+ sigOffset += L * PolyZPackedBytes;
990
+
991
+ /* Decode h */
992
+ let k = 0;
993
+ for (let i = 0; i < K; ++i) {
994
+ for (let j = 0; j < N; ++j) {
995
+ h.vec[i].coeffs[j] = 0;
996
+ }
997
+
998
+ if (sig[sigOffset + OMEGA + i] < k || sig[sigOffset + OMEGA + i] > OMEGA) {
999
+ return 1;
1000
+ }
1001
+
1002
+ for (let j = k; j < sig[sigOffset + OMEGA + i]; ++j) {
1003
+ /* Coefficients are ordered for strong unforgeability */
1004
+ if (j > k && sig[sigOffset + j] <= sig[sigOffset + j - 1]) {
1005
+ return 1;
1006
+ }
1007
+ h.vec[i].coeffs[sig[sigOffset + j]] = 1;
1008
+ }
1009
+
1010
+ k = sig[sigOffset + OMEGA + i];
1011
+ }
1012
+
1013
+ /* Extra indices are zero for strong unforgeability */
1014
+ for (let j = k; j < OMEGA; ++j) {
1015
+ if (sig[sigOffset + j]) {
1016
+ return 1;
1017
+ }
1018
+ }
1019
+
1020
+ return 0;
1021
+ }
1022
+
1023
+ const randomBytes = pkg;
1024
+
1025
+ /**
1026
+ * Default signing context ("ZOND" in ASCII).
1027
+ * Used for domain separation per FIPS 204.
1028
+ * @constant {Uint8Array}
1029
+ */
1030
+ const DEFAULT_CTX = new Uint8Array([0x5a, 0x4f, 0x4e, 0x44]); // "ZOND"
1031
+
1032
+ /**
1033
+ * Convert hex string to Uint8Array
1034
+ * @param {string} hex - Hex-encoded string
1035
+ * @returns {Uint8Array} Decoded bytes
1036
+ * @private
1037
+ */
1038
+ function hexToBytes(hex) {
1039
+ const len = hex.length / 2;
1040
+ const result = new Uint8Array(len);
1041
+ for (let i = 0; i < len; i++) {
1042
+ result[i] = parseInt(hex.substr(i * 2, 2), 16);
1043
+ }
1044
+ return result;
1045
+ }
1046
+
1047
+ /**
1048
+ * Generate an ML-DSA-87 key pair.
1049
+ *
1050
+ * Key generation follows FIPS 204, using domain separator [K, L] during
1051
+ * seed expansion to ensure algorithm binding.
1052
+ *
1053
+ * @param {Uint8Array|null} passedSeed - Optional 32-byte seed for deterministic key generation.
1054
+ * Pass null for random key generation.
1055
+ * @param {Uint8Array} pk - Output buffer for public key (must be CryptoPublicKeyBytes = 2592 bytes)
1056
+ * @param {Uint8Array} sk - Output buffer for secret key (must be CryptoSecretKeyBytes = 4896 bytes)
1057
+ * @returns {Uint8Array} The seed used for key generation (useful when passedSeed is null)
1058
+ * @throws {Error} If pk/sk buffers are null or wrong size, or if seed is wrong size
1059
+ *
1060
+ * @example
1061
+ * const pk = new Uint8Array(CryptoPublicKeyBytes);
1062
+ * const sk = new Uint8Array(CryptoSecretKeyBytes);
1063
+ * const seed = cryptoSignKeypair(null, pk, sk);
1064
+ */
1065
+ function cryptoSignKeypair(passedSeed, pk, sk) {
1066
+ try {
1067
+ if (pk.length !== CryptoPublicKeyBytes) {
1068
+ throw new Error(`invalid pk length ${pk.length} | Expected length ${CryptoPublicKeyBytes}`);
1069
+ }
1070
+ if (sk.length !== CryptoSecretKeyBytes) {
1071
+ throw new Error(`invalid sk length ${sk.length} | Expected length ${CryptoSecretKeyBytes}`);
1072
+ }
1073
+ } catch (e) {
1074
+ if (e instanceof TypeError) {
1075
+ throw new Error(`pk/sk cannot be null`);
1076
+ } else {
1077
+ throw new Error(`${e.message}`);
1078
+ }
1079
+ }
1080
+
1081
+ // Validate seed length if provided
1082
+ if (passedSeed !== null && passedSeed !== undefined) {
1083
+ if (passedSeed.length !== SeedBytes) {
1084
+ throw new Error(`invalid seed length ${passedSeed.length} | Expected length ${SeedBytes}`);
1085
+ }
1086
+ }
1087
+
1088
+ const mat = new Array(K).fill().map(() => new PolyVecL());
1089
+ const s1 = new PolyVecL();
1090
+ const s2 = new PolyVecK();
1091
+ const t1 = new PolyVecK();
1092
+ const t0 = new PolyVecK();
1093
+
1094
+ // Expand seed -> rho(32), rhoPrime(64), key(32) with domain sep [K, L]
1095
+ const seed = passedSeed || randomBytes(SeedBytes);
1096
+
1097
+ const outputLength = 2 * SeedBytes + CRHBytes;
1098
+ const domainSep = new Uint8Array([K, L]);
1099
+ const seedBuf = sha3.shake256.create({}).update(seed).update(domainSep).xof(outputLength);
1100
+ const rho = seedBuf.slice(0, SeedBytes);
1101
+ const rhoPrime = seedBuf.slice(SeedBytes, SeedBytes + CRHBytes);
1102
+ const key = seedBuf.slice(SeedBytes + CRHBytes);
1103
+
1104
+ // Expand matrix
1105
+ polyVecMatrixExpand(mat, rho);
1106
+
1107
+ // Sample short vectors s1 and s2
1108
+ polyVecLUniformEta(s1, rhoPrime, 0);
1109
+ polyVecKUniformEta(s2, rhoPrime, L);
1110
+
1111
+ // Matrix-vector multiplication
1112
+ const s1hat = new PolyVecL();
1113
+ s1hat.copy(s1);
1114
+ polyVecLNTT(s1hat);
1115
+ polyVecMatrixPointWiseMontgomery(t1, mat, s1hat);
1116
+ polyVecKReduce(t1);
1117
+ polyVecKInvNTTToMont(t1);
1118
+
1119
+ // Add error vector s2
1120
+ polyVecKAdd(t1, t1, s2);
1121
+
1122
+ // Extract t1 and write public key
1123
+ polyVecKCAddQ(t1);
1124
+ polyVecKPower2round(t1, t0, t1);
1125
+ packPk(pk, rho, t1);
1126
+
1127
+ // Compute tr = SHAKE256(pk) (64 bytes) and write secret key
1128
+ const tr = sha3.shake256.create({}).update(pk).xof(TRBytes);
1129
+ packSk(sk, rho, tr, key, t0, s1, s2);
1130
+
1131
+ return seed;
1132
+ }
1133
+
1134
+ /**
1135
+ * Create a detached signature for a message with optional context.
1136
+ *
1137
+ * Uses the ML-DSA-87 (FIPS 204) signing algorithm with rejection sampling.
1138
+ * The context parameter provides domain separation as required by FIPS 204.
1139
+ *
1140
+ * @param {Uint8Array} sig - Output buffer for signature (must be at least CryptoBytes = 4627 bytes)
1141
+ * @param {string|Uint8Array} m - Message to sign (hex string or Uint8Array)
1142
+ * @param {Uint8Array} sk - Secret key (must be CryptoSecretKeyBytes = 4896 bytes)
1143
+ * @param {boolean} randomizedSigning - If true, use random nonce for hedged signing.
1144
+ * If false, use deterministic nonce derived from message and key.
1145
+ * @param {Uint8Array} [ctx=DEFAULT_CTX] - Context string for domain separation (max 255 bytes).
1146
+ * Defaults to "ZOND" for QRL compatibility.
1147
+ * @returns {number} 0 on success
1148
+ * @throws {Error} If sk is wrong size or context exceeds 255 bytes
1149
+ *
1150
+ * @example
1151
+ * const sig = new Uint8Array(CryptoBytes);
1152
+ * cryptoSignSignature(sig, message, sk, false);
1153
+ * // Or with custom context:
1154
+ * cryptoSignSignature(sig, message, sk, false, new Uint8Array([0x01, 0x02]));
1155
+ */
1156
+ function cryptoSignSignature(sig, m, sk, randomizedSigning, ctx = DEFAULT_CTX) {
1157
+ if (ctx.length > 255) throw new Error(`invalid context length: ${ctx.length} (max 255)`);
1158
+ if (sk.length !== CryptoSecretKeyBytes) {
1159
+ throw new Error(`invalid sk length ${sk.length} | Expected length ${CryptoSecretKeyBytes}`);
1160
+ }
1161
+
1162
+ const rho = new Uint8Array(SeedBytes);
1163
+ const tr = new Uint8Array(TRBytes);
1164
+ const key = new Uint8Array(SeedBytes);
1165
+ let rhoPrime = new Uint8Array(CRHBytes);
1166
+ let nonce = 0;
1167
+ const mat = Array(K)
1168
+ .fill()
1169
+ .map(() => new PolyVecL());
1170
+ const s1 = new PolyVecL();
1171
+ const y = new PolyVecL();
1172
+ const z = new PolyVecL();
1173
+ const t0 = new PolyVecK();
1174
+ const s2 = new PolyVecK();
1175
+ const w1 = new PolyVecK();
1176
+ const w0 = new PolyVecK();
1177
+ const h = new PolyVecK();
1178
+ const cp = new Poly();
1179
+
1180
+ unpackSk(rho, tr, key, t0, s1, s2, sk);
1181
+
1182
+ // pre = 0x00 || len(ctx) || ctx
1183
+ const pre = new Uint8Array(2 + ctx.length);
1184
+ pre[0] = 0;
1185
+ pre[1] = ctx.length;
1186
+ pre.set(ctx, 2);
1187
+
1188
+ // Convert hex message to bytes
1189
+ const mBytes = typeof m === 'string' ? hexToBytes(m) : m;
1190
+
1191
+ // mu = SHAKE256(tr || pre || m)
1192
+ const mu = sha3.shake256.create({}).update(tr).update(pre).update(mBytes).xof(CRHBytes);
1193
+
1194
+ // rhoPrime = SHAKE256(key || rnd || mu)
1195
+ const rnd = randomizedSigning ? randomBytes(RNDBytes) : new Uint8Array(RNDBytes);
1196
+ rhoPrime = sha3.shake256.create({}).update(key).update(rnd).update(mu).xof(CRHBytes);
1197
+
1198
+ polyVecMatrixExpand(mat, rho);
1199
+ polyVecLNTT(s1);
1200
+ polyVecKNTT(s2);
1201
+ polyVecKNTT(t0);
1202
+
1203
+ while (true) {
1204
+ polyVecLUniformGamma1(y, rhoPrime, nonce++);
1205
+ // Matrix-vector multiplication
1206
+ z.copy(y);
1207
+ polyVecLNTT(z);
1208
+ polyVecMatrixPointWiseMontgomery(w1, mat, z);
1209
+ polyVecKReduce(w1);
1210
+ polyVecKInvNTTToMont(w1);
1211
+
1212
+ // Decompose w and call the random oracle
1213
+ polyVecKCAddQ(w1);
1214
+ polyVecKDecompose(w1, w0, w1);
1215
+ polyVecKPackW1(sig, w1);
1216
+
1217
+ // ctilde = SHAKE256(mu || w1_packed) (64 bytes)
1218
+ const ctilde = sha3.shake256
1219
+ .create({})
1220
+ .update(mu)
1221
+ .update(sig.slice(0, K * PolyW1PackedBytes))
1222
+ .xof(CTILDEBytes);
1223
+
1224
+ polyChallenge(cp, ctilde);
1225
+ polyNTT(cp);
1226
+
1227
+ // Compute z, reject if it reveals secret
1228
+ polyVecLPointWisePolyMontgomery(z, cp, s1);
1229
+ polyVecLInvNTTToMont(z);
1230
+ polyVecLAdd(z, z, y);
1231
+ polyVecLReduce(z);
1232
+ if (polyVecLChkNorm(z, GAMMA1 - BETA) !== 0) {
1233
+ continue;
1234
+ }
1235
+
1236
+ polyVecKPointWisePolyMontgomery(h, cp, s2);
1237
+ polyVecKInvNTTToMont(h);
1238
+ polyVecKSub(w0, w0, h);
1239
+ polyVecKReduce(w0);
1240
+ if (polyVecKChkNorm(w0, GAMMA2 - BETA) !== 0) {
1241
+ continue;
1242
+ }
1243
+
1244
+ polyVecKPointWisePolyMontgomery(h, cp, t0);
1245
+ polyVecKInvNTTToMont(h);
1246
+ polyVecKReduce(h);
1247
+ if (polyVecKChkNorm(h, GAMMA2) !== 0) {
1248
+ continue;
1249
+ }
1250
+
1251
+ polyVecKAdd(w0, w0, h);
1252
+ const n = polyVecKMakeHint(h, w0, w1);
1253
+ if (n > OMEGA) {
1254
+ continue;
1255
+ }
1256
+
1257
+ packSig(sig, ctilde, z, h);
1258
+ return 0;
1259
+ }
1260
+ }
1261
+
1262
+ /**
1263
+ * Sign a message, returning signature concatenated with message.
1264
+ *
1265
+ * This is the combined sign operation that produces a "signed message" containing
1266
+ * both the signature and the original message (signature || message).
1267
+ *
1268
+ * @param {Uint8Array} msg - Message to sign
1269
+ * @param {Uint8Array} sk - Secret key (must be CryptoSecretKeyBytes = 4896 bytes)
1270
+ * @param {boolean} randomizedSigning - If true, use random nonce; if false, deterministic
1271
+ * @param {Uint8Array} [ctx=DEFAULT_CTX] - Context string for domain separation (max 255 bytes).
1272
+ * Defaults to "ZOND" for QRL compatibility.
1273
+ * @returns {Uint8Array} Signed message (CryptoBytes + msg.length bytes)
1274
+ * @throws {Error} If signing fails
1275
+ *
1276
+ * @example
1277
+ * const signedMsg = cryptoSign(message, sk, false);
1278
+ * // signedMsg contains: signature (4627 bytes) || message
1279
+ */
1280
+ function cryptoSign(msg, sk, randomizedSigning, ctx = DEFAULT_CTX) {
1281
+ const sm = new Uint8Array(CryptoBytes + msg.length);
1282
+ const mLen = msg.length;
1283
+ for (let i = 0; i < mLen; ++i) {
1284
+ sm[CryptoBytes + mLen - 1 - i] = msg[mLen - 1 - i];
1285
+ }
1286
+ const result = cryptoSignSignature(sm, msg, sk, randomizedSigning, ctx);
1287
+
1288
+ if (result !== 0) {
1289
+ throw new Error('failed to sign');
1290
+ }
1291
+ return sm;
1292
+ }
1293
+
1294
+ /**
1295
+ * Verify a detached signature with optional context.
1296
+ *
1297
+ * Performs constant-time verification to prevent timing side-channel attacks.
1298
+ * The context must match the one used during signing.
1299
+ *
1300
+ * @param {Uint8Array} sig - Signature to verify (must be CryptoBytes = 4627 bytes)
1301
+ * @param {string|Uint8Array} m - Message that was signed (hex string or Uint8Array)
1302
+ * @param {Uint8Array} pk - Public key (must be CryptoPublicKeyBytes = 2592 bytes)
1303
+ * @param {Uint8Array} [ctx=DEFAULT_CTX] - Context string used during signing (max 255 bytes).
1304
+ * Defaults to "ZOND" for QRL compatibility.
1305
+ * @returns {boolean} true if signature is valid, false otherwise
1306
+ *
1307
+ * @example
1308
+ * const isValid = cryptoSignVerify(signature, message, pk);
1309
+ * if (!isValid) {
1310
+ * throw new Error('Invalid signature');
1311
+ * }
1312
+ */
1313
+ function cryptoSignVerify(sig, m, pk, ctx = DEFAULT_CTX) {
1314
+ if (ctx.length > 255) return false;
1315
+ let i;
1316
+ const buf = new Uint8Array(K * PolyW1PackedBytes);
1317
+ const rho = new Uint8Array(SeedBytes);
1318
+ const mu = new Uint8Array(CRHBytes);
1319
+ const c = new Uint8Array(CTILDEBytes);
1320
+ const c2 = new Uint8Array(CTILDEBytes);
1321
+ const cp = new Poly();
1322
+ const mat = new Array(K).fill().map(() => new PolyVecL());
1323
+ const z = new PolyVecL();
1324
+ const t1 = new PolyVecK();
1325
+ const w1 = new PolyVecK();
1326
+ const h = new PolyVecK();
1327
+
1328
+ if (sig.length !== CryptoBytes) {
1329
+ return false;
1330
+ }
1331
+ if (pk.length !== CryptoPublicKeyBytes) {
1332
+ return false;
1333
+ }
1334
+
1335
+ unpackPk(rho, t1, pk);
1336
+ if (unpackSig(c, z, h, sig)) {
1337
+ return false;
1338
+ }
1339
+ if (polyVecLChkNorm(z, GAMMA1 - BETA)) {
1340
+ return false;
1341
+ }
1342
+
1343
+ /* Compute mu = SHAKE256(tr || pre || m) with tr = SHAKE256(pk) */
1344
+ const tr = sha3.shake256.create({}).update(pk).xof(TRBytes);
1345
+
1346
+ const pre = new Uint8Array(2 + ctx.length);
1347
+ pre[0] = 0;
1348
+ pre[1] = ctx.length;
1349
+ pre.set(ctx, 2);
1350
+
1351
+ // Convert hex message to bytes
1352
+ const mBytes = typeof m === 'string' ? hexToBytes(m) : m;
1353
+ const muFull = sha3.shake256.create({}).update(tr).update(pre).update(mBytes).xof(CRHBytes);
1354
+ mu.set(muFull);
1355
+
1356
+ /* Matrix-vector multiplication; compute Az - c2^dt1 */
1357
+ polyChallenge(cp, c);
1358
+ polyVecMatrixExpand(mat, rho);
1359
+
1360
+ polyVecLNTT(z);
1361
+ polyVecMatrixPointWiseMontgomery(w1, mat, z);
1362
+
1363
+ polyNTT(cp);
1364
+ polyVecKShiftL(t1);
1365
+ polyVecKNTT(t1);
1366
+ polyVecKPointWisePolyMontgomery(t1, cp, t1);
1367
+
1368
+ polyVecKSub(w1, w1, t1);
1369
+ polyVecKReduce(w1);
1370
+ polyVecKInvNTTToMont(w1);
1371
+
1372
+ /* Reconstruct w1 */
1373
+ polyVecKCAddQ(w1);
1374
+ polyVecKUseHint(w1, w1, h);
1375
+ polyVecKPackW1(buf, w1);
1376
+
1377
+ /* Call random oracle and verify challenge */
1378
+ const c2Hash = sha3.shake256.create({}).update(mu).update(buf).xof(CTILDEBytes);
1379
+ c2.set(c2Hash);
1380
+
1381
+ // Constant-time comparison to prevent timing attacks
1382
+ let diff = 0;
1383
+ for (i = 0; i < CTILDEBytes; ++i) {
1384
+ diff |= c[i] ^ c2[i];
1385
+ }
1386
+ return diff === 0;
1387
+ }
1388
+
1389
+ /**
1390
+ * Open a signed message (verify and extract message).
1391
+ *
1392
+ * This is the counterpart to cryptoSign(). It verifies the signature and
1393
+ * extracts the original message from a signed message.
1394
+ *
1395
+ * @param {Uint8Array} sm - Signed message (signature || message)
1396
+ * @param {Uint8Array} pk - Public key (must be CryptoPublicKeyBytes = 2592 bytes)
1397
+ * @param {Uint8Array} [ctx=DEFAULT_CTX] - Context string used during signing (max 255 bytes).
1398
+ * Defaults to "ZOND" for QRL compatibility.
1399
+ * @returns {Uint8Array|undefined} The original message if valid, undefined if verification fails
1400
+ *
1401
+ * @example
1402
+ * const message = cryptoSignOpen(signedMsg, pk);
1403
+ * if (message === undefined) {
1404
+ * throw new Error('Invalid signature');
1405
+ * }
1406
+ */
1407
+ function cryptoSignOpen(sm, pk, ctx = DEFAULT_CTX) {
1408
+ if (sm.length < CryptoBytes) {
1409
+ return undefined;
1410
+ }
1411
+
1412
+ const sig = sm.slice(0, CryptoBytes);
1413
+ const msg = sm.slice(CryptoBytes);
1414
+ if (!cryptoSignVerify(sig, msg, pk, ctx)) {
1415
+ return undefined;
1416
+ }
1417
+
1418
+ return msg;
1419
+ }
1420
+
1421
+ /**
1422
+ * Security utilities for ML-DSA-87
1423
+ *
1424
+ * IMPORTANT: JavaScript cannot guarantee secure memory zeroization.
1425
+ * See SECURITY.md for details on limitations.
1426
+ */
1427
+
1428
+ /**
1429
+ * Attempts to zero out a Uint8Array buffer.
1430
+ *
1431
+ * WARNING: This is a BEST-EFFORT operation. Due to JavaScript/JIT limitations:
1432
+ * - The write may be optimized away if the buffer is unused afterward
1433
+ * - Copies may exist in garbage collector memory
1434
+ * - Data may have been swapped to disk
1435
+ *
1436
+ * For high-security applications, consider native implementations (go-qrllib)
1437
+ * or hardware security modules.
1438
+ *
1439
+ * @param {Uint8Array} buffer - The buffer to zero
1440
+ * @returns {void}
1441
+ */
1442
+ function zeroize(buffer) {
1443
+ if (!(buffer instanceof Uint8Array)) {
1444
+ throw new TypeError('zeroize requires a Uint8Array');
1445
+ }
1446
+ // Use fill(0) for zeroing - best effort
1447
+ buffer.fill(0);
1448
+ // Additional volatile-like access to discourage optimization
1449
+ // (This is a hint to the JIT, not a guarantee)
1450
+ if (buffer.length > 0 && buffer[0] !== 0) {
1451
+ throw new Error('zeroize failed'); // Should never happen
1452
+ }
1453
+ }
1454
+
1455
+ /**
1456
+ * Checks if a buffer is all zeros.
1457
+ * Uses constant-time comparison to avoid timing leaks.
1458
+ *
1459
+ * @param {Uint8Array} buffer - The buffer to check
1460
+ * @returns {boolean} True if all bytes are zero
1461
+ */
1462
+ function isZero(buffer) {
1463
+ if (!(buffer instanceof Uint8Array)) {
1464
+ throw new TypeError('isZero requires a Uint8Array');
1465
+ }
1466
+ let acc = 0;
1467
+ for (let i = 0; i < buffer.length; i++) {
1468
+ acc |= buffer[i];
1469
+ }
1470
+ return acc === 0;
1471
+ }
1472
+
1473
+ exports.BETA = BETA;
1474
+ exports.CRHBytes = CRHBytes;
1475
+ exports.CTILDEBytes = CTILDEBytes;
1476
+ exports.CryptoBytes = CryptoBytes;
1477
+ exports.CryptoPublicKeyBytes = CryptoPublicKeyBytes;
1478
+ exports.CryptoSecretKeyBytes = CryptoSecretKeyBytes;
1479
+ exports.D = D;
1480
+ exports.ETA = ETA;
1481
+ exports.GAMMA1 = GAMMA1;
1482
+ exports.GAMMA2 = GAMMA2;
1483
+ exports.K = K;
1484
+ exports.KeccakState = KeccakState;
1485
+ exports.L = L;
1486
+ exports.N = N;
1487
+ exports.OMEGA = OMEGA;
1488
+ exports.Poly = Poly;
1489
+ exports.PolyETAPackedBytes = PolyETAPackedBytes;
1490
+ exports.PolyT0PackedBytes = PolyT0PackedBytes;
1491
+ exports.PolyT1PackedBytes = PolyT1PackedBytes;
1492
+ exports.PolyUniformETANBlocks = PolyUniformETANBlocks;
1493
+ exports.PolyUniformGamma1NBlocks = PolyUniformGamma1NBlocks;
1494
+ exports.PolyUniformNBlocks = PolyUniformNBlocks;
1495
+ exports.PolyVecHPackedBytes = PolyVecHPackedBytes;
1496
+ exports.PolyVecK = PolyVecK;
1497
+ exports.PolyVecL = PolyVecL;
1498
+ exports.PolyW1PackedBytes = PolyW1PackedBytes;
1499
+ exports.PolyZPackedBytes = PolyZPackedBytes;
1500
+ exports.Q = Q;
1501
+ exports.QInv = QInv;
1502
+ exports.RNDBytes = RNDBytes;
1503
+ exports.SeedBytes = SeedBytes;
1504
+ exports.Shake128Rate = Shake128Rate;
1505
+ exports.Shake256Rate = Shake256Rate;
1506
+ exports.Stream128BlockBytes = Stream128BlockBytes;
1507
+ exports.Stream256BlockBytes = Stream256BlockBytes;
1508
+ exports.TAU = TAU;
1509
+ exports.TRBytes = TRBytes;
1510
+ exports.cAddQ = cAddQ;
1511
+ exports.cryptoSign = cryptoSign;
1512
+ exports.cryptoSignKeypair = cryptoSignKeypair;
1513
+ exports.cryptoSignOpen = cryptoSignOpen;
1514
+ exports.cryptoSignSignature = cryptoSignSignature;
1515
+ exports.cryptoSignVerify = cryptoSignVerify;
1516
+ exports.decompose = decompose;
1517
+ exports.invNTTToMont = invNTTToMont;
1518
+ exports.isZero = isZero;
1519
+ exports.makeHint = makeHint;
1520
+ exports.mldsaShake128StreamInit = mldsaShake128StreamInit;
1521
+ exports.mldsaShake256StreamInit = mldsaShake256StreamInit;
1522
+ exports.montgomeryReduce = montgomeryReduce;
1523
+ exports.ntt = ntt;
1524
+ exports.packPk = packPk;
1525
+ exports.packSig = packSig;
1526
+ exports.packSk = packSk;
1527
+ exports.polyAdd = polyAdd;
1528
+ exports.polyCAddQ = polyCAddQ;
1529
+ exports.polyChallenge = polyChallenge;
1530
+ exports.polyChkNorm = polyChkNorm;
1531
+ exports.polyDecompose = polyDecompose;
1532
+ exports.polyEtaPack = polyEtaPack;
1533
+ exports.polyEtaUnpack = polyEtaUnpack;
1534
+ exports.polyInvNTTToMont = polyInvNTTToMont;
1535
+ exports.polyMakeHint = polyMakeHint;
1536
+ exports.polyNTT = polyNTT;
1537
+ exports.polyPointWiseMontgomery = polyPointWiseMontgomery;
1538
+ exports.polyPower2round = polyPower2round;
1539
+ exports.polyReduce = polyReduce;
1540
+ exports.polyShiftL = polyShiftL;
1541
+ exports.polySub = polySub;
1542
+ exports.polyT0Pack = polyT0Pack;
1543
+ exports.polyT0Unpack = polyT0Unpack;
1544
+ exports.polyT1Pack = polyT1Pack;
1545
+ exports.polyT1Unpack = polyT1Unpack;
1546
+ exports.polyUniform = polyUniform;
1547
+ exports.polyUniformEta = polyUniformEta;
1548
+ exports.polyUniformGamma1 = polyUniformGamma1;
1549
+ exports.polyUseHint = polyUseHint;
1550
+ exports.polyVecKAdd = polyVecKAdd;
1551
+ exports.polyVecKCAddQ = polyVecKCAddQ;
1552
+ exports.polyVecKChkNorm = polyVecKChkNorm;
1553
+ exports.polyVecKDecompose = polyVecKDecompose;
1554
+ exports.polyVecKInvNTTToMont = polyVecKInvNTTToMont;
1555
+ exports.polyVecKMakeHint = polyVecKMakeHint;
1556
+ exports.polyVecKNTT = polyVecKNTT;
1557
+ exports.polyVecKPackW1 = polyVecKPackW1;
1558
+ exports.polyVecKPointWisePolyMontgomery = polyVecKPointWisePolyMontgomery;
1559
+ exports.polyVecKPower2round = polyVecKPower2round;
1560
+ exports.polyVecKReduce = polyVecKReduce;
1561
+ exports.polyVecKShiftL = polyVecKShiftL;
1562
+ exports.polyVecKSub = polyVecKSub;
1563
+ exports.polyVecKUniformEta = polyVecKUniformEta;
1564
+ exports.polyVecKUseHint = polyVecKUseHint;
1565
+ exports.polyVecLAdd = polyVecLAdd;
1566
+ exports.polyVecLChkNorm = polyVecLChkNorm;
1567
+ exports.polyVecLInvNTTToMont = polyVecLInvNTTToMont;
1568
+ exports.polyVecLNTT = polyVecLNTT;
1569
+ exports.polyVecLPointWiseAccMontgomery = polyVecLPointWiseAccMontgomery;
1570
+ exports.polyVecLPointWisePolyMontgomery = polyVecLPointWisePolyMontgomery;
1571
+ exports.polyVecLReduce = polyVecLReduce;
1572
+ exports.polyVecLUniformEta = polyVecLUniformEta;
1573
+ exports.polyVecLUniformGamma1 = polyVecLUniformGamma1;
1574
+ exports.polyVecMatrixExpand = polyVecMatrixExpand;
1575
+ exports.polyVecMatrixPointWiseMontgomery = polyVecMatrixPointWiseMontgomery;
1576
+ exports.polyW1Pack = polyW1Pack;
1577
+ exports.polyZPack = polyZPack;
1578
+ exports.polyZUnpack = polyZUnpack;
1579
+ exports.power2round = power2round;
1580
+ exports.reduce32 = reduce32;
1581
+ exports.rejEta = rejEta;
1582
+ exports.rejUniform = rejUniform;
1583
+ exports.shake128Absorb = shake128Absorb;
1584
+ exports.shake128Finalize = shake128Finalize;
1585
+ exports.shake128Init = shake128Init;
1586
+ exports.shake128SqueezeBlocks = shake128SqueezeBlocks;
1587
+ exports.shake256Absorb = shake256Absorb;
1588
+ exports.shake256Finalize = shake256Finalize;
1589
+ exports.shake256Init = shake256Init;
1590
+ exports.shake256SqueezeBlocks = shake256SqueezeBlocks;
1591
+ exports.unpackPk = unpackPk;
1592
+ exports.unpackSig = unpackSig;
1593
+ exports.unpackSk = unpackSk;
1594
+ exports.useHint = useHint;
1595
+ exports.zeroize = zeroize;
1596
+ exports.zetas = zetas;