@hpke/hybridkem-x-wing 0.7.0 → 0.7.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 CHANGED
@@ -75,6 +75,10 @@ try {
75
75
  }
76
76
  ```
77
77
 
78
+ Auth and AuthPSK require a KEM that supports AuthEncap/AuthDecap. ML-KEM, X-Wing
79
+ and X25519-Kyber768 support only Base and PSK modes; requesting authentication
80
+ with these KEMs throws `NotSupportedError` (RFC 9180 Section 7.1.5).
81
+
78
82
  ## Index
79
83
 
80
84
  - [Installation](#installation)
@@ -133,24 +137,20 @@ Using esm.sh:
133
137
  ```html
134
138
  <!-- use a specific version -->
135
139
  <script type="module">
136
- import {
137
- Aes256Gcm,
138
- CipherSuite,
139
- HkdfSha256,
140
- } from "https://esm.sh/@hpke/core@<SEMVER>";
141
- import { XWing } from "https://esm.sh/@hpke/hybridkem-x-wing@<SEMVER>";
142
- // ...
140
+ import {
141
+ Aes256Gcm,
142
+ CipherSuite,
143
+ HkdfSha256,
144
+ } from "https://esm.sh/@hpke/core@<SEMVER>";
145
+ import { XWing } from "https://esm.sh/@hpke/hybridkem-x-wing@<SEMVER>";
146
+ // ...
143
147
  </script>
144
148
 
145
149
  <!-- use the latest stable version -->
146
150
  <script type="module">
147
- import {
148
- Aes256Gcm,
149
- CipherSuite,
150
- HkdfSha256,
151
- } from "https://esm.sh/@hpke/core";
152
- import { XWing } from "https://esm.sh/@hpke/hybridkem-x-wing";
153
- // ...
151
+ import { Aes256Gcm, CipherSuite, HkdfSha256 } from "https://esm.sh/@hpke/core";
152
+ import { XWing } from "https://esm.sh/@hpke/hybridkem-x-wing";
153
+ // ...
154
154
  </script>
155
155
  ```
156
156
 
@@ -159,13 +159,13 @@ Using unpkg:
159
159
  ```html
160
160
  <!-- use a specific version -->
161
161
  <script type="module">
162
- import {
163
- Aes256Gcm,
164
- CipherSuite,
165
- HkdfSha256,
166
- } from "https://unpkg.com/@hpke/core@<SEMVER>/esm/mod.js";
167
- import { XWing } from "https://unpkg.com/@hpke/hybridkem-x-wing@<SEMVER>/esm/mod.js";
168
- // ...
162
+ import {
163
+ Aes256Gcm,
164
+ CipherSuite,
165
+ HkdfSha256,
166
+ } from "https://unpkg.com/@hpke/core@<SEMVER>/esm/mod.js";
167
+ import { XWing } from "https://unpkg.com/@hpke/hybridkem-x-wing@<SEMVER>/esm/mod.js";
168
+ // ...
169
169
  </script>
170
170
  ```
171
171
 
@@ -266,46 +266,42 @@ try {
266
266
  <head></head>
267
267
  <body>
268
268
  <script type="module">
269
- import {
270
- Aes256Gcm,
271
- CipherSuite,
272
- HkdfSha256,
273
- } from "https://esm.sh/@hpke/core";
274
- import { XWing } from "https://esm.sh/@hpke/hybridkem-x-wing";
275
-
276
- globalThis.doHpke = async () => {
277
- try {
278
- const suite = new CipherSuite({
279
- kem: new XWing(),
280
- kdf: new HkdfSha256(),
281
- aead: new Aes256Gcm(),
282
- });
283
-
284
- const rkp = await suite.kem.generateKeyPair();
285
-
286
- // Note that the `ct` resulting from X-Wing::Encapsulate() is set to `sender.enc`.
287
- const sender = await suite.createSenderContext({
288
- recipientPublicKey: rkp.publicKey,
289
- });
290
- // encrypt
291
- const encrypted = await sender.seal(
292
- new TextEncoder().encode("Hello world!"),
293
- );
294
-
295
- const recipient = await suite.createRecipientContext({
296
- recipientKey: rkp.privateKey, // rkp (CryptoKeyPair) is also acceptable.
297
- enc: sender.enc, // == `ct` (ciphertext) in the context of X-Wing
298
- });
299
-
300
- // decrypt
301
- const pt = await recipient.open(encrypted);
302
-
303
- // Hello world!
304
- alert(new TextDecoder().decode(pt));
305
- } catch (err) {
306
- alert("failed:", err.message);
307
- }
308
- };
269
+ import { Aes256Gcm, CipherSuite, HkdfSha256 } from "https://esm.sh/@hpke/core";
270
+ import { XWing } from "https://esm.sh/@hpke/hybridkem-x-wing";
271
+
272
+ globalThis.doHpke = async () => {
273
+ try {
274
+ const suite = new CipherSuite({
275
+ kem: new XWing(),
276
+ kdf: new HkdfSha256(),
277
+ aead: new Aes256Gcm(),
278
+ });
279
+
280
+ const rkp = await suite.kem.generateKeyPair();
281
+
282
+ // Note that the `ct` resulting from X-Wing::Encapsulate() is set to `sender.enc`.
283
+ const sender = await suite.createSenderContext({
284
+ recipientPublicKey: rkp.publicKey,
285
+ });
286
+ // encrypt
287
+ const encrypted = await sender.seal(
288
+ new TextEncoder().encode("Hello world!"),
289
+ );
290
+
291
+ const recipient = await suite.createRecipientContext({
292
+ recipientKey: rkp.privateKey, // rkp (CryptoKeyPair) is also acceptable.
293
+ enc: sender.enc, // == `ct` (ciphertext) in the context of X-Wing
294
+ });
295
+
296
+ // decrypt
297
+ const pt = await recipient.open(encrypted);
298
+
299
+ // Hello world!
300
+ alert(new TextDecoder().decode(pt));
301
+ } catch (err) {
302
+ alert("failed:", err.message);
303
+ }
304
+ };
309
305
  </script>
310
306
  <button type="button" onclick="doHpke()">do HPKE</button>
311
307
  </body>
package/esm/package.json CHANGED
@@ -1,3 +1,4 @@
1
1
  {
2
- "type": "module"
2
+ "type": "module",
3
+ "sideEffects": false
3
4
  }
@@ -1,7 +1,6 @@
1
1
  import { MlKem768 } from "mlkem";
2
2
  import type { JsonWebKeyExtended, KemInterface, RecipientContextParams, SenderContextParams } from "@hpke/common";
3
- import { KemId } from "@hpke/common";
4
- import { X25519 } from "@hpke/dhkem-x25519";
3
+ import type { KemId } from "@hpke/common";
5
4
  /**
6
5
  * The Hybrid Post-Quantum KEM (X25519, Kyber768).
7
6
  *
@@ -32,7 +31,6 @@ export declare class XWing implements KemInterface {
32
31
  readonly privateKeySize: number;
33
32
  readonly auth: boolean;
34
33
  protected _m: MlKem768;
35
- protected _x25519: X25519;
36
34
  private _api;
37
35
  constructor();
38
36
  serializePublicKey(key: CryptoKey): Promise<ArrayBuffer>;
@@ -77,6 +75,7 @@ export declare class XWing implements KemInterface {
77
75
  * @returns {Promise<{ sharedSecret: ArrayBuffer; enc: ArrayBuffer }>} A promise that resolves with the `ss` (shared secret) as `sharedSecret` and the `ct` (ciphertext) as `enc`.
78
76
  * @throws {InvalidParamError} Thrown if the length of the `ekm` is not 64 bytes.
79
77
  * @throws {EncapError} Thrown if the shared secret cannot be encapsulated.
78
+ * @throws {NotSupportedError} if `senderKey` is provided.
80
79
  */
81
80
  encap(params: SenderContextParams): Promise<{
82
81
  sharedSecret: ArrayBuffer;
@@ -90,6 +89,7 @@ export declare class XWing implements KemInterface {
90
89
  * @returns {Promise<ArrayBuffer>} A promise that resolves with the shared secret.
91
90
  * @throws {InvalidParamError} Thrown if the length of the `enc` is not 1120 bytes.
92
91
  * @throws {DecapError} Thrown if the shared secret cannot be decapsulated.
92
+ * @throws {NotSupportedError} if `senderPublicKey` is provided.
93
93
  */
94
94
  decap(params: RecipientContextParams): Promise<ArrayBuffer>;
95
95
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"xWing.d.ts","sourceRoot":"","sources":["../../src/src/xWing.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAsB,MAAM,OAAO,CAAC;AAErD,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,sBAAsB,EACtB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAUL,KAAK,EAMN,MAAM,cAAc,CAAC;AAItB,OAAO,EAAc,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAkCxD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,KAAM,YAAW,YAAY;IACxC,SAAgB,EAAE,EAAE,KAAK,CAAe;IACxC,SAAgB,IAAI,EAAE,MAAM,CAAY;IACxC,SAAgB,UAAU,EAAE,MAAM,CAAM;IACxC,SAAgB,OAAO,EAAE,MAAM,CAAQ;IACvC,SAAgB,aAAa,EAAE,MAAM,CAAQ;IAC7C,SAAgB,cAAc,EAAE,MAAM,CAAM;IAC5C,SAAgB,IAAI,EAAE,OAAO,CAAS;IACtC,SAAS,CAAC,EAAE,EAAE,QAAQ,CAAC;IACvB,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,IAAI,CAAiC;;IAOhC,kBAAkB,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASxD,oBAAoB,CAC/B,GAAG,EAAE,eAAe,GAAG,eAAe,GACrC,OAAO,CAAC,SAAS,CAAC;IASR,mBAAmB,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASzD,qBAAqB,CAChC,GAAG,EAAE,eAAe,GAAG,eAAe,GACrC,OAAO,CAAC,SAAS,CAAC;IASrB;;;;OAIG;IACU,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC;IAkBtD;;;;;;OAMG;IACU,qBAAqB,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;IAc1E;;;;;;;OAOG;IACU,aAAa,CACxB,GAAG,EAAE,eAAe,GAAG,eAAe,GACrC,OAAO,CAAC,aAAa,CAAC;IAgBzB;;;;;;;OAOG;IACU,SAAS,CACpB,MAAM,EAAE,KAAK,GAAG,KAAK,EACrB,GAAG,EAAE,WAAW,GAAG,kBAAkB,EACrC,QAAQ,UAAO,GACd,OAAO,CAAC,SAAS,CAAC;IAmCrB;;;;;;OAMG;IACU,KAAK,CAChB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC;QAAE,YAAY,EAAE,WAAW,CAAC;QAAC,GAAG,EAAE,WAAW,CAAA;KAAE,CAAC;IA4C3D;;;;;;;;OAQG;IACU,KAAK,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC;IA0BxE;;;;OAIG;YACW,MAAM;IAOpB;;;;OAIG;YACW,sBAAsB;IAOpC;;;;OAIG;YACW,uBAAuB;IAUrC,OAAO,CAAC,mBAAmB;IAe3B,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,UAAU;CAmCnB"}
1
+ {"version":3,"file":"xWing.d.ts","sourceRoot":"","sources":["../../src/src/xWing.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAsB,MAAM,OAAO,CAAC;AAErD,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,sBAAsB,EACtB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AAmBtB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AA4B1C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,KAAM,YAAW,YAAY;IACxC,SAAgB,EAAE,EAAE,KAAK,CAAU;IACnC,SAAgB,IAAI,EAAE,MAAM,CAAY;IACxC,SAAgB,UAAU,EAAE,MAAM,CAAM;IACxC,SAAgB,OAAO,EAAE,MAAM,CAAQ;IACvC,SAAgB,aAAa,EAAE,MAAM,CAAQ;IAC7C,SAAgB,cAAc,EAAE,MAAM,CAAM;IAC5C,SAAgB,IAAI,EAAE,OAAO,CAAS;IACtC,SAAS,CAAC,EAAE,EAAE,QAAQ,CAAC;IACvB,OAAO,CAAC,IAAI,CAAiC;;IAMhC,kBAAkB,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASxD,oBAAoB,CAC/B,GAAG,EAAE,eAAe,GAAG,eAAe,GACrC,OAAO,CAAC,SAAS,CAAC;IASR,mBAAmB,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASzD,qBAAqB,CAChC,GAAG,EAAE,eAAe,GAAG,eAAe,GACrC,OAAO,CAAC,SAAS,CAAC;IASrB;;;;OAIG;IACU,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC;IAkBtD;;;;;;OAMG;IACU,qBAAqB,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;IAc1E;;;;;;;OAOG;IACU,aAAa,CACxB,GAAG,EAAE,eAAe,GAAG,eAAe,GACrC,OAAO,CAAC,aAAa,CAAC;IAgBzB;;;;;;;OAOG;IACU,SAAS,CACpB,MAAM,EAAE,KAAK,GAAG,KAAK,EACrB,GAAG,EAAE,WAAW,GAAG,kBAAkB,EACrC,QAAQ,UAAO,GACd,OAAO,CAAC,SAAS,CAAC;IAmCrB;;;;;;;OAOG;IACU,KAAK,CAChB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC;QAAE,YAAY,EAAE,WAAW,CAAC;QAAC,GAAG,EAAE,WAAW,CAAA;KAAE,CAAC;IAkD3D;;;;;;;;;OASG;IACU,KAAK,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC;IA+BxE;;;;OAIG;YACW,MAAM;IAOpB;;;;OAIG;YACW,sBAAsB;IAOpC;;;;OAIG;YACW,uBAAuB;IAUrC,OAAO,CAAC,mBAAmB;IAe3B,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,UAAU;CAmCnB"}
package/esm/src/xWing.js CHANGED
@@ -1,15 +1,7 @@
1
1
  // @ts-ignore: Unreachable code error
2
2
  import { MlKem768, sha3_256, shake256 } from "mlkem";
3
- import { base64UrlToBytes, concat, DecapError, DeriveKeyPairError, DeserializeError, EncapError, InvalidParamError, isCryptoKeyPair, KEM_USAGES, KemId, loadCrypto, NotSupportedError, SerializeError, toArrayBuffer, XCryptoKey, } from "@hpke/common";
3
+ import { base64UrlToBytes, concat, DecapError, DeriveKeyPairError, DeserializeError, EncapError, InvalidParamError, isCryptoKeyPair, KEM_USAGES, loadCrypto, NotSupportedError, SerializeError, toArrayBuffer, x25519, XCryptoKey, } from "@hpke/common";
4
4
  const ALG_NAME = "X-Wing";
5
- import { HkdfSha256, X25519 } from "@hpke/dhkem-x25519";
6
- // deno-fmt-ignore
7
- const X25519_BASE = new Uint8Array([
8
- 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12
- ]);
13
5
  // XWingLabel = concat(
14
6
  // "\./",
15
7
  // "/^\",
@@ -52,8 +44,8 @@ export class XWing {
52
44
  enumerable: true,
53
45
  configurable: true,
54
46
  writable: true,
55
- value: KemId.XWing
56
- });
47
+ value: 0x647a
48
+ }); // KemId.XWing
57
49
  Object.defineProperty(this, "name", {
58
50
  enumerable: true,
59
51
  configurable: true,
@@ -96,12 +88,6 @@ export class XWing {
96
88
  writable: true,
97
89
  value: void 0
98
90
  });
99
- Object.defineProperty(this, "_x25519", {
100
- enumerable: true,
101
- configurable: true,
102
- writable: true,
103
- value: void 0
104
- });
105
91
  Object.defineProperty(this, "_api", {
106
92
  enumerable: true,
107
93
  configurable: true,
@@ -109,7 +95,6 @@ export class XWing {
109
95
  value: undefined
110
96
  });
111
97
  this._m = new MlKem768();
112
- this._x25519 = new X25519(new HkdfSha256());
113
98
  }
114
99
  async serializePublicKey(key) {
115
100
  await this._setup();
@@ -263,8 +248,12 @@ export class XWing {
263
248
  * @returns {Promise<{ sharedSecret: ArrayBuffer; enc: ArrayBuffer }>} A promise that resolves with the `ss` (shared secret) as `sharedSecret` and the `ct` (ciphertext) as `enc`.
264
249
  * @throws {InvalidParamError} Thrown if the length of the `ekm` is not 64 bytes.
265
250
  * @throws {EncapError} Thrown if the shared secret cannot be encapsulated.
251
+ * @throws {NotSupportedError} if `senderKey` is provided.
266
252
  */
267
253
  async encap(params) {
254
+ if (params.senderKey !== undefined) {
255
+ throw new NotSupportedError("Auth and AuthPSK modes are not supported by this KEM");
256
+ }
268
257
  let ekm = undefined;
269
258
  if (params.ekm !== undefined && !isCryptoKeyPair(params.ekm)) {
270
259
  ekm = toArrayBuffer(params.ekm);
@@ -281,13 +270,14 @@ export class XWing {
281
270
  ekX = ek.subarray(32, 64);
282
271
  }
283
272
  else {
284
- ekX = new Uint8Array(32);
273
+ const randomEkX = new Uint8Array(32);
285
274
  try {
286
- this._api.getRandomValues(ekX);
275
+ this._api.getRandomValues(randomEkX);
287
276
  }
288
277
  catch (e) {
289
278
  throw new NotSupportedError(e);
290
279
  }
280
+ ekX = randomEkX;
291
281
  }
292
282
  const pk = new Uint8Array(await this.serializePublicKey(params.recipientPublicKey));
293
283
  if (pk.byteLength !== 1216) {
@@ -296,8 +286,8 @@ export class XWing {
296
286
  try {
297
287
  const pkM = pk.subarray(0, 1184);
298
288
  const pkX = pk.subarray(1184, 1216);
299
- const ctX = await this._x25519.derive(ekX, X25519_BASE);
300
- const ssX = await this._x25519.derive(ekX, pkX);
289
+ const ctX = x25519.getPublicKey(ekX);
290
+ const ssX = x25519.getSharedSecret(ekX, pkX);
301
291
  const [ctM, ssM] = await this._m.encap(pkM, ekM);
302
292
  return {
303
293
  sharedSecret: combiner(ssM, ssX, ctX, pkX).buffer,
@@ -316,8 +306,12 @@ export class XWing {
316
306
  * @returns {Promise<ArrayBuffer>} A promise that resolves with the shared secret.
317
307
  * @throws {InvalidParamError} Thrown if the length of the `enc` is not 1120 bytes.
318
308
  * @throws {DecapError} Thrown if the shared secret cannot be decapsulated.
309
+ * @throws {NotSupportedError} if `senderPublicKey` is provided.
319
310
  */
320
311
  async decap(params) {
312
+ if (params.senderPublicKey !== undefined) {
313
+ throw new NotSupportedError("Auth and AuthPSK modes are not supported by this KEM");
314
+ }
321
315
  const enc = toArrayBuffer(params.enc);
322
316
  const rSk = isCryptoKeyPair(params.recipientKey)
323
317
  ? params.recipientKey.privateKey
@@ -336,7 +330,7 @@ export class XWing {
336
330
  const ctM = ct.subarray(0, 1088);
337
331
  const ctX = ct.subarray(1088);
338
332
  const ssM = await this._m.decap(ctM, skM);
339
- const ssX = await this._x25519.derive(skX, ctX);
333
+ const ssX = x25519.getSharedSecret(skX, ctX);
340
334
  return combiner(ssM, ssX, ctX, pkX).buffer;
341
335
  }
342
336
  catch (e) {
@@ -372,7 +366,7 @@ export class XWing {
372
366
  const expanded = shake256.create({ dkLen: 96 }).update(sk).digest();
373
367
  const [pkM, skM] = await this._m.deriveKeyPair(expanded.subarray(0, 64));
374
368
  const skX = expanded.subarray(64, 96);
375
- const pkX = await this._x25519.derive(skX, X25519_BASE);
369
+ const pkX = x25519.getPublicKey(skX);
376
370
  return [skM, skX, pkM, pkX];
377
371
  }
378
372
  _serializePublicKey(k) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hpke/hybridkem-x-wing",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "A Hybrid Public Key Encryption (HPKE) module extension for X-Wing: general-purpose hybrid post-quantum KEM.",
5
5
  "keywords": [
6
6
  "hpke",
@@ -33,19 +33,17 @@
33
33
  },
34
34
  "./package.json": "./package.json"
35
35
  },
36
+ "funding": {
37
+ "type": "github",
38
+ "url": "https://github.com/sponsors/dajiaji"
39
+ },
36
40
  "sideEffects": false,
37
41
  "engines": {
38
42
  "node": ">=16.0.0"
39
43
  },
40
44
  "dependencies": {
41
- "@hpke/common": "^1.10.0",
42
- "@hpke/dhkem-x25519": "^1.8.0",
43
- "mlkem": "^2.5.0"
44
- },
45
- "devDependencies": {
46
- "@types/node": "^20.9.0",
47
- "@deno/shim-deno": "~0.18.0",
48
- "picocolors": "^1.0.0"
45
+ "@hpke/common": "^1.13.0",
46
+ "mlkem": "^2.7.0"
49
47
  },
50
48
  "_generatedBy": "dnt@dev"
51
- }
49
+ }
@@ -1,7 +1,6 @@
1
1
  import { MlKem768 } from "mlkem";
2
2
  import type { JsonWebKeyExtended, KemInterface, RecipientContextParams, SenderContextParams } from "@hpke/common";
3
- import { KemId } from "@hpke/common";
4
- import { X25519 } from "@hpke/dhkem-x25519";
3
+ import type { KemId } from "@hpke/common";
5
4
  /**
6
5
  * The Hybrid Post-Quantum KEM (X25519, Kyber768).
7
6
  *
@@ -32,7 +31,6 @@ export declare class XWing implements KemInterface {
32
31
  readonly privateKeySize: number;
33
32
  readonly auth: boolean;
34
33
  protected _m: MlKem768;
35
- protected _x25519: X25519;
36
34
  private _api;
37
35
  constructor();
38
36
  serializePublicKey(key: CryptoKey): Promise<ArrayBuffer>;
@@ -77,6 +75,7 @@ export declare class XWing implements KemInterface {
77
75
  * @returns {Promise<{ sharedSecret: ArrayBuffer; enc: ArrayBuffer }>} A promise that resolves with the `ss` (shared secret) as `sharedSecret` and the `ct` (ciphertext) as `enc`.
78
76
  * @throws {InvalidParamError} Thrown if the length of the `ekm` is not 64 bytes.
79
77
  * @throws {EncapError} Thrown if the shared secret cannot be encapsulated.
78
+ * @throws {NotSupportedError} if `senderKey` is provided.
80
79
  */
81
80
  encap(params: SenderContextParams): Promise<{
82
81
  sharedSecret: ArrayBuffer;
@@ -90,6 +89,7 @@ export declare class XWing implements KemInterface {
90
89
  * @returns {Promise<ArrayBuffer>} A promise that resolves with the shared secret.
91
90
  * @throws {InvalidParamError} Thrown if the length of the `enc` is not 1120 bytes.
92
91
  * @throws {DecapError} Thrown if the shared secret cannot be decapsulated.
92
+ * @throws {NotSupportedError} if `senderPublicKey` is provided.
93
93
  */
94
94
  decap(params: RecipientContextParams): Promise<ArrayBuffer>;
95
95
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"xWing.d.ts","sourceRoot":"","sources":["../../src/src/xWing.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAsB,MAAM,OAAO,CAAC;AAErD,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,sBAAsB,EACtB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAUL,KAAK,EAMN,MAAM,cAAc,CAAC;AAItB,OAAO,EAAc,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAkCxD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,KAAM,YAAW,YAAY;IACxC,SAAgB,EAAE,EAAE,KAAK,CAAe;IACxC,SAAgB,IAAI,EAAE,MAAM,CAAY;IACxC,SAAgB,UAAU,EAAE,MAAM,CAAM;IACxC,SAAgB,OAAO,EAAE,MAAM,CAAQ;IACvC,SAAgB,aAAa,EAAE,MAAM,CAAQ;IAC7C,SAAgB,cAAc,EAAE,MAAM,CAAM;IAC5C,SAAgB,IAAI,EAAE,OAAO,CAAS;IACtC,SAAS,CAAC,EAAE,EAAE,QAAQ,CAAC;IACvB,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,IAAI,CAAiC;;IAOhC,kBAAkB,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASxD,oBAAoB,CAC/B,GAAG,EAAE,eAAe,GAAG,eAAe,GACrC,OAAO,CAAC,SAAS,CAAC;IASR,mBAAmB,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASzD,qBAAqB,CAChC,GAAG,EAAE,eAAe,GAAG,eAAe,GACrC,OAAO,CAAC,SAAS,CAAC;IASrB;;;;OAIG;IACU,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC;IAkBtD;;;;;;OAMG;IACU,qBAAqB,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;IAc1E;;;;;;;OAOG;IACU,aAAa,CACxB,GAAG,EAAE,eAAe,GAAG,eAAe,GACrC,OAAO,CAAC,aAAa,CAAC;IAgBzB;;;;;;;OAOG;IACU,SAAS,CACpB,MAAM,EAAE,KAAK,GAAG,KAAK,EACrB,GAAG,EAAE,WAAW,GAAG,kBAAkB,EACrC,QAAQ,UAAO,GACd,OAAO,CAAC,SAAS,CAAC;IAmCrB;;;;;;OAMG;IACU,KAAK,CAChB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC;QAAE,YAAY,EAAE,WAAW,CAAC;QAAC,GAAG,EAAE,WAAW,CAAA;KAAE,CAAC;IA4C3D;;;;;;;;OAQG;IACU,KAAK,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC;IA0BxE;;;;OAIG;YACW,MAAM;IAOpB;;;;OAIG;YACW,sBAAsB;IAOpC;;;;OAIG;YACW,uBAAuB;IAUrC,OAAO,CAAC,mBAAmB;IAe3B,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,UAAU;CAmCnB"}
1
+ {"version":3,"file":"xWing.d.ts","sourceRoot":"","sources":["../../src/src/xWing.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAsB,MAAM,OAAO,CAAC;AAErD,OAAO,KAAK,EACV,kBAAkB,EAClB,YAAY,EACZ,sBAAsB,EACtB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AAmBtB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AA4B1C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,KAAM,YAAW,YAAY;IACxC,SAAgB,EAAE,EAAE,KAAK,CAAU;IACnC,SAAgB,IAAI,EAAE,MAAM,CAAY;IACxC,SAAgB,UAAU,EAAE,MAAM,CAAM;IACxC,SAAgB,OAAO,EAAE,MAAM,CAAQ;IACvC,SAAgB,aAAa,EAAE,MAAM,CAAQ;IAC7C,SAAgB,cAAc,EAAE,MAAM,CAAM;IAC5C,SAAgB,IAAI,EAAE,OAAO,CAAS;IACtC,SAAS,CAAC,EAAE,EAAE,QAAQ,CAAC;IACvB,OAAO,CAAC,IAAI,CAAiC;;IAMhC,kBAAkB,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASxD,oBAAoB,CAC/B,GAAG,EAAE,eAAe,GAAG,eAAe,GACrC,OAAO,CAAC,SAAS,CAAC;IASR,mBAAmB,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASzD,qBAAqB,CAChC,GAAG,EAAE,eAAe,GAAG,eAAe,GACrC,OAAO,CAAC,SAAS,CAAC;IASrB;;;;OAIG;IACU,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC;IAkBtD;;;;;;OAMG;IACU,qBAAqB,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;IAc1E;;;;;;;OAOG;IACU,aAAa,CACxB,GAAG,EAAE,eAAe,GAAG,eAAe,GACrC,OAAO,CAAC,aAAa,CAAC;IAgBzB;;;;;;;OAOG;IACU,SAAS,CACpB,MAAM,EAAE,KAAK,GAAG,KAAK,EACrB,GAAG,EAAE,WAAW,GAAG,kBAAkB,EACrC,QAAQ,UAAO,GACd,OAAO,CAAC,SAAS,CAAC;IAmCrB;;;;;;;OAOG;IACU,KAAK,CAChB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC;QAAE,YAAY,EAAE,WAAW,CAAC;QAAC,GAAG,EAAE,WAAW,CAAA;KAAE,CAAC;IAkD3D;;;;;;;;;OASG;IACU,KAAK,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC;IA+BxE;;;;OAIG;YACW,MAAM;IAOpB;;;;OAIG;YACW,sBAAsB;IAOpC;;;;OAIG;YACW,uBAAuB;IAUrC,OAAO,CAAC,mBAAmB;IAe3B,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,UAAU;CAmCnB"}
@@ -4,7 +4,7 @@
4
4
  if (v !== undefined) module.exports = v;
5
5
  }
6
6
  else if (typeof define === "function" && define.amd) {
7
- define(["require", "exports", "mlkem", "@hpke/common", "@hpke/dhkem-x25519"], factory);
7
+ define(["require", "exports", "mlkem", "@hpke/common"], factory);
8
8
  }
9
9
  })(function (require, exports) {
10
10
  "use strict";
@@ -14,14 +14,6 @@
14
14
  const mlkem_1 = require("mlkem");
15
15
  const common_1 = require("@hpke/common");
16
16
  const ALG_NAME = "X-Wing";
17
- const dhkem_x25519_1 = require("@hpke/dhkem-x25519");
18
- // deno-fmt-ignore
19
- const X25519_BASE = new Uint8Array([
20
- 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
21
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
24
- ]);
25
17
  // XWingLabel = concat(
26
18
  // "\./",
27
19
  // "/^\",
@@ -64,8 +56,8 @@
64
56
  enumerable: true,
65
57
  configurable: true,
66
58
  writable: true,
67
- value: common_1.KemId.XWing
68
- });
59
+ value: 0x647a
60
+ }); // KemId.XWing
69
61
  Object.defineProperty(this, "name", {
70
62
  enumerable: true,
71
63
  configurable: true,
@@ -108,12 +100,6 @@
108
100
  writable: true,
109
101
  value: void 0
110
102
  });
111
- Object.defineProperty(this, "_x25519", {
112
- enumerable: true,
113
- configurable: true,
114
- writable: true,
115
- value: void 0
116
- });
117
103
  Object.defineProperty(this, "_api", {
118
104
  enumerable: true,
119
105
  configurable: true,
@@ -121,7 +107,6 @@
121
107
  value: undefined
122
108
  });
123
109
  this._m = new mlkem_1.MlKem768();
124
- this._x25519 = new dhkem_x25519_1.X25519(new dhkem_x25519_1.HkdfSha256());
125
110
  }
126
111
  async serializePublicKey(key) {
127
112
  await this._setup();
@@ -275,8 +260,12 @@
275
260
  * @returns {Promise<{ sharedSecret: ArrayBuffer; enc: ArrayBuffer }>} A promise that resolves with the `ss` (shared secret) as `sharedSecret` and the `ct` (ciphertext) as `enc`.
276
261
  * @throws {InvalidParamError} Thrown if the length of the `ekm` is not 64 bytes.
277
262
  * @throws {EncapError} Thrown if the shared secret cannot be encapsulated.
263
+ * @throws {NotSupportedError} if `senderKey` is provided.
278
264
  */
279
265
  async encap(params) {
266
+ if (params.senderKey !== undefined) {
267
+ throw new common_1.NotSupportedError("Auth and AuthPSK modes are not supported by this KEM");
268
+ }
280
269
  let ekm = undefined;
281
270
  if (params.ekm !== undefined && !(0, common_1.isCryptoKeyPair)(params.ekm)) {
282
271
  ekm = (0, common_1.toArrayBuffer)(params.ekm);
@@ -293,13 +282,14 @@
293
282
  ekX = ek.subarray(32, 64);
294
283
  }
295
284
  else {
296
- ekX = new Uint8Array(32);
285
+ const randomEkX = new Uint8Array(32);
297
286
  try {
298
- this._api.getRandomValues(ekX);
287
+ this._api.getRandomValues(randomEkX);
299
288
  }
300
289
  catch (e) {
301
290
  throw new common_1.NotSupportedError(e);
302
291
  }
292
+ ekX = randomEkX;
303
293
  }
304
294
  const pk = new Uint8Array(await this.serializePublicKey(params.recipientPublicKey));
305
295
  if (pk.byteLength !== 1216) {
@@ -308,8 +298,8 @@
308
298
  try {
309
299
  const pkM = pk.subarray(0, 1184);
310
300
  const pkX = pk.subarray(1184, 1216);
311
- const ctX = await this._x25519.derive(ekX, X25519_BASE);
312
- const ssX = await this._x25519.derive(ekX, pkX);
301
+ const ctX = common_1.x25519.getPublicKey(ekX);
302
+ const ssX = common_1.x25519.getSharedSecret(ekX, pkX);
313
303
  const [ctM, ssM] = await this._m.encap(pkM, ekM);
314
304
  return {
315
305
  sharedSecret: combiner(ssM, ssX, ctX, pkX).buffer,
@@ -328,8 +318,12 @@
328
318
  * @returns {Promise<ArrayBuffer>} A promise that resolves with the shared secret.
329
319
  * @throws {InvalidParamError} Thrown if the length of the `enc` is not 1120 bytes.
330
320
  * @throws {DecapError} Thrown if the shared secret cannot be decapsulated.
321
+ * @throws {NotSupportedError} if `senderPublicKey` is provided.
331
322
  */
332
323
  async decap(params) {
324
+ if (params.senderPublicKey !== undefined) {
325
+ throw new common_1.NotSupportedError("Auth and AuthPSK modes are not supported by this KEM");
326
+ }
333
327
  const enc = (0, common_1.toArrayBuffer)(params.enc);
334
328
  const rSk = (0, common_1.isCryptoKeyPair)(params.recipientKey)
335
329
  ? params.recipientKey.privateKey
@@ -348,7 +342,7 @@
348
342
  const ctM = ct.subarray(0, 1088);
349
343
  const ctX = ct.subarray(1088);
350
344
  const ssM = await this._m.decap(ctM, skM);
351
- const ssX = await this._x25519.derive(skX, ctX);
345
+ const ssX = common_1.x25519.getSharedSecret(skX, ctX);
352
346
  return combiner(ssM, ssX, ctX, pkX).buffer;
353
347
  }
354
348
  catch (e) {
@@ -384,7 +378,7 @@
384
378
  const expanded = mlkem_1.shake256.create({ dkLen: 96 }).update(sk).digest();
385
379
  const [pkM, skM] = await this._m.deriveKeyPair(expanded.subarray(0, 64));
386
380
  const skX = expanded.subarray(64, 96);
387
- const pkX = await this._x25519.derive(skX, X25519_BASE);
381
+ const pkX = common_1.x25519.getPublicKey(skX);
388
382
  return [skM, skX, pkM, pkX];
389
383
  }
390
384
  _serializePublicKey(k) {