@noble/post-quantum 0.6.0 → 0.6.1
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 +45 -32
- package/_crystals.d.ts +17 -15
- package/_crystals.d.ts.map +1 -1
- package/_crystals.js +13 -3
- package/_crystals.js.map +1 -1
- package/falcon.d.ts +7 -7
- package/falcon.d.ts.map +1 -1
- package/falcon.js +27 -20
- package/falcon.js.map +1 -1
- package/hybrid.d.ts +23 -23
- package/hybrid.d.ts.map +1 -1
- package/hybrid.js +37 -28
- package/hybrid.js.map +1 -1
- package/index.js +8 -0
- package/index.js.map +1 -1
- package/ml-dsa.d.ts +7 -7
- package/ml-dsa.d.ts.map +1 -1
- package/ml-dsa.js +54 -28
- package/ml-dsa.js.map +1 -1
- package/ml-kem.d.ts +4 -4
- package/ml-kem.d.ts.map +1 -1
- package/ml-kem.js +43 -26
- package/ml-kem.js.map +1 -1
- package/package.json +5 -5
- package/slh-dsa.d.ts +21 -21
- package/slh-dsa.d.ts.map +1 -1
- package/slh-dsa.js +57 -35
- package/slh-dsa.js.map +1 -1
- package/src/_crystals.ts +44 -27
- package/src/falcon.ts +150 -117
- package/src/hybrid.ts +145 -96
- package/src/index.ts +8 -0
- package/src/ml-dsa.ts +124 -69
- package/src/ml-kem.ts +114 -85
- package/src/slh-dsa.ts +211 -132
- package/src/utils.ts +174 -34
- package/utils.d.ts +81 -22
- package/utils.d.ts.map +1 -1
- package/utils.js +30 -8
- package/utils.js.map +1 -1
package/src/ml-kem.ts
CHANGED
|
@@ -33,6 +33,8 @@ import {
|
|
|
33
33
|
type KEM,
|
|
34
34
|
randomBytes,
|
|
35
35
|
splitCoder,
|
|
36
|
+
type TArg,
|
|
37
|
+
type TRet,
|
|
36
38
|
vecCoder,
|
|
37
39
|
} from './utils.ts';
|
|
38
40
|
|
|
@@ -50,7 +52,7 @@ const crystals = /* @__PURE__ */ genCrystals({
|
|
|
50
52
|
Q,
|
|
51
53
|
F,
|
|
52
54
|
ROOT_OF_UNITY,
|
|
53
|
-
newPoly: (n: number): Uint16Array => new Uint16Array(n)
|
|
55
|
+
newPoly: (n: number): TRet<Uint16Array> => new Uint16Array(n) as TRet<Uint16Array>,
|
|
54
56
|
brvBits: 7,
|
|
55
57
|
isKyber: true,
|
|
56
58
|
});
|
|
@@ -82,11 +84,12 @@ export type KEMParam = {
|
|
|
82
84
|
* `RBGstrength` is Table 2's required randomness-source strength in bits,
|
|
83
85
|
* not a generic security label.
|
|
84
86
|
*/
|
|
85
|
-
export const PARAMS: Record<string, KEMParam> = /* @__PURE__ */ (() =>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
export const PARAMS: Record<string, KEMParam> = /* @__PURE__ */ (() =>
|
|
88
|
+
Object.freeze({
|
|
89
|
+
512: Object.freeze({ N, Q, K: 2, ETA1: 3, ETA2: 2, du: 10, dv: 4, RBGstrength: 128 }),
|
|
90
|
+
768: Object.freeze({ N, Q, K: 3, ETA1: 2, ETA2: 2, du: 10, dv: 4, RBGstrength: 192 }),
|
|
91
|
+
1024: Object.freeze({ N, Q, K: 4, ETA1: 2, ETA2: 2, du: 11, dv: 5, RBGstrength: 256 }),
|
|
92
|
+
} as const))();
|
|
90
93
|
|
|
91
94
|
// FIPS-203: compress/decompress
|
|
92
95
|
const compress = (d: number): Coder<number, number> => {
|
|
@@ -126,13 +129,17 @@ const byteCoder = (d: number) =>
|
|
|
126
129
|
const polyCoder = (d: number) => (d === 12 ? byteCoder(12) : crystals.bitsCoder(d, compress(d)));
|
|
127
130
|
|
|
128
131
|
// Poly is mod Q, so 12 bits
|
|
129
|
-
type Poly = Uint16Array
|
|
132
|
+
type Poly = Uint16Array;
|
|
130
133
|
|
|
131
|
-
function polyAdd(
|
|
134
|
+
function polyAdd(a_: TArg<Poly>, b_: TArg<Poly>) {
|
|
135
|
+
const a = a_ as Poly;
|
|
136
|
+
const b = b_ as Poly;
|
|
132
137
|
// Mutates `a` in place; callers must pass two N=256 polynomials.
|
|
133
138
|
for (let i = 0; i < N; i++) a[i] = crystals.mod(a[i] + b[i]); // a += b
|
|
134
139
|
}
|
|
135
|
-
function polySub(
|
|
140
|
+
function polySub(a_: TArg<Poly>, b_: TArg<Poly>) {
|
|
141
|
+
const a = a_ as Poly;
|
|
142
|
+
const b = b_ as Poly;
|
|
136
143
|
// Mutates `a` in place; callers must pass two N=256 polynomials.
|
|
137
144
|
for (let i = 0; i < N; i++) a[i] = crystals.mod(a[i] - b[i]); // a -= b
|
|
138
145
|
}
|
|
@@ -147,7 +154,9 @@ function BaseCaseMultiply(a0: number, a1: number, b0: number, b1: number, zeta:
|
|
|
147
154
|
|
|
148
155
|
// FIPS-203: Computes the product (in the ring Tq) of two NTT representations.
|
|
149
156
|
// Works in place on `f`; `g` is read-only and both inputs must already be in NTT form.
|
|
150
|
-
function MultiplyNTTs(
|
|
157
|
+
function MultiplyNTTs(f_: TArg<Poly>, g_: TArg<Poly>): TRet<Poly> {
|
|
158
|
+
const f = f_ as Poly;
|
|
159
|
+
const g = g_ as Poly;
|
|
151
160
|
for (let i = 0; i < N / 2; i++) {
|
|
152
161
|
let z = crystals.nttZetas[64 + (i >> 1)];
|
|
153
162
|
if (i & 1) z = -z;
|
|
@@ -155,7 +164,7 @@ function MultiplyNTTs(f: Poly, g: Poly): Poly {
|
|
|
155
164
|
f[2 * i + 0] = c0;
|
|
156
165
|
f[2 * i + 1] = c1;
|
|
157
166
|
}
|
|
158
|
-
return f
|
|
167
|
+
return f as TRet<Poly>;
|
|
159
168
|
}
|
|
160
169
|
|
|
161
170
|
type PRF = (l: number, key: Uint8Array, nonce: number) => Uint8Array;
|
|
@@ -165,14 +174,14 @@ type XofGet = ReturnType<ReturnType<XOF>['get']>;
|
|
|
165
174
|
type KyberOpts = KEMParam & {
|
|
166
175
|
HASH256: CHash;
|
|
167
176
|
HASH512: CHash;
|
|
168
|
-
|
|
169
|
-
KDF: any;
|
|
177
|
+
KDF: CHash<any, { dkLen?: number }>;
|
|
170
178
|
XOF: XOF; // (seed: Uint8Array, len: number, x: number, y: number) => Uint8Array;
|
|
171
179
|
PRF: PRF;
|
|
172
180
|
};
|
|
173
181
|
|
|
174
182
|
// Return poly in NTT representation
|
|
175
|
-
function SampleNTT(
|
|
183
|
+
function SampleNTT(xof_: TArg<XofGet>): TRet<Poly> {
|
|
184
|
+
const xof = xof_ as XofGet;
|
|
176
185
|
// The reader must already bind the Algorithm 7 seed||j||i bytes
|
|
177
186
|
// and return block lengths divisible by 3.
|
|
178
187
|
const r: Poly = new Uint16Array(N);
|
|
@@ -186,13 +195,13 @@ function SampleNTT(xof: XofGet) {
|
|
|
186
195
|
if (j < N && d2 < Q) r[j++] = d2;
|
|
187
196
|
}
|
|
188
197
|
}
|
|
189
|
-
return r
|
|
198
|
+
return r as TRet<Poly>;
|
|
190
199
|
}
|
|
191
200
|
|
|
192
201
|
// Sampling from the centered binomial distribution
|
|
193
202
|
// Returns poly with small coefficients (noise/errors) stored modulo q in ordinary coefficient form.
|
|
194
203
|
// Current callers only use Table 2 eta values {2,3} and PRF outputs of exactly 64*eta bytes.
|
|
195
|
-
const sampleCBDBytes = (buf: Uint8Array
|
|
204
|
+
const sampleCBDBytes = (buf: TArg<Uint8Array>, eta: number): TRet<Poly> => {
|
|
196
205
|
const r: Poly = new Uint16Array(N);
|
|
197
206
|
// CBD consumes the PRF bitstream in little-endian byte order; normalize the word view on BE,
|
|
198
207
|
// then swap it back so callers still observe `buf` as read-only.
|
|
@@ -217,10 +226,16 @@ const sampleCBDBytes = (buf: Uint8Array, eta: number): Poly => {
|
|
|
217
226
|
}
|
|
218
227
|
swap32IfBE(b32);
|
|
219
228
|
if (len) throw new Error(`sampleCBD: leftover bits: ${len}`);
|
|
220
|
-
return r
|
|
229
|
+
return r as TRet<Poly>;
|
|
221
230
|
};
|
|
222
231
|
|
|
223
|
-
function sampleCBD(
|
|
232
|
+
function sampleCBD(
|
|
233
|
+
PRF_: TArg<PRF>,
|
|
234
|
+
seed: TArg<Uint8Array>,
|
|
235
|
+
nonce: number,
|
|
236
|
+
eta: number
|
|
237
|
+
): TRet<Poly> {
|
|
238
|
+
const PRF = PRF_ as PRF;
|
|
224
239
|
return sampleCBDBytes(PRF((eta * N) / 4, seed, nonce), eta);
|
|
225
240
|
}
|
|
226
241
|
|
|
@@ -228,7 +243,8 @@ function sampleCBD(PRF: PRF, seed: Uint8Array, nonce: number, eta: number): Poly
|
|
|
228
243
|
// Internal ML-KEM subroutine only: exact 32-byte `seed` / `msg` inputs
|
|
229
244
|
// come from Algorithms 13-15, and the helper mutates decoded temporary
|
|
230
245
|
// polynomials in place while leaving caller byte arrays unchanged.
|
|
231
|
-
const genKPKE = (
|
|
246
|
+
const genKPKE = (opts_: TArg<KyberOpts>) => {
|
|
247
|
+
const opts = opts_ as KyberOpts;
|
|
232
248
|
const { K, PRF, XOF, HASH512, ETA1, ETA2, du, dv } = opts;
|
|
233
249
|
const poly1 = polyCoder(1);
|
|
234
250
|
const polyV = polyCoder(dv);
|
|
@@ -244,7 +260,7 @@ const genKPKE = (opts: KyberOpts) => {
|
|
|
244
260
|
publicKey: publicCoder.bytesLen,
|
|
245
261
|
cipherText: cipherCoder.bytesLen,
|
|
246
262
|
},
|
|
247
|
-
keygen: (seed: Uint8Array) => {
|
|
263
|
+
keygen: (seed: TArg<Uint8Array>) => {
|
|
248
264
|
abytes(seed, 32, 'seed');
|
|
249
265
|
const seedDst = new Uint8Array(33);
|
|
250
266
|
seedDst.set(seed);
|
|
@@ -275,7 +291,11 @@ const genKPKE = (opts: KyberOpts) => {
|
|
|
275
291
|
cleanBytes(rho, sigma, sHat, tHat, seedDst, seedHash);
|
|
276
292
|
return res;
|
|
277
293
|
},
|
|
278
|
-
encrypt: (
|
|
294
|
+
encrypt: (
|
|
295
|
+
publicKey: TArg<Uint8Array>,
|
|
296
|
+
msg: TArg<Uint8Array>,
|
|
297
|
+
seed: TArg<Uint8Array>
|
|
298
|
+
): TRet<Uint8Array> => {
|
|
279
299
|
const [tHat, rho] = publicCoder.decode(publicKey);
|
|
280
300
|
const rHat = [];
|
|
281
301
|
for (let i = 0; i < K; i++) rHat.push(crystals.NTT.encode(sampleCBD(PRF, seed, i, ETA1)));
|
|
@@ -300,9 +320,9 @@ const genKPKE = (opts: KyberOpts) => {
|
|
|
300
320
|
const v = poly1.decode(msg); // encode plaintext m into polynomial v
|
|
301
321
|
polyAdd(v, e2); // v += e2
|
|
302
322
|
cleanBytes(tHat, rHat, tmp2, e2);
|
|
303
|
-
return cipherCoder.encode([u, v])
|
|
323
|
+
return cipherCoder.encode([u, v]) as TRet<Uint8Array>;
|
|
304
324
|
},
|
|
305
|
-
decrypt: (cipherText: Uint8Array
|
|
325
|
+
decrypt: (cipherText: TArg<Uint8Array>, privateKey: TArg<Uint8Array>): TRet<Uint8Array> => {
|
|
306
326
|
const [u, v] = cipherCoder.decode(cipherText);
|
|
307
327
|
const sk = secretCoder.decode(privateKey); // s ← ByteDecode_12(dkPKE)
|
|
308
328
|
const tmp = new Uint16Array(N);
|
|
@@ -310,7 +330,7 @@ const genKPKE = (opts: KyberOpts) => {
|
|
|
310
330
|
for (let i = 0; i < K; i++) polyAdd(tmp, MultiplyNTTs(sk[i], crystals.NTT.encode(u[i])));
|
|
311
331
|
polySub(v, crystals.NTT.decode(tmp)); // w = v' - tmp
|
|
312
332
|
cleanBytes(tmp, sk, u);
|
|
313
|
-
return poly1.encode(v)
|
|
333
|
+
return poly1.encode(v) as TRet<Uint8Array>;
|
|
314
334
|
},
|
|
315
335
|
};
|
|
316
336
|
};
|
|
@@ -324,36 +344,41 @@ const genKPKE = (opts: KyberOpts) => {
|
|
|
324
344
|
* mismatch, and zeroizing the non-returned shared-secret candidate; JS/JIT still provides no
|
|
325
345
|
* constant-time guarantees for that path.
|
|
326
346
|
*/
|
|
327
|
-
function createKyber(opts: KyberOpts) {
|
|
328
|
-
const
|
|
329
|
-
const
|
|
347
|
+
function createKyber(opts: TArg<KyberOpts>): TRet<KEM> {
|
|
348
|
+
const rawOpts = opts as KyberOpts;
|
|
349
|
+
const KPKE = genKPKE(rawOpts);
|
|
350
|
+
const { HASH256, HASH512, KDF } = rawOpts;
|
|
330
351
|
const { secretCoder: KPKESecretCoder, lengths } = KPKE;
|
|
331
352
|
const secretCoder = splitCoder('secretKey', lengths.secretKey, lengths.publicKey, 32, 32);
|
|
332
353
|
const msgLen = 32;
|
|
333
354
|
const seedLen = 64;
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
},
|
|
343
|
-
|
|
355
|
+
const kemLengths = Object.freeze({
|
|
356
|
+
...lengths,
|
|
357
|
+
seed: 64,
|
|
358
|
+
msg: msgLen,
|
|
359
|
+
msgRand: msgLen,
|
|
360
|
+
secretKey: secretCoder.bytesLen,
|
|
361
|
+
});
|
|
362
|
+
return Object.freeze({
|
|
363
|
+
info: Object.freeze({ type: 'ml-kem' }),
|
|
364
|
+
lengths: kemLengths,
|
|
365
|
+
keygen: (seed: TArg<Uint8Array> = randomBytes(seedLen)) => {
|
|
344
366
|
abytes(seed, seedLen, 'seed');
|
|
345
367
|
const { publicKey, secretKey: sk } = KPKE.keygen(seed.subarray(0, 32));
|
|
346
368
|
const publicKeyHash = HASH256(publicKey);
|
|
347
369
|
// (dkPKE||ek||H(ek)||z)
|
|
348
370
|
const secretKey = secretCoder.encode([sk, publicKey, publicKeyHash, seed.subarray(32)]);
|
|
349
371
|
cleanBytes(sk, publicKeyHash);
|
|
350
|
-
return {
|
|
372
|
+
return {
|
|
373
|
+
publicKey: publicKey as TRet<Uint8Array>,
|
|
374
|
+
secretKey: secretKey as TRet<Uint8Array>,
|
|
375
|
+
};
|
|
351
376
|
},
|
|
352
|
-
getPublicKey: (secretKey: Uint8Array) => {
|
|
377
|
+
getPublicKey: (secretKey: TArg<Uint8Array>): TRet<Uint8Array> => {
|
|
353
378
|
const [_sk, publicKey, _publicKeyHash, _z] = secretCoder.decode(secretKey);
|
|
354
|
-
return Uint8Array.from(publicKey)
|
|
379
|
+
return Uint8Array.from(publicKey) as TRet<Uint8Array>;
|
|
355
380
|
},
|
|
356
|
-
encapsulate: (publicKey: Uint8Array
|
|
381
|
+
encapsulate: (publicKey: TArg<Uint8Array>, msg: TArg<Uint8Array> = randomBytes(msgLen)) => {
|
|
357
382
|
abytes(publicKey, lengths.publicKey, 'publicKey');
|
|
358
383
|
abytes(msg, msgLen, 'message');
|
|
359
384
|
|
|
@@ -372,9 +397,12 @@ function createKyber(opts: KyberOpts) {
|
|
|
372
397
|
const kr = HASH512.create().update(msg).update(HASH256(publicKey)).digest();
|
|
373
398
|
const cipherText = KPKE.encrypt(publicKey, msg, kr.subarray(32, 64));
|
|
374
399
|
cleanBytes(kr.subarray(32));
|
|
375
|
-
return {
|
|
400
|
+
return {
|
|
401
|
+
cipherText: cipherText as TRet<Uint8Array>,
|
|
402
|
+
sharedSecret: kr.subarray(0, 32) as TRet<Uint8Array>,
|
|
403
|
+
};
|
|
376
404
|
},
|
|
377
|
-
decapsulate: (cipherText: Uint8Array
|
|
405
|
+
decapsulate: (cipherText: TArg<Uint8Array>, secretKey: TArg<Uint8Array>): TRet<Uint8Array> => {
|
|
378
406
|
abytes(secretKey, secretCoder.bytesLen, 'secretKey'); // 768*k + 96
|
|
379
407
|
abytes(cipherText, lengths.cipherText, 'cipherText'); // 32(du*k + dv)
|
|
380
408
|
// test ← H(dk[384𝑘 ∶ 768𝑘 + 32])) .
|
|
@@ -395,19 +423,19 @@ function createKyber(opts: KyberOpts) {
|
|
|
395
423
|
const isValid = equalBytes(cipherText, cipherText2);
|
|
396
424
|
const Kbar = KDF.create({ dkLen: 32 }).update(z).update(cipherText).digest();
|
|
397
425
|
cleanBytes(msg, cipherText2, !isValid ? Khat : Kbar);
|
|
398
|
-
return isValid ? Khat : Kbar
|
|
426
|
+
return (isValid ? Khat : Kbar) as TRet<Uint8Array>;
|
|
399
427
|
},
|
|
400
|
-
};
|
|
428
|
+
});
|
|
401
429
|
}
|
|
402
430
|
|
|
403
431
|
// FIPS 203's PRF_eta binding: current callers use only 32-byte keys, one-byte nonces,
|
|
404
432
|
// and dkLen values {128, 192}; out-of-range nonce numbers still wrap modulo 256 here.
|
|
405
|
-
function shakePRF(dkLen: number, key: Uint8Array
|
|
433
|
+
function shakePRF(dkLen: number, key: TArg<Uint8Array>, nonce: number): TRet<Uint8Array> {
|
|
406
434
|
return shake256
|
|
407
435
|
.create({ dkLen })
|
|
408
436
|
.update(key)
|
|
409
437
|
.update(new Uint8Array([nonce]))
|
|
410
|
-
.digest()
|
|
438
|
+
.digest() as TRet<Uint8Array>;
|
|
411
439
|
}
|
|
412
440
|
|
|
413
441
|
// Fixed ML-KEM hash/XOF bindings. `KDF` here is the spec's fixed 32-byte `J` call,
|
|
@@ -431,52 +459,53 @@ const mk = (params: KEMParam) =>
|
|
|
431
459
|
* ML-KEM-512: Table 2 row `k=2, η1=3, η2=2, du=10, dv=4`; Table 3 sizes `800/1632/768/32`.
|
|
432
460
|
* The ASD lifecycle note here is external policy guidance, not a FIPS 203 requirement.
|
|
433
461
|
*/
|
|
434
|
-
export const ml_kem512: KEM = /* @__PURE__ */ (() => mk(PARAMS[512]))();
|
|
462
|
+
export const ml_kem512: TRet<KEM> = /* @__PURE__ */ (() => mk(PARAMS[512]))();
|
|
435
463
|
/**
|
|
436
464
|
* ML-KEM-768: Table 2 row `k=3, η1=2, η2=2, du=10, dv=4`; Table 3 sizes `1184/2400/1088/32`.
|
|
437
465
|
* The ASD lifecycle note here is external policy guidance, not a FIPS 203 requirement.
|
|
438
466
|
*/
|
|
439
|
-
export const ml_kem768: KEM = /* @__PURE__ */ (() => mk(PARAMS[768]))();
|
|
467
|
+
export const ml_kem768: TRet<KEM> = /* @__PURE__ */ (() => mk(PARAMS[768]))();
|
|
440
468
|
/**
|
|
441
469
|
* ML-KEM-1024: Table 2 row `k=4, η1=2, η2=2, du=11, dv=5`; Table 3 sizes `1568/3168/1568/32`.
|
|
442
470
|
* The ASD lifecycle note here is external policy guidance, not a FIPS 203 requirement.
|
|
443
471
|
*/
|
|
444
|
-
export const ml_kem1024: KEM = /* @__PURE__ */ (() => mk(PARAMS[1024]))();
|
|
472
|
+
export const ml_kem1024: TRet<KEM> = /* @__PURE__ */ (() => mk(PARAMS[1024]))();
|
|
445
473
|
|
|
446
474
|
// NOTE: for tests only, don't use. This keeps the exact internal ML-KEM math surfaces available
|
|
447
475
|
// without re-implementing them in separate test code.
|
|
448
|
-
export const __tests: any = /* @__PURE__ */ (() =>
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
MultiplyNTTs(
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
}
|
|
476
|
+
export const __tests: any = /* @__PURE__ */ (() =>
|
|
477
|
+
Object.freeze({
|
|
478
|
+
Compress_d: (x: number, d: number) => {
|
|
479
|
+
if (d < 1 || d > 11) throw new Error(`Compress_d: expected d in [1..11], got ${d}`);
|
|
480
|
+
return compress(d).encode(x) & getMask(d);
|
|
481
|
+
},
|
|
482
|
+
Decompress_d: (y: number, d: number) => {
|
|
483
|
+
if (d < 1 || d > 11) throw new Error(`Decompress_d: expected d in [1..11], got ${d}`);
|
|
484
|
+
return compress(d).decode(y);
|
|
485
|
+
},
|
|
486
|
+
ByteEncode_d: (F: TArg<Uint16Array>, d: number) => {
|
|
487
|
+
if (d < 1 || d > 12) throw new Error(`ByteEncode_d: expected d in [1..12], got ${d}`);
|
|
488
|
+
return byteCoder(d).encode(F as TRet<Uint16Array>);
|
|
489
|
+
},
|
|
490
|
+
ByteDecode_d: (B: TArg<Uint8Array>, d: number) => {
|
|
491
|
+
if (d < 1 || d > 12) throw new Error(`ByteDecode_d: expected d in [1..12], got ${d}`);
|
|
492
|
+
return byteCoder(d).decode(B);
|
|
493
|
+
},
|
|
494
|
+
NTT: (f: TArg<Uint16Array>) => crystals.NTT.encode(Uint16Array.from(f)),
|
|
495
|
+
NTT_inv: (fHat: TArg<Uint16Array>) => crystals.NTT.decode(Uint16Array.from(fHat)),
|
|
496
|
+
MultiplyNTTs: (fHat: TArg<Uint16Array>, gHat: TArg<Uint16Array>) =>
|
|
497
|
+
MultiplyNTTs(Uint16Array.from(fHat), Uint16Array.from(gHat)),
|
|
498
|
+
SamplePolyCBD: (B: TArg<Uint8Array>, eta: number) => {
|
|
499
|
+
abytes(B, 64 * eta, 'B');
|
|
500
|
+
return sampleCBDBytes(B, eta);
|
|
501
|
+
},
|
|
502
|
+
SampleNTT: (B: TArg<Uint8Array>) => {
|
|
503
|
+
abytes(B, 34, 'B');
|
|
504
|
+
const xof = XOF128(B.subarray(0, 32));
|
|
505
|
+
try {
|
|
506
|
+
return SampleNTT(xof.get(B[32], B[33]));
|
|
507
|
+
} finally {
|
|
508
|
+
xof.clean();
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
}))();
|