@vex-chat/crypto 2.0.1 → 2.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.
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
7
+ import {
8
+ getCryptoProfile,
9
+ setCryptoProfile,
10
+ xDH,
11
+ xMakeNonce,
12
+ xRandomBytes,
13
+ XUtils,
14
+ } from "../index.js";
15
+
16
+ afterEach(() => {
17
+ setCryptoProfile("tweetnacl");
18
+ });
19
+
20
+ test("crypto profile defaults to tweetnacl", () => {
21
+ expect(getCryptoProfile()).toBe("tweetnacl");
22
+ });
23
+
24
+ test("fips profile rejects nacl-coupled operations", () => {
25
+ setCryptoProfile("fips");
26
+
27
+ const myPrivateKey = XUtils.decodeHex(
28
+ "918ed243e2c6c507168b20e8b167cff33a10c30e99e8defe28dc2147f5cce703",
29
+ );
30
+ const theirPublicKey = XUtils.decodeHex(
31
+ "6f4cc1ffc4009bd4f94628ba5922e40afa3491f0daa43ec9da0f7dc39bb1c026",
32
+ );
33
+
34
+ expect(() => xDH(myPrivateKey, theirPublicKey)).toThrow(
35
+ 'Crypto profile "fips" does not implement xDH yet.',
36
+ );
37
+ });
38
+
39
+ test("fips profile still supports random bytes", () => {
40
+ setCryptoProfile("fips");
41
+
42
+ const bytes = xRandomBytes(32);
43
+ const nonce = xMakeNonce();
44
+
45
+ expect(bytes.length).toBe(32);
46
+ expect(nonce.length).toBe(24);
47
+ });
48
+
49
+ test("switching back to tweetnacl restores behavior", () => {
50
+ const myPrivateKey = XUtils.decodeHex(
51
+ "918ed243e2c6c507168b20e8b167cff33a10c30e99e8defe28dc2147f5cce703",
52
+ );
53
+ const theirPublicKey = XUtils.decodeHex(
54
+ "6f4cc1ffc4009bd4f94628ba5922e40afa3491f0daa43ec9da0f7dc39bb1c026",
55
+ );
56
+ const correctDerivedKey =
57
+ "19a8594bdcf875ec9d4b8b9615ea8b73a0b327bb64b8f727dd2dee3a603a2230";
58
+
59
+ setCryptoProfile("fips");
60
+ setCryptoProfile("tweetnacl");
61
+
62
+ const derived = XUtils.encodeHex(xDH(myPrivateKey, theirPublicKey));
63
+ expect(derived).toBe(correctDerivedKey);
64
+ });
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
7
+ import {
8
+ setCryptoProfile,
9
+ xBoxKeyPairAsync,
10
+ xDHAsync,
11
+ xSecretboxAsync,
12
+ xSecretboxOpenAsync,
13
+ xSignAsync,
14
+ xSignKeyPairAsync,
15
+ xSignOpenAsync,
16
+ XUtils,
17
+ } from "../index.js";
18
+
19
+ afterEach(() => {
20
+ setCryptoProfile("tweetnacl");
21
+ });
22
+
23
+ test("tweetnacl async wrappers preserve sign/open semantics", async () => {
24
+ setCryptoProfile("tweetnacl");
25
+ const keys = await xSignKeyPairAsync();
26
+ const message = XUtils.decodeUTF8("hello async");
27
+ const signed = await xSignAsync(message, keys.secretKey);
28
+ const opened = await xSignOpenAsync(signed, keys.publicKey);
29
+
30
+ if (opened === null) {
31
+ throw new Error("Expected signed message to verify in tweetnacl mode.");
32
+ }
33
+ expect(XUtils.encodeUTF8(opened)).toBe("hello async");
34
+ });
35
+
36
+ test("fips async sign/open roundtrip", async () => {
37
+ setCryptoProfile("fips");
38
+ const keys = await xSignKeyPairAsync();
39
+ const message = XUtils.decodeUTF8("hello fips");
40
+ const signed = await xSignAsync(message, keys.secretKey);
41
+ const opened = await xSignOpenAsync(signed, keys.publicKey);
42
+
43
+ if (opened === null) {
44
+ throw new Error("Expected signed message to verify in fips mode.");
45
+ }
46
+ expect(XUtils.encodeUTF8(opened)).toBe("hello fips");
47
+ });
48
+
49
+ test("fips async ecdh and aes-gcm roundtrip", async () => {
50
+ setCryptoProfile("fips");
51
+ const alice = await xBoxKeyPairAsync();
52
+ const bob = await xBoxKeyPairAsync();
53
+ const aliceShared = await xDHAsync(alice.secretKey, bob.publicKey);
54
+ const bobShared = await xDHAsync(bob.secretKey, alice.publicKey);
55
+
56
+ expect(XUtils.bytesEqual(aliceShared, bobShared)).toBe(true);
57
+
58
+ const nonce = new Uint8Array(24);
59
+ nonce.set(crypto.getRandomValues(new Uint8Array(24)));
60
+ const plaintext = XUtils.decodeUTF8("portable fips path");
61
+
62
+ const ciphertext = await xSecretboxAsync(plaintext, nonce, aliceShared);
63
+ const decrypted = await xSecretboxOpenAsync(ciphertext, nonce, bobShared);
64
+
65
+ if (decrypted === null) {
66
+ throw new Error("Expected ciphertext to decrypt in fips mode.");
67
+ }
68
+ expect(XUtils.encodeUTF8(decrypted)).toBe("portable fips path");
69
+ });
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import { xConcat, XUtils } from "../index.js";
2
8
 
3
9
  test("xConcat", () => {
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import { xDH, XUtils } from "../index.js";
2
8
 
3
9
  test("xDH", () => {
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import { xEncode, XUtils } from "../index.js";
2
8
 
3
9
  test("xEncode", () => {
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import { createHmac } from "crypto";
2
8
 
3
9
  import { Packr } from "msgpackr";
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2020-2026 Vex Heavy Industries LLC
3
+ * Licensed under AGPL-3.0. See LICENSE for details.
4
+ * Commercial licenses available at vex.wtf
5
+ */
6
+
1
7
  import { xMnemonic, XUtils } from "../index.js";
2
8
 
3
9
  test("xMnemonic", () => {