@noble/post-quantum 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/ml-dsa.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) */
2
2
  import { shake256 } from '@noble/hashes/sha3';
3
- import { genCrystals, XOF, XOF128, XOF256, XOF_AES } from './_crystals.js';
3
+ import { genCrystals, XOF, XOF128, XOF256 } from './_crystals.js';
4
4
  import {
5
5
  BytesCoderLen,
6
6
  Signer,
@@ -18,11 +18,6 @@ Lattice-based digital signature algorithm. See
18
18
  [repo](https://github.com/pq-crystals/dilithium).
19
19
  Dilithium has similar internals to Kyber, but their keys and params are different.
20
20
 
21
- Three versions are provided:
22
-
23
- 1. Dilithium v3.0, v3.0 AES
24
- 2. Dilithium v3.1, v3.1 AES
25
- 3. ML-DSA aka [FIPS-204](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.ipd.pdf)
26
21
  */
27
22
 
28
23
  // Constants
@@ -135,13 +130,11 @@ type DilithiumOpts = {
135
130
  TR_BYTES: number;
136
131
  XOF128: XOF;
137
132
  XOF256: XOF;
138
- FIPS204?: boolean;
139
- V31?: boolean;
140
133
  };
141
134
 
142
135
  function getDilithium(opts: DilithiumOpts): Signer {
143
136
  const { K, L, GAMMA1, GAMMA2, TAU, ETA, OMEGA } = opts;
144
- const { FIPS204, V31, CRH_BYTES, TR_BYTES, C_TILDE_BYTES, XOF128, XOF256 } = opts;
137
+ const { CRH_BYTES, TR_BYTES, C_TILDE_BYTES, XOF128, XOF256 } = opts;
145
138
 
146
139
  if (![2, 4].includes(ETA)) throw new Error('Wrong ETA');
147
140
  if (![1 << 17, 1 << 19].includes(GAMMA1)) throw new Error('Wrong GAMMA1');
@@ -171,6 +164,8 @@ function getDilithium(opts: DilithiumOpts): Signer {
171
164
  // But they return different results! However, decompose is same.
172
165
  // So, either there is a bug in Dilithium ref implementation or in FIPS204.
173
166
  // For now, lets use dilithium one, so test vectors can be passed.
167
+ // See
168
+ // https://github.com/GiacomoPope/dilithium-py?tab=readme-ov-file#optimising-decomposition-and-making-hints
174
169
  return res0;
175
170
  };
176
171
 
@@ -262,7 +257,7 @@ function getDilithium(opts: DilithiumOpts): Signer {
262
257
  const SampleInBall = (seed: Uint8Array) => {
263
258
  // Samples a polynomial c ∈ Rq with coeffcients from {−1, 0, 1} and Hamming weight τ
264
259
  const pre = newPoly(N);
265
- const s = shake256.create({}).update(seed.slice(0, 32));
260
+ const s = shake256.create({}).update(seed);
266
261
  const buf = new Uint8Array(shake256.blockLen);
267
262
  s.xofInto(buf);
268
263
  const masks = buf.slice(0, 8);
@@ -309,15 +304,21 @@ function getDilithium(opts: DilithiumOpts): Signer {
309
304
  return { v, cnt };
310
305
  };
311
306
 
312
- const signRandBytes = FIPS204 ? 32 : CRH_BYTES;
313
- const seedCoder = splitCoder(32, V31 ? 64 : 32, 32);
314
- const seedXOF = V31 ? XOF256 : XOF128;
307
+ const signRandBytes = 32;
308
+ const seedCoder = splitCoder(32, 64, 32);
315
309
  // API & argument positions are exactly as in FIPS204.
316
310
  return {
317
311
  signRandBytes,
318
312
  keygen: (seed = randomBytes(32)) => {
319
- const [rho, rhoPrime, K_] = seedCoder.decode(shake256(seed, { dkLen: seedCoder.bytesLen }));
320
- const xofPrime = seedXOF(rhoPrime);
313
+ // H(𝜉||IntegerToBytes(𝑘, 1)||IntegerToBytes(ℓ, 1), 128) 2: expand seed
314
+ const seedDst = new Uint8Array(32 + 2);
315
+ seedDst.set(seed);
316
+ seedDst[32] = K;
317
+ seedDst[33] = L;
318
+ const [rho, rhoPrime, K_] = seedCoder.decode(
319
+ shake256(seedDst, { dkLen: seedCoder.bytesLen })
320
+ );
321
+ const xofPrime = XOF256(rhoPrime);
321
322
  const s1 = [];
322
323
  for (let i = 0; i < L; i++) s1.push(RejBoundedPoly(xofPrime.get(i & 0xff, (i >> 8) & 0xff)));
323
324
  const s2 = [];
@@ -348,7 +349,7 @@ function getDilithium(opts: DilithiumOpts): Signer {
348
349
  // STATS
349
350
  // Kyber512: { calls: 4, xofs: 12 }, Kyber768: { calls: 9, xofs: 27 }, Kyber1024: { calls: 16, xofs: 48 }
350
351
  // DSA44: { calls: 24, xofs: 24 }, DSA65: { calls: 41, xofs: 41 }, DSA87: { calls: 71, xofs: 71 }
351
- cleanBytes(rho, rhoPrime, K_, s1, s2, s1Hat, t, t0, t1, tr);
352
+ cleanBytes(rho, rhoPrime, K_, s1, s2, s1Hat, t, t0, t1, tr, seedDst);
352
353
  return { publicKey, secretKey };
353
354
  },
354
355
  // NOTE: random is optional.
@@ -372,16 +373,17 @@ function getDilithium(opts: DilithiumOpts): Signer {
372
373
  }
373
374
  // This part is per msg
374
375
  const mu = shake256.create({ dkLen: CRH_BYTES }).update(tr).update(msg).digest(); // 6: µ ← H(tr||M, 512) ▷ Compute message representative µ
375
- let rhoprime; // Compute private random seed
376
- if (FIPS204) {
377
- const rnd = random ? random : new Uint8Array(32);
378
- ensureBytes(rnd);
379
- rhoprime = shake256.create({ dkLen: CRH_BYTES }).update(_K).update(rnd).update(mu).digest(); // ρ′← H(K||rnd||µ, 512)
380
- } else {
381
- rhoprime = random
382
- ? random
383
- : shake256.create({ dkLen: CRH_BYTES }).update(_K).update(mu).digest();
384
- }
376
+
377
+ // Compute private random seed
378
+ const rnd = random ? random : new Uint8Array(32);
379
+ ensureBytes(rnd);
380
+ const rhoprime = shake256
381
+ .create({ dkLen: CRH_BYTES })
382
+ .update(_K)
383
+ .update(rnd)
384
+ .update(mu)
385
+ .digest(); // ρ′← H(K||rnd||µ, 512)
386
+
385
387
  ensureBytes(rhoprime, CRH_BYTES);
386
388
  const x256 = XOF256(rhoprime, ZCoder.bytesLen);
387
389
  // Rejection sampling loop
@@ -407,7 +409,7 @@ function getDilithium(opts: DilithiumOpts): Signer {
407
409
  .update(W1Vec.encode(w1))
408
410
  .digest();
409
411
  // Verifer’s challenge
410
- const cHat = NTT.encode(SampleInBall(cTilde.subarray(0, 32))); // c ← SampleInBall(c˜1); cˆ ← NTT(c)
412
+ const cHat = NTT.encode(SampleInBall(cTilde)); // c ← SampleInBall(c˜1); cˆ ← NTT(c)
411
413
  // ⟨⟨cs1⟩⟩ ← NTT−1(cˆ◦ sˆ1)
412
414
  const cs1 = s1.map((i) => MultiplyNTTs(i, cHat));
413
415
  for (let i = 0; i < L; i++) {
@@ -450,7 +452,7 @@ function getDilithium(opts: DilithiumOpts): Signer {
450
452
  for (let i = 0; i < L; i++) if (polyChknorm(z[i], GAMMA1 - BETA)) return false;
451
453
  const mu = shake256.create({ dkLen: CRH_BYTES }).update(tr).update(msg).digest(); // 7: µ ← H(tr||M, 512)
452
454
  // Compute verifer’s challenge from c˜
453
- const c = NTT.encode(SampleInBall(cTilde.subarray(0, 32))); // c ← SampleInBall(c˜1)
455
+ const c = NTT.encode(SampleInBall(cTilde)); // c ← SampleInBall(c˜1)
454
456
  const zNtt = z.map((i) => i.slice()); // zNtt = NTT(z)
455
457
  for (let i = 0; i < L; i++) NTT.encode(zNtt[i]);
456
458
  const wTick1 = [];
@@ -474,66 +476,18 @@ function getDilithium(opts: DilithiumOpts): Signer {
474
476
  .update(mu)
475
477
  .update(W1Vec.encode(wTick1))
476
478
  .digest();
477
- if (FIPS204) {
478
- // Additional checks in FIPS-204:
479
- // [[ ||z||∞ < γ1 − β ]] and [[c ˜ = c˜′]] and [[number of 1’s in h is ≤ ω]]
480
- for (const t of h) {
481
- const sum = t.reduce((acc, i) => acc + i, 0);
482
- if (!(sum <= OMEGA)) return false;
483
- }
484
- for (const t of z) if (polyChknorm(t, GAMMA1 - BETA)) return false;
479
+ // Additional checks in FIPS-204:
480
+ // [[ ||z||∞ < γ1 − β ]] and [[c ˜ = c˜′]] and [[number of 1’s in h is ≤ ω]]
481
+ for (const t of h) {
482
+ const sum = t.reduce((acc, i) => acc + i, 0);
483
+ if (!(sum <= OMEGA)) return false;
485
484
  }
485
+ for (const t of z) if (polyChknorm(t, GAMMA1 - BETA)) return false;
486
486
  return equalBytes(cTilde, c2);
487
487
  },
488
488
  };
489
489
  }
490
490
 
491
- function getDilithiumVersions(cfg: Partial<DilithiumOpts>) {
492
- return {
493
- dilithium2: getDilithium({ ...PARAMS[2], ...cfg } as DilithiumOpts),
494
- dilithium3: getDilithium({ ...PARAMS[3], ...cfg } as DilithiumOpts),
495
- dilithium5: getDilithium({ ...PARAMS[5], ...cfg } as DilithiumOpts),
496
- };
497
- }
498
-
499
- // v30 is NIST round 3 submission, for original vectors and benchmarking.
500
- // v31 is kyber: more secure than v30.
501
- // ml-dsa is NIST FIPS 204, but it is still a draft and may change.
502
-
503
- export const dilithium_v30 = /* @__PURE__ */ getDilithiumVersions({
504
- CRH_BYTES: 48,
505
- TR_BYTES: 48,
506
- C_TILDE_BYTES: 32,
507
- XOF128,
508
- XOF256,
509
- });
510
-
511
- export const dilithium_v31 = /* @__PURE__ */ getDilithiumVersions({
512
- CRH_BYTES: 64,
513
- TR_BYTES: 32,
514
- C_TILDE_BYTES: 32,
515
- XOF128,
516
- XOF256,
517
- V31: true,
518
- });
519
-
520
- export const dilithium_v30_aes = /* @__PURE__ */ getDilithiumVersions({
521
- CRH_BYTES: 48,
522
- TR_BYTES: 48,
523
- C_TILDE_BYTES: 32,
524
- XOF128: XOF_AES,
525
- XOF256: XOF_AES,
526
- });
527
-
528
- export const dilithium_v31_aes = /* @__PURE__ */ getDilithiumVersions({
529
- CRH_BYTES: 64,
530
- TR_BYTES: 32,
531
- C_TILDE_BYTES: 32,
532
- XOF128: XOF_AES,
533
- XOF256: XOF_AES,
534
- V31: true,
535
- });
536
-
537
491
  // ML-DSA
538
492
  export const ml_dsa44 = /* @__PURE__ */ getDilithium({
539
493
  ...PARAMS[2],
@@ -542,8 +496,6 @@ export const ml_dsa44 = /* @__PURE__ */ getDilithium({
542
496
  C_TILDE_BYTES: 32,
543
497
  XOF128,
544
498
  XOF256,
545
- V31: true,
546
- FIPS204: true,
547
499
  });
548
500
 
549
501
  export const ml_dsa65 = /* @__PURE__ */ getDilithium({
@@ -553,8 +505,6 @@ export const ml_dsa65 = /* @__PURE__ */ getDilithium({
553
505
  C_TILDE_BYTES: 48,
554
506
  XOF128,
555
507
  XOF256,
556
- V31: true,
557
- FIPS204: true,
558
508
  });
559
509
 
560
510
  export const ml_dsa87 = /* @__PURE__ */ getDilithium({
@@ -564,6 +514,4 @@ export const ml_dsa87 = /* @__PURE__ */ getDilithium({
564
514
  C_TILDE_BYTES: 64,
565
515
  XOF128,
566
516
  XOF256,
567
- V31: true,
568
- FIPS204: true,
569
517
  });
package/src/ml-kem.ts CHANGED
@@ -1,9 +1,7 @@
1
1
  /*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) */
2
- import { ctr } from '@noble/ciphers/aes';
3
- import { sha256, sha512 } from '@noble/hashes/sha2';
4
2
  import { sha3_256, sha3_512, shake256 } from '@noble/hashes/sha3';
5
3
  import { u32, wrapConstructor, wrapConstructorWithOpts } from '@noble/hashes/utils';
6
- import { genCrystals, XOF, XOF_AES, XOF128 } from './_crystals.js';
4
+ import { genCrystals, XOF, XOF128 } from './_crystals.js';
7
5
  import {
8
6
  Coder,
9
7
  cleanBytes,
@@ -34,16 +32,11 @@ There are some concerns with regards to security: see
34
32
  [djb blog](https://blog.cr.yp.to/20231003-countcorrectly.html) and
35
33
  [mailing list](https://groups.google.com/a/list.nist.gov/g/pqc-forum/c/W2VOzy0wz_E).
36
34
 
37
- Three versions are provided:
38
-
39
- 1. Kyber
40
- 2. Kyber-90s, using algorithms from 1990s
41
- 3. ML-KEM aka [FIPS-203](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.ipd.pdf)
42
35
  */
43
36
 
44
37
  const N = 256; // Kyber (not FIPS-203) supports different lengths, but all std modes were using 256
45
38
  const Q = 3329; // 13*(2**8)+1, modulo prime
46
- const F = 3303; // 3303 ≡ 128−1 mod q (FIPS-203)
39
+ const F = 3303; // 3303 ≡ 128**(−1) mod q (FIPS-203)
47
40
  const ROOT_OF_UNITY = 17; // ζ = 17 ∈ Zq is a primitive 256-th root of unity modulo Q. ζ**128 ≡−1
48
41
  const { mod, nttZetas, NTT, bitsCoder } = genCrystals({
49
42
  N,
@@ -136,7 +129,6 @@ type KyberOpts = ParameterSet & {
136
129
  KDF: Hash | HashWOpts;
137
130
  XOF: XOF; // (seed: Uint8Array, len: number, x: number, y: number) => Uint8Array;
138
131
  PRF: PRF;
139
- FIPS203?: boolean;
140
132
  };
141
133
 
142
134
  // Return poly in NTT representation
@@ -185,7 +177,7 @@ function sampleCBD(PRF: PRF, seed: Uint8Array, nonce: number, eta: number): Poly
185
177
  // K-PKE
186
178
  // As per FIPS-203, it doesn't perform any input validation and can't be used in standalone fashion.
187
179
  const genKPKE = (opts: KyberOpts) => {
188
- const { K, PRF, XOF, HASH512, ETA1, ETA2, du, dv, FIPS203 } = opts;
180
+ const { K, PRF, XOF, HASH512, ETA1, ETA2, du, dv } = opts;
189
181
  const poly1 = polyCoder(1);
190
182
  const polyV = polyCoder(dv);
191
183
  const polyU = polyCoder(du);
@@ -199,7 +191,12 @@ const genKPKE = (opts: KyberOpts) => {
199
191
  publicKeyLen: publicCoder.bytesLen,
200
192
  cipherTextLen: cipherCoder.bytesLen,
201
193
  keygen: (seed: Uint8Array) => {
202
- const [rho, sigma] = seedCoder.decode(HASH512(seed));
194
+ const seedDst = new Uint8Array(33);
195
+ seedDst.set(seed);
196
+ seedDst[32] = K;
197
+ const seedHash = HASH512(seedDst);
198
+
199
+ const [rho, sigma] = seedCoder.decode(seedHash);
203
200
  const sHat: Poly[] = [];
204
201
  const tHat: Poly[] = [];
205
202
  for (let i = 0; i < K; i++) sHat.push(NTT.encode(sampleCBD(PRF, sigma, i, ETA1)));
@@ -207,7 +204,7 @@ const genKPKE = (opts: KyberOpts) => {
207
204
  for (let i = 0; i < K; i++) {
208
205
  const e = NTT.encode(sampleCBD(PRF, sigma, K + i, ETA1));
209
206
  for (let j = 0; j < K; j++) {
210
- const aji = SampleNTT(FIPS203 ? x.get(i, j) : x.get(j, i)); // A[j][i], inplace
207
+ const aji = SampleNTT(x.get(j, i)); // A[j][i], inplace
211
208
  polyAdd(e, MultiplyNTTs(aji, sHat[j]));
212
209
  }
213
210
  tHat.push(e); // t ← A ◦ s + e
@@ -217,7 +214,7 @@ const genKPKE = (opts: KyberOpts) => {
217
214
  publicKey: publicCoder.encode([tHat, rho]),
218
215
  secretKey: secretCoder.encode(sHat),
219
216
  };
220
- cleanBytes(rho, sigma, sHat, tHat);
217
+ cleanBytes(rho, sigma, sHat, tHat, seedDst, seedHash);
221
218
  return res;
222
219
  },
223
220
  encrypt: (publicKey: Uint8Array, msg: Uint8Array, seed: Uint8Array) => {
@@ -231,7 +228,7 @@ const genKPKE = (opts: KyberOpts) => {
231
228
  const e1 = sampleCBD(PRF, seed, K + i, ETA2);
232
229
  const tmp = new Uint16Array(N);
233
230
  for (let j = 0; j < K; j++) {
234
- const aij = SampleNTT(FIPS203 ? x.get(j, i) : x.get(i, j)); // A[i][j], inplace
231
+ const aij = SampleNTT(x.get(i, j)); // A[i][j], inplace
235
232
  polyAdd(tmp, MultiplyNTTs(aij, rHat[j])); // t += aij * rHat[j]
236
233
  }
237
234
  polyAdd(e1, NTT.decode(tmp)); // e1 += tmp
@@ -261,7 +258,7 @@ const genKPKE = (opts: KyberOpts) => {
261
258
 
262
259
  function createKyber(opts: KyberOpts) {
263
260
  const KPKE = genKPKE(opts);
264
- const { HASH256, HASH512, KDF, FIPS203 } = opts;
261
+ const { HASH256, HASH512, KDF } = opts;
265
262
  const { secretCoder: KPKESecretCoder, cipherTextLen } = KPKE;
266
263
  const publicKeyLen = KPKE.publicKeyLen; // 384*K+32
267
264
  const secretCoder = splitCoder(KPKE.secretKeyLen, KPKE.publicKeyLen, 32, 32);
@@ -282,29 +279,21 @@ function createKyber(opts: KyberOpts) {
282
279
  encapsulate: (publicKey: Uint8Array, msg = randomBytes(32)) => {
283
280
  ensureBytes(publicKey, publicKeyLen);
284
281
  ensureBytes(msg, msgLen);
285
- if (!FIPS203) msg = HASH256(msg); // NOTE: ML-KEM doesn't have this step!
286
- else {
287
- // FIPS-203 includes additional verification check for modulus
288
- const eke = publicKey.subarray(0, 384 * opts.K);
289
- const ek = KPKESecretCoder.encode(KPKESecretCoder.decode(eke.slice())); // Copy because of inplace encoding
290
- // (Modulus check.) Perform the computation ek ByteEncode12(ByteDecode12(eke)).
291
- // If ek = ̸ eke, the input is invalid. (See Section 4.2.1.)
292
- if (!equalBytes(ek, eke)) {
293
- cleanBytes(ek);
294
- throw new Error('ML-KEM.encapsulate: wrong publicKey modulus');
295
- }
282
+
283
+ // FIPS-203 includes additional verification check for modulus
284
+ const eke = publicKey.subarray(0, 384 * opts.K);
285
+ const ek = KPKESecretCoder.encode(KPKESecretCoder.decode(eke.slice())); // Copy because of inplace encoding
286
+ // (Modulus check.) Perform the computation ek ByteEncode12(ByteDecode12(eke)).
287
+ // If ek = ̸ eke, the input is invalid. (See Section 4.2.1.)
288
+ if (!equalBytes(ek, eke)) {
296
289
  cleanBytes(ek);
290
+ throw new Error('ML-KEM.encapsulate: wrong publicKey modulus');
297
291
  }
292
+ cleanBytes(ek);
298
293
  const kr = HASH512.create().update(msg).update(HASH256(publicKey)).digest(); // derive randomness
299
294
  const cipherText = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64));
300
- if (FIPS203) return { cipherText, sharedSecret: kr.subarray(0, 32) };
301
- const cipherTextHash = HASH256(cipherText);
302
- const sharedSecret = KDF.create({})
303
- .update(kr.subarray(0, 32))
304
- .update(cipherTextHash)
305
- .digest();
306
- cleanBytes(kr, cipherTextHash);
307
- return { cipherText, sharedSecret };
295
+ kr.subarray(32).fill(0);
296
+ return { cipherText, sharedSecret: kr.subarray(0, 32) };
308
297
  },
309
298
  decapsulate: (cipherText: Uint8Array, secretKey: Uint8Array) => {
310
299
  ensureBytes(secretKey, secretKeyLen); // 768*k + 96
@@ -315,43 +304,13 @@ function createKyber(opts: KyberOpts) {
315
304
  const Khat = kr.subarray(0, 32);
316
305
  const cipherText2 = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64)); // re-encrypt using the derived randomness
317
306
  const isValid = equalBytes(cipherText, cipherText2); // if ciphertexts do not match, “implicitly reject”
318
- if (FIPS203) {
319
- const Kbar = KDF.create({ dkLen: 32 }).update(z).update(cipherText).digest();
320
- cleanBytes(msg, cipherText2, !isValid ? Khat : Kbar);
321
- return isValid ? Khat : Kbar;
322
- }
323
- const cipherTextHash = HASH256(cipherText);
324
- const sharedSecret = KDF.create({ dkLen: 32 })
325
- .update(isValid ? Khat : z)
326
- .update(cipherTextHash)
327
- .digest();
328
- cleanBytes(msg, cipherTextHash, cipherText2, Khat, z);
329
- return sharedSecret;
307
+ const Kbar = KDF.create({ dkLen: 32 }).update(z).update(cipherText).digest();
308
+ cleanBytes(msg, cipherText2, !isValid ? Khat : Kbar);
309
+ return isValid ? Khat : Kbar;
330
310
  },
331
311
  };
332
312
  }
333
313
 
334
- function PRF(l: number, key: Uint8Array, nonce: number) {
335
- const _nonce = new Uint8Array(16);
336
- _nonce[0] = nonce;
337
- return ctr(key, _nonce).encrypt(new Uint8Array(l));
338
- }
339
-
340
- const opts90s = { HASH256: sha256, HASH512: sha512, KDF: sha256, XOF: XOF_AES, PRF };
341
-
342
- export const kyber512_90s = /* @__PURE__ */ createKyber({
343
- ...opts90s,
344
- ...PARAMS[512],
345
- });
346
- export const kyber768_90s = /* @__PURE__ */ createKyber({
347
- ...opts90s,
348
- ...PARAMS[768],
349
- });
350
- export const kyber1024_90s = /* @__PURE__ */ createKyber({
351
- ...opts90s,
352
- ...PARAMS[1024],
353
- });
354
-
355
314
  function shakePRF(dkLen: number, key: Uint8Array, nonce: number) {
356
315
  return shake256
357
316
  .create({ dkLen })
@@ -368,36 +327,18 @@ const opts = {
368
327
  PRF: shakePRF,
369
328
  };
370
329
 
371
- export const kyber512 = /* @__PURE__ */ createKyber({
372
- ...opts,
373
- ...PARAMS[512],
374
- });
375
- export const kyber768 = /* @__PURE__ */ createKyber({
376
- ...opts,
377
- ...PARAMS[768],
378
- });
379
- export const kyber1024 = /* @__PURE__ */ createKyber({
380
- ...opts,
381
- ...PARAMS[1024],
382
- });
383
-
384
330
  /**
385
- * FIPS-203 (draft) ML-KEM.
386
- * Unsafe: we can't cross-verify, because there are no test vectors or other implementations.
331
+ * FIPS-203 ML-KEM.
387
332
  */
388
-
389
333
  export const ml_kem512 = /* @__PURE__ */ createKyber({
390
334
  ...opts,
391
335
  ...PARAMS[512],
392
- FIPS203: true,
393
336
  });
394
337
  export const ml_kem768 = /* @__PURE__ */ createKyber({
395
338
  ...opts,
396
339
  ...PARAMS[768],
397
- FIPS203: true,
398
340
  });
399
341
  export const ml_kem1024 = /* @__PURE__ */ createKyber({
400
342
  ...opts,
401
343
  ...PARAMS[1024],
402
- FIPS203: true,
403
344
  });