@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/falcon.js CHANGED
@@ -12,7 +12,7 @@ import { bytesToNumberLE, numberToHexUnpadded } from '@noble/curves/utils.js';
12
12
  import { shake256 } from '@noble/hashes/sha3.js';
13
13
  import { abytes, bytesToHex, createView, hexToBytes, randomBytes, swap32IfBE, u32, u8, } from '@noble/hashes/utils.js';
14
14
  import { genCrystals } from "./_crystals.js";
15
- import { cleanBytes, getMask, baswap64If, splitCoder, validateSigOpts, validateVerOpts, } from "./utils.js";
15
+ import { baswap64If, cleanBytes, getMask, splitCoder, validateSigOpts, validateVerOpts, } from "./utils.js";
16
16
  /*
17
17
  FIPS-206 would likely improve the situation with spec.
18
18
 
@@ -124,10 +124,11 @@ const bitsCoderMSB = (newPoly, N, d, c) => {
124
124
  // encode() zeroizes the temporary encoded body after copying, so wrapped encoders must return
125
125
  // owned scratch bytes rather than caller-owned buffers.
126
126
  const headerCoder = (tag, restCoder) => {
127
+ const coder = restCoder;
127
128
  return {
128
- bytesLen: 1 + restCoder.bytesLen,
129
+ bytesLen: 1 + coder.bytesLen,
129
130
  encode(value) {
130
- const body = restCoder.encode(value);
131
+ const body = coder.encode(value);
131
132
  const out = new Uint8Array(1 + body.length);
132
133
  out[0] = tag;
133
134
  out.set(body, 1);
@@ -137,7 +138,7 @@ const headerCoder = (tag, restCoder) => {
137
138
  decode(data) {
138
139
  if (data[0] !== tag)
139
140
  throw new Error(`wrong tag: expected ${tag}, got 0x${data[0]}`);
140
- return restCoder.decode(data.subarray(1));
141
+ return coder.decode(data.subarray(1));
141
142
  },
142
143
  };
143
144
  };
@@ -377,7 +378,7 @@ const u8f = (arr) => new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);
377
378
  const f64a = (arr) => new Float64Array(baswap64If(Uint8Array.from(arr.subarray(0, Math.floor(arr.byteLength / 8) * 8))).buffer);
378
379
  // Exact big-endian binary64 hex helper for constants. Only decode() is currently used; malformed
379
380
  // inputs fail through lower-level hex / DataView checks instead of an explicit wrapper guard.
380
- const Float = {
381
+ const Float = /* @__PURE__ */ Object.freeze({
381
382
  encode(n) {
382
383
  const bytes = new Uint8Array(8);
383
384
  const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
@@ -389,7 +390,7 @@ const Float = {
389
390
  const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
390
391
  return view.getFloat64(0, false);
391
392
  },
392
- };
393
+ });
393
394
  // Decode a 64-bit bigint bit pattern into the exact binary64 value.
394
395
  const f64b = (n) => Float.decode(numberToHexUnpadded(n));
395
396
  // Constants
@@ -402,6 +403,17 @@ const Q = 12289; // 12 * 1024 + 1
402
403
  // Falcon's midpoint floor(q/2); the only live use is the mirrored G-reconstruction reduction below.
403
404
  const Qhalf = Q >> 1;
404
405
  const QBig = BigInt(Q);
406
+ const _0n = /* @__PURE__ */ BigInt(0);
407
+ const _1n = /* @__PURE__ */ BigInt(1);
408
+ const _10n = /* @__PURE__ */ BigInt(10);
409
+ const _25n = /* @__PURE__ */ BigInt(25);
410
+ const _31n = /* @__PURE__ */ BigInt(31);
411
+ const _32n = /* @__PURE__ */ BigInt(32);
412
+ const _63n = /* @__PURE__ */ BigInt(63);
413
+ const _64n = /* @__PURE__ */ BigInt(64);
414
+ // Low 32 bits and low 63 bits of a bigint, used by the chacha20 counter and gaussian sampler.
415
+ const MASK_32n = /* @__PURE__ */ BigInt('0xffffffff');
416
+ const MASK_63n = /* @__PURE__ */ BigInt('0x7fffffffffffffff');
405
417
  //const R = 4091; // 2^16 mod q
406
418
  // This 16-bit Montgomery kernel uses R = 2^16, so mul(x, R2) converts x into Montgomery form.
407
419
  const R2 = 10952; // 2^32 mod q
@@ -438,38 +450,38 @@ const BITLENGTH = [
438
450
  // Smaller Falcon dimensions reuse the N = 1024, q = 12289 table by summing 2^(10-logn) draws.
439
451
  // The trailing 0 sentinel guarantees gaussSingle()
440
452
  // always selects a tail bucket when x = 0 is missed.
441
- const gauss_1024_12289 = [
442
- 1283868770400643928n,
443
- 6416574995475331444n,
444
- 4078260278032692663n,
445
- 2353523259288686585n,
446
- 1227179971273316331n,
447
- 575931623374121527n,
448
- 242543240509105209n,
449
- 91437049221049666n,
450
- 30799446349977173n,
451
- 9255276791179340n,
452
- 2478152334826140n,
453
- 590642893610164n,
454
- 125206034929641n,
455
- 23590435911403n,
456
- 3948334035941n,
457
- 586753615614n,
458
- 77391054539n,
459
- 9056793210n,
460
- 940121950n,
461
- 86539696n,
462
- 7062824n,
463
- 510971n,
464
- 32764n,
465
- 1862n,
466
- 94n,
467
- 4n,
468
- 0n,
469
- ];
453
+ const gauss_1024_12289 = /* @__PURE__ */ [
454
+ '1283868770400643928',
455
+ '6416574995475331444',
456
+ '4078260278032692663',
457
+ '2353523259288686585',
458
+ '1227179971273316331',
459
+ '575931623374121527',
460
+ '242543240509105209',
461
+ '91437049221049666',
462
+ '30799446349977173',
463
+ '9255276791179340',
464
+ '2478152334826140',
465
+ '590642893610164',
466
+ '125206034929641',
467
+ '23590435911403',
468
+ '3948334035941',
469
+ '586753615614',
470
+ '77391054539',
471
+ '9056793210',
472
+ '940121950',
473
+ '86539696',
474
+ '7062824',
475
+ '510971',
476
+ '32764',
477
+ '1862',
478
+ '94',
479
+ '4',
480
+ '0',
481
+ ].map(BigInt);
470
482
  // Exact binary64 1/sigma payloads from round-3 fpr.h. Nearby decimal spellings round 1 ULP low in
471
483
  // JS, so keep these as decoded bit patterns and recheck the raw payloads after edits.
472
- const INV_SIGMA = [
484
+ const INV_SIGMA = /* @__PURE__ */ Object.freeze([
473
485
  0.0, // unused
474
486
  f64b(BigInt('4574611497772390042')),
475
487
  f64b(BigInt('4574501679055810265')),
@@ -481,11 +493,11 @@ const INV_SIGMA = [
481
493
  f64b(BigInt('4573721358406441454')),
482
494
  f64b(BigInt('4573606369665796042')),
483
495
  f64b(BigInt('4573496814039276259')),
484
- ];
496
+ ]);
485
497
  // Exact binary64 sigma_min constants from round-3 fpr.h indexed by logn; despite one PQClean
486
498
  // summary comment, these are sigma_min itself, not 1/sigma_min, which is why this table stays
487
499
  // separate from INV_SIGMA.
488
- const SIGMA_MIN = [
500
+ const SIGMA_MIN = /* @__PURE__ */ Object.freeze([
489
501
  0.0, // unused
490
502
  f64b(BigInt('4607707126469777035')),
491
503
  f64b(BigInt('4607777455861499430')),
@@ -497,7 +509,7 @@ const SIGMA_MIN = [
497
509
  f64b(BigInt('4608340089478362016')),
498
510
  f64b(BigInt('4608433670533905013')),
499
511
  f64b(BigInt('4608525754002622308')),
500
- ];
512
+ ]);
501
513
  // Falcon Table 3.1 RCDT values for chi, split into 24-bit limbs; storage is [high, mid, low],
502
514
  // so gaussian0() intentionally compares them against v0, v1, v2 in reverse order. The final
503
515
  // RCDT[18] = 0 row is omitted because the algorithm iterates only over i = 0..17.
@@ -1146,9 +1158,9 @@ function genFalcon(opts) {
1146
1158
  let val = 0;
1147
1159
  for (let i = 0; i < g; i++) {
1148
1160
  const r128 = bytesToNumberLE(this.shake.xof(16));
1149
- const r1 = r128 & 0x7fffffffffffffffn;
1150
- const r2 = (r128 >> 64n) & 0x7fffffffffffffffn;
1151
- const sign = Number((r128 >> 63n) & 1n);
1161
+ const r1 = r128 & MASK_63n;
1162
+ const r2 = (r128 >> _64n) & MASK_63n;
1163
+ const sign = Number((r128 >> _63n) & _1n);
1152
1164
  let f = r1 < gauss_1024_12289[0] ? 1 : 0;
1153
1165
  let v = 0;
1154
1166
  for (let k = 1; k < gauss_1024_12289.length; k++) {
@@ -1185,7 +1197,7 @@ function genFalcon(opts) {
1185
1197
  const n = 1 << logn;
1186
1198
  const d = new Array(n >> 1);
1187
1199
  for (let k = 0; k < n; k += 2) {
1188
- let s = 0n;
1200
+ let s = _0n;
1189
1201
  for (let i = 0; i <= k; i += 2)
1190
1202
  s += a[i] * a[k - i];
1191
1203
  for (let i = k + 2; i < n; i += 2)
@@ -1193,7 +1205,7 @@ function genFalcon(opts) {
1193
1205
  d[k >>> 1] = s;
1194
1206
  }
1195
1207
  for (let k = 0; k < n; k += 2) {
1196
- let s = 0n;
1208
+ let s = _0n;
1197
1209
  for (let i = 1; i < k; i += 2)
1198
1210
  s += a[i] * a[k - i];
1199
1211
  for (let i = k + 1; i < n; i += 2)
@@ -1205,7 +1217,7 @@ function genFalcon(opts) {
1205
1217
  mulConjD(logn, d, a, b) {
1206
1218
  const n = 1 << logn;
1207
1219
  for (let k = 0; k < n; k++) {
1208
- let s = 0n;
1220
+ let s = _0n;
1209
1221
  for (let i = 0; i <= k; i += 2)
1210
1222
  s += b[i >>> 1] * a[k - i];
1211
1223
  for (let i = k + 2 - (k & 1); i < n; i += 2)
@@ -1220,7 +1232,7 @@ function genFalcon(opts) {
1220
1232
  subMul(logn, a, b, c, e) {
1221
1233
  const n = 1 << logn;
1222
1234
  for (let k = 0; k < n; k++) {
1223
- let s = 0n;
1235
+ let s = _0n;
1224
1236
  for (let i = 0; i <= k; i++)
1225
1237
  s += b[i] * c[k - i];
1226
1238
  for (let i = k + 1; i < n; i++)
@@ -1264,7 +1276,7 @@ function genFalcon(opts) {
1264
1276
  const Gx = new Float64Array(n);
1265
1277
  const k = new Array(n);
1266
1278
  while (true) {
1267
- let scaleFG = 31n * (FGlen - 10n);
1279
+ let scaleFG = _31n * (FGlen - _10n);
1268
1280
  for (let i = 0; i < n; i++) {
1269
1281
  Fx[i] = Number(F[i] >> scaleFG);
1270
1282
  Gx[i] = Number(G[i] >> scaleFG);
@@ -1283,16 +1295,16 @@ function genFalcon(opts) {
1283
1295
  }
1284
1296
  F = this.subMul(logn, F, f, k, scaleK); // 3: F ← F - kf
1285
1297
  G = this.subMul(logn, G, g, k, scaleK); // 4: G ← G - kg
1286
- const maxfgNew = scaleK + BigInt(Math.round(fgMaxBits)) + 10n;
1298
+ const maxfgNew = scaleK + BigInt(Math.round(fgMaxBits)) + _10n;
1287
1299
  if (maxfgNew < maxFGBits)
1288
1300
  maxFGBits = maxfgNew;
1289
- if (FGlen > 1n && FGlen * 31n >= maxFGBits + 31n)
1301
+ if (FGlen > _1n && FGlen * _31n >= maxFGBits + _31n)
1290
1302
  FGlen--;
1291
- if (scaleK <= 0n)
1303
+ if (scaleK <= _0n)
1292
1304
  break;
1293
- scaleK -= 25n;
1294
- if (scaleK < 0n)
1295
- scaleK = 0n;
1305
+ scaleK -= _25n;
1306
+ if (scaleK < _0n)
1307
+ scaleK = _0n;
1296
1308
  }
1297
1309
  return true;
1298
1310
  }
@@ -1320,11 +1332,11 @@ function genFalcon(opts) {
1320
1332
  const xf = f[0];
1321
1333
  const xg = g[0];
1322
1334
  // We can rely on 'invert' to throw if they are not coprime.
1323
- if (xf <= 0n || xg <= 0n)
1335
+ if (xf <= _0n || xg <= _0n)
1324
1336
  return false;
1325
1337
  try {
1326
1338
  const u1 = invert(xf, xg); // if gcd(f, g) ≠ 1 then
1327
- const v1 = (1n - u1 * xf) / xg;
1339
+ const v1 = (_1n - u1 * xf) / xg;
1328
1340
  F[0] = -v1 * QBig; // 5: (F, G) ← (vq, uq)
1329
1341
  G[0] = u1 * QBig;
1330
1342
  return true;
@@ -1606,7 +1618,14 @@ function genFalcon(opts) {
1606
1618
  return headerCoder(0x30 + logn, splitCoder('falcon.signature', NONCELEN, sigLen, msg.length)).encode([nonce, pad(sigLen).encode(s2), msg]);
1607
1619
  },
1608
1620
  decode(data) {
1621
+ // Keep API misuse on the coder's TypeError path before reading the container length.
1622
+ abytes(data, undefined, 'signature');
1623
+ // The compressed-signature field is fixed-width here; only the message is variable. A
1624
+ // container shorter than the fixed part would make the s2 field borrow bytes from nowhere
1625
+ // and let a truncated encoding open to the same message.
1609
1626
  const msgLen = data.length - NONCELEN - sigLen - 1;
1627
+ if (msgLen < 0)
1628
+ throw new Error('signature coder: wrong length');
1610
1629
  const [nonce, s2, msg] = headerCoder(0x30 + logn, splitCoder('falcon.signature', NONCELEN, sigLen, msgLen)).decode(data);
1611
1630
  return { nonce, s2: decodeSig(s2), msg };
1612
1631
  },
@@ -1621,7 +1640,13 @@ function genFalcon(opts) {
1621
1640
  return headerCoder(0x30 + logn, splitCoder('falcon.detachedSignature', NONCELEN, getSigLen(s2))).encode([nonce, opts.padded ? pad(sigLen).encode(s2) : s2]);
1622
1641
  },
1623
1642
  decode(data) {
1624
- const [nonce, raw] = headerCoder(0x30 + logn, splitCoder('falcon.detachedSignature', NONCELEN, data.length - NONCELEN - 1)).decode(data);
1643
+ // Padded detached signatures are fixed-length (`lengths.signature`), so the payload width
1644
+ // must come from the parameter set, not from the input: deriving it would accept appended
1645
+ // zero bytes and truncated padding as extra valid encodings of the same signature.
1646
+ // Unpadded signatures are variable-length; decodeUnpaddedSig() enforces the exact canonical
1647
+ // bitlength of whatever remains.
1648
+ const payloadLen = opts.padded ? sigLen : data.length - NONCELEN - 1;
1649
+ const [nonce, raw] = headerCoder(0x30 + logn, splitCoder('falcon.detachedSignature', NONCELEN, payloadLen)).decode(data);
1625
1650
  const s2 = decodeSig(raw);
1626
1651
  return { nonce, s2 };
1627
1652
  },
@@ -1709,7 +1734,7 @@ function genFalcon(opts) {
1709
1734
  shakeBuf;
1710
1735
  ctrView;
1711
1736
  // ChaCha
1712
- ctr = 0n;
1737
+ ctr = _0n;
1713
1738
  buf;
1714
1739
  buf32;
1715
1740
  pos;
@@ -1759,8 +1784,8 @@ function genFalcon(opts) {
1759
1784
  const out32 = swap32IfBE(this.buf32);
1760
1785
  for (let i = 0; i < 8; i++, this.ctr++) {
1761
1786
  const n = swap32IfBE(this.nonce32.slice()); // [n0, n1, n2, n3]
1762
- n[2] ^= Number(this.ctr & 0xffffffffn);
1763
- n[3] ^= Number(this.ctr >> 32n);
1787
+ n[2] ^= Number(this.ctr & MASK_32n);
1788
+ n[3] ^= Number(this.ctr >> _32n);
1764
1789
  // chacha20() takes raw nonce bytes; on BE the word-normalized temp must be swapped back.
1765
1790
  swap32IfBE(n.subarray(1));
1766
1791
  chacha20(this.key, u8(n.subarray(1)), EMPTY_CHACHA20_BLOCK, this.curBlock, n[0]);
@@ -2077,7 +2102,8 @@ function genFalcon(opts) {
2077
2102
  // ▷ Remove 1 byte for the header, and 40 bytes for r
2078
2103
  // 11: while (s = ⊥)
2079
2104
  // 12: return sig = (r, s)
2080
- abytes(msg);
2105
+ abytes(msg, undefined, 'msg');
2106
+ abytes(sk, secretKeyCoder.bytesLen, 'secretKey');
2081
2107
  // One RNG stream drives both the public 40-byte nonce and the 48-byte sampler seed, so
2082
2108
  // deterministic rnd hooks make signatures deterministic for fixed secretKey/message inputs.
2083
2109
  const nonce = rnd(40);
@@ -2171,18 +2197,20 @@ function genFalcon(opts) {
2171
2197
  intPoly.sub(s1, c0); // 5: s₁ ← c - s₂h mod q ▷ s₁ should be normalized between -q/2 and q/2
2172
2198
  return intPoly.isShort(signedCoder.encode(s1), s2); // 6: if ||(s₁, s₂)||² < [β²] then
2173
2199
  };
2174
- const info = { type: 'falcon' };
2175
- const keyLengths = {
2200
+ const info = Object.freeze({ type: 'falcon' });
2201
+ const keyLengths = Object.freeze({
2176
2202
  seed: 48,
2177
2203
  publicKey: publicKeyCoder.bytesLen,
2178
2204
  secretKey: secretKeyCoder.bytesLen,
2179
- };
2205
+ });
2180
2206
  // Noble exposes a 48-byte sampler-seed hook,
2181
2207
  // but Falcon still samples/encodes a separate 40-byte nonce per signature.
2182
2208
  const getRnd = (opts = {}) => {
2183
2209
  validateSigOpts(opts);
2184
2210
  if (opts.context !== undefined)
2185
2211
  throw new Error('context is not supported');
2212
+ if (opts.random !== undefined && typeof opts.random !== 'function')
2213
+ throw new TypeError('"opts.random" expected function, got type=' + typeof opts.random);
2186
2214
  if (opts.random !== undefined)
2187
2215
  return opts.random;
2188
2216
  if (opts.extraEntropy === undefined)
@@ -2197,11 +2225,17 @@ function genFalcon(opts) {
2197
2225
  if (opts.context !== undefined)
2198
2226
  throw new Error('context is not supported');
2199
2227
  };
2200
- const tests = { publicKeyCoder, privateKeyCoder: secretKeyCoder, maxS2Len: opts.maxS2Len };
2228
+ const tests = Object.freeze({
2229
+ publicKeyCoder: Object.freeze(publicKeyCoder),
2230
+ privateKeyCoder: Object.freeze(secretKeyCoder),
2231
+ maxS2Len: opts.maxS2Len,
2232
+ });
2201
2233
  // `signRand` documents only the sampler-seed input length;
2202
2234
  // detached/attached signatures still include their own 40-byte nonce.
2203
- const attachedLengths = { ...keyLengths, signRand: 48 };
2204
- const lengths = opts.padded ? { ...attachedLengths, signature: opts.sigLen } : attachedLengths;
2235
+ const attachedLengths = Object.freeze({ ...keyLengths, signRand: 48 });
2236
+ const lengths = opts.padded
2237
+ ? Object.freeze({ ...attachedLengths, signature: opts.sigLen })
2238
+ : attachedLengths;
2205
2239
  const keygen = (seed) => {
2206
2240
  const randSeed = seed === undefined;
2207
2241
  if (randSeed)
@@ -2216,6 +2250,7 @@ function genFalcon(opts) {
2216
2250
  return { publicKey: pk, secretKey: sk };
2217
2251
  };
2218
2252
  const getPublicKey = (sk) => {
2253
+ abytes(sk, secretKeyCoder.bytesLen, 'secretKey');
2219
2254
  const [f, g, F] = secretKeyCoder.decode(sk);
2220
2255
  try {
2221
2256
  const h = computePublic(f, g);
@@ -2238,9 +2273,10 @@ function genFalcon(opts) {
2238
2273
  */
2239
2274
  const verify = (sig, msg, pk, verOpts = {}) => {
2240
2275
  checkVerOpts(verOpts);
2241
- abytes(sig);
2242
- abytes(msg);
2243
- abytes(pk);
2276
+ abytes(sig, undefined, 'signature');
2277
+ abytes(msg, undefined, 'msg');
2278
+ // Length/canonical public-key failures are decoded below and return false; only type is fatal.
2279
+ abytes(pk, undefined, 'publicKey');
2244
2280
  try {
2245
2281
  const { s2, nonce } = SignatureCoderDetached(logn).decode(sig);
2246
2282
  return verifyRaw(pk, s2, nonce, msg);
@@ -2249,7 +2285,7 @@ function genFalcon(opts) {
2249
2285
  return false;
2250
2286
  }
2251
2287
  };
2252
- const attached = {
2288
+ const attached = Object.freeze({
2253
2289
  info,
2254
2290
  lengths: attachedLengths,
2255
2291
  keygen,
@@ -2267,7 +2303,7 @@ function genFalcon(opts) {
2267
2303
  return msg;
2268
2304
  throw new Error('invalid signature');
2269
2305
  },
2270
- };
2306
+ });
2271
2307
  const res = {
2272
2308
  info,
2273
2309
  lengths,
@@ -2278,7 +2314,7 @@ function genFalcon(opts) {
2278
2314
  verify,
2279
2315
  };
2280
2316
  res.__test = tests;
2281
- return res;
2317
+ return Object.freeze(res);
2282
2318
  }
2283
2319
  const falcon512opts = {
2284
2320
  N: 512,
@@ -2362,7 +2398,7 @@ export const falcon1024padded = /* @__PURE__ */ (() => genFalcon({
2362
2398
  maxS2Len: 1239,
2363
2399
  }))();
2364
2400
  // NOTE: for tests only, don't use
2365
- export const __tests = /* @__PURE__ */ (() => ({
2401
+ export const __tests = /* @__PURE__ */ (() => Object.freeze({
2366
2402
  BNORM_MAX,
2367
2403
  COMPLEX_ROOTS,
2368
2404
  Float,
@@ -2375,4 +2411,3 @@ export const __tests = /* @__PURE__ */ (() => ({
2375
2411
  falcon1024: falcon1024.__test,
2376
2412
  falcon1024padded: falcon1024padded.__test,
2377
2413
  }))();
2378
- //# sourceMappingURL=falcon.js.map
package/hybrid.d.ts CHANGED
@@ -78,7 +78,7 @@ import { type EdDSA } from '@noble/curves/abstract/edwards.js';
78
78
  import { type MontgomeryECDH } from '@noble/curves/abstract/montgomery.js';
79
79
  import { type ECDSA } from '@noble/curves/abstract/weierstrass.js';
80
80
  import { type CHash, type CHashXOF } from '@noble/hashes/utils.js';
81
- import { type KEM, type Signer } from './utils.ts';
81
+ import { type KEM, type Signer, type TArg, type TRet } from './utils.ts';
82
82
  type CurveECDH = ECDSA | MontgomeryECDH;
83
83
  type CurveSign = ECDSA | EdDSA;
84
84
  /**
@@ -104,7 +104,7 @@ type CurveSign = ECDSA | EdDSA;
104
104
  * const publicKeyLen = kem.lengths.publicKey;
105
105
  * ```
106
106
  */
107
- export declare function ecdhKem(curve: CurveECDH, allowZeroKey?: boolean): KEM;
107
+ export declare function ecdhKem(curve: CurveECDH, allowZeroKey?: boolean): TRet<KEM>;
108
108
  /**
109
109
  * Wraps a curve signer as a generic `Signer`.
110
110
  * Signatures stay in the wrapped curve's native byte encoding.
@@ -126,9 +126,9 @@ export declare function ecdhKem(curve: CurveECDH, allowZeroKey?: boolean): KEM;
126
126
  * const sigLen = signer.lengths.signature;
127
127
  * ```
128
128
  */
129
- export declare function ecSigner(curve: CurveSign, allowZeroKey?: boolean): Signer;
129
+ export declare function ecSigner(curve: CurveSign, allowZeroKey?: boolean): TRet<Signer>;
130
130
  /** Seed-expansion callback used by the hybrid combiners. */
131
- export type ExpandSeed = (seed: Uint8Array, len: number) => Uint8Array;
131
+ export type ExpandSeed = (seed: TArg<Uint8Array>, len: number) => TRet<Uint8Array>;
132
132
  type XOF = CHashXOF<any, {
133
133
  dkLen: number;
134
134
  }>;
@@ -146,9 +146,9 @@ type XOF = CHashXOF<any, {
146
146
  * const seed = expandSeed(new Uint8Array([1]), 4);
147
147
  * ```
148
148
  */
149
- export declare function expandSeedXof(xof: XOF): ExpandSeed;
149
+ export declare function expandSeedXof(xof: TArg<XOF>): TRet<ExpandSeed>;
150
150
  /** Combines public keys, ciphertexts, and shared secrets into one shared secret. */
151
- export type Combiner = (publicKeys: Uint8Array[], cipherTexts: Uint8Array[], sharedSecrets: Uint8Array[]) => Uint8Array;
151
+ export type Combiner = (publicKeys: TArg<Uint8Array[]>, cipherTexts: TArg<Uint8Array[]>, sharedSecrets: TArg<Uint8Array[]>) => TRet<Uint8Array>;
152
152
  /**
153
153
  * Combines multiple KEMs into one composite KEM.
154
154
  * @param realSeedLen - Input seed length expected by `expandSeed`.
@@ -176,7 +176,7 @@ export type Combiner = (publicKeys: Uint8Array[], cipherTexts: Uint8Array[], sha
176
176
  */
177
177
  export declare function combineKEMS(realSeedLen: number | undefined, // how much bytes expandSeed expects
178
178
  realMsgLen: number | undefined, // how much bytes combiner returns
179
- expandSeed: ExpandSeed, combiner: Combiner, ...kems: KEM[]): KEM;
179
+ expandSeed: TArg<ExpandSeed>, combiner: TArg<Combiner>, ...kems: TArg<KEM[]>): TRet<KEM>;
180
180
  /**
181
181
  * Combines multiple signers into one composite signer.
182
182
  * @param realSeedLen - Input seed length expected by `expandSeed`.
@@ -190,10 +190,14 @@ expandSeed: ExpandSeed, combiner: Combiner, ...kems: KEM[]): KEM;
190
190
  * import { combineSigners, expandSeedXof } from '@noble/post-quantum/hybrid.js';
191
191
  * import { ml_dsa44 } from '@noble/post-quantum/ml-dsa.js';
192
192
  * const hybrid = combineSigners(32, expandSeedXof(shake256), ml_dsa44, ml_dsa44);
193
- * const { publicKey } = hybrid.keygen();
193
+ * const seed = new Uint8Array(hybrid.lengths.seed!).fill(1);
194
+ * const { secretKey, publicKey } = hybrid.keygen(seed);
195
+ * const msg = new TextEncoder().encode('hello noble');
196
+ * const sig = hybrid.sign(msg, secretKey);
197
+ * const isValid = hybrid.verify(sig, msg, publicKey);
194
198
  * ```
195
199
  */
196
- export declare function combineSigners(realSeedLen: number | undefined, expandSeed: ExpandSeed, ...signers: Signer[]): Signer;
200
+ export declare function combineSigners(realSeedLen: number | undefined, expandSeed: TArg<ExpandSeed>, ...signers: TArg<Signer[]>): TRet<Signer>;
197
201
  /**
198
202
  * Builds a QSF hybrid KEM preset from a PQ KEM and an elliptic-curve KEM.
199
203
  * The combined shared-secret length follows `kdf.outputLen`; the built-in presets use 32-byte
@@ -218,11 +222,11 @@ export declare function combineSigners(realSeedLen: number | undefined, expandSe
218
222
  * const publicKeyLen = kem.lengths.publicKey;
219
223
  * ```
220
224
  */
221
- export declare function QSF(label: string, pqc: KEM, curveKEM: KEM, xof: XOF, kdf: CHash): KEM;
225
+ export declare function QSF(label: string, pqc: TArg<KEM>, curveKEM: TArg<KEM>, xof: TArg<XOF>, kdf: CHash): TRet<KEM>;
222
226
  /** QSF preset combining ML-KEM-768 with P-256. */
223
- export declare const QSF_ml_kem768_p256: KEM;
227
+ export declare const QSF_ml_kem768_p256: TRet<KEM>;
224
228
  /** QSF preset combining ML-KEM-1024 with P-384. */
225
- export declare const QSF_ml_kem1024_p384: KEM;
229
+ export declare const QSF_ml_kem1024_p384: TRet<KEM>;
226
230
  /**
227
231
  * Builds the "KitchenSink" hybrid KEM combiner.
228
232
  * The current builder always derives a fixed 32-byte output,
@@ -249,33 +253,18 @@ export declare const QSF_ml_kem1024_p384: KEM;
249
253
  * const publicKeyLen = kem.lengths.publicKey;
250
254
  * ```
251
255
  */
252
- export declare function createKitchenSink(label: string, pqc: KEM, curveKEM: KEM, xof: XOF, hash: CHash): KEM;
256
+ export declare function createKitchenSink(label: string, pqc: TArg<KEM>, curveKEM: TArg<KEM>, xof: TArg<XOF>, hash: CHash): TRet<KEM>;
253
257
  /** KitchenSink preset combining ML-KEM-768 with X25519.
254
258
  * Caller randomness splits into 32 ML-KEM coins plus a 32-byte X25519 ephemeral-secret seed.
255
259
  */
256
- export declare const KitchenSink_ml_kem768_x25519: KEM;
260
+ export declare const KitchenSink_ml_kem768_x25519: TRet<KEM>;
257
261
  /** X25519 + ML-KEM-768 hybrid preset.
258
262
  * Uses the hard-coded domain-separation label `\\.//^\\` and hashes only `ct1 || pk1`
259
263
  * from the X25519 side in addition to the two component shared secrets.
260
264
  */
261
- export declare const ml_kem768_x25519: KEM;
265
+ export declare const ml_kem768_x25519: TRet<KEM>;
262
266
  /** P-256 + ML-KEM-768 hybrid preset. */
263
- export declare const ml_kem768_p256: KEM;
267
+ export declare const ml_kem768_p256: TRet<KEM>;
264
268
  /** P-384 + ML-KEM-1024 hybrid preset. */
265
- export declare const ml_kem1024_p384: KEM;
266
- /** Legacy alias for `ml_kem768_x25519`. */
267
- export declare const XWing: KEM;
268
- /** Legacy alias for `ml_kem768_x25519`. */
269
- export declare const MLKEM768X25519: KEM;
270
- /** Legacy alias for `ml_kem768_p256`. */
271
- export declare const MLKEM768P256: KEM;
272
- /** Legacy alias for `ml_kem1024_p384`. */
273
- export declare const MLKEM1024P384: KEM;
274
- /** Legacy alias for `QSF_ml_kem768_p256`. */
275
- export declare const QSFMLKEM768P256: KEM;
276
- /** Legacy alias for `QSF_ml_kem1024_p384`. */
277
- export declare const QSFMLKEM1024P384: KEM;
278
- /** Legacy alias for `KitchenSink_ml_kem768_x25519`. */
279
- export declare const KitchenSinkMLKEM768X25519: KEM;
269
+ export declare const ml_kem1024_p384: TRet<KEM>;
280
270
  export {};
281
- //# sourceMappingURL=hybrid.d.ts.map