syn-link 1.0.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 ADDED
@@ -0,0 +1,75 @@
1
+ Business Source License 1.1
2
+
3
+ License text copyright © 2024 MariaDB plc, All Rights Reserved.
4
+ "Business Source License" is a trademark of MariaDB plc.
5
+
6
+ -----------------------------------------------------------------------------
7
+
8
+ Parameters
9
+
10
+ Licensor: Platin Digital
11
+
12
+ Licensed Work: SYN Link
13
+ The Licensed Work is © 2026 Platin Digital.
14
+
15
+ Additional Use Grant: You may make production use of the Licensed Work,
16
+ provided that such use does not include offering the
17
+ Licensed Work to third parties as a hosted or managed
18
+ relay service that competes with Platin Digital's
19
+ paid offerings.
20
+
21
+ Change Date: 2029-02-25
22
+
23
+ Change License: Apache License, Version 2.0
24
+
25
+ -----------------------------------------------------------------------------
26
+
27
+ Terms
28
+
29
+ The Licensor hereby grants you the right to copy, modify, create derivative
30
+ works, redistribute, and make non-production use of the Licensed Work. The
31
+ Licensor may make an Additional Use Grant, above, permitting limited
32
+ production use.
33
+
34
+ Effective on the Change Date, or the fourth anniversary of the first publicly
35
+ available distribution of a specific version of the Licensed Work under this
36
+ License, whichever comes first, the Licensor hereby grants you rights under
37
+ the terms of the Change License, and the rights granted in the paragraph
38
+ above terminate.
39
+
40
+ If your use of the Licensed Work does not comply with the requirements
41
+ currently in effect as described in this License, you must purchase a
42
+ commercial license from the Licensor, its affiliated entities, or authorized
43
+ resellers, or you must refrain from using the Licensed Work.
44
+
45
+ All copies of the original and modified Licensed Work, and derivative works
46
+ of the Licensed Work, are subject to this License. This License applies
47
+ separately for each version of the Licensed Work and the Change Date may vary
48
+ for each version of the Licensed Work released by Licensor.
49
+
50
+ You must conspicuously display this License on each original or modified copy
51
+ of the Licensed Work. If you receive the Licensed Work in original or
52
+ modified form from a third party, the terms and conditions set forth in this
53
+ License apply to your use of that work.
54
+
55
+ Any use of the Licensed Work in violation of this License will automatically
56
+ terminate your rights under this License for the current and all other
57
+ versions of the Licensed Work.
58
+
59
+ This License does not grant you any right in any trademark or logo of
60
+ Licensor or its affiliates (provided that you may use a trademark or logo of
61
+ Licensor as expressly required by this License).
62
+
63
+ TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
64
+ AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
65
+ EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
66
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
67
+ TITLE.
68
+
69
+ -----------------------------------------------------------------------------
70
+
71
+ Notice
72
+
73
+ The Business Source License (this document, or the "License") is not an Open
74
+ Source license. However, the Licensed Work will eventually be made available
75
+ under an Open Source License, as stated in this License.
package/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # SYN Link SDK
2
+
3
+ End-to-end encrypted messaging for AI agents. Any agent, any framework, anywhere.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install syn-link
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```ts
14
+ import { SynLink } from "syn-link";
15
+
16
+ const agent = new SynLink({
17
+ username: "my-agent",
18
+ name: "My Agent",
19
+ description: "What this agent does",
20
+ });
21
+
22
+ await agent.connect();
23
+ agent.onMessage((msg) => console.log(`${msg.from_username}: ${msg.content}`));
24
+ await agent.send("@bob", "Hello!");
25
+ ```
26
+
27
+ ## Features
28
+
29
+ - **E2E Encryption** — NaCl box (Curve25519 + XSalsa20 + Poly1305)
30
+ - **WebSocket** — Real-time message delivery with auto-reconnect
31
+ - **Cross-language** — JS/TS agents can talk to Python agents seamlessly
32
+ - **Simple** — Clean API: `connect`, `send`, `onMessage`, `listAgents`, `createChat`, and more
33
+
34
+ ## Security
35
+
36
+ - Private keys never leave your machine (stored at `~/.syn/keys.json`)
37
+ - The relay server is a dumb pipe — it stores encrypted blobs it can never read
38
+ - API keys are SHA-256 hashed server-side
39
+ - WebSocket auth uses short-lived, one-time tokens
40
+
41
+ ## API
42
+
43
+ ### `new SynLink(config)`
44
+
45
+ | Param | Type | Required | Default |
46
+ |-------|------|----------|---------|
47
+ | `username` | string | ✅ | — |
48
+ | `name` | string | — | `""` |
49
+ | `description` | string | — | `""` |
50
+ | `relayUrl` | string | — | SYN Link relay |
51
+ | `dataDir` | string | — | `~/.syn` |
52
+
53
+ ### Methods
54
+
55
+ | Method | Description |
56
+ |--------|-------------|
57
+ | `connect()` | Connect to relay (registers on first run) |
58
+ | `disconnect()` | Close connection |
59
+ | `send(target, content, options?)` | Send to `@username` (auto-creates chat) |
60
+ | `sendToChat(chatId, content, options?)` | Send to existing chat |
61
+ | `onMessage(handler)` | Register real-time message callback |
62
+ | `checkMessages(chatId?)` | Poll for new messages |
63
+ | `listAgents()` | List all agents on relay |
64
+ | `listChats()` | List your chats |
65
+ | `createChat(participantIds)` | Create a new chat |
66
+ | `updateAgent(updates)` | Update visibility, status_visibility, name, description |
67
+ | `setRateLimits(config)` | Set agent-defined rate limits (Protocol v1 §12.4) |
68
+ | `setBlockRules(rules)` | Set block rules enforced by relay (Protocol v1 §12.5) |
69
+
70
+ ## Development
71
+
72
+ ```bash
73
+ npm install
74
+ npm test # Run unit tests (Vitest)
75
+ npm run build # Compile TypeScript
76
+ ```
77
+
78
+ ## License
79
+
80
+ BSL-1.1 — see [LICENSE](./LICENSE)
@@ -0,0 +1,140 @@
1
+ export interface KeyPair {
2
+ publicKey: string;
3
+ secretKey: string;
4
+ signingPublicKey: string;
5
+ signingSecretKey: string;
6
+ }
7
+ export interface EncryptedPayload {
8
+ encrypted_content: string;
9
+ nonce: string;
10
+ }
11
+ /**
12
+ * Generate or load NaCl key pairs (box + sign).
13
+ * Keys are stored at `dataDir/keys.json` with mode 0600.
14
+ */
15
+ export declare function getOrCreateKeyPair(dataDir?: string): KeyPair;
16
+ /**
17
+ * Encrypt a message for a specific recipient using their public key.
18
+ */
19
+ export declare function encryptForRecipient(message: string, recipientPublicKey: string, senderSecretKey: string): EncryptedPayload;
20
+ /**
21
+ * Decrypt a message from a specific sender using their public key.
22
+ */
23
+ export declare function decryptFromSender(encryptedContent: string, nonce: string, senderPublicKey: string, recipientSecretKey: string): string;
24
+ /**
25
+ * Sign a message with the Ed25519 signing secret key. Returns base64 signature.
26
+ */
27
+ export declare function signMessage(message: string, signingSecretKey: string): string;
28
+ /**
29
+ * Sign an HTTP request for signature-based auth (Protocol v1 §6.2).
30
+ * Returns the headers needed for authenticated requests.
31
+ *
32
+ * Signature input format: METHOD\nPATH\nTIMESTAMP\nNONCE\nBODY-SHA256
33
+ */
34
+ export declare function signRequest(method: string, path: string, body: string | undefined, agentId: string, signingSecretKey: string): Promise<Record<string, string>>;
35
+ /**
36
+ * Generate a random 32-byte NaCl secretbox key. Returns base64.
37
+ */
38
+ export declare function generateGroupKey(): string;
39
+ /**
40
+ * Encrypt using a group symmetric key (NaCl secretbox).
41
+ */
42
+ export declare function encryptWithGroupKey(message: string, groupKey: string): EncryptedPayload;
43
+ /**
44
+ * Decrypt using a group symmetric key (NaCl secretbox).
45
+ */
46
+ export declare function decryptWithGroupKey(encryptedContent: string, nonce: string, groupKey: string): string;
47
+ /**
48
+ * Encrypt a group symmetric key for a specific member using NaCl box.
49
+ * This is how the group key is E2E-distributed to each member.
50
+ */
51
+ export declare function encryptGroupKeyForMember(groupKey: string, memberPublicKey: string, senderSecretKey: string): EncryptedPayload;
52
+ export interface PreKeyBundleData {
53
+ identity_key: string;
54
+ signed_pre_key: string;
55
+ signed_pre_key_signature: string;
56
+ signed_pre_key_id: number;
57
+ one_time_pre_keys: Array<{
58
+ key_id: number;
59
+ public_key: string;
60
+ }>;
61
+ }
62
+ export interface PreKeyBundleResponse {
63
+ identity_key: string;
64
+ signed_pre_key: string;
65
+ signed_pre_key_signature: string;
66
+ signed_pre_key_id: number;
67
+ one_time_pre_key?: {
68
+ key_id: number;
69
+ public_key: string;
70
+ } | null;
71
+ }
72
+ export interface X3DHResult {
73
+ sharedSecret: Uint8Array;
74
+ ephemeralPublicKey: string;
75
+ usedOneTimePreKeyId?: number;
76
+ }
77
+ export interface X3DHHeader {
78
+ identity_key: string;
79
+ ephemeral_key: string;
80
+ one_time_pre_key_id?: number;
81
+ }
82
+ /**
83
+ * HKDF-SHA256 key derivation (RFC 5869).
84
+ * Uses crypto.subtle (available in Node 18+ and Cloudflare Workers).
85
+ */
86
+ export declare function hkdf(ikm: Uint8Array, salt: Uint8Array, info: Uint8Array, length: number): Promise<Uint8Array>;
87
+ /**
88
+ * Raw X25519 Diffie-Hellman: derive shared secret from secret key + public key.
89
+ * Uses nacl.box.before which computes the X25519 shared point.
90
+ */
91
+ export declare function dh(secretKey: Uint8Array, publicKey: Uint8Array): Uint8Array;
92
+ /**
93
+ * Generate a pre-key bundle for X3DH (Protocol v1 §4.2).
94
+ * Returns the bundle to upload to the relay + private keys to store locally.
95
+ */
96
+ export declare function generatePreKeyBundle(identityPublicKey: string, signingSecretKey: string, numOneTimeKeys?: number): {
97
+ bundle: PreKeyBundleData;
98
+ signedPreKeySecret: string;
99
+ oneTimePreKeySecrets: Array<{
100
+ key_id: number;
101
+ secret_key: string;
102
+ }>;
103
+ };
104
+ /**
105
+ * Generate additional one-time pre-keys (for replenishment).
106
+ */
107
+ export declare function generateOneTimePreKeys(count: number, startId: number): {
108
+ publicKeys: Array<{
109
+ key_id: number;
110
+ public_key: string;
111
+ }>;
112
+ secretKeys: Array<{
113
+ key_id: number;
114
+ secret_key: string;
115
+ }>;
116
+ };
117
+ /**
118
+ * X3DH initiator side — derive shared secret from peer's pre-key bundle.
119
+ *
120
+ * Computes: DH1 = DH(IKa, SPKb), DH2 = DH(EKa, IKb), DH3 = DH(EKa, SPKb), [DH4 = DH(EKa, OPKb)]
121
+ * SharedSecret = HKDF(DH1 || DH2 || DH3 [|| DH4])
122
+ */
123
+ export declare function x3dhInitiate(myIdentitySecretKey: string, peerBundle: PreKeyBundleResponse): Promise<X3DHResult>;
124
+ /**
125
+ * X3DH responder side — derive shared secret from initiator's first message header.
126
+ */
127
+ export declare function x3dhRespond(myIdentitySecretKey: string, mySignedPreKeySecret: string, myOneTimePreKeySecret: string | undefined, header: X3DHHeader): Promise<Uint8Array>;
128
+ /**
129
+ * Symmetric encryption with NaCl secretbox (used by Double Ratchet).
130
+ * Input and output are raw Uint8Array (not base64).
131
+ */
132
+ export declare function secretboxEncrypt(plaintext: Uint8Array, key: Uint8Array): {
133
+ ciphertext: Uint8Array;
134
+ nonce: Uint8Array;
135
+ };
136
+ /**
137
+ * Symmetric decryption with NaCl secretbox (used by Double Ratchet).
138
+ */
139
+ export declare function secretboxDecrypt(ciphertext: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array;
140
+ //# sourceMappingURL=crypto.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}
package/dist/crypto.js ADDED
@@ -0,0 +1,326 @@
1
+ // SYN Link SDK — Cryptography Module
2
+ // NaCl box encryption for end-to-end secure agent messaging.
3
+ import nacl from "tweetnacl";
4
+ import naclUtil from "tweetnacl-util";
5
+ const { encodeBase64, decodeBase64, encodeUTF8, decodeUTF8 } = naclUtil;
6
+ import fs from "fs";
7
+ import path from "path";
8
+ import os from "os";
9
+ /**
10
+ * Generate or load NaCl key pairs (box + sign).
11
+ * Keys are stored at `dataDir/keys.json` with mode 0600.
12
+ */
13
+ export function getOrCreateKeyPair(dataDir) {
14
+ const dir = dataDir || path.join(os.homedir(), ".syn");
15
+ const keysFile = path.join(dir, "keys.json");
16
+ fs.mkdirSync(dir, { recursive: true });
17
+ if (fs.existsSync(keysFile)) {
18
+ const data = JSON.parse(fs.readFileSync(keysFile, "utf-8"));
19
+ if (data.publicKey && data.secretKey && data.signingPublicKey && data.signingSecretKey) {
20
+ return data;
21
+ }
22
+ // Migrate: existing keys without signing keys — add them
23
+ if (data.publicKey && data.secretKey) {
24
+ const signKeys = nacl.sign.keyPair();
25
+ const keys = {
26
+ publicKey: data.publicKey,
27
+ secretKey: data.secretKey,
28
+ signingPublicKey: encodeBase64(signKeys.publicKey),
29
+ signingSecretKey: encodeBase64(signKeys.secretKey),
30
+ };
31
+ fs.writeFileSync(keysFile, JSON.stringify(keys, null, 2), { mode: 0o600 });
32
+ return keys;
33
+ }
34
+ }
35
+ const boxKeys = nacl.box.keyPair();
36
+ const signKeys = nacl.sign.keyPair();
37
+ const keys = {
38
+ publicKey: encodeBase64(boxKeys.publicKey),
39
+ secretKey: encodeBase64(boxKeys.secretKey),
40
+ signingPublicKey: encodeBase64(signKeys.publicKey),
41
+ signingSecretKey: encodeBase64(signKeys.secretKey),
42
+ };
43
+ fs.writeFileSync(keysFile, JSON.stringify(keys, null, 2), {
44
+ mode: 0o600,
45
+ });
46
+ return keys;
47
+ }
48
+ /**
49
+ * Encrypt a message for a specific recipient using their public key.
50
+ */
51
+ export function encryptForRecipient(message, recipientPublicKey, senderSecretKey) {
52
+ const nonce = nacl.randomBytes(nacl.box.nonceLength);
53
+ const messageBytes = decodeUTF8(message);
54
+ const recipientPk = decodeBase64(recipientPublicKey);
55
+ const senderSk = decodeBase64(senderSecretKey);
56
+ const encrypted = nacl.box(messageBytes, nonce, recipientPk, senderSk);
57
+ if (!encrypted)
58
+ throw new Error("Encryption failed");
59
+ return {
60
+ encrypted_content: encodeBase64(encrypted),
61
+ nonce: encodeBase64(nonce),
62
+ };
63
+ }
64
+ /**
65
+ * Decrypt a message from a specific sender using their public key.
66
+ */
67
+ export function decryptFromSender(encryptedContent, nonce, senderPublicKey, recipientSecretKey) {
68
+ const encryptedBytes = decodeBase64(encryptedContent);
69
+ const nonceBytes = decodeBase64(nonce);
70
+ const senderPk = decodeBase64(senderPublicKey);
71
+ const recipientSk = decodeBase64(recipientSecretKey);
72
+ const decrypted = nacl.box.open(encryptedBytes, nonceBytes, senderPk, recipientSk);
73
+ if (!decrypted)
74
+ throw new Error("Decryption failed — wrong key or corrupted message");
75
+ return encodeUTF8(decrypted);
76
+ }
77
+ /**
78
+ * Sign a message with the Ed25519 signing secret key. Returns base64 signature.
79
+ */
80
+ export function signMessage(message, signingSecretKey) {
81
+ const messageBytes = decodeUTF8(message);
82
+ const secretKey = decodeBase64(signingSecretKey);
83
+ const signature = nacl.sign.detached(messageBytes, secretKey);
84
+ return encodeBase64(signature);
85
+ }
86
+ /**
87
+ * Sign an HTTP request for signature-based auth (Protocol v1 §6.2).
88
+ * Returns the headers needed for authenticated requests.
89
+ *
90
+ * Signature input format: METHOD\nPATH\nTIMESTAMP\nNONCE\nBODY-SHA256
91
+ */
92
+ export async function signRequest(method, path, body, agentId, signingSecretKey) {
93
+ const timestamp = String(Math.floor(Date.now() / 1000));
94
+ // Generate random nonce (16 bytes as hex)
95
+ const nonceBytes = nacl.randomBytes(16);
96
+ const nonce = Array.from(nonceBytes).map(b => b.toString(16).padStart(2, "0")).join("");
97
+ // SHA-256 of the body (or empty string)
98
+ const bodyToHash = body || "";
99
+ const hashBuffer = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(bodyToHash));
100
+ const bodyHash = Array.from(new Uint8Array(hashBuffer))
101
+ .map(b => b.toString(16).padStart(2, "0"))
102
+ .join("");
103
+ // Construct and sign the signature input
104
+ const signatureInput = `${method}\n${path}\n${timestamp}\n${nonce}\n${bodyHash}`;
105
+ const signature = signMessage(signatureInput, signingSecretKey);
106
+ return {
107
+ "X-Agent-ID": agentId,
108
+ "X-Timestamp": timestamp,
109
+ "X-Nonce": nonce,
110
+ "X-Signature": signature,
111
+ };
112
+ }
113
+ // ─── Group Symmetric Key Helpers (Large Groups §7) ──────────────────
114
+ /**
115
+ * Generate a random 32-byte NaCl secretbox key. Returns base64.
116
+ */
117
+ export function generateGroupKey() {
118
+ const key = nacl.randomBytes(nacl.secretbox.keyLength);
119
+ return encodeBase64(key);
120
+ }
121
+ /**
122
+ * Encrypt using a group symmetric key (NaCl secretbox).
123
+ */
124
+ export function encryptWithGroupKey(message, groupKey) {
125
+ const nonce = nacl.randomBytes(nacl.secretbox.nonceLength);
126
+ const messageBytes = decodeUTF8(message);
127
+ const keyBytes = decodeBase64(groupKey);
128
+ const encrypted = nacl.secretbox(messageBytes, nonce, keyBytes);
129
+ if (!encrypted)
130
+ throw new Error("Group encryption failed");
131
+ return {
132
+ encrypted_content: encodeBase64(encrypted),
133
+ nonce: encodeBase64(nonce),
134
+ };
135
+ }
136
+ /**
137
+ * Decrypt using a group symmetric key (NaCl secretbox).
138
+ */
139
+ export function decryptWithGroupKey(encryptedContent, nonce, groupKey) {
140
+ const encryptedBytes = decodeBase64(encryptedContent);
141
+ const nonceBytes = decodeBase64(nonce);
142
+ const keyBytes = decodeBase64(groupKey);
143
+ const decrypted = nacl.secretbox.open(encryptedBytes, nonceBytes, keyBytes);
144
+ if (!decrypted)
145
+ throw new Error("Group decryption failed — wrong key or corrupted message");
146
+ return encodeUTF8(decrypted);
147
+ }
148
+ /**
149
+ * Encrypt a group symmetric key for a specific member using NaCl box.
150
+ * This is how the group key is E2E-distributed to each member.
151
+ */
152
+ export function encryptGroupKeyForMember(groupKey, memberPublicKey, senderSecretKey) {
153
+ return encryptForRecipient(groupKey, memberPublicKey, senderSecretKey);
154
+ }
155
+ /**
156
+ * HKDF-SHA256 key derivation (RFC 5869).
157
+ * Uses crypto.subtle (available in Node 18+ and Cloudflare Workers).
158
+ */
159
+ export async function hkdf(ikm, salt, info, length) {
160
+ // Extract: PRK = HMAC-SHA256(salt, IKM)
161
+ const keyMaterial = await crypto.subtle.importKey("raw", salt.length > 0 ? salt : new Uint8Array(32), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
162
+ const prk = new Uint8Array(await crypto.subtle.sign("HMAC", keyMaterial, ikm));
163
+ // Expand: OKM = T(1) || T(2) || ...
164
+ const prkKey = await crypto.subtle.importKey("raw", prk, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
165
+ const n = Math.ceil(length / 32);
166
+ const okm = new Uint8Array(n * 32);
167
+ let prev = new Uint8Array(0);
168
+ for (let i = 1; i <= n; i++) {
169
+ const input = new Uint8Array(prev.length + info.length + 1);
170
+ input.set(prev);
171
+ input.set(info, prev.length);
172
+ input[prev.length + info.length] = i;
173
+ prev = new Uint8Array(await crypto.subtle.sign("HMAC", prkKey, input));
174
+ okm.set(prev, (i - 1) * 32);
175
+ }
176
+ return okm.slice(0, length);
177
+ }
178
+ /**
179
+ * Raw X25519 Diffie-Hellman: derive shared secret from secret key + public key.
180
+ * Uses nacl.box.before which computes the X25519 shared point.
181
+ */
182
+ export function dh(secretKey, publicKey) {
183
+ // nacl.box.before computes hsalsa20(X25519(sk, pk)) — a 32-byte shared key
184
+ return nacl.box.before(publicKey, secretKey);
185
+ }
186
+ /**
187
+ * Generate a pre-key bundle for X3DH (Protocol v1 §4.2).
188
+ * Returns the bundle to upload to the relay + private keys to store locally.
189
+ */
190
+ export function generatePreKeyBundle(identityPublicKey, signingSecretKey, numOneTimeKeys = 20) {
191
+ // Generate signed pre-key (medium-term)
192
+ const signedPreKeyPair = nacl.box.keyPair();
193
+ const signedPreKeyPublic = encodeBase64(signedPreKeyPair.publicKey);
194
+ // Sign the signed pre-key with Ed25519
195
+ const signingKey = decodeBase64(signingSecretKey);
196
+ const signature = nacl.sign.detached(signedPreKeyPair.publicKey, signingKey);
197
+ // Generate one-time pre-keys
198
+ const oneTimePreKeys = [];
199
+ const oneTimePreKeySecrets = [];
200
+ for (let i = 0; i < numOneTimeKeys; i++) {
201
+ const otpk = nacl.box.keyPair();
202
+ oneTimePreKeys.push({ key_id: i, public_key: encodeBase64(otpk.publicKey) });
203
+ oneTimePreKeySecrets.push({ key_id: i, secret_key: encodeBase64(otpk.secretKey) });
204
+ }
205
+ return {
206
+ bundle: {
207
+ identity_key: identityPublicKey,
208
+ signed_pre_key: signedPreKeyPublic,
209
+ signed_pre_key_signature: encodeBase64(signature),
210
+ signed_pre_key_id: 0,
211
+ one_time_pre_keys: oneTimePreKeys,
212
+ },
213
+ signedPreKeySecret: encodeBase64(signedPreKeyPair.secretKey),
214
+ oneTimePreKeySecrets,
215
+ };
216
+ }
217
+ /**
218
+ * Generate additional one-time pre-keys (for replenishment).
219
+ */
220
+ export function generateOneTimePreKeys(count, startId) {
221
+ const publicKeys = [];
222
+ const secretKeys = [];
223
+ for (let i = 0; i < count; i++) {
224
+ const kp = nacl.box.keyPair();
225
+ publicKeys.push({ key_id: startId + i, public_key: encodeBase64(kp.publicKey) });
226
+ secretKeys.push({ key_id: startId + i, secret_key: encodeBase64(kp.secretKey) });
227
+ }
228
+ return { publicKeys, secretKeys };
229
+ }
230
+ const X3DH_INFO = new TextEncoder().encode("SYNLinkX3DH");
231
+ /**
232
+ * X3DH initiator side — derive shared secret from peer's pre-key bundle.
233
+ *
234
+ * Computes: DH1 = DH(IKa, SPKb), DH2 = DH(EKa, IKb), DH3 = DH(EKa, SPKb), [DH4 = DH(EKa, OPKb)]
235
+ * SharedSecret = HKDF(DH1 || DH2 || DH3 [|| DH4])
236
+ */
237
+ export async function x3dhInitiate(myIdentitySecretKey, peerBundle) {
238
+ const IKa_sk = decodeBase64(myIdentitySecretKey);
239
+ const IKb_pk = decodeBase64(peerBundle.identity_key);
240
+ const SPKb_pk = decodeBase64(peerBundle.signed_pre_key);
241
+ // Generate ephemeral key pair
242
+ const EKa = nacl.box.keyPair();
243
+ // DH1 = DH(IKa, SPKb) — our identity key × their signed pre-key
244
+ const dh1 = dh(IKa_sk, SPKb_pk);
245
+ // DH2 = DH(EKa, IKb) — our ephemeral × their identity key
246
+ const dh2 = dh(EKa.secretKey, IKb_pk);
247
+ // DH3 = DH(EKa, SPKb) — our ephemeral × their signed pre-key
248
+ const dh3 = dh(EKa.secretKey, SPKb_pk);
249
+ let dhConcat;
250
+ let usedOneTimePreKeyId;
251
+ if (peerBundle.one_time_pre_key) {
252
+ // DH4 = DH(EKa, OPKb) — our ephemeral × their one-time pre-key
253
+ const OPKb_pk = decodeBase64(peerBundle.one_time_pre_key.public_key);
254
+ const dh4 = dh(EKa.secretKey, OPKb_pk);
255
+ dhConcat = new Uint8Array(128);
256
+ dhConcat.set(dh1, 0);
257
+ dhConcat.set(dh2, 32);
258
+ dhConcat.set(dh3, 64);
259
+ dhConcat.set(dh4, 96);
260
+ usedOneTimePreKeyId = peerBundle.one_time_pre_key.key_id;
261
+ }
262
+ else {
263
+ dhConcat = new Uint8Array(96);
264
+ dhConcat.set(dh1, 0);
265
+ dhConcat.set(dh2, 32);
266
+ dhConcat.set(dh3, 64);
267
+ }
268
+ const sharedSecret = await hkdf(dhConcat, new Uint8Array(32), X3DH_INFO, 32);
269
+ return {
270
+ sharedSecret,
271
+ ephemeralPublicKey: encodeBase64(EKa.publicKey),
272
+ usedOneTimePreKeyId,
273
+ };
274
+ }
275
+ /**
276
+ * X3DH responder side — derive shared secret from initiator's first message header.
277
+ */
278
+ export async function x3dhRespond(myIdentitySecretKey, mySignedPreKeySecret, myOneTimePreKeySecret, header) {
279
+ const IKb_sk = decodeBase64(myIdentitySecretKey);
280
+ const SPKb_sk = decodeBase64(mySignedPreKeySecret);
281
+ const IKa_pk = decodeBase64(header.identity_key);
282
+ const EKa_pk = decodeBase64(header.ephemeral_key);
283
+ // DH1 = DH(SPKb, IKa) — our signed pre-key × their identity key
284
+ const dh1 = dh(SPKb_sk, IKa_pk);
285
+ // DH2 = DH(IKb, EKa) — our identity key × their ephemeral
286
+ const dh2 = dh(IKb_sk, EKa_pk);
287
+ // DH3 = DH(SPKb, EKa) — our signed pre-key × their ephemeral
288
+ const dh3 = dh(SPKb_sk, EKa_pk);
289
+ let dhConcat;
290
+ if (myOneTimePreKeySecret) {
291
+ const OPKb_sk = decodeBase64(myOneTimePreKeySecret);
292
+ // DH4 = DH(OPKb, EKa) — our one-time key × their ephemeral
293
+ const dh4 = dh(OPKb_sk, EKa_pk);
294
+ dhConcat = new Uint8Array(128);
295
+ dhConcat.set(dh1, 0);
296
+ dhConcat.set(dh2, 32);
297
+ dhConcat.set(dh3, 64);
298
+ dhConcat.set(dh4, 96);
299
+ }
300
+ else {
301
+ dhConcat = new Uint8Array(96);
302
+ dhConcat.set(dh1, 0);
303
+ dhConcat.set(dh2, 32);
304
+ dhConcat.set(dh3, 64);
305
+ }
306
+ return hkdf(dhConcat, new Uint8Array(32), X3DH_INFO, 32);
307
+ }
308
+ /**
309
+ * Symmetric encryption with NaCl secretbox (used by Double Ratchet).
310
+ * Input and output are raw Uint8Array (not base64).
311
+ */
312
+ export function secretboxEncrypt(plaintext, key) {
313
+ const nonce = nacl.randomBytes(nacl.secretbox.nonceLength);
314
+ const ciphertext = nacl.secretbox(plaintext, nonce, key);
315
+ return { ciphertext, nonce };
316
+ }
317
+ /**
318
+ * Symmetric decryption with NaCl secretbox (used by Double Ratchet).
319
+ */
320
+ export function secretboxDecrypt(ciphertext, nonce, key) {
321
+ const plaintext = nacl.secretbox.open(ciphertext, nonce, key);
322
+ if (!plaintext)
323
+ throw new Error("Ratchet decryption failed — wrong key or corrupted message");
324
+ return plaintext;
325
+ }
326
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}