@hpke/hybridkem-x-wing 0.1.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/LICENSE +21 -0
- package/README.md +264 -0
- package/esm/_dnt.test_shims.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/almost_equals.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/array_includes.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/assert.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/assertion_error.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/equal.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/equals.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/exists.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/fail.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/false.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/greater.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/greater_or_equal.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/instance_of.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/is_error.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/less.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/less_or_equal.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/match.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/mod.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/not_equals.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/not_instance_of.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/not_match.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/not_strict_equals.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/object_match.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/rejects.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/strict_equals.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/string_includes.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/throws.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/unimplemented.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/assert/1.0.0/unreachable.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/internal/1.0.3/build_message.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/internal/1.0.3/diff.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/internal/1.0.3/diff_str.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/internal/1.0.3/format.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/internal/1.0.3/mod.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/internal/1.0.3/styles.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/internal/1.0.3/types.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/testing/1.0.2/_test_suite.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/testing/1.0.2/bdd.d.ts.map +1 -0
- package/esm/mod.d.ts +2 -0
- package/esm/mod.d.ts.map +1 -0
- package/esm/mod.js +1 -0
- package/esm/package.json +3 -0
- package/esm/src/hybridkemXWing.d.ts +94 -0
- package/esm/src/hybridkemXWing.d.ts.map +1 -0
- package/esm/src/hybridkemXWing.js +381 -0
- package/esm/test/hybridkemXWing.test.d.ts.map +1 -0
- package/esm/test/testVectors.d.ts.map +1 -0
- package/package.json +55 -0
- package/script/_dnt.test_shims.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/almost_equals.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/array_includes.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/assert.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/assertion_error.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/equal.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/equals.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/exists.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/fail.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/false.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/greater.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/greater_or_equal.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/instance_of.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/is_error.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/less.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/less_or_equal.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/match.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/mod.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/not_equals.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/not_instance_of.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/not_match.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/not_strict_equals.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/object_match.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/rejects.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/strict_equals.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/string_includes.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/throws.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/unimplemented.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/assert/1.0.0/unreachable.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/internal/1.0.3/build_message.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/internal/1.0.3/diff.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/internal/1.0.3/diff_str.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/internal/1.0.3/format.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/internal/1.0.3/mod.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/internal/1.0.3/styles.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/internal/1.0.3/types.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/testing/1.0.2/_test_suite.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/testing/1.0.2/bdd.d.ts.map +1 -0
- package/script/mod.d.ts +2 -0
- package/script/mod.d.ts.map +1 -0
- package/script/mod.js +15 -0
- package/script/package.json +3 -0
- package/script/src/hybridkemXWing.d.ts +94 -0
- package/script/src/hybridkemXWing.d.ts.map +1 -0
- package/script/src/hybridkemXWing.js +395 -0
- package/script/test/hybridkemXWing.test.d.ts.map +1 -0
- package/script/test/testVectors.d.ts.map +1 -0
package/script/mod.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
(function (factory) {
|
|
2
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
3
|
+
var v = factory(require, exports);
|
|
4
|
+
if (v !== undefined) module.exports = v;
|
|
5
|
+
}
|
|
6
|
+
else if (typeof define === "function" && define.amd) {
|
|
7
|
+
define(["require", "exports", "./src/hybridkemXWing.js"], factory);
|
|
8
|
+
}
|
|
9
|
+
})(function (require, exports) {
|
|
10
|
+
"use strict";
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.HybridkemXWing = void 0;
|
|
13
|
+
var hybridkemXWing_js_1 = require("./src/hybridkemXWing.js");
|
|
14
|
+
Object.defineProperty(exports, "HybridkemXWing", { enumerable: true, get: function () { return hybridkemXWing_js_1.HybridkemXWing; } });
|
|
15
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { MlKem768 } from "mlkem";
|
|
2
|
+
import type { KemInterface, RecipientContextParams, SenderContextParams } from "@hpke/common";
|
|
3
|
+
import { KemId } from "@hpke/common";
|
|
4
|
+
import { X25519 } from "@hpke/dhkem-x25519";
|
|
5
|
+
/**
|
|
6
|
+
* The Hybrid Post-Quantum KEM (X25519, Kyber768).
|
|
7
|
+
*
|
|
8
|
+
* This class is implemented using
|
|
9
|
+
* {@link https://github.com/Argyle-Software/kyber | pqc-kyber }.
|
|
10
|
+
*
|
|
11
|
+
* The instance of this class can be specified to the
|
|
12
|
+
* {@link https://jsr.io/@hpke/core/doc/~/CipherSuiteParams | CipherSuiteParams} as follows:
|
|
13
|
+
*
|
|
14
|
+
* @example Use with `@hpke/core`:
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { Aes128Gcm, CipherSuite, HkdfSha256 } from "@hpke/core";
|
|
18
|
+
* import { HybridkemXWing } from "@hpke/hybridkem-x-wing";
|
|
19
|
+
* const suite = new CipherSuite({
|
|
20
|
+
* kem: new HybridkemXWing(),
|
|
21
|
+
* kdf: new HkdfSha256(),
|
|
22
|
+
* aead: new Aes128Gcm(),
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare class HybridkemXWing implements KemInterface {
|
|
27
|
+
readonly id: KemId;
|
|
28
|
+
readonly name: string;
|
|
29
|
+
readonly secretSize: number;
|
|
30
|
+
readonly encSize: number;
|
|
31
|
+
readonly publicKeySize: number;
|
|
32
|
+
readonly privateKeySize: number;
|
|
33
|
+
readonly auth: boolean;
|
|
34
|
+
protected _m: MlKem768;
|
|
35
|
+
protected _x25519: X25519;
|
|
36
|
+
private _api;
|
|
37
|
+
constructor();
|
|
38
|
+
serializePublicKey(key: CryptoKey): Promise<ArrayBuffer>;
|
|
39
|
+
deserializePublicKey(key: ArrayBuffer): Promise<CryptoKey>;
|
|
40
|
+
serializePrivateKey(key: CryptoKey): Promise<ArrayBuffer>;
|
|
41
|
+
deserializePrivateKey(key: ArrayBuffer): Promise<CryptoKey>;
|
|
42
|
+
/**
|
|
43
|
+
* Generates a new key pair.
|
|
44
|
+
*
|
|
45
|
+
* @returns {Promise<CryptoKeyPair>} A promise that resolves with a new key pair.
|
|
46
|
+
*/
|
|
47
|
+
generateKeyPair(): Promise<CryptoKeyPair>;
|
|
48
|
+
/**
|
|
49
|
+
* Generates a key pair from the secret key.
|
|
50
|
+
* @param sk The secret key.
|
|
51
|
+
* @returns {Promise<CryptoKeyPair>} A promise that resolves with a new key pair.
|
|
52
|
+
* @throws {InvalidParamError} Thrown if the length of the secret key is not 32 bytes.
|
|
53
|
+
* @throws {DeriveKeyPairError} Thrown if the key pair cannot be derived.
|
|
54
|
+
*/
|
|
55
|
+
generateKeyPairDerand(sk: Uint8Array): Promise<CryptoKeyPair>;
|
|
56
|
+
/**
|
|
57
|
+
* Derives a key pair from the input keying material.
|
|
58
|
+
*
|
|
59
|
+
* @param {ArrayBuffer} ikm The input keying material.
|
|
60
|
+
* @returns {Promise<CryptoKeyPair>} A promise that resolves with a new key pair.
|
|
61
|
+
* @throws {DeriveKeyPairError} Thrown if the key pair cannot be derived.
|
|
62
|
+
* @throws {InvalidParamError} Thrown if the length of the IKM is not 32 bytes.
|
|
63
|
+
*/
|
|
64
|
+
deriveKeyPair(ikm: ArrayBuffer): Promise<CryptoKeyPair>;
|
|
65
|
+
importKey(_format: "raw" | "jwk", _key: ArrayBuffer | JsonWebKey, _isPublic?: boolean): Promise<CryptoKey>;
|
|
66
|
+
encap(params: SenderContextParams): Promise<{
|
|
67
|
+
sharedSecret: ArrayBuffer;
|
|
68
|
+
enc: ArrayBuffer;
|
|
69
|
+
}>;
|
|
70
|
+
decap(params: RecipientContextParams): Promise<ArrayBuffer>;
|
|
71
|
+
/**
|
|
72
|
+
* Sets up the MlKemBase instance by loading the necessary crypto library.
|
|
73
|
+
* If the crypto library is already loaded, this method does nothing.
|
|
74
|
+
* @returns {Promise<void>} A promise that resolves when the setup is complete.
|
|
75
|
+
*/
|
|
76
|
+
private _setup;
|
|
77
|
+
/**
|
|
78
|
+
* Generates a key pair from the secret key.
|
|
79
|
+
* @param sk The secret key.
|
|
80
|
+
* @returns {Promise<[Uint8Array, Uint8Array]>} A promise that resolves with the key pair derived from the secret key.
|
|
81
|
+
*/
|
|
82
|
+
private _generateKeyPairDerand;
|
|
83
|
+
/**
|
|
84
|
+
* Expands the decapsulation key.
|
|
85
|
+
* @param sk The secret key.
|
|
86
|
+
* @returns {Promise<[Uint8Array, Uint8Array, Uint8Array, Uint8Array]>} A promise that resolves with the keys derived by expanding the secret key.
|
|
87
|
+
*/
|
|
88
|
+
private _expandDecapsulationKey;
|
|
89
|
+
private _serializePublicKey;
|
|
90
|
+
private _deserializePublicKey;
|
|
91
|
+
private _serializePrivateKey;
|
|
92
|
+
private _deserializePrivateKey;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=hybridkemXWing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hybridkemXWing.d.ts","sourceRoot":"","sources":["../../src/src/hybridkemXWing.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjC,OAAO,KAAK,EACV,YAAY,EACZ,sBAAsB,EACtB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAQL,KAAK,EAKN,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAc,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAwCxD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,cAAe,YAAW,YAAY;IACjD,SAAgB,EAAE,EAAE,KAAK,CAAwB;IACjD,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,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC;IAS1D,mBAAmB,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASzD,qBAAqB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC;IASxE;;;;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,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC;IAevD,SAAS,CACpB,OAAO,EAAE,KAAK,GAAG,KAAK,EACtB,IAAI,EAAE,WAAW,GAAG,UAAU,EAC9B,SAAS,UAAO,GACf,OAAO,CAAC,SAAS,CAAC;IAcR,KAAK,CAChB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC;QAAE,YAAY,EAAE,WAAW,CAAC;QAAC,GAAG,EAAE,WAAW,CAAA;KAAE,CAAC;IA4C9C,KAAK,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC;IAyBxE;;;;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;CAU/B"}
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
(function (factory) {
|
|
2
|
+
if (typeof module === "object" && typeof module.exports === "object") {
|
|
3
|
+
var v = factory(require, exports);
|
|
4
|
+
if (v !== undefined) module.exports = v;
|
|
5
|
+
}
|
|
6
|
+
else if (typeof define === "function" && define.amd) {
|
|
7
|
+
define(["require", "exports", "@noble/hashes/sha3", "mlkem", "@hpke/common", "@hpke/dhkem-x25519"], factory);
|
|
8
|
+
}
|
|
9
|
+
})(function (require, exports) {
|
|
10
|
+
"use strict";
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.HybridkemXWing = void 0;
|
|
13
|
+
const sha3_1 = require("@noble/hashes/sha3");
|
|
14
|
+
// @ts-ignore: Unreachable code error
|
|
15
|
+
const mlkem_1 = require("mlkem");
|
|
16
|
+
const common_1 = require("@hpke/common");
|
|
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
|
+
// XWingLabel = concat(
|
|
26
|
+
// "\./",
|
|
27
|
+
// "/^\",
|
|
28
|
+
// );
|
|
29
|
+
// deno-fmt-ignore
|
|
30
|
+
const XWING_LABEL = new Uint8Array([46, 47, 47, 94, 92]);
|
|
31
|
+
function emitNotSupported() {
|
|
32
|
+
return new Promise((_resolve, reject) => {
|
|
33
|
+
reject(new common_1.NotSupportedError("Not supported"));
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function combiner(ssM, ssX, ctX, pkX) {
|
|
37
|
+
const ret = new Uint8Array(ssM.length + ssX.length + ctX.length + pkX.length + XWING_LABEL.length);
|
|
38
|
+
ret.set(ssM, 0);
|
|
39
|
+
ret.set(ssX, ssM.length);
|
|
40
|
+
ret.set(ctX, ssM.length + ssX.length);
|
|
41
|
+
ret.set(pkX, ssM.length + ssX.length + ctX.length);
|
|
42
|
+
ret.set(XWING_LABEL, ssM.length + ssX.length + ctX.length + pkX.length);
|
|
43
|
+
return sha3_1.sha3_256.create().update(ret).digest();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The Hybrid Post-Quantum KEM (X25519, Kyber768).
|
|
47
|
+
*
|
|
48
|
+
* This class is implemented using
|
|
49
|
+
* {@link https://github.com/Argyle-Software/kyber | pqc-kyber }.
|
|
50
|
+
*
|
|
51
|
+
* The instance of this class can be specified to the
|
|
52
|
+
* {@link https://jsr.io/@hpke/core/doc/~/CipherSuiteParams | CipherSuiteParams} as follows:
|
|
53
|
+
*
|
|
54
|
+
* @example Use with `@hpke/core`:
|
|
55
|
+
*
|
|
56
|
+
* ```ts
|
|
57
|
+
* import { Aes128Gcm, CipherSuite, HkdfSha256 } from "@hpke/core";
|
|
58
|
+
* import { HybridkemXWing } from "@hpke/hybridkem-x-wing";
|
|
59
|
+
* const suite = new CipherSuite({
|
|
60
|
+
* kem: new HybridkemXWing(),
|
|
61
|
+
* kdf: new HkdfSha256(),
|
|
62
|
+
* aead: new Aes128Gcm(),
|
|
63
|
+
* });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
class HybridkemXWing {
|
|
67
|
+
constructor() {
|
|
68
|
+
Object.defineProperty(this, "id", {
|
|
69
|
+
enumerable: true,
|
|
70
|
+
configurable: true,
|
|
71
|
+
writable: true,
|
|
72
|
+
value: common_1.KemId.HybridkemXWing
|
|
73
|
+
});
|
|
74
|
+
Object.defineProperty(this, "name", {
|
|
75
|
+
enumerable: true,
|
|
76
|
+
configurable: true,
|
|
77
|
+
writable: true,
|
|
78
|
+
value: "X-Wing"
|
|
79
|
+
});
|
|
80
|
+
Object.defineProperty(this, "secretSize", {
|
|
81
|
+
enumerable: true,
|
|
82
|
+
configurable: true,
|
|
83
|
+
writable: true,
|
|
84
|
+
value: 32
|
|
85
|
+
});
|
|
86
|
+
Object.defineProperty(this, "encSize", {
|
|
87
|
+
enumerable: true,
|
|
88
|
+
configurable: true,
|
|
89
|
+
writable: true,
|
|
90
|
+
value: 1120
|
|
91
|
+
});
|
|
92
|
+
Object.defineProperty(this, "publicKeySize", {
|
|
93
|
+
enumerable: true,
|
|
94
|
+
configurable: true,
|
|
95
|
+
writable: true,
|
|
96
|
+
value: 1216
|
|
97
|
+
});
|
|
98
|
+
Object.defineProperty(this, "privateKeySize", {
|
|
99
|
+
enumerable: true,
|
|
100
|
+
configurable: true,
|
|
101
|
+
writable: true,
|
|
102
|
+
value: 32
|
|
103
|
+
});
|
|
104
|
+
Object.defineProperty(this, "auth", {
|
|
105
|
+
enumerable: true,
|
|
106
|
+
configurable: true,
|
|
107
|
+
writable: true,
|
|
108
|
+
value: false
|
|
109
|
+
});
|
|
110
|
+
Object.defineProperty(this, "_m", {
|
|
111
|
+
enumerable: true,
|
|
112
|
+
configurable: true,
|
|
113
|
+
writable: true,
|
|
114
|
+
value: void 0
|
|
115
|
+
});
|
|
116
|
+
Object.defineProperty(this, "_x25519", {
|
|
117
|
+
enumerable: true,
|
|
118
|
+
configurable: true,
|
|
119
|
+
writable: true,
|
|
120
|
+
value: void 0
|
|
121
|
+
});
|
|
122
|
+
Object.defineProperty(this, "_api", {
|
|
123
|
+
enumerable: true,
|
|
124
|
+
configurable: true,
|
|
125
|
+
writable: true,
|
|
126
|
+
value: undefined
|
|
127
|
+
});
|
|
128
|
+
this._m = new mlkem_1.MlKem768();
|
|
129
|
+
this._x25519 = new dhkem_x25519_1.X25519(new dhkem_x25519_1.HkdfSha256());
|
|
130
|
+
}
|
|
131
|
+
async serializePublicKey(key) {
|
|
132
|
+
await this._setup();
|
|
133
|
+
try {
|
|
134
|
+
return await this._serializePublicKey(key);
|
|
135
|
+
}
|
|
136
|
+
catch (e) {
|
|
137
|
+
throw new common_1.SerializeError(e);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async deserializePublicKey(key) {
|
|
141
|
+
await this._setup();
|
|
142
|
+
try {
|
|
143
|
+
return await this._deserializePublicKey(key);
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
throw new common_1.DeserializeError(e);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async serializePrivateKey(key) {
|
|
150
|
+
await this._setup();
|
|
151
|
+
try {
|
|
152
|
+
return await this._serializePrivateKey(key);
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
throw new common_1.SerializeError(e);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async deserializePrivateKey(key) {
|
|
159
|
+
await this._setup();
|
|
160
|
+
try {
|
|
161
|
+
return await this._deserializePrivateKey(key);
|
|
162
|
+
}
|
|
163
|
+
catch (e) {
|
|
164
|
+
throw new common_1.DeserializeError(e);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Generates a new key pair.
|
|
169
|
+
*
|
|
170
|
+
* @returns {Promise<CryptoKeyPair>} A promise that resolves with a new key pair.
|
|
171
|
+
*/
|
|
172
|
+
async generateKeyPair() {
|
|
173
|
+
await this._setup();
|
|
174
|
+
const sk = new Uint8Array(32);
|
|
175
|
+
try {
|
|
176
|
+
this._api.getRandomValues(sk);
|
|
177
|
+
}
|
|
178
|
+
catch (e) {
|
|
179
|
+
throw new common_1.NotSupportedError(e);
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const [_sk, pk] = await this._generateKeyPairDerand(sk);
|
|
183
|
+
const dSk = await this.deserializePrivateKey(sk);
|
|
184
|
+
const dPk = await this.deserializePublicKey(pk);
|
|
185
|
+
return { privateKey: dSk, publicKey: dPk };
|
|
186
|
+
}
|
|
187
|
+
catch (e) {
|
|
188
|
+
throw new common_1.DeriveKeyPairError(e);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Generates a key pair from the secret key.
|
|
193
|
+
* @param sk The secret key.
|
|
194
|
+
* @returns {Promise<CryptoKeyPair>} A promise that resolves with a new key pair.
|
|
195
|
+
* @throws {InvalidParamError} Thrown if the length of the secret key is not 32 bytes.
|
|
196
|
+
* @throws {DeriveKeyPairError} Thrown if the key pair cannot be derived.
|
|
197
|
+
*/
|
|
198
|
+
async generateKeyPairDerand(sk) {
|
|
199
|
+
if (sk.byteLength !== 32) {
|
|
200
|
+
throw new common_1.InvalidParamError("Invalid length of sk");
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
const [_sk, pk] = await this._generateKeyPairDerand(sk);
|
|
204
|
+
const dSk = await this.deserializePrivateKey(sk);
|
|
205
|
+
const dPk = await this.deserializePublicKey(pk);
|
|
206
|
+
return { privateKey: dSk, publicKey: dPk };
|
|
207
|
+
}
|
|
208
|
+
catch (e) {
|
|
209
|
+
throw new common_1.DeriveKeyPairError(e);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Derives a key pair from the input keying material.
|
|
214
|
+
*
|
|
215
|
+
* @param {ArrayBuffer} ikm The input keying material.
|
|
216
|
+
* @returns {Promise<CryptoKeyPair>} A promise that resolves with a new key pair.
|
|
217
|
+
* @throws {DeriveKeyPairError} Thrown if the key pair cannot be derived.
|
|
218
|
+
* @throws {InvalidParamError} Thrown if the length of the IKM is not 32 bytes.
|
|
219
|
+
*/
|
|
220
|
+
async deriveKeyPair(ikm) {
|
|
221
|
+
await this._setup();
|
|
222
|
+
try {
|
|
223
|
+
const sk = sha3_1.shake256.create({ dkLen: 32 })
|
|
224
|
+
.update(new Uint8Array(ikm))
|
|
225
|
+
.digest();
|
|
226
|
+
const [_sk, pk] = await this._generateKeyPairDerand(sk);
|
|
227
|
+
const dSk = await this.deserializePrivateKey(sk);
|
|
228
|
+
const dPk = await this.deserializePublicKey(pk);
|
|
229
|
+
return { privateKey: dSk, publicKey: dPk };
|
|
230
|
+
}
|
|
231
|
+
catch (e) {
|
|
232
|
+
throw new common_1.DeriveKeyPairError(e);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
async importKey(_format, _key, _isPublic = true) {
|
|
236
|
+
return await emitNotSupported();
|
|
237
|
+
// if (format !== "raw") {
|
|
238
|
+
// throw new NotSupportedError("'jwk' is not supported");
|
|
239
|
+
// }
|
|
240
|
+
// if (!(key instanceof ArrayBuffer)) {
|
|
241
|
+
// throw new InvalidParamError("Invalid type of key");
|
|
242
|
+
// }
|
|
243
|
+
// if (isPublic) {
|
|
244
|
+
// return await this.deserializePublicKey(key as ArrayBuffer);
|
|
245
|
+
// }
|
|
246
|
+
// return await this.deserializePrivateKey(key as ArrayBuffer);
|
|
247
|
+
}
|
|
248
|
+
async encap(params) {
|
|
249
|
+
let ekm = undefined;
|
|
250
|
+
if (params.ekm !== undefined && !(0, common_1.isCryptoKeyPair)(params.ekm)) {
|
|
251
|
+
if (params.ekm.byteLength !== 64) {
|
|
252
|
+
throw new common_1.InvalidParamError("ekm must be 64 bytes in length");
|
|
253
|
+
}
|
|
254
|
+
ekm = params.ekm;
|
|
255
|
+
}
|
|
256
|
+
let ekM = undefined;
|
|
257
|
+
let ekX;
|
|
258
|
+
if (ekm !== undefined) {
|
|
259
|
+
const ek = new Uint8Array(ekm);
|
|
260
|
+
ekM = ek.subarray(0, 32);
|
|
261
|
+
ekX = ek.subarray(32, 64);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
ekX = new Uint8Array(32);
|
|
265
|
+
try {
|
|
266
|
+
this._api.getRandomValues(ekX);
|
|
267
|
+
}
|
|
268
|
+
catch (e) {
|
|
269
|
+
throw new common_1.NotSupportedError(e);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const pk = new Uint8Array(await this.serializePublicKey(params.recipientPublicKey));
|
|
273
|
+
if (pk.byteLength !== 1216) {
|
|
274
|
+
throw new common_1.InvalidParamError("Invalid length of recipientPublicKey");
|
|
275
|
+
}
|
|
276
|
+
await this._setup();
|
|
277
|
+
try {
|
|
278
|
+
const pkM = pk.subarray(0, 1184);
|
|
279
|
+
const pkX = pk.subarray(1184, 1216);
|
|
280
|
+
const ctX = await this._x25519.derive(ekX, X25519_BASE);
|
|
281
|
+
const ssX = await this._x25519.derive(ekX, pkX);
|
|
282
|
+
const [ctM, ssM] = await this._m.encap(pkM, ekM);
|
|
283
|
+
return {
|
|
284
|
+
sharedSecret: combiner(ssM, ssX, ctX, pkX),
|
|
285
|
+
enc: (0, common_1.concat)(ctM, ctX),
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
catch (e) {
|
|
289
|
+
throw new common_1.EncapError(e);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
async decap(params) {
|
|
293
|
+
const rSk = (0, common_1.isCryptoKeyPair)(params.recipientKey)
|
|
294
|
+
? params.recipientKey.privateKey
|
|
295
|
+
: params.recipientKey;
|
|
296
|
+
if (params.enc.byteLength !== 1120) {
|
|
297
|
+
throw new common_1.InvalidParamError("Invalid length of enc");
|
|
298
|
+
}
|
|
299
|
+
const sk = new Uint8Array(await this.serializePrivateKey(rSk));
|
|
300
|
+
if (sk.byteLength !== 32) {
|
|
301
|
+
throw new common_1.InvalidParamError("Invalid length of recipientKey");
|
|
302
|
+
}
|
|
303
|
+
await this._setup();
|
|
304
|
+
try {
|
|
305
|
+
const [skM, skX, _pkM, pkX] = await this._expandDecapsulationKey(sk);
|
|
306
|
+
const ct = new Uint8Array(params.enc);
|
|
307
|
+
const ctM = ct.subarray(0, 1088);
|
|
308
|
+
const ctX = ct.subarray(1088);
|
|
309
|
+
const ssM = await this._m.decap(ctM, skM);
|
|
310
|
+
const ssX = await this._x25519.derive(skX, ctX);
|
|
311
|
+
return combiner(ssM, ssX, ctX, pkX);
|
|
312
|
+
}
|
|
313
|
+
catch (e) {
|
|
314
|
+
throw new common_1.DecapError(e);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Sets up the MlKemBase instance by loading the necessary crypto library.
|
|
319
|
+
* If the crypto library is already loaded, this method does nothing.
|
|
320
|
+
* @returns {Promise<void>} A promise that resolves when the setup is complete.
|
|
321
|
+
*/
|
|
322
|
+
async _setup() {
|
|
323
|
+
if (this._api !== undefined) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
this._api = await (0, common_1.loadCrypto)();
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Generates a key pair from the secret key.
|
|
330
|
+
* @param sk The secret key.
|
|
331
|
+
* @returns {Promise<[Uint8Array, Uint8Array]>} A promise that resolves with the key pair derived from the secret key.
|
|
332
|
+
*/
|
|
333
|
+
async _generateKeyPairDerand(sk) {
|
|
334
|
+
const [_skM, _skX, pkM, pkX] = await this._expandDecapsulationKey(sk);
|
|
335
|
+
return [sk, (0, common_1.concat)(pkM, pkX)];
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Expands the decapsulation key.
|
|
339
|
+
* @param sk The secret key.
|
|
340
|
+
* @returns {Promise<[Uint8Array, Uint8Array, Uint8Array, Uint8Array]>} A promise that resolves with the keys derived by expanding the secret key.
|
|
341
|
+
*/
|
|
342
|
+
async _expandDecapsulationKey(sk) {
|
|
343
|
+
const expanded = sha3_1.shake256.create({ dkLen: 96 }).update(sk).digest();
|
|
344
|
+
const [pkM, skM] = await this._m.deriveKeyPair(expanded.subarray(0, 64));
|
|
345
|
+
const skX = expanded.subarray(64, 96);
|
|
346
|
+
const pkX = await this._x25519.derive(skX, X25519_BASE);
|
|
347
|
+
return [skM, skX, pkM, pkX];
|
|
348
|
+
}
|
|
349
|
+
_serializePublicKey(k) {
|
|
350
|
+
return new Promise((resolve, reject) => {
|
|
351
|
+
if (k.type !== "public") {
|
|
352
|
+
reject(new Error("Not public key"));
|
|
353
|
+
}
|
|
354
|
+
if (k.algorithm.name !== this.name) {
|
|
355
|
+
reject(new Error(`Invalid algorithm name: ${k.algorithm.name}`));
|
|
356
|
+
}
|
|
357
|
+
if (k.key.byteLength !== this.publicKeySize) {
|
|
358
|
+
reject(new Error(`Invalid key length: ${k.key.byteLength}`));
|
|
359
|
+
}
|
|
360
|
+
resolve(k.key.buffer);
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
_deserializePublicKey(k) {
|
|
364
|
+
return new Promise((resolve, reject) => {
|
|
365
|
+
if (k.byteLength !== this.publicKeySize) {
|
|
366
|
+
reject(new Error(`Invalid key length: ${k.byteLength}`));
|
|
367
|
+
}
|
|
368
|
+
resolve(new common_1.XCryptoKey(this.name, new Uint8Array(k), "public"));
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
_serializePrivateKey(k) {
|
|
372
|
+
return new Promise((resolve, reject) => {
|
|
373
|
+
if (k.type !== "private") {
|
|
374
|
+
reject(new Error("Not private key"));
|
|
375
|
+
}
|
|
376
|
+
if (k.algorithm.name !== this.name) {
|
|
377
|
+
reject(new Error(`Invalid algorithm name: ${k.algorithm.name}`));
|
|
378
|
+
}
|
|
379
|
+
if (k.key.byteLength !== this.privateKeySize) {
|
|
380
|
+
reject(new Error(`Invalid key length: ${k.key.byteLength}`));
|
|
381
|
+
}
|
|
382
|
+
resolve(k.key.buffer);
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
_deserializePrivateKey(k) {
|
|
386
|
+
return new Promise((resolve, reject) => {
|
|
387
|
+
if (k.byteLength !== this.privateKeySize) {
|
|
388
|
+
reject(new Error(`Invalid key length: ${k.byteLength}`));
|
|
389
|
+
}
|
|
390
|
+
resolve(new common_1.XCryptoKey(this.name, new Uint8Array(k), "private", ["deriveBits"]));
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
exports.HybridkemXWing = HybridkemXWing;
|
|
395
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hybridkemXWing.test.d.ts","sourceRoot":"","sources":["../../src/test/hybridkemXWing.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testVectors.d.ts","sourceRoot":"","sources":["../../src/test/testVectors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,UAAU,CAY1C,CAAC"}
|