@f0rest8/metamorphic-crypto 0.7.0 → 0.7.2
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 +44 -1
- package/metamorphic_crypto.d.ts +2 -2
- package/metamorphic_crypto.js +17 -17
- package/metamorphic_crypto_bg.wasm +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @f0rest8/metamorphic-crypto
|
|
2
2
|
|
|
3
|
-
Zero-knowledge end-to-end encryption with post-quantum hybrid KEM (ML-KEM-512/768/1024 + X25519).
|
|
3
|
+
Zero-knowledge end-to-end encryption with post-quantum hybrid KEM (ML-KEM-512/768/1024 + X25519), hybrid PQ signatures (ML-DSA + Ed25519), and an opt-in CNSA 2.0 suite axis.
|
|
4
4
|
|
|
5
5
|
Built for [Metamorphic](https://metamorphic.app) and [Mosslet](https://mosslet.com) — privacy-first apps by [Moss Piglet Corporation](https://mosspiglet.dev) where all user data is encrypted client-side and the server only stores opaque ciphertext.
|
|
6
6
|
|
|
@@ -218,6 +218,49 @@ across native Rust, WASM, and the Elixir NIF.
|
|
|
218
218
|
> composite remains at least as strong as Ed25519 even if a flaw is found in the
|
|
219
219
|
> young post-quantum implementation. Pinned and tracked for the FIPS-mode roadmap.
|
|
220
220
|
|
|
221
|
+
### CNSA 2.0 suite axis (opt-in)
|
|
222
|
+
|
|
223
|
+
Everything above is the default **`hybrid`** suite (classical+PQ strict-AND). If
|
|
224
|
+
you have no specific mandate, that is the recommended choice. For deployments
|
|
225
|
+
that must follow the NSA's **CNSA 2.0** suite (NIST IR 8547), a `suite` argument
|
|
226
|
+
raises the posture. It is **orthogonal** to the `"cat1"`/`"cat3"`/`"cat5"` level,
|
|
227
|
+
so you have two independent knobs.
|
|
228
|
+
|
|
229
|
+
| `suite` string | What it is | Status |
|
|
230
|
+
|----------------|------------|--------|
|
|
231
|
+
| `"hybrid"` | Existing classical+PQ strict-AND. Byte-for-byte unchanged. | **Default, recommended** |
|
|
232
|
+
| `"hybridMatched"` | Classical partner matched to the PQ category (KEM: Cat-3→X448, Cat-5→P-521 · Sign: Cat-3→Ed448, Cat-5→ECDSA-P-521) | Opt-in |
|
|
233
|
+
| `"pureCnsa2"` | Pure post-quantum, no classical half (ML-KEM-1024 / AES-256-GCM; ML-DSA-87) | Opt-in, **Cat-5 only** |
|
|
234
|
+
|
|
235
|
+
```js
|
|
236
|
+
import {
|
|
237
|
+
generateHybridKeyPairSuite, hybridSealSuite, hybridOpenWithContext,
|
|
238
|
+
generateSigningKeyPairSuite, sign, verify,
|
|
239
|
+
} from "@f0rest8/metamorphic-crypto";
|
|
240
|
+
|
|
241
|
+
// Pure CNSA-2.0 KEM box (ML-KEM-1024 + AES-256-GCM)
|
|
242
|
+
const kp = generateHybridKeyPairSuite("pureCnsa2", "cat5"); // { publicKey, secretKey }
|
|
243
|
+
const sealed = hybridSealSuite(plaintextBase64, kp.publicKey, "pureCnsa2", "cat5");
|
|
244
|
+
// Open with the context label used at seal time (default "metamorphic/seal/v1"):
|
|
245
|
+
const opened = hybridOpenWithContext(sealed, kp.secretKey, "metamorphic/seal/v1"); // base64
|
|
246
|
+
|
|
247
|
+
// Pure ML-DSA-87 signatures — sign/verify auto-detect the suite from the tag
|
|
248
|
+
const sk = generateSigningKeyPairSuite("pureCnsa2", "cat5");
|
|
249
|
+
const sig = sign(btoa("checkpoint"), "metamorphic/sign/v1", sk.secretKey);
|
|
250
|
+
const ok = verify(btoa("checkpoint"), "metamorphic/sign/v1", sig, sk.publicKey); // true
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
The new suites bind a versioned **context label** (`"<namespace>/<purpose>/v<major>"`)
|
|
254
|
+
into the seal — use `hybridSealSuiteWithContext(..., "mosslet/seal/v1")` for a
|
|
255
|
+
custom per-tenant namespace and open with the same label. `sealForUserWithSuite`
|
|
256
|
+
mirrors `sealForUser` with the suite/level appended (legacy X25519 fallback when
|
|
257
|
+
no PQ key is present).
|
|
258
|
+
|
|
259
|
+
> **Honest claims.** "CNSA 2.0 algorithm suite, NCC-audited components,
|
|
260
|
+
> pure-Rust, memory-safe (`forbid-unsafe`)" — **not** "FIPS 140-3 validated."
|
|
261
|
+
> `pureCnsa2` drops the classical backstop, so the strict-AND `hybrid` default
|
|
262
|
+
> stays recommended until the lattice implementations are independently audited.
|
|
263
|
+
|
|
221
264
|
## Security levels
|
|
222
265
|
|
|
223
266
|
| Level | ML-KEM | NIST Category | Equivalent | Default |
|
package/metamorphic_crypto.d.ts
CHANGED
|
@@ -265,10 +265,10 @@ export interface InitOutput {
|
|
|
265
265
|
readonly deriveSigningPublicKey: (a: number, b: number, c: number) => void;
|
|
266
266
|
readonly sign: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
267
267
|
readonly verify: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => void;
|
|
268
|
-
readonly decryptPrivateKeyWithRecovery: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
269
|
-
readonly decryptSecretboxToString: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
270
268
|
readonly encryptSecretboxString: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
271
269
|
readonly encryptPrivateKeyForRecovery: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
270
|
+
readonly decryptSecretboxToString: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
271
|
+
readonly decryptPrivateKeyWithRecovery: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
272
272
|
readonly __wbindgen_export: (a: number, b: number) => number;
|
|
273
273
|
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
274
274
|
readonly __wbindgen_export3: (a: number) => void;
|
package/metamorphic_crypto.js
CHANGED
|
@@ -1221,34 +1221,34 @@ export function verify(message_b64, context, signature_b64, public_key_b64) {
|
|
|
1221
1221
|
function __wbg_get_imports() {
|
|
1222
1222
|
const import0 = {
|
|
1223
1223
|
__proto__: null,
|
|
1224
|
-
|
|
1224
|
+
__wbg___wbindgen_debug_string_c25d447a39f5578f: function(arg0, arg1) {
|
|
1225
1225
|
const ret = debugString(getObject(arg1));
|
|
1226
1226
|
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
1227
1227
|
const len1 = WASM_VECTOR_LEN;
|
|
1228
1228
|
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
1229
1229
|
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
1230
1230
|
},
|
|
1231
|
-
|
|
1231
|
+
__wbg___wbindgen_is_function_1ff95bcc5517c252: function(arg0) {
|
|
1232
1232
|
const ret = typeof(getObject(arg0)) === 'function';
|
|
1233
1233
|
return ret;
|
|
1234
1234
|
},
|
|
1235
|
-
|
|
1235
|
+
__wbg___wbindgen_is_object_a27215656b807791: function(arg0) {
|
|
1236
1236
|
const val = getObject(arg0);
|
|
1237
1237
|
const ret = typeof(val) === 'object' && val !== null;
|
|
1238
1238
|
return ret;
|
|
1239
1239
|
},
|
|
1240
|
-
|
|
1240
|
+
__wbg___wbindgen_is_string_ea5e6cc2e4141dfe: function(arg0) {
|
|
1241
1241
|
const ret = typeof(getObject(arg0)) === 'string';
|
|
1242
1242
|
return ret;
|
|
1243
1243
|
},
|
|
1244
|
-
|
|
1244
|
+
__wbg___wbindgen_is_undefined_c05833b95a3cf397: function(arg0) {
|
|
1245
1245
|
const ret = getObject(arg0) === undefined;
|
|
1246
1246
|
return ret;
|
|
1247
1247
|
},
|
|
1248
|
-
|
|
1248
|
+
__wbg___wbindgen_throw_344f42d3211c4765: function(arg0, arg1) {
|
|
1249
1249
|
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
1250
1250
|
},
|
|
1251
|
-
|
|
1251
|
+
__wbg_call_a6e5c5dce5018821: function() { return handleError(function (arg0, arg1, arg2) {
|
|
1252
1252
|
const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
|
|
1253
1253
|
return addHeapObject(ret);
|
|
1254
1254
|
}, arguments); },
|
|
@@ -1259,7 +1259,7 @@ function __wbg_get_imports() {
|
|
|
1259
1259
|
__wbg_getRandomValues_c44a50d8cfdaebeb: function() { return handleError(function (arg0, arg1) {
|
|
1260
1260
|
getObject(arg0).getRandomValues(getObject(arg1));
|
|
1261
1261
|
}, arguments); },
|
|
1262
|
-
|
|
1262
|
+
__wbg_length_1f0964f4a5e2c6d8: function(arg0) {
|
|
1263
1263
|
const ret = getObject(arg0).length;
|
|
1264
1264
|
return ret;
|
|
1265
1265
|
},
|
|
@@ -1267,11 +1267,11 @@ function __wbg_get_imports() {
|
|
|
1267
1267
|
const ret = getObject(arg0).msCrypto;
|
|
1268
1268
|
return addHeapObject(ret);
|
|
1269
1269
|
},
|
|
1270
|
-
|
|
1270
|
+
__wbg_new_da52cf8fe3429cb2: function() {
|
|
1271
1271
|
const ret = new Object();
|
|
1272
1272
|
return addHeapObject(ret);
|
|
1273
1273
|
},
|
|
1274
|
-
|
|
1274
|
+
__wbg_new_with_length_e6785c33c8e4cce8: function(arg0) {
|
|
1275
1275
|
const ret = new Uint8Array(arg0 >>> 0);
|
|
1276
1276
|
return addHeapObject(ret);
|
|
1277
1277
|
},
|
|
@@ -1283,7 +1283,7 @@ function __wbg_get_imports() {
|
|
|
1283
1283
|
const ret = getObject(arg0).process;
|
|
1284
1284
|
return addHeapObject(ret);
|
|
1285
1285
|
},
|
|
1286
|
-
|
|
1286
|
+
__wbg_prototypesetcall_4770620bbe4688a0: function(arg0, arg1, arg2) {
|
|
1287
1287
|
Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), getObject(arg2));
|
|
1288
1288
|
},
|
|
1289
1289
|
__wbg_randomFillSync_6c25eac9869eb53c: function() { return handleError(function (arg0, arg1) {
|
|
@@ -1293,27 +1293,27 @@ function __wbg_get_imports() {
|
|
|
1293
1293
|
const ret = module.require;
|
|
1294
1294
|
return addHeapObject(ret);
|
|
1295
1295
|
}, arguments); },
|
|
1296
|
-
|
|
1296
|
+
__wbg_set_8535240470bf2500: function() { return handleError(function (arg0, arg1, arg2) {
|
|
1297
1297
|
const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2));
|
|
1298
1298
|
return ret;
|
|
1299
1299
|
}, arguments); },
|
|
1300
|
-
|
|
1300
|
+
__wbg_static_accessor_GLOBAL_4ef717fb391d88b7: function() {
|
|
1301
1301
|
const ret = typeof global === 'undefined' ? null : global;
|
|
1302
1302
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
|
1303
1303
|
},
|
|
1304
|
-
|
|
1304
|
+
__wbg_static_accessor_GLOBAL_THIS_8d1badc68b5a74f4: function() {
|
|
1305
1305
|
const ret = typeof globalThis === 'undefined' ? null : globalThis;
|
|
1306
1306
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
|
1307
1307
|
},
|
|
1308
|
-
|
|
1308
|
+
__wbg_static_accessor_SELF_146583524fe1469b: function() {
|
|
1309
1309
|
const ret = typeof self === 'undefined' ? null : self;
|
|
1310
1310
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
|
1311
1311
|
},
|
|
1312
|
-
|
|
1312
|
+
__wbg_static_accessor_WINDOW_f2829a2234d7819e: function() {
|
|
1313
1313
|
const ret = typeof window === 'undefined' ? null : window;
|
|
1314
1314
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
|
1315
1315
|
},
|
|
1316
|
-
|
|
1316
|
+
__wbg_subarray_3ed232c8a6baee09: function(arg0, arg1, arg2) {
|
|
1317
1317
|
const ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0);
|
|
1318
1318
|
return addHeapObject(ret);
|
|
1319
1319
|
},
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@f0rest8/metamorphic-crypto",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"description": "Zero-knowledge end-to-end encryption with post-quantum hybrid KEM (ML-KEM + X25519) and an opt-in CNSA 2.0 suite axis (matched-strength hybrid + pure ML-KEM-1024 / ML-DSA-87 / AES-256-GCM)",
|
|
5
|
-
"version": "0.7.
|
|
5
|
+
"version": "0.7.2",
|
|
6
6
|
"license": "MIT OR Apache-2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|