@omnituum/pqc-shared 0.3.1 → 0.4.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/dist/crypto/index.cjs +39 -71
- package/dist/crypto/index.d.cts +48 -45
- package/dist/crypto/index.d.ts +48 -45
- package/dist/crypto/index.js +33 -72
- package/dist/crypto/safe/index.cjs +556 -0
- package/dist/crypto/safe/index.d.cts +341 -0
- package/dist/crypto/safe/index.d.ts +341 -0
- package/dist/crypto/safe/index.js +524 -0
- package/dist/fs/index.cjs +6 -34
- package/dist/fs/index.js +6 -34
- package/dist/index.cjs +39 -71
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +33 -72
- package/dist/{integrity-Dx9jukMH.d.cts → integrity-BenoFsmP.d.cts} +1 -1
- package/dist/{integrity-CCYjrap3.d.ts → integrity-D9J98Bty.d.ts} +1 -1
- package/dist/{types-61c7Q9ri.d.ts → types-CRka8PC7.d.cts} +54 -2
- package/dist/{types-Ch0y-n7K.d.cts → types-CRka8PC7.d.ts} +54 -2
- package/dist/utils/index.d.cts +2 -3
- package/dist/utils/index.d.ts +2 -3
- package/dist/vault/index.cjs +13 -41
- package/dist/vault/index.d.cts +2 -3
- package/dist/vault/index.d.ts +2 -3
- package/dist/vault/index.js +13 -41
- package/package.json +13 -5
- package/src/crypto/dilithium.ts +8 -4
- package/src/crypto/hybrid.ts +13 -29
- package/src/crypto/index.ts +9 -1
- package/src/crypto/kyber.ts +80 -118
- package/src/crypto/safe/adapters.ts +306 -0
- package/src/crypto/safe/dilithium.ts +74 -0
- package/src/crypto/safe/index.ts +97 -0
- package/src/crypto/safe/kyber.ts +47 -0
- package/src/crypto/safe/manifests.ts +192 -0
- package/src/crypto/safe/secretbox.ts +24 -0
- package/src/crypto/safe/types.ts +88 -0
- package/src/crypto/safe/x25519.ts +31 -0
- package/src/index.ts +12 -4
- package/src/version.ts +9 -4
- package/dist/version-BygzPVGs.d.cts +0 -55
- package/dist/version-BygzPVGs.d.ts +0 -55
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
require('@noble/hashes/sha2.js');
|
|
4
|
+
require('@noble/hashes/hmac.js');
|
|
5
|
+
var mlKem_js = require('@noble/post-quantum/ml-kem.js');
|
|
6
|
+
var nacl3 = require('tweetnacl');
|
|
7
|
+
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var nacl3__default = /*#__PURE__*/_interopDefault(nacl3);
|
|
11
|
+
|
|
12
|
+
var __defProp = Object.defineProperty;
|
|
13
|
+
var __export = (target, all) => {
|
|
14
|
+
for (var name in all)
|
|
15
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// src/crypto/safe/dilithium.ts
|
|
19
|
+
var dilithium_exports = {};
|
|
20
|
+
__export(dilithium_exports, {
|
|
21
|
+
keygen: () => keygen,
|
|
22
|
+
sign: () => sign,
|
|
23
|
+
verify: () => verify
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// src/crypto/safe/manifests.ts
|
|
27
|
+
var ML_DSA_65 = {
|
|
28
|
+
algorithm: "ML-DSA-65",
|
|
29
|
+
publicKeyBytes: 1952,
|
|
30
|
+
secretKeyBytes: 4032,
|
|
31
|
+
signatureBytes: 3309
|
|
32
|
+
};
|
|
33
|
+
var ML_KEM_768 = {
|
|
34
|
+
algorithm: "ML-KEM-768",
|
|
35
|
+
encapsulationKeyBytes: 1184,
|
|
36
|
+
decapsulationKeyBytes: 2400,
|
|
37
|
+
ciphertextBytes: 1088,
|
|
38
|
+
sharedSecretBytes: 32
|
|
39
|
+
};
|
|
40
|
+
var X25519 = {
|
|
41
|
+
algorithm: "X25519",
|
|
42
|
+
publicKeyBytes: 32,
|
|
43
|
+
secretKeyBytes: 32,
|
|
44
|
+
sharedSecretBytes: 32
|
|
45
|
+
};
|
|
46
|
+
var XSALSA20_POLY1305 = {
|
|
47
|
+
algorithm: "XSalsa20-Poly1305",
|
|
48
|
+
keyBytes: 32,
|
|
49
|
+
nonceBytes: 24,
|
|
50
|
+
tagBytes: 16
|
|
51
|
+
};
|
|
52
|
+
function assertSignaturePrimitive(noble, manifest) {
|
|
53
|
+
const msg = new Uint8Array([222, 173, 190, 239]);
|
|
54
|
+
const { publicKey, secretKey } = noble.keygen();
|
|
55
|
+
const sig = noble.sign(msg, secretKey);
|
|
56
|
+
if (publicKey.length !== manifest.publicKeyBytes) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`${manifest.algorithm}: publicKey ${publicKey.length} bytes, expected ${manifest.publicKeyBytes}`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
if (secretKey.length !== manifest.secretKeyBytes) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`${manifest.algorithm}: secretKey ${secretKey.length} bytes, expected ${manifest.secretKeyBytes}`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
if (sig.length !== manifest.signatureBytes) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`${manifest.algorithm}: signature ${sig.length} bytes, expected ${manifest.signatureBytes}`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
if (!noble.verify(sig, msg, publicKey)) {
|
|
72
|
+
throw new Error(`${manifest.algorithm}: sign/verify roundtrip failed`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function assertKemPrimitive(noble, manifest) {
|
|
76
|
+
const { publicKey, secretKey } = noble.keygen();
|
|
77
|
+
const { ciphertext, sharedSecret: ss1 } = noble.encapsulate(publicKey);
|
|
78
|
+
const ss2 = noble.decapsulate(ciphertext, secretKey);
|
|
79
|
+
if (publicKey.length !== manifest.encapsulationKeyBytes) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`${manifest.algorithm}: encapsulationKey ${publicKey.length} bytes, expected ${manifest.encapsulationKeyBytes}`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
if (secretKey.length !== manifest.decapsulationKeyBytes) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`${manifest.algorithm}: decapsulationKey ${secretKey.length} bytes, expected ${manifest.decapsulationKeyBytes}`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
if (ciphertext.length !== manifest.ciphertextBytes) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`${manifest.algorithm}: ciphertext ${ciphertext.length} bytes, expected ${manifest.ciphertextBytes}`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
if (ss1.length !== manifest.sharedSecretBytes) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`${manifest.algorithm}: sharedSecret ${ss1.length} bytes, expected ${manifest.sharedSecretBytes}`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
if (ss2.length !== manifest.sharedSecretBytes) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`${manifest.algorithm}: decapsulated sharedSecret ${ss2.length} bytes, expected ${manifest.sharedSecretBytes}`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
for (let i = 0; i < ss1.length; i++) {
|
|
105
|
+
if (ss1[i] !== ss2[i]) {
|
|
106
|
+
throw new Error(`${manifest.algorithm}: encap/decap shared secrets differ at byte ${i}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function assertDhPrimitive(noble, manifest) {
|
|
111
|
+
const sk = noble.utils.randomPrivateKey();
|
|
112
|
+
const pk = noble.getPublicKey(sk);
|
|
113
|
+
if (pk.length !== manifest.publicKeyBytes) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
`${manifest.algorithm}: publicKey ${pk.length} bytes, expected ${manifest.publicKeyBytes}`
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
if (sk.length !== manifest.secretKeyBytes) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`${manifest.algorithm}: secretKey ${sk.length} bytes, expected ${manifest.secretKeyBytes}`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
const sk2 = noble.utils.randomPrivateKey();
|
|
124
|
+
const pk2 = noble.getPublicKey(sk2);
|
|
125
|
+
const ss1 = noble.getSharedSecret(sk, pk2);
|
|
126
|
+
const ss2 = noble.getSharedSecret(sk2, pk);
|
|
127
|
+
if (ss1.length !== manifest.sharedSecretBytes) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
`${manifest.algorithm}: sharedSecret ${ss1.length} bytes, expected ${manifest.sharedSecretBytes}`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
for (let i = 0; i < ss1.length; i++) {
|
|
133
|
+
if (ss1[i] !== ss2[i]) {
|
|
134
|
+
throw new Error(`${manifest.algorithm}: DH commutativity check failed at byte ${i}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/crypto/safe/dilithium.ts
|
|
140
|
+
var _mod = null;
|
|
141
|
+
var _invariantChecked = false;
|
|
142
|
+
async function load() {
|
|
143
|
+
if (!_mod) {
|
|
144
|
+
const { ml_dsa65 } = await import('@noble/post-quantum/ml-dsa.js');
|
|
145
|
+
_mod = ml_dsa65;
|
|
146
|
+
}
|
|
147
|
+
return _mod;
|
|
148
|
+
}
|
|
149
|
+
async function checkInvariant() {
|
|
150
|
+
if (_invariantChecked) return;
|
|
151
|
+
const mod = await load();
|
|
152
|
+
assertSignaturePrimitive(mod, ML_DSA_65);
|
|
153
|
+
_invariantChecked = true;
|
|
154
|
+
}
|
|
155
|
+
async function keygen() {
|
|
156
|
+
const mod = await load();
|
|
157
|
+
await checkInvariant();
|
|
158
|
+
const kp = mod.keygen();
|
|
159
|
+
return {
|
|
160
|
+
publicKey: kp.publicKey,
|
|
161
|
+
secretKey: kp.secretKey
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
async function sign(params) {
|
|
165
|
+
const mod = await load();
|
|
166
|
+
await checkInvariant();
|
|
167
|
+
return mod.sign(params.message, params.secretKey);
|
|
168
|
+
}
|
|
169
|
+
async function verify(params) {
|
|
170
|
+
const mod = await load();
|
|
171
|
+
await checkInvariant();
|
|
172
|
+
try {
|
|
173
|
+
return mod.verify(params.signature, params.message, params.publicKey);
|
|
174
|
+
} catch {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// src/crypto/safe/kyber.ts
|
|
180
|
+
var kyber_exports = {};
|
|
181
|
+
__export(kyber_exports, {
|
|
182
|
+
decapsulate: () => decapsulate,
|
|
183
|
+
encapsulate: () => encapsulate,
|
|
184
|
+
keygen: () => keygen2
|
|
185
|
+
});
|
|
186
|
+
new TextEncoder();
|
|
187
|
+
new TextDecoder();
|
|
188
|
+
function toB64(bytes) {
|
|
189
|
+
let binary = "";
|
|
190
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
191
|
+
binary += String.fromCharCode(bytes[i]);
|
|
192
|
+
}
|
|
193
|
+
return btoa(binary);
|
|
194
|
+
}
|
|
195
|
+
function fromB64(str) {
|
|
196
|
+
const binary = atob(str);
|
|
197
|
+
const bytes = new Uint8Array(binary.length);
|
|
198
|
+
for (let i = 0; i < binary.length; i++) {
|
|
199
|
+
bytes[i] = binary.charCodeAt(i);
|
|
200
|
+
}
|
|
201
|
+
return bytes;
|
|
202
|
+
}
|
|
203
|
+
function toHex(bytes) {
|
|
204
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
205
|
+
}
|
|
206
|
+
function assertLen(label, arr, n) {
|
|
207
|
+
if (arr.length !== n) {
|
|
208
|
+
throw new Error(`${label} must be ${n} bytes, got ${arr.length}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function randN(n) {
|
|
212
|
+
return globalThis.crypto.getRandomValues(new Uint8Array(n));
|
|
213
|
+
}
|
|
214
|
+
var b64 = toB64;
|
|
215
|
+
var ub64 = fromB64;
|
|
216
|
+
async function generateKyberKeypair() {
|
|
217
|
+
const seed = randN(64);
|
|
218
|
+
const kp = mlKem_js.ml_kem1024.keygen(seed);
|
|
219
|
+
return {
|
|
220
|
+
publicB64: b64(kp.publicKey),
|
|
221
|
+
secretB64: b64(kp.secretKey)
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
async function kyberEncapsulate(pubKeyB64) {
|
|
225
|
+
const pk = ub64(pubKeyB64);
|
|
226
|
+
const enc = mlKem_js.ml_kem1024.encapsulate(pk);
|
|
227
|
+
return {
|
|
228
|
+
ciphertext: enc.cipherText,
|
|
229
|
+
sharedSecret: enc.sharedSecret
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
async function kyberDecapsulate(kemCiphertextB64, secretKeyB64) {
|
|
233
|
+
const ct = ub64(kemCiphertextB64);
|
|
234
|
+
const sk = ub64(secretKeyB64);
|
|
235
|
+
return mlKem_js.ml_kem1024.decapsulate(ct, sk);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// src/crypto/safe/kyber.ts
|
|
239
|
+
async function keygen2() {
|
|
240
|
+
const kp = await generateKyberKeypair();
|
|
241
|
+
if (!kp) return null;
|
|
242
|
+
return {
|
|
243
|
+
encapsulationKey: fromB64(kp.publicB64),
|
|
244
|
+
decapsulationKey: fromB64(kp.secretB64)
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
async function encapsulate(params) {
|
|
248
|
+
const result = await kyberEncapsulate(toB64(params.encapsulationKey));
|
|
249
|
+
return {
|
|
250
|
+
ciphertext: result.ciphertext,
|
|
251
|
+
sharedSecret: result.sharedSecret
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
async function decapsulate(params) {
|
|
255
|
+
const ss = await kyberDecapsulate(toB64(params.ciphertext), toB64(params.decapsulationKey));
|
|
256
|
+
return ss;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// src/crypto/safe/x25519.ts
|
|
260
|
+
var x25519_exports = {};
|
|
261
|
+
__export(x25519_exports, {
|
|
262
|
+
keygen: () => keygen3,
|
|
263
|
+
sharedSecret: () => sharedSecret
|
|
264
|
+
});
|
|
265
|
+
function generateX25519Keypair() {
|
|
266
|
+
const kp = nacl3__default.default.box.keyPair();
|
|
267
|
+
return {
|
|
268
|
+
publicHex: "0x" + toHex(kp.publicKey),
|
|
269
|
+
secretHex: "0x" + toHex(kp.secretKey),
|
|
270
|
+
publicBytes: kp.publicKey,
|
|
271
|
+
secretBytes: kp.secretKey
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
function x25519SharedSecret(ourSecretKey, theirPublicKey) {
|
|
275
|
+
assertLen("secret key", ourSecretKey, 32);
|
|
276
|
+
assertLen("public key", theirPublicKey, 32);
|
|
277
|
+
return nacl3__default.default.scalarMult(ourSecretKey, theirPublicKey);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/crypto/safe/x25519.ts
|
|
281
|
+
function keygen3() {
|
|
282
|
+
const kp = generateX25519Keypair();
|
|
283
|
+
return {
|
|
284
|
+
publicKey: kp.publicBytes,
|
|
285
|
+
secretKey: kp.secretBytes
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function sharedSecret(params) {
|
|
289
|
+
return x25519SharedSecret(params.ourSecretKey, params.theirPublicKey);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// src/crypto/safe/secretbox.ts
|
|
293
|
+
var secretbox_exports = {};
|
|
294
|
+
__export(secretbox_exports, {
|
|
295
|
+
open: () => open,
|
|
296
|
+
seal: () => seal
|
|
297
|
+
});
|
|
298
|
+
function secretboxRaw(key, plaintext, nonce) {
|
|
299
|
+
assertLen("secretbox key", key, 32);
|
|
300
|
+
assertLen("nonce", nonce, 24);
|
|
301
|
+
return nacl3__default.default.secretbox(plaintext, nonce, key);
|
|
302
|
+
}
|
|
303
|
+
function secretboxOpenRaw(key, ciphertext, nonce) {
|
|
304
|
+
assertLen("secretbox key", key, 32);
|
|
305
|
+
assertLen("nonce", nonce, 24);
|
|
306
|
+
return nacl3__default.default.secretbox.open(ciphertext, nonce, key) || null;
|
|
307
|
+
}
|
|
308
|
+
nacl3__default.default.secretbox.keyLength;
|
|
309
|
+
nacl3__default.default.secretbox.nonceLength;
|
|
310
|
+
nacl3__default.default.secretbox.overheadLength;
|
|
311
|
+
nacl3__default.default.box.publicKeyLength;
|
|
312
|
+
nacl3__default.default.box.nonceLength;
|
|
313
|
+
|
|
314
|
+
// src/crypto/safe/secretbox.ts
|
|
315
|
+
function seal(params) {
|
|
316
|
+
return secretboxRaw(params.key, params.plaintext, params.nonce);
|
|
317
|
+
}
|
|
318
|
+
function open(params) {
|
|
319
|
+
return secretboxOpenRaw(params.key, params.ciphertext, params.nonce);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// src/crypto/safe/types.ts
|
|
323
|
+
function asMessage(data) {
|
|
324
|
+
return data;
|
|
325
|
+
}
|
|
326
|
+
function asDilithiumSecretKey(data) {
|
|
327
|
+
return data;
|
|
328
|
+
}
|
|
329
|
+
function asDilithiumPublicKey(data) {
|
|
330
|
+
return data;
|
|
331
|
+
}
|
|
332
|
+
function asKyberEncapsulationKey(data) {
|
|
333
|
+
return data;
|
|
334
|
+
}
|
|
335
|
+
function asKyberDecapsulationKey(data) {
|
|
336
|
+
return data;
|
|
337
|
+
}
|
|
338
|
+
function asX25519PublicKey(data) {
|
|
339
|
+
return data;
|
|
340
|
+
}
|
|
341
|
+
function asX25519SecretKey(data) {
|
|
342
|
+
return data;
|
|
343
|
+
}
|
|
344
|
+
function asSymmetricKey(data) {
|
|
345
|
+
return data;
|
|
346
|
+
}
|
|
347
|
+
function asNonce(data) {
|
|
348
|
+
return data;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// src/crypto/safe/adapters.ts
|
|
352
|
+
function makeSignatureAdapter(noble, manifest) {
|
|
353
|
+
let checked = false;
|
|
354
|
+
const alg = manifest.algorithm;
|
|
355
|
+
function ensureInvariant() {
|
|
356
|
+
if (checked) return;
|
|
357
|
+
const msg = new Uint8Array([222, 173, 190, 239]);
|
|
358
|
+
const { publicKey, secretKey } = noble.keygen();
|
|
359
|
+
const sig = noble.sign(msg, secretKey);
|
|
360
|
+
if (publicKey.length !== manifest.publicKeyBytes) {
|
|
361
|
+
throw new Error(`${alg}: publicKey ${publicKey.length}B, expected ${manifest.publicKeyBytes}B`);
|
|
362
|
+
}
|
|
363
|
+
if (secretKey.length !== manifest.secretKeyBytes) {
|
|
364
|
+
throw new Error(`${alg}: secretKey ${secretKey.length}B, expected ${manifest.secretKeyBytes}B`);
|
|
365
|
+
}
|
|
366
|
+
if (sig.length !== manifest.signatureBytes) {
|
|
367
|
+
throw new Error(`${alg}: signature ${sig.length}B, expected ${manifest.signatureBytes}B`);
|
|
368
|
+
}
|
|
369
|
+
if (!noble.verify(sig, msg, publicKey)) {
|
|
370
|
+
throw new Error(`${alg}: sign/verify roundtrip failed`);
|
|
371
|
+
}
|
|
372
|
+
checked = true;
|
|
373
|
+
}
|
|
374
|
+
return {
|
|
375
|
+
keygen() {
|
|
376
|
+
ensureInvariant();
|
|
377
|
+
const kp = noble.keygen();
|
|
378
|
+
return {
|
|
379
|
+
publicKey: kp.publicKey,
|
|
380
|
+
secretKey: kp.secretKey
|
|
381
|
+
};
|
|
382
|
+
},
|
|
383
|
+
sign(params) {
|
|
384
|
+
ensureInvariant();
|
|
385
|
+
return noble.sign(params.message, params.secretKey);
|
|
386
|
+
},
|
|
387
|
+
verify(params) {
|
|
388
|
+
ensureInvariant();
|
|
389
|
+
return noble.verify(params.signature, params.message, params.publicKey);
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
function asSigMessage(v) {
|
|
394
|
+
return v;
|
|
395
|
+
}
|
|
396
|
+
function makeKemAdapter(noble, manifest) {
|
|
397
|
+
let checked = false;
|
|
398
|
+
const alg = manifest.algorithm;
|
|
399
|
+
function ensureInvariant() {
|
|
400
|
+
if (checked) return;
|
|
401
|
+
const { publicKey, secretKey } = noble.keygen();
|
|
402
|
+
const { ciphertext, sharedSecret: ss1 } = noble.encapsulate(publicKey);
|
|
403
|
+
const ss2 = noble.decapsulate(ciphertext, secretKey);
|
|
404
|
+
if (publicKey.length !== manifest.encapsulationKeyBytes) {
|
|
405
|
+
throw new Error(`${alg}: encapsKey ${publicKey.length}B, expected ${manifest.encapsulationKeyBytes}B`);
|
|
406
|
+
}
|
|
407
|
+
if (secretKey.length !== manifest.decapsulationKeyBytes) {
|
|
408
|
+
throw new Error(`${alg}: decapsKey ${secretKey.length}B, expected ${manifest.decapsulationKeyBytes}B`);
|
|
409
|
+
}
|
|
410
|
+
if (ciphertext.length !== manifest.ciphertextBytes) {
|
|
411
|
+
throw new Error(`${alg}: ciphertext ${ciphertext.length}B, expected ${manifest.ciphertextBytes}B`);
|
|
412
|
+
}
|
|
413
|
+
if (ss1.length !== manifest.sharedSecretBytes) {
|
|
414
|
+
throw new Error(`${alg}: sharedSecret ${ss1.length}B, expected ${manifest.sharedSecretBytes}B`);
|
|
415
|
+
}
|
|
416
|
+
if (ss2.length !== ss1.length) {
|
|
417
|
+
throw new Error(`${alg}: encap/decap shared secret length mismatch`);
|
|
418
|
+
}
|
|
419
|
+
for (let i = 0; i < ss1.length; i++) {
|
|
420
|
+
if (ss1[i] !== ss2[i]) throw new Error(`${alg}: encap/decap shared secrets differ`);
|
|
421
|
+
}
|
|
422
|
+
checked = true;
|
|
423
|
+
}
|
|
424
|
+
return {
|
|
425
|
+
keygen() {
|
|
426
|
+
ensureInvariant();
|
|
427
|
+
const kp = noble.keygen();
|
|
428
|
+
return {
|
|
429
|
+
encapsulationKey: kp.publicKey,
|
|
430
|
+
decapsulationKey: kp.secretKey
|
|
431
|
+
};
|
|
432
|
+
},
|
|
433
|
+
encapsulate(params) {
|
|
434
|
+
ensureInvariant();
|
|
435
|
+
const result = noble.encapsulate(params.encapsulationKey);
|
|
436
|
+
return {
|
|
437
|
+
ciphertext: result.ciphertext,
|
|
438
|
+
sharedSecret: result.sharedSecret
|
|
439
|
+
};
|
|
440
|
+
},
|
|
441
|
+
decapsulate(params) {
|
|
442
|
+
ensureInvariant();
|
|
443
|
+
return noble.decapsulate(params.ciphertext, params.decapsulationKey);
|
|
444
|
+
}
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
function makeDhAdapter(noble, manifest) {
|
|
448
|
+
let checked = false;
|
|
449
|
+
const alg = manifest.algorithm;
|
|
450
|
+
function ensureInvariant() {
|
|
451
|
+
if (checked) return;
|
|
452
|
+
const sk = noble.utils.randomPrivateKey();
|
|
453
|
+
const pk = noble.getPublicKey(sk);
|
|
454
|
+
if (pk.length !== manifest.publicKeyBytes) {
|
|
455
|
+
throw new Error(`${alg}: publicKey ${pk.length}B, expected ${manifest.publicKeyBytes}B`);
|
|
456
|
+
}
|
|
457
|
+
if (sk.length !== manifest.secretKeyBytes) {
|
|
458
|
+
throw new Error(`${alg}: secretKey ${sk.length}B, expected ${manifest.secretKeyBytes}B`);
|
|
459
|
+
}
|
|
460
|
+
const sk2 = noble.utils.randomPrivateKey();
|
|
461
|
+
const pk2 = noble.getPublicKey(sk2);
|
|
462
|
+
const ss1 = noble.getSharedSecret(sk, pk2);
|
|
463
|
+
const ss2 = noble.getSharedSecret(sk2, pk);
|
|
464
|
+
if (ss1.length !== manifest.sharedSecretBytes) {
|
|
465
|
+
throw new Error(`${alg}: sharedSecret ${ss1.length}B, expected ${manifest.sharedSecretBytes}B`);
|
|
466
|
+
}
|
|
467
|
+
for (let i = 0; i < ss1.length; i++) {
|
|
468
|
+
if (ss1[i] !== ss2[i]) throw new Error(`${alg}: DH commutativity failed`);
|
|
469
|
+
}
|
|
470
|
+
checked = true;
|
|
471
|
+
}
|
|
472
|
+
return {
|
|
473
|
+
keygen() {
|
|
474
|
+
ensureInvariant();
|
|
475
|
+
const secretKey = noble.utils.randomPrivateKey();
|
|
476
|
+
const publicKey = noble.getPublicKey(secretKey);
|
|
477
|
+
return {
|
|
478
|
+
publicKey,
|
|
479
|
+
secretKey
|
|
480
|
+
};
|
|
481
|
+
},
|
|
482
|
+
sharedSecret(params) {
|
|
483
|
+
ensureInvariant();
|
|
484
|
+
return noble.getSharedSecret(params.ourSecretKey, params.theirPublicKey);
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
function makeSecretboxAdapter(impl, manifest) {
|
|
489
|
+
let checked = false;
|
|
490
|
+
const alg = manifest.algorithm;
|
|
491
|
+
function ensureInvariant() {
|
|
492
|
+
if (checked) return;
|
|
493
|
+
const key = new Uint8Array(manifest.keyBytes);
|
|
494
|
+
crypto.getRandomValues(key);
|
|
495
|
+
const nonce = new Uint8Array(manifest.nonceBytes);
|
|
496
|
+
crypto.getRandomValues(nonce);
|
|
497
|
+
const plaintext = new Uint8Array([202, 254, 186, 190]);
|
|
498
|
+
const ct = impl.seal(key, plaintext, nonce);
|
|
499
|
+
const overhead = ct.length - plaintext.length;
|
|
500
|
+
if (overhead !== manifest.tagBytes) {
|
|
501
|
+
throw new Error(`${alg}: overhead ${overhead}B, expected ${manifest.tagBytes}B tag`);
|
|
502
|
+
}
|
|
503
|
+
const pt = impl.open(key, ct, nonce);
|
|
504
|
+
if (!pt || pt.length !== plaintext.length) {
|
|
505
|
+
throw new Error(`${alg}: seal/open roundtrip failed`);
|
|
506
|
+
}
|
|
507
|
+
for (let i = 0; i < plaintext.length; i++) {
|
|
508
|
+
if (pt[i] !== plaintext[i]) throw new Error(`${alg}: seal/open roundtrip mismatch`);
|
|
509
|
+
}
|
|
510
|
+
checked = true;
|
|
511
|
+
}
|
|
512
|
+
return {
|
|
513
|
+
seal(params) {
|
|
514
|
+
ensureInvariant();
|
|
515
|
+
return impl.seal(params.key, params.plaintext, params.nonce);
|
|
516
|
+
},
|
|
517
|
+
open(params) {
|
|
518
|
+
ensureInvariant();
|
|
519
|
+
return impl.open(params.key, params.ciphertext, params.nonce);
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
function asBoxKey(v) {
|
|
524
|
+
return v;
|
|
525
|
+
}
|
|
526
|
+
function asBoxNonce(v) {
|
|
527
|
+
return v;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
exports.ML_DSA_65 = ML_DSA_65;
|
|
531
|
+
exports.ML_KEM_768 = ML_KEM_768;
|
|
532
|
+
exports.X25519 = X25519;
|
|
533
|
+
exports.XSALSA20_POLY1305 = XSALSA20_POLY1305;
|
|
534
|
+
exports.asBoxKey = asBoxKey;
|
|
535
|
+
exports.asBoxNonce = asBoxNonce;
|
|
536
|
+
exports.asDilithiumPublicKey = asDilithiumPublicKey;
|
|
537
|
+
exports.asDilithiumSecretKey = asDilithiumSecretKey;
|
|
538
|
+
exports.asKyberDecapsulationKey = asKyberDecapsulationKey;
|
|
539
|
+
exports.asKyberEncapsulationKey = asKyberEncapsulationKey;
|
|
540
|
+
exports.asMessage = asMessage;
|
|
541
|
+
exports.asNonce = asNonce;
|
|
542
|
+
exports.asSigMessage = asSigMessage;
|
|
543
|
+
exports.asSymmetricKey = asSymmetricKey;
|
|
544
|
+
exports.asX25519PublicKey = asX25519PublicKey;
|
|
545
|
+
exports.asX25519SecretKey = asX25519SecretKey;
|
|
546
|
+
exports.assertDhPrimitive = assertDhPrimitive;
|
|
547
|
+
exports.assertKemPrimitive = assertKemPrimitive;
|
|
548
|
+
exports.assertSignaturePrimitive = assertSignaturePrimitive;
|
|
549
|
+
exports.dilithium = dilithium_exports;
|
|
550
|
+
exports.kyber = kyber_exports;
|
|
551
|
+
exports.makeDhAdapter = makeDhAdapter;
|
|
552
|
+
exports.makeKemAdapter = makeKemAdapter;
|
|
553
|
+
exports.makeSecretboxAdapter = makeSecretboxAdapter;
|
|
554
|
+
exports.makeSignatureAdapter = makeSignatureAdapter;
|
|
555
|
+
exports.secretbox = secretbox_exports;
|
|
556
|
+
exports.x25519 = x25519_exports;
|