@omnituum/pqc-shared 0.3.0 → 0.4.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.
Files changed (41) hide show
  1. package/dist/crypto/index.cjs +29 -71
  2. package/dist/crypto/index.d.cts +38 -45
  3. package/dist/crypto/index.d.ts +38 -45
  4. package/dist/crypto/index.js +28 -72
  5. package/dist/crypto/safe/index.cjs +556 -0
  6. package/dist/crypto/safe/index.d.cts +341 -0
  7. package/dist/crypto/safe/index.d.ts +341 -0
  8. package/dist/crypto/safe/index.js +524 -0
  9. package/dist/fs/index.cjs +6 -34
  10. package/dist/fs/index.js +6 -34
  11. package/dist/index.cjs +29 -71
  12. package/dist/index.d.cts +4 -4
  13. package/dist/index.d.ts +4 -4
  14. package/dist/index.js +28 -72
  15. package/dist/{integrity-CCYjrap3.d.ts → integrity-BPvNsC50.d.ts} +1 -1
  16. package/dist/{integrity-Dx9jukMH.d.cts → integrity-ByMp24VA.d.cts} +1 -1
  17. package/dist/{types-61c7Q9ri.d.ts → types-Dx_AFqow.d.cts} +54 -2
  18. package/dist/{types-Ch0y-n7K.d.cts → types-Dx_AFqow.d.ts} +54 -2
  19. package/dist/utils/index.d.cts +2 -3
  20. package/dist/utils/index.d.ts +2 -3
  21. package/dist/vault/index.cjs +13 -41
  22. package/dist/vault/index.d.cts +2 -3
  23. package/dist/vault/index.d.ts +2 -3
  24. package/dist/vault/index.js +13 -41
  25. package/package.json +27 -13
  26. package/src/crypto/dilithium.ts +8 -4
  27. package/src/crypto/hybrid.ts +13 -29
  28. package/src/crypto/index.ts +3 -0
  29. package/src/crypto/kyber.ts +63 -121
  30. package/src/crypto/safe/adapters.ts +306 -0
  31. package/src/crypto/safe/dilithium.ts +74 -0
  32. package/src/crypto/safe/index.ts +97 -0
  33. package/src/crypto/safe/kyber.ts +47 -0
  34. package/src/crypto/safe/manifests.ts +192 -0
  35. package/src/crypto/safe/secretbox.ts +24 -0
  36. package/src/crypto/safe/types.ts +88 -0
  37. package/src/crypto/safe/x25519.ts +31 -0
  38. package/src/index.ts +7 -4
  39. package/src/version.ts +9 -4
  40. package/dist/version-BygzPVGs.d.cts +0 -55
  41. package/dist/version-BygzPVGs.d.ts +0 -55
@@ -1,6 +1,5 @@
1
- import { O as OmnituumVault, E as EncryptedVaultFile, a as EncryptedVaultFileV2, H as HybridIdentityRecord, V as VaultSettings, b as VaultSession } from '../types-61c7Q9ri.js';
2
- export { D as DEFAULT_VAULT_SETTINGS, c as EncryptedVaultFileV1, d as HealthStatus, I as IdentityHealth, P as PBKDF2_ITERATIONS } from '../types-61c7Q9ri.js';
3
- import '../version-BygzPVGs.js';
1
+ import { O as OmnituumVault, E as EncryptedVaultFile, k as EncryptedVaultFileV2, H as HybridIdentityRecord, l as VaultSettings, m as VaultSession } from '../types-Dx_AFqow.js';
2
+ export { D as DEFAULT_VAULT_SETTINGS, n as EncryptedVaultFileV1, o as HealthStatus, I as IdentityHealth, P as PBKDF2_ITERATIONS } from '../types-Dx_AFqow.js';
4
3
 
5
4
  /**
6
5
  * Omnituum PQC Shared - Vault Encryption
@@ -1,7 +1,9 @@
1
1
  import '@noble/hashes/sha2.js';
2
2
  import '@noble/hashes/hmac.js';
3
+ import { OMNI_VERSIONS, DEPRECATED_VERSIONS } from '@omnituum/envelope-registry';
3
4
  import { argon2id } from 'hash-wasm';
4
5
  import nacl from 'tweetnacl';
6
+ import { ml_kem1024 } from '@noble/post-quantum/ml-kem.js';
5
7
  import '@noble/hashes/blake3.js';
6
8
  import '@noble/ciphers/chacha.js';
7
9
  import '@noble/hashes/hkdf.js';
@@ -33,9 +35,12 @@ function fromB64(str) {
33
35
  function toHex(bytes) {
34
36
  return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
35
37
  }
38
+ function randN(n) {
39
+ return globalThis.crypto.getRandomValues(new Uint8Array(n));
40
+ }
36
41
  var b64 = toB64;
37
-
38
- // src/version.ts
42
+ OMNI_VERSIONS.HYBRID_V1;
43
+ DEPRECATED_VERSIONS.PQC_DEMO_HYBRID_V1;
39
44
  var VAULT_VERSION = "omnituum.vault.v1";
40
45
  var VAULT_ENCRYPTED_VERSION = "omnituum.vault.enc.v1";
41
46
  var VAULT_ENCRYPTED_VERSION_V2 = "omnituum.vault.enc.v2";
@@ -358,46 +363,13 @@ function generateX25519Keypair() {
358
363
  secretBytes: kp.secretKey
359
364
  };
360
365
  }
361
- var kyberModule = null;
362
- async function loadKyber() {
363
- if (kyberModule) return kyberModule;
364
- try {
365
- const m = await import('kyber-crystals');
366
- const k = m.default ?? m;
367
- kyberModule = k.kyber ?? k;
368
- return kyberModule;
369
- } catch (e) {
370
- console.warn("[Kyber] Failed to load kyber-crystals:", e);
371
- return null;
372
- }
373
- }
374
366
  async function generateKyberKeypair() {
375
- try {
376
- const mod = await loadKyber();
377
- if (!mod) return null;
378
- if (mod?.ready?.then) {
379
- await mod.ready;
380
- }
381
- const fn = mod?.keypair ?? mod?.keyPair ?? mod?.generateKeyPair ?? null;
382
- if (typeof fn !== "function") {
383
- console.warn("[Kyber] No keypair function found");
384
- return null;
385
- }
386
- const kp = await fn.call(mod);
387
- const pub = kp?.publicKey ?? kp?.public ?? kp?.pk;
388
- const priv = kp?.privateKey ?? kp?.secretKey ?? kp?.secret ?? kp?.sk;
389
- if (!pub || !priv) {
390
- console.warn("[Kyber] Invalid keypair result");
391
- return null;
392
- }
393
- return {
394
- publicB64: b64(new Uint8Array(pub)),
395
- secretB64: b64(new Uint8Array(priv))
396
- };
397
- } catch (e) {
398
- console.warn("[Kyber] Key generation failed:", e);
399
- return null;
400
- }
367
+ const seed = randN(64);
368
+ const kp = ml_kem1024.keygen(seed);
369
+ return {
370
+ publicB64: b64(kp.publicKey),
371
+ secretB64: b64(kp.secretKey)
372
+ };
401
373
  }
402
374
 
403
375
  // src/vault/manager.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnituum/pqc-shared",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Omnituum PQC Shared Library - Crypto, Vault, File Encryption, and Utilities",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -31,25 +31,43 @@
31
31
  "types": "./dist/fs/index.d.ts",
32
32
  "import": "./dist/fs/index.js",
33
33
  "require": "./dist/fs/index.cjs"
34
+ },
35
+ "./safe": {
36
+ "types": "./dist/crypto/safe/index.d.ts",
37
+ "import": "./dist/crypto/safe/index.js",
38
+ "require": "./dist/crypto/safe/index.cjs"
34
39
  }
35
40
  },
36
41
  "files": [
37
42
  "dist",
38
43
  "src"
39
44
  ],
45
+ "scripts": {
46
+ "build": "tsup",
47
+ "dev": "tsup --watch",
48
+ "clean": "rm -rf dist",
49
+ "typecheck": "tsc --noEmit",
50
+ "test:golden:generate": "pnpm -s build && tsx tests/golden/generate-vectors.ts",
51
+ "test:golden:verify": "pnpm -s build && tsx tests/golden/verify-vectors.ts",
52
+ "test:golden": "pnpm test:golden:verify",
53
+ "test": "vitest run tests/",
54
+ "test:watch": "vitest tests/",
55
+ "pretest": "pnpm build"
56
+ },
40
57
  "dependencies": {
41
58
  "@noble/ciphers": "~2.0.0",
42
59
  "@noble/hashes": "~2.0.0",
60
+ "@omnituum/envelope-registry": "github:Omnituum/envelope-registry#v0.1.2",
43
61
  "@noble/post-quantum": "~0.5.4",
44
62
  "hash-wasm": "^4.11.0",
45
- "kyber-crystals": "^1.0.7",
46
63
  "tweetnacl": "^1.0.3"
47
64
  },
48
65
  "devDependencies": {
49
66
  "@types/node": "^25.0.9",
50
67
  "tsup": "^8.5.0",
51
68
  "tsx": "^4.19.0",
52
- "typescript": "^5.9.3"
69
+ "typescript": "^5.9.3",
70
+ "vitest": "^3.1.0"
53
71
  },
54
72
  "keywords": [
55
73
  "pqc",
@@ -73,14 +91,10 @@
73
91
  "url": "https://github.com/Omnituum/pqc-shared/issues"
74
92
  },
75
93
  "homepage": "https://github.com/Omnituum/pqc-shared#readme",
76
- "scripts": {
77
- "build": "tsup",
78
- "dev": "tsup --watch",
79
- "clean": "rm -rf dist",
80
- "typecheck": "tsc --noEmit",
81
- "test:golden:generate": "pnpm -s build && tsx tests/golden/generate-vectors.ts",
82
- "test:golden:verify": "pnpm -s build && tsx tests/golden/verify-vectors.ts",
83
- "test:golden": "npm run test:golden:verify",
84
- "pretest": "npm run build"
94
+ "packageManager": "pnpm@10.32.1",
95
+ "pnpm": {
96
+ "onlyBuiltDependencies": [
97
+ "@omnituum/envelope-registry"
98
+ ]
85
99
  }
86
- }
100
+ }
@@ -140,7 +140,8 @@ export async function dilithiumSign(
140
140
  const sk = fromB64(secretKeyB64);
141
141
  const msg = typeof message === 'string' ? new TextEncoder().encode(message) : message;
142
142
 
143
- const signature = mod.sign(sk, msg);
143
+ // noble API: sign(message, secretKey)
144
+ const signature = mod.sign(msg, sk);
144
145
 
145
146
  return {
146
147
  signature: toB64(signature),
@@ -160,7 +161,8 @@ export async function dilithiumSignRaw(
160
161
  throw new Error('Dilithium library not available');
161
162
  }
162
163
 
163
- return mod.sign(secretKey, message);
164
+ // noble API: sign(message, secretKey)
165
+ return mod.sign(message, secretKey);
164
166
  }
165
167
 
166
168
  // ═══════════════════════════════════════════════════════════════════════════
@@ -190,7 +192,8 @@ export async function dilithiumVerify(
190
192
  const msg = typeof message === 'string' ? new TextEncoder().encode(message) : message;
191
193
 
192
194
  try {
193
- return mod.verify(pk, msg, sig);
195
+ // noble API: verify(signature, message, publicKey)
196
+ return mod.verify(sig, msg, pk);
194
197
  } catch {
195
198
  return false;
196
199
  }
@@ -210,7 +213,8 @@ export async function dilithiumVerifyRaw(
210
213
  }
211
214
 
212
215
  try {
213
- return mod.verify(publicKey, message, signature);
216
+ // noble API: verify(signature, message, publicKey)
217
+ return mod.verify(signature, message, publicKey);
214
218
  } catch {
215
219
  return false;
216
220
  }
@@ -75,38 +75,22 @@ export interface HybridSecretKeys {
75
75
  kyberSecB64: string;
76
76
  }
77
77
 
78
- export interface HybridEnvelope {
79
- /** Version identifier (FROZEN - see pqc-docs/specs/envelope.v1.md) */
80
- v: typeof ENVELOPE_VERSION;
81
- /** Algorithm suite */
82
- suite: typeof ENVELOPE_SUITE;
83
- /** AEAD algorithm */
84
- aead: typeof ENVELOPE_AEAD;
85
- /** X25519 ephemeral public key (hex) */
86
- x25519Epk: string;
87
- /** X25519 wrapped content key */
88
- x25519Wrap: {
89
- nonce: string;
90
- wrapped: string;
91
- };
92
- /** Kyber KEM ciphertext (base64) */
93
- kyberKemCt: string;
94
- /** Kyber wrapped content key */
95
- kyberWrap: {
96
- nonce: string;
97
- wrapped: string;
98
- };
99
- /** Content encryption nonce (base64) */
100
- contentNonce: string;
101
- /** Encrypted content (base64) */
102
- ciphertext: string;
103
- /** Metadata */
104
- meta: {
105
- createdAt: string;
78
+ /**
79
+ * HybridEnvelope -- OmniHybridV1 from the registry with
80
+ * app-semantic meta fields (senderName, senderId).
81
+ * The Omni registry type defines only the crypto-relevant surface.
82
+ *
83
+ * Intentionally a type alias (not interface extends) to discourage
84
+ * further field additions here. New app-semantic fields belong in
85
+ * product-level types, not in the shared crypto layer.
86
+ */
87
+ import type { OmniHybridV1 } from '@omnituum/envelope-registry';
88
+ export type HybridEnvelope = Omit<OmniHybridV1, 'meta'> & {
89
+ meta: OmniHybridV1['meta'] & {
106
90
  senderName?: string;
107
91
  senderId?: string;
108
92
  };
109
- }
93
+ };
110
94
 
111
95
  // ═══════════════════════════════════════════════════════════════════════════
112
96
  // HELPERS
@@ -83,11 +83,14 @@ export type {
83
83
  export {
84
84
  isKyberAvailable,
85
85
  generateKyberKeypair,
86
+ generateKyberKeypairFromSeed,
86
87
  kyberEncapsulate,
87
88
  kyberDecapsulate,
88
89
  kyberWrapKey,
89
90
  kyberUnwrapKey,
91
+ KYBER_SUITE,
90
92
  } from './kyber';
93
+ export type { KyberSuite } from './kyber';
91
94
 
92
95
  // ═══════════════════════════════════════════════════════════════════════════
93
96
  // DILITHIUM ML-DSA-65 (Post-Quantum Signatures)
@@ -1,11 +1,25 @@
1
1
  /**
2
- * Omnituum PQC Shared - Kyber ML-KEM-768
2
+ * Omnituum PQC Shared Kyber (ML-KEM-1024, FIPS 203)
3
3
  *
4
- * Browser-compatible Kyber operations using kyber-crystals.
5
- * NIST Level 3 security - quantum-resistant.
4
+ * Backend: @noble/post-quantum `ml_kem1024`. NIST FIPS 203 (final, 2024).
5
+ *
6
+ * Wire-format note: previous releases (<= 0.3.x) of this package were backed by
7
+ * `kyber-crystals`, which implements an earlier draft of Kyber and is NOT
8
+ * interoperable with FIPS 203 — see `tests/interop/historical/` and
9
+ * `package-docs/GAPS_AND_TASKS.md` (PQC-02 result). 0.4.0 is an intentional
10
+ * clean break: legacy draft-Kyber material cannot be read by this version.
11
+ *
12
+ * Sizes (ML-KEM-1024):
13
+ * publicKey 1568 bytes
14
+ * secretKey 3168 bytes
15
+ * ciphertext 1568 bytes
16
+ * sharedSecret 32 bytes
17
+ *
18
+ * Suite tag for new material: "ML-KEM-1024-FIPS203".
6
19
  */
7
20
 
8
- import { b64, ub64, sha256 } from './primitives';
21
+ import { ml_kem1024 } from '@noble/post-quantum/ml-kem.js';
22
+ import { b64, ub64, sha256, randN } from './primitives';
9
23
  import nacl from 'tweetnacl';
10
24
 
11
25
  // ═══════════════════════════════════════════════════════════════════════════
@@ -27,33 +41,21 @@ export interface KyberEncapsulation {
27
41
  sharedSecret: Uint8Array;
28
42
  }
29
43
 
30
- // ═══════════════════════════════════════════════════════════════════════════
31
- // KYBER LIBRARY LOADING
32
- // ═══════════════════════════════════════════════════════════════════════════
33
-
34
- let kyberModule: any = null;
35
-
36
- async function loadKyber(): Promise<any> {
37
- if (kyberModule) return kyberModule;
38
-
39
- try {
40
- const m = await import('kyber-crystals');
41
- const k = (m as any).default ?? m;
42
- kyberModule = k.kyber ?? k;
43
- return kyberModule;
44
- } catch (e) {
45
- console.warn('[Kyber] Failed to load kyber-crystals:', e);
46
- return null;
47
- }
48
- }
44
+ /** Canonical suite identifier for new material produced by this package. */
45
+ export const KYBER_SUITE = 'ML-KEM-1024-FIPS203' as const;
46
+ export type KyberSuite = typeof KYBER_SUITE;
49
47
 
50
48
  // ═══════════════════════════════════════════════════════════════════════════
51
- // AVAILABILITY CHECK
49
+ // AVAILABILITY
52
50
  // ═══════════════════════════════════════════════════════════════════════════
53
51
 
52
+ /**
53
+ * @deprecated Always returns true. Retained for API stability across the
54
+ * 0.3.x → 0.4.x cut. The noble backend is statically imported and always
55
+ * present; there is no runtime feature-detection path.
56
+ */
54
57
  export async function isKyberAvailable(): Promise<boolean> {
55
- const mod = await loadKyber();
56
- return mod !== null;
58
+ return true;
57
59
  }
58
60
 
59
61
  // ═══════════════════════════════════════════════════════════════════════════
@@ -61,139 +63,79 @@ export async function isKyberAvailable(): Promise<boolean> {
61
63
  // ═══════════════════════════════════════════════════════════════════════════
62
64
 
63
65
  /**
64
- * Generate a Kyber ML-KEM-768 keypair.
66
+ * Generate a fresh ML-KEM-1024 keypair using a cryptographically random seed.
65
67
  */
66
68
  export async function generateKyberKeypair(): Promise<KyberKeypairB64 | null> {
67
- try {
68
- const mod = await loadKyber();
69
- if (!mod) return null;
70
-
71
- if (mod?.ready?.then) {
72
- await mod.ready;
73
- }
74
-
75
- const fn = mod?.keypair ?? mod?.keyPair ?? mod?.generateKeyPair ?? null;
76
- if (typeof fn !== 'function') {
77
- console.warn('[Kyber] No keypair function found');
78
- return null;
79
- }
80
-
81
- const kp = await fn.call(mod);
82
- const pub = kp?.publicKey ?? kp?.public ?? kp?.pk;
83
- const priv = kp?.privateKey ?? kp?.secretKey ?? kp?.secret ?? kp?.sk;
84
-
85
- if (!pub || !priv) {
86
- console.warn('[Kyber] Invalid keypair result');
87
- return null;
88
- }
89
-
90
- return {
91
- publicB64: b64(new Uint8Array(pub)),
92
- secretB64: b64(new Uint8Array(priv)),
93
- };
94
- } catch (e) {
95
- console.warn('[Kyber] Key generation failed:', e);
96
- return null;
69
+ const seed = randN(64);
70
+ const kp = ml_kem1024.keygen(seed);
71
+ return {
72
+ publicB64: b64(kp.publicKey),
73
+ secretB64: b64(kp.secretKey),
74
+ };
75
+ }
76
+
77
+ /**
78
+ * Derive a deterministic ML-KEM-1024 keypair from a 64-byte seed.
79
+ * Same seed → byte-identical keypair, across runtimes (Node, browser).
80
+ *
81
+ * The seed is passed verbatim to the FIPS 203 keygen. Callers that need
82
+ * domain separation between Kyber and other key types must apply it
83
+ * upstream (e.g. via SHA-256 with a domain tag) before calling.
84
+ */
85
+ export function generateKyberKeypairFromSeed(seed: Uint8Array): KyberKeypair {
86
+ if (seed.length !== 64) {
87
+ throw new Error('Kyber seed must be 64 bytes');
97
88
  }
89
+ const kp = ml_kem1024.keygen(seed);
90
+ return { publicKey: kp.publicKey, secretKey: kp.secretKey };
98
91
  }
99
92
 
100
93
  // ═══════════════════════════════════════════════════════════════════════════
101
94
  // ENCAPSULATION / DECAPSULATION
102
95
  // ═══════════════════════════════════════════════════════════════════════════
103
96
 
104
- /**
105
- * Encapsulate a shared secret using Kyber ML-KEM-768.
106
- */
107
97
  export async function kyberEncapsulate(pubKeyB64: string): Promise<KyberEncapsulation> {
108
- const kyber = await loadKyber();
109
- if (!kyber?.encrypt) {
110
- throw new Error('Kyber encrypt not available');
111
- }
112
-
113
98
  const pk = ub64(pubKeyB64);
114
- const r: any = await kyber.encrypt(pk);
115
-
116
- // Normalize ciphertext
117
- const ctRaw =
118
- r?.ciphertext ?? r?.cyphertext ?? r?.ct ??
119
- r?.bytes?.ciphertext ?? r?.bytes?.cyphertext ?? r?.bytes?.ct ??
120
- (Array.isArray(r) ? r[0] : undefined);
121
-
122
- // Normalize shared secret
123
- const ssRaw =
124
- r?.key ?? r?.sharedSecret ?? r?.secret ??
125
- r?.bytes?.key ?? r?.bytes?.sharedSecret ??
126
- (Array.isArray(r) ? r[1] : undefined);
127
-
128
- if (!ctRaw || !ssRaw) {
129
- throw new Error('Kyber encapsulate failed: missing ciphertext or shared secret');
130
- }
131
-
99
+ const enc = ml_kem1024.encapsulate(pk);
132
100
  return {
133
- ciphertext: new Uint8Array(ctRaw),
134
- sharedSecret: new Uint8Array(ssRaw),
101
+ ciphertext: enc.cipherText,
102
+ sharedSecret: enc.sharedSecret,
135
103
  };
136
104
  }
137
105
 
138
- /**
139
- * Decapsulate a shared secret using Kyber ML-KEM-768.
140
- */
141
106
  export async function kyberDecapsulate(
142
107
  kemCiphertextB64: string,
143
- secretKeyB64: string
108
+ secretKeyB64: string,
144
109
  ): Promise<Uint8Array> {
145
- const kyber = await loadKyber();
146
- if (!kyber?.decrypt && !kyber?.decapsulate) {
147
- throw new Error('Kyber decrypt/decapsulate not available');
148
- }
149
-
150
110
  const ct = ub64(kemCiphertextB64);
151
111
  const sk = ub64(secretKeyB64);
152
-
153
- const r: any = kyber.decrypt
154
- ? await kyber.decrypt(ct, sk)
155
- : await kyber.decapsulate(ct, sk);
156
-
157
- const key = (r && (r.key ?? r.sharedSecret)) ? (r.key ?? r.sharedSecret) : r;
158
- return new Uint8Array(key);
112
+ return ml_kem1024.decapsulate(ct, sk);
159
113
  }
160
114
 
161
115
  // ═══════════════════════════════════════════════════════════════════════════
162
- // KEY WRAPPING HELPERS
116
+ // KEY WRAPPING (library-agnostic; NaCl secretbox over derived KEK)
163
117
  // ═══════════════════════════════════════════════════════════════════════════
164
118
 
165
- /**
166
- * Wrap a message key using Kyber shared secret.
167
- */
168
- export function kyberWrapKey(sharedSecret: Uint8Array, msgKey32: Uint8Array): {
169
- nonce: string;
170
- wrapped: string;
171
- } {
119
+ export function kyberWrapKey(
120
+ sharedSecret: Uint8Array,
121
+ msgKey32: Uint8Array,
122
+ ): { nonce: string; wrapped: string } {
172
123
  if (msgKey32.length !== 32) {
173
124
  throw new Error('Message key must be 32 bytes');
174
125
  }
175
-
176
- const kek = sha256(sharedSecret); // Derive KEK from shared secret
126
+ const kek = sha256(sharedSecret);
177
127
  const nonce = globalThis.crypto.getRandomValues(new Uint8Array(24));
178
128
  const wrapped = nacl.secretbox(msgKey32, nonce, kek);
179
-
180
- return {
181
- nonce: b64(nonce),
182
- wrapped: b64(wrapped),
183
- };
129
+ return { nonce: b64(nonce), wrapped: b64(wrapped) };
184
130
  }
185
131
 
186
- /**
187
- * Unwrap a message key using Kyber shared secret.
188
- */
189
132
  export function kyberUnwrapKey(
190
133
  sharedSecret: Uint8Array,
191
134
  nonceB64: string,
192
- wrappedB64: string
135
+ wrappedB64: string,
193
136
  ): Uint8Array | null {
194
137
  const kek = sha256(sharedSecret);
195
138
  const nonce = ub64(nonceB64);
196
139
  const wrapped = ub64(wrappedB64);
197
-
198
140
  return nacl.secretbox.open(wrapped, nonce, kek) || null;
199
141
  }