@noble/post-quantum 0.6.0 → 0.7.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/README.md +106 -80
- package/_crystals.d.ts +23 -16
- package/_crystals.js +50 -12
- package/falcon.d.ts +7 -8
- package/falcon.js +109 -74
- package/hybrid.d.ts +21 -32
- package/hybrid.js +157 -78
- package/index.d.ts +0 -1
- package/index.js +8 -1
- package/ml-dsa.d.ts +35 -9
- package/ml-dsa.js +116 -43
- package/ml-kem.d.ts +46 -5
- package/ml-kem.js +175 -67
- package/package.json +10 -18
- package/slh-dsa.d.ts +44 -24
- package/slh-dsa.js +150 -84
- package/src/_crystals.ts +86 -35
- package/src/falcon.ts +230 -169
- package/src/hybrid.ts +243 -129
- package/src/index.ts +8 -0
- package/src/ml-dsa.ts +194 -87
- package/src/ml-kem.ts +283 -122
- package/src/slh-dsa.ts +310 -182
- package/src/utils.ts +244 -48
- package/utils.d.ts +99 -24
- package/utils.js +92 -24
- package/_crystals.d.ts.map +0 -1
- package/_crystals.js.map +0 -1
- package/falcon.d.ts.map +0 -1
- package/falcon.js.map +0 -1
- package/hybrid.d.ts.map +0 -1
- package/hybrid.js.map +0 -1
- package/index.d.ts.map +0 -1
- package/index.js.map +0 -1
- package/ml-dsa.d.ts.map +0 -1
- package/ml-dsa.js.map +0 -1
- package/ml-kem.d.ts.map +0 -1
- package/ml-kem.js.map +0 -1
- package/slh-dsa.d.ts.map +0 -1
- package/slh-dsa.js.map +0 -1
- package/utils.d.ts.map +0 -1
- package/utils.js.map +0 -1
package/ml-dsa.js
CHANGED
|
@@ -40,10 +40,16 @@ const GAMMA2_2 = Math.floor((Q - 1) / 32) | 0;
|
|
|
40
40
|
* This is only the Table 1 subset used directly here: `BETA = TAU * ETA` is derived later,
|
|
41
41
|
* while `C_TILDE_BYTES`, `TR_BYTES`, `CRH_BYTES`, and `securityLevel` live in the preset wrappers.
|
|
42
42
|
*/
|
|
43
|
-
export const PARAMS = /* @__PURE__ */ (() => ({
|
|
44
|
-
2: {
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
export const PARAMS = /* @__PURE__ */ (() => Object.freeze({
|
|
44
|
+
2: Object.freeze({
|
|
45
|
+
K: 4, L: 4, D, GAMMA1: 2 ** 17, GAMMA2: GAMMA2_1, TAU: 39, ETA: 2, OMEGA: 80
|
|
46
|
+
}),
|
|
47
|
+
3: Object.freeze({
|
|
48
|
+
K: 6, L: 5, D, GAMMA1: 2 ** 19, GAMMA2: GAMMA2_2, TAU: 49, ETA: 4, OMEGA: 55
|
|
49
|
+
}),
|
|
50
|
+
5: Object.freeze({
|
|
51
|
+
K: 8, L: 7, D, GAMMA1: 2 ** 19, GAMMA2: GAMMA2_2, TAU: 60, ETA: 2, OMEGA: 75
|
|
52
|
+
}),
|
|
47
53
|
}))();
|
|
48
54
|
const newPoly = (n) => new Int32Array(n);
|
|
49
55
|
// Shared CRYSTALS helper in the ML-DSA branch: non-Kyber mode, 8-bit bit-reversal,
|
|
@@ -66,24 +72,32 @@ const polyCoder = (d, compress = id, verify = id) => crystals.bitsCoder(d, {
|
|
|
66
72
|
decode: (i) => verify(compress(i)),
|
|
67
73
|
});
|
|
68
74
|
// Mutates `a` in place; callers must pass same-length polynomials.
|
|
69
|
-
|
|
75
|
+
// NOTE: conditional-reduction variants (as in ml-kem) were measured performance-neutral here —
|
|
76
|
+
// int32 `%` with 23-bit Q is already cheap — so the simpler mod() form is kept for audit.
|
|
77
|
+
const polyAdd = (a_, b_) => {
|
|
78
|
+
const a = a_;
|
|
79
|
+
const b = b_;
|
|
70
80
|
for (let i = 0; i < a.length; i++)
|
|
71
81
|
a[i] = crystals.mod(a[i] + b[i]);
|
|
72
82
|
return a;
|
|
73
83
|
};
|
|
74
84
|
// Mutates `a` in place; callers must pass same-length polynomials.
|
|
75
|
-
const polySub = (
|
|
85
|
+
const polySub = (a_, b_) => {
|
|
86
|
+
const a = a_;
|
|
87
|
+
const b = b_;
|
|
76
88
|
for (let i = 0; i < a.length; i++)
|
|
77
89
|
a[i] = crystals.mod(a[i] - b[i]);
|
|
78
90
|
return a;
|
|
79
91
|
};
|
|
80
92
|
// Mutates `p` in place and assumes it is a decoded `t1`-range polynomial.
|
|
81
|
-
const polyShiftl = (
|
|
93
|
+
const polyShiftl = (p_) => {
|
|
94
|
+
const p = p_;
|
|
82
95
|
for (let i = 0; i < N; i++)
|
|
83
96
|
p[i] <<= D;
|
|
84
97
|
return p;
|
|
85
98
|
};
|
|
86
|
-
const polyChknorm = (
|
|
99
|
+
const polyChknorm = (p_, B) => {
|
|
100
|
+
const p = p_;
|
|
87
101
|
// FIPS 204 Algorithms 7 and 8 express the same centered-norm check with explicit inequalities.
|
|
88
102
|
for (let i = 0; i < N; i++)
|
|
89
103
|
if (Math.abs(crystals.smod(p[i])) >= B)
|
|
@@ -91,7 +105,9 @@ const polyChknorm = (p, B) => {
|
|
|
91
105
|
return false;
|
|
92
106
|
};
|
|
93
107
|
// Both inputs must already be in NTT / `T_q` form.
|
|
94
|
-
const MultiplyNTTs = (
|
|
108
|
+
const MultiplyNTTs = (a_, b_) => {
|
|
109
|
+
const a = a_;
|
|
110
|
+
const b = b_;
|
|
95
111
|
// NOTE: we don't use montgomery reduction in code, since it requires 64 bit ints,
|
|
96
112
|
// which is not available in JS. mod(a[i] * b[i]) is ok, since Q is 23 bit,
|
|
97
113
|
// which means a[i] * b[i] is 46 bit, which is safe to use in JS. (number is 53 bits).
|
|
@@ -102,7 +118,8 @@ const MultiplyNTTs = (a, b) => {
|
|
|
102
118
|
return c;
|
|
103
119
|
};
|
|
104
120
|
// Return poly in NTT representation
|
|
105
|
-
function RejNTTPoly(
|
|
121
|
+
function RejNTTPoly(xof_) {
|
|
122
|
+
const xof = xof_;
|
|
106
123
|
// Samples a polynomial ∈ Tq. xof() must return byte lengths divisible by 3.
|
|
107
124
|
const r = newPoly(N);
|
|
108
125
|
// NOTE: we can represent 3xu24 as 4xu32, but it doesn't improve perf :(
|
|
@@ -121,7 +138,8 @@ function RejNTTPoly(xof) {
|
|
|
121
138
|
}
|
|
122
139
|
// Instantiate one ML-DSA parameter set from the Table 1 lattice constants plus the
|
|
123
140
|
// Table 2 byte lengths / hash-width choices used by the public wrappers below.
|
|
124
|
-
function getDilithium(
|
|
141
|
+
function getDilithium(opts_) {
|
|
142
|
+
const opts = opts_;
|
|
125
143
|
const { K, L, GAMMA1, GAMMA2, TAU, ETA, OMEGA } = opts;
|
|
126
144
|
const { CRH_BYTES, TR_BYTES, C_TILDE_BYTES, XOF128, XOF256, securityLevel } = opts;
|
|
127
145
|
if (![2, 4].includes(ETA))
|
|
@@ -163,14 +181,16 @@ function getDilithium(opts) {
|
|
|
163
181
|
// See dilithium-py README section "Optimising decomposition and making hints".
|
|
164
182
|
return res0;
|
|
165
183
|
};
|
|
184
|
+
// m = (q-1)/(2γ2): 44 for ML-DSA-44, 16 for 65/87. Hoisted out of UseHint, which runs
|
|
185
|
+
// per coefficient during verification.
|
|
186
|
+
const HINT_M = Math.floor((Q - 1) / (2 * GAMMA2));
|
|
166
187
|
const UseHint = (h, r) => {
|
|
167
188
|
// Returns the high bits of r adjusted according to hint h
|
|
168
|
-
const m = Math.floor((Q - 1) / (2 * GAMMA2));
|
|
169
189
|
const { r1, r0 } = decompose(r);
|
|
170
190
|
// 3: if h = 1 and r0 > 0 return (r1 + 1) mod m
|
|
171
191
|
// 4: if h = 1 and r0 ≤ 0 return (r1 − 1) mod m
|
|
172
192
|
if (h === 1)
|
|
173
|
-
return r0 > 0 ? crystals.mod(r1 + 1,
|
|
193
|
+
return r0 > 0 ? crystals.mod(r1 + 1, HINT_M) | 0 : crystals.mod(r1 - 1, HINT_M) | 0;
|
|
174
194
|
return r1 | 0;
|
|
175
195
|
};
|
|
176
196
|
const Power2Round = (r) => {
|
|
@@ -181,7 +201,8 @@ function getDilithium(opts) {
|
|
|
181
201
|
};
|
|
182
202
|
const hintCoder = {
|
|
183
203
|
bytesLen: OMEGA + K,
|
|
184
|
-
encode: (
|
|
204
|
+
encode: (h_) => {
|
|
205
|
+
const h = h_;
|
|
185
206
|
if (h === false)
|
|
186
207
|
throw new Error('hint.encode: hint is false'); // should never happen
|
|
187
208
|
const res = new Uint8Array(OMEGA + K);
|
|
@@ -235,7 +256,8 @@ function getDilithium(opts) {
|
|
|
235
256
|
// Return poly in ordinary representation.
|
|
236
257
|
// This helper returns ordinary-form `[-ETA, ETA]` coefficients for ExpandS; callers apply
|
|
237
258
|
// `NTT.encode()` later when needed.
|
|
238
|
-
function RejBoundedPoly(
|
|
259
|
+
function RejBoundedPoly(xof_) {
|
|
260
|
+
const xof = xof_;
|
|
239
261
|
// Samples an element a ∈ Rq with coeffcients in [−η, η] computed via rejection sampling from ρ.
|
|
240
262
|
const r = newPoly(N);
|
|
241
263
|
for (let j = 0; j < N;) {
|
|
@@ -279,7 +301,8 @@ function getDilithium(opts) {
|
|
|
279
301
|
}
|
|
280
302
|
return pre;
|
|
281
303
|
};
|
|
282
|
-
const polyPowerRound = (
|
|
304
|
+
const polyPowerRound = (p_) => {
|
|
305
|
+
const p = p_;
|
|
283
306
|
const res0 = newPoly(N);
|
|
284
307
|
const res1 = newPoly(N);
|
|
285
308
|
for (let i = 0; i < p.length; i++) {
|
|
@@ -289,14 +312,18 @@ function getDilithium(opts) {
|
|
|
289
312
|
}
|
|
290
313
|
return { r0: res0, r1: res1 };
|
|
291
314
|
};
|
|
292
|
-
const polyUseHint = (
|
|
315
|
+
const polyUseHint = (u_, h_) => {
|
|
316
|
+
const u = u_;
|
|
317
|
+
const h = h_;
|
|
293
318
|
// In-place on `u`: verification only needs the recovered high bits, so reuse the
|
|
294
319
|
// temporary `wApprox` buffer instead of allocating another polynomial.
|
|
295
320
|
for (let i = 0; i < N; i++)
|
|
296
321
|
u[i] = UseHint(h[i], u[i]);
|
|
297
322
|
return u;
|
|
298
323
|
};
|
|
299
|
-
const polyMakeHint = (
|
|
324
|
+
const polyMakeHint = (a_, b_) => {
|
|
325
|
+
const a = a_;
|
|
326
|
+
const b = b_;
|
|
300
327
|
const v = newPoly(N);
|
|
301
328
|
let cnt = 0;
|
|
302
329
|
for (let i = 0; i < N; i++) {
|
|
@@ -309,15 +336,15 @@ function getDilithium(opts) {
|
|
|
309
336
|
const signRandBytes = 32;
|
|
310
337
|
const seedCoder = splitCoder('seed', 32, 64, 32);
|
|
311
338
|
// API & argument positions are exactly as in FIPS204.
|
|
312
|
-
const internal = {
|
|
313
|
-
info: { type: 'internal-ml-dsa' },
|
|
314
|
-
lengths: {
|
|
339
|
+
const internal = Object.freeze({
|
|
340
|
+
info: Object.freeze({ type: 'internal-ml-dsa' }),
|
|
341
|
+
lengths: Object.freeze({
|
|
315
342
|
secretKey: secretCoder.bytesLen,
|
|
316
343
|
publicKey: publicCoder.bytesLen,
|
|
317
344
|
seed: 32,
|
|
318
345
|
signature: sigCoder.bytesLen,
|
|
319
346
|
signRand: signRandBytes,
|
|
320
|
-
},
|
|
347
|
+
}),
|
|
321
348
|
keygen: (seed) => {
|
|
322
349
|
// H(𝜉||IntegerToBytes(𝑘, 1)||IntegerToBytes(ℓ, 1), 128) 2: ▷ expand seed
|
|
323
350
|
const seedDst = new Uint8Array(32 + 2);
|
|
@@ -367,7 +394,10 @@ function getDilithium(opts) {
|
|
|
367
394
|
// DSA44: { calls: 24, xofs: 24 }, DSA65: { calls: 41, xofs: 41 },
|
|
368
395
|
// DSA87: { calls: 71, xofs: 71 }
|
|
369
396
|
cleanBytes(rho, rhoPrime, K_, s1, s2, s1Hat, t, t0, t1, tr, seedDst);
|
|
370
|
-
return {
|
|
397
|
+
return {
|
|
398
|
+
publicKey: publicKey,
|
|
399
|
+
secretKey: secretKey,
|
|
400
|
+
};
|
|
371
401
|
},
|
|
372
402
|
getPublicKey: (secretKey) => {
|
|
373
403
|
// (ρ, K,tr, s1, s2, t0) ← skDecode(sk)
|
|
@@ -395,11 +425,34 @@ function getDilithium(opts) {
|
|
|
395
425
|
sign: (msg, secretKey, opts = {}) => {
|
|
396
426
|
validateSigOpts(opts);
|
|
397
427
|
validateInternalOpts(opts);
|
|
398
|
-
|
|
428
|
+
const { extraEntropy: random, externalMu = false } = opts;
|
|
429
|
+
// FIPS 204 external-mu mode expects the 64-byte message representative µ = H(tr || M).
|
|
430
|
+
if (externalMu)
|
|
431
|
+
abytes(msg, CRH_BYTES, 'mu');
|
|
432
|
+
// Prepare entropy before touching decoded secrets: randomBytes() may throw, and an RNG
|
|
433
|
+
// failure must not leave expanded secret-polynomial copies behind.
|
|
434
|
+
const ownRnd = random === false || random === undefined;
|
|
435
|
+
const rnd = random === false
|
|
436
|
+
? new Uint8Array(32)
|
|
437
|
+
: random === undefined
|
|
438
|
+
? randomBytes(signRandBytes)
|
|
439
|
+
: random;
|
|
440
|
+
abytes(rnd, 32, 'extraEntropy');
|
|
399
441
|
// This part can be pre-cached per secretKey, but there is only minor performance improvement,
|
|
400
442
|
// since we re-use a lot of variables to computation.
|
|
401
443
|
// (ρ, K,tr, s1, s2, t0) ← skDecode(sk)
|
|
402
|
-
const
|
|
444
|
+
const decoded = (() => {
|
|
445
|
+
try {
|
|
446
|
+
return secretCoder.decode(secretKey);
|
|
447
|
+
}
|
|
448
|
+
catch (error) {
|
|
449
|
+
// A malformed key must not strand entropy owned by the library.
|
|
450
|
+
if (ownRnd)
|
|
451
|
+
cleanBytes(rnd);
|
|
452
|
+
throw error;
|
|
453
|
+
}
|
|
454
|
+
})();
|
|
455
|
+
const [rho, _K, tr, s1, s2, t0] = decoded;
|
|
403
456
|
// Cache matrix to avoid re-compute later
|
|
404
457
|
const A = []; // A ← ExpandA(ρ)
|
|
405
458
|
const xof = XOF128(rho);
|
|
@@ -422,19 +475,15 @@ function getDilithium(opts) {
|
|
|
422
475
|
: // 6: µ ← H(tr||M, 512)
|
|
423
476
|
// ▷ Compute message representative µ
|
|
424
477
|
shake256.create({ dkLen: CRH_BYTES }).update(tr).update(msg).digest();
|
|
425
|
-
// Compute private random seed
|
|
426
|
-
const rnd = random === false
|
|
427
|
-
? new Uint8Array(32)
|
|
428
|
-
: random === undefined
|
|
429
|
-
? randomBytes(signRandBytes)
|
|
430
|
-
: random;
|
|
431
|
-
abytes(rnd, 32, 'extraEntropy');
|
|
432
478
|
const rhoprime = shake256
|
|
433
479
|
.create({ dkLen: CRH_BYTES })
|
|
434
480
|
.update(_K)
|
|
435
481
|
.update(rnd)
|
|
436
482
|
.update(mu)
|
|
437
483
|
.digest(); // ρ′← H(K||rnd||µ, 512)
|
|
484
|
+
// Only wipe entropy we generated; caller-provided extraEntropy stays caller-owned.
|
|
485
|
+
if (ownRnd)
|
|
486
|
+
cleanBytes(rnd);
|
|
438
487
|
abytes(rhoprime, CRH_BYTES);
|
|
439
488
|
const x256 = XOF256(rhoprime, ZCoder.bytesLen);
|
|
440
489
|
// Rejection sampling loop
|
|
@@ -506,6 +555,9 @@ function getDilithium(opts) {
|
|
|
506
555
|
verify: (sig, msg, publicKey, opts = {}) => {
|
|
507
556
|
validateInternalOpts(opts);
|
|
508
557
|
const { externalMu = false } = opts;
|
|
558
|
+
// FIPS 204 external-mu mode expects the 64-byte message representative µ = H(tr || M).
|
|
559
|
+
if (externalMu)
|
|
560
|
+
abytes(msg, CRH_BYTES, 'mu');
|
|
509
561
|
// ML-DSA.Verify(pk, M, σ): Verifes a signature σ for a message M.
|
|
510
562
|
const [rho, t1] = publicCoder.decode(publicKey); // (ρ, t1) ← pkDecode(pk)
|
|
511
563
|
const tr = shake256(publicKey, { dkLen: TR_BYTES }); // 6: tr ← H(BytesToBits(pk), 512)
|
|
@@ -561,9 +613,9 @@ function getDilithium(opts) {
|
|
|
561
613
|
return false;
|
|
562
614
|
return equalBytes(cTilde, c2);
|
|
563
615
|
},
|
|
564
|
-
};
|
|
565
|
-
return {
|
|
566
|
-
info: { type: 'ml-dsa' },
|
|
616
|
+
});
|
|
617
|
+
return Object.freeze({
|
|
618
|
+
info: Object.freeze({ type: 'ml-dsa' }),
|
|
567
619
|
internal,
|
|
568
620
|
securityLevel: securityLevel,
|
|
569
621
|
keygen: internal.keygen,
|
|
@@ -578,32 +630,54 @@ function getDilithium(opts) {
|
|
|
578
630
|
},
|
|
579
631
|
verify: (sig, msg, publicKey, opts = {}) => {
|
|
580
632
|
validateVerOpts(opts);
|
|
633
|
+
abytes(sig, undefined, 'signature');
|
|
581
634
|
return internal.verify(sig, getMessage(msg, opts.context), publicKey);
|
|
582
635
|
},
|
|
583
636
|
prehash: (hash) => {
|
|
584
637
|
checkHash(hash, securityLevel);
|
|
585
|
-
|
|
586
|
-
|
|
638
|
+
const rawHash = hash;
|
|
639
|
+
return Object.freeze({
|
|
640
|
+
info: Object.freeze({ type: 'hashml-dsa' }),
|
|
587
641
|
securityLevel: securityLevel,
|
|
588
642
|
lengths: internal.lengths,
|
|
589
643
|
keygen: internal.keygen,
|
|
590
644
|
getPublicKey: internal.getPublicKey,
|
|
591
645
|
sign: (msg, secretKey, opts = {}) => {
|
|
592
646
|
validateSigOpts(opts);
|
|
593
|
-
const M = getMessagePrehash(
|
|
647
|
+
const M = getMessagePrehash(rawHash, msg, opts.context);
|
|
594
648
|
const res = internal.sign(M, secretKey, opts);
|
|
595
649
|
cleanBytes(M);
|
|
596
650
|
return res;
|
|
597
651
|
},
|
|
598
652
|
verify: (sig, msg, publicKey, opts = {}) => {
|
|
599
653
|
validateVerOpts(opts);
|
|
600
|
-
|
|
654
|
+
abytes(sig, undefined, 'signature');
|
|
655
|
+
return internal.verify(sig, getMessagePrehash(rawHash, msg, opts.context), publicKey);
|
|
601
656
|
},
|
|
602
|
-
};
|
|
657
|
+
});
|
|
603
658
|
},
|
|
604
|
-
};
|
|
659
|
+
});
|
|
605
660
|
}
|
|
606
|
-
/**
|
|
661
|
+
/**
|
|
662
|
+
* ML-DSA-44 for 128-bit security level. Not recommended after 2030, as per ASD.
|
|
663
|
+
* @example
|
|
664
|
+
* Generate deterministic ML-DSA-44 keys, sign one message, and verify the signature.
|
|
665
|
+
* ```ts
|
|
666
|
+
* import { sha256 } from '@noble/hashes/sha2.js';
|
|
667
|
+
* import { ml_dsa44 } from '@noble/post-quantum/ml-dsa.js';
|
|
668
|
+
* const seed = new Uint8Array(ml_dsa44.lengths.seed!);
|
|
669
|
+
* const { secretKey, publicKey } = ml_dsa44.keygen(seed);
|
|
670
|
+
* const msg = new TextEncoder().encode('hello noble');
|
|
671
|
+
* const sig = ml_dsa44.sign(msg, secretKey);
|
|
672
|
+
* const isValid = ml_dsa44.verify(sig, msg, publicKey);
|
|
673
|
+
* const recovered = ml_dsa44.getPublicKey(secretKey);
|
|
674
|
+
* const context = new Uint8Array([1, 2, 3]);
|
|
675
|
+
* const prehash = ml_dsa44.prehash(sha256);
|
|
676
|
+
* const preSig = prehash.sign(msg, secretKey, { context });
|
|
677
|
+
* const preValid = prehash.verify(preSig, msg, publicKey, { context });
|
|
678
|
+
* const internalSig = ml_dsa44.internal.sign(msg, secretKey);
|
|
679
|
+
* ```
|
|
680
|
+
*/
|
|
607
681
|
export const ml_dsa44 = /* @__PURE__ */ (() => getDilithium({
|
|
608
682
|
...PARAMS[2],
|
|
609
683
|
CRH_BYTES: 64,
|
|
@@ -633,4 +707,3 @@ export const ml_dsa87 = /* @__PURE__ */ (() => getDilithium({
|
|
|
633
707
|
XOF256,
|
|
634
708
|
securityLevel: 256,
|
|
635
709
|
}))();
|
|
636
|
-
//# sourceMappingURL=ml-dsa.js.map
|
package/ml-kem.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type KEM } from './utils.ts';
|
|
1
|
+
import { type KEM, type TRet } from './utils.ts';
|
|
2
2
|
/** FIPS 203: 7. Parameter Sets */
|
|
3
3
|
/** Public ML-KEM parameter-set description. */
|
|
4
4
|
export type KEMParam = {
|
|
@@ -26,20 +26,61 @@ export type KEMParam = {
|
|
|
26
26
|
* not a generic security label.
|
|
27
27
|
*/
|
|
28
28
|
export declare const PARAMS: Record<string, KEMParam>;
|
|
29
|
+
/**
|
|
30
|
+
* Prepared (pre-expanded) ML-KEM public key. Experimental prototype.
|
|
31
|
+
* Caches only public data: packed ek, the expanded matrix Â, decoded t̂ and H(ek). No secret
|
|
32
|
+
* material is retained between calls; secret keys passed to `decapsulate` are decoded and wiped
|
|
33
|
+
* per call, exactly like the one-shot API. `clean()` wipes the expanded Â/t̂ cache; the packed
|
|
34
|
+
* public key and H(ek) are public and are not wiped. The object must not be used afterwards.
|
|
35
|
+
*/
|
|
36
|
+
export type KEMPrepared = {
|
|
37
|
+
/**
|
|
38
|
+
* Detached copy of the source public key. Treat as read-only while the prepared object is in use.
|
|
39
|
+
* Callers may wipe it after final use; any mutation invalidates subsequent operations.
|
|
40
|
+
*/
|
|
41
|
+
publicKey: Uint8Array;
|
|
42
|
+
/** Same as `KEM.encapsulate`, minus per-call ek re-validation and  re-expansion. */
|
|
43
|
+
encapsulate: (msg?: Uint8Array) => {
|
|
44
|
+
cipherText: Uint8Array;
|
|
45
|
+
sharedSecret: Uint8Array;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Same as `KEM.decapsulate`; throws if `secretKey` does not embed this public key.
|
|
49
|
+
* The embedded-ek byte comparison plus stored-hash comparison is equivalent to the
|
|
50
|
+
* FIPS 203 §7.3 hash input check.
|
|
51
|
+
*/
|
|
52
|
+
decapsulate: (cipherText: Uint8Array, secretKey: Uint8Array) => Uint8Array;
|
|
53
|
+
/** Wipe cached (public) data. */
|
|
54
|
+
clean: () => void;
|
|
55
|
+
};
|
|
56
|
+
/** KEM with prepared-key support. */
|
|
57
|
+
export type MLKEM = KEM & {
|
|
58
|
+
prepare: (publicKey: Uint8Array) => KEMPrepared;
|
|
59
|
+
};
|
|
29
60
|
/**
|
|
30
61
|
* ML-KEM-512: Table 2 row `k=2, η1=3, η2=2, du=10, dv=4`; Table 3 sizes `800/1632/768/32`.
|
|
31
62
|
* The ASD lifecycle note here is external policy guidance, not a FIPS 203 requirement.
|
|
63
|
+
* @example
|
|
64
|
+
* Generate deterministic ML-KEM-512 keys, encapsulate a shared secret, and decapsulate it.
|
|
65
|
+
* ```ts
|
|
66
|
+
* import { ml_kem512 } from '@noble/post-quantum/ml-kem.js';
|
|
67
|
+
* const seed = new Uint8Array(ml_kem512.lengths.seed!);
|
|
68
|
+
* const { secretKey, publicKey } = ml_kem512.keygen(seed);
|
|
69
|
+
* const msg = new Uint8Array(ml_kem512.lengths.msgRand!);
|
|
70
|
+
* const { cipherText, sharedSecret } = ml_kem512.encapsulate(publicKey, msg);
|
|
71
|
+
* const recovered = ml_kem512.decapsulate(cipherText, secretKey);
|
|
72
|
+
* const publicKey2 = ml_kem512.getPublicKey(secretKey);
|
|
73
|
+
* ```
|
|
32
74
|
*/
|
|
33
|
-
export declare const ml_kem512:
|
|
75
|
+
export declare const ml_kem512: TRet<MLKEM>;
|
|
34
76
|
/**
|
|
35
77
|
* ML-KEM-768: Table 2 row `k=3, η1=2, η2=2, du=10, dv=4`; Table 3 sizes `1184/2400/1088/32`.
|
|
36
78
|
* The ASD lifecycle note here is external policy guidance, not a FIPS 203 requirement.
|
|
37
79
|
*/
|
|
38
|
-
export declare const ml_kem768:
|
|
80
|
+
export declare const ml_kem768: TRet<MLKEM>;
|
|
39
81
|
/**
|
|
40
82
|
* ML-KEM-1024: Table 2 row `k=4, η1=2, η2=2, du=11, dv=5`; Table 3 sizes `1568/3168/1568/32`.
|
|
41
83
|
* The ASD lifecycle note here is external policy guidance, not a FIPS 203 requirement.
|
|
42
84
|
*/
|
|
43
|
-
export declare const ml_kem1024:
|
|
85
|
+
export declare const ml_kem1024: TRet<MLKEM>;
|
|
44
86
|
export declare const __tests: any;
|
|
45
|
-
//# sourceMappingURL=ml-kem.d.ts.map
|