@sumicom/quicksave-shared 0.1.0 → 0.2.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.
@@ -1,337 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import {
3
- generateKeyPair,
4
- generateSigningKeyPair,
5
- encrypt,
6
- decrypt,
7
- deriveSharedSecret,
8
- encryptWithSharedSecret,
9
- decryptWithSharedSecret,
10
- generateSessionDEK,
11
- encryptDEK,
12
- decryptDEK,
13
- sign,
14
- verify,
15
- encodeKeyPair,
16
- decodeKeyPair,
17
- generateAgentId,
18
- encodeBase64,
19
- decodeBase64,
20
- } from './crypto.js';
21
-
22
- describe('Key Generation', () => {
23
- it('should generate valid encryption key pair', () => {
24
- const keyPair = generateKeyPair();
25
- expect(keyPair.publicKey).toBeInstanceOf(Uint8Array);
26
- expect(keyPair.secretKey).toBeInstanceOf(Uint8Array);
27
- expect(keyPair.publicKey.length).toBe(32);
28
- expect(keyPair.secretKey.length).toBe(32);
29
- });
30
-
31
- it('should generate unique key pairs each time', () => {
32
- const keyPair1 = generateKeyPair();
33
- const keyPair2 = generateKeyPair();
34
- expect(encodeBase64(keyPair1.publicKey)).not.toBe(encodeBase64(keyPair2.publicKey));
35
- expect(encodeBase64(keyPair1.secretKey)).not.toBe(encodeBase64(keyPair2.secretKey));
36
- });
37
-
38
- it('should generate valid signing key pair', () => {
39
- const keyPair = generateSigningKeyPair();
40
- expect(keyPair.publicKey).toBeInstanceOf(Uint8Array);
41
- expect(keyPair.secretKey).toBeInstanceOf(Uint8Array);
42
- expect(keyPair.publicKey.length).toBe(32);
43
- expect(keyPair.secretKey.length).toBe(64);
44
- });
45
- });
46
-
47
- describe('Encryption / Decryption', () => {
48
- it('should encrypt and decrypt a message correctly', () => {
49
- const alice = generateKeyPair();
50
- const bob = generateKeyPair();
51
- const message = 'Hello, Bob!';
52
-
53
- const encrypted = encrypt(message, bob.publicKey, alice.secretKey);
54
- expect(typeof encrypted).toBe('string');
55
- expect(encrypted).not.toBe(message);
56
-
57
- const decrypted = decrypt(encrypted, alice.publicKey, bob.secretKey);
58
- expect(decrypted).toBe(message);
59
- });
60
-
61
- it('should produce different ciphertext for same message (due to random nonce)', () => {
62
- const alice = generateKeyPair();
63
- const bob = generateKeyPair();
64
- const message = 'Same message';
65
-
66
- const encrypted1 = encrypt(message, bob.publicKey, alice.secretKey);
67
- const encrypted2 = encrypt(message, bob.publicKey, alice.secretKey);
68
-
69
- expect(encrypted1).not.toBe(encrypted2);
70
- });
71
-
72
- it('should fail to decrypt with wrong key', () => {
73
- const alice = generateKeyPair();
74
- const bob = generateKeyPair();
75
- const eve = generateKeyPair();
76
- const message = 'Secret message';
77
-
78
- const encrypted = encrypt(message, bob.publicKey, alice.secretKey);
79
-
80
- expect(() => {
81
- decrypt(encrypted, alice.publicKey, eve.secretKey);
82
- }).toThrow('Decryption failed');
83
- });
84
-
85
- it('should handle unicode and special characters', () => {
86
- const alice = generateKeyPair();
87
- const bob = generateKeyPair();
88
- const message = '你好世界 🚀 émojis & spëcial çhars!';
89
-
90
- const encrypted = encrypt(message, bob.publicKey, alice.secretKey);
91
- const decrypted = decrypt(encrypted, alice.publicKey, bob.secretKey);
92
-
93
- expect(decrypted).toBe(message);
94
- });
95
-
96
- it('should handle empty string', () => {
97
- const alice = generateKeyPair();
98
- const bob = generateKeyPair();
99
- const message = '';
100
-
101
- const encrypted = encrypt(message, bob.publicKey, alice.secretKey);
102
- const decrypted = decrypt(encrypted, alice.publicKey, bob.secretKey);
103
-
104
- expect(decrypted).toBe(message);
105
- });
106
-
107
- it('should handle large messages', () => {
108
- const alice = generateKeyPair();
109
- const bob = generateKeyPair();
110
- const message = 'x'.repeat(100000);
111
-
112
- const encrypted = encrypt(message, bob.publicKey, alice.secretKey);
113
- const decrypted = decrypt(encrypted, alice.publicKey, bob.secretKey);
114
-
115
- expect(decrypted).toBe(message);
116
- });
117
- });
118
-
119
- describe('Shared Secret Encryption', () => {
120
- it('should derive same shared secret from both sides', () => {
121
- const alice = generateKeyPair();
122
- const bob = generateKeyPair();
123
-
124
- const aliceShared = deriveSharedSecret(bob.publicKey, alice.secretKey);
125
- const bobShared = deriveSharedSecret(alice.publicKey, bob.secretKey);
126
-
127
- expect(encodeBase64(aliceShared)).toBe(encodeBase64(bobShared));
128
- });
129
-
130
- it('should encrypt and decrypt with shared secret', () => {
131
- const alice = generateKeyPair();
132
- const bob = generateKeyPair();
133
- const message = 'Shared secret message';
134
-
135
- const sharedSecret = deriveSharedSecret(bob.publicKey, alice.secretKey);
136
-
137
- const encrypted = encryptWithSharedSecret(message, sharedSecret);
138
- const decrypted = decryptWithSharedSecret(encrypted, sharedSecret);
139
-
140
- expect(decrypted).toBe(message);
141
- });
142
-
143
- it('should fail to decrypt with wrong shared secret', () => {
144
- const alice = generateKeyPair();
145
- const bob = generateKeyPair();
146
- const eve = generateKeyPair();
147
- const message = 'Secret';
148
-
149
- const aliceShared = deriveSharedSecret(bob.publicKey, alice.secretKey);
150
- const eveShared = deriveSharedSecret(eve.publicKey, eve.secretKey);
151
-
152
- const encrypted = encryptWithSharedSecret(message, aliceShared);
153
-
154
- expect(() => {
155
- decryptWithSharedSecret(encrypted, eveShared);
156
- }).toThrow('Decryption failed');
157
- });
158
- });
159
-
160
- describe('Session DEK (V2 Protocol)', () => {
161
- it('should generate 32-byte session DEK', () => {
162
- const dek = generateSessionDEK();
163
- expect(dek).toBeInstanceOf(Uint8Array);
164
- expect(dek.length).toBe(32);
165
- });
166
-
167
- it('should generate unique DEKs each time', () => {
168
- const dek1 = generateSessionDEK();
169
- const dek2 = generateSessionDEK();
170
- expect(encodeBase64(dek1)).not.toBe(encodeBase64(dek2));
171
- });
172
-
173
- it('should encrypt and decrypt DEK correctly', () => {
174
- const agent = generateKeyPair();
175
- const dek = generateSessionDEK();
176
-
177
- const encryptedDEK = encryptDEK(dek, agent.publicKey);
178
- expect(typeof encryptedDEK).toBe('string');
179
-
180
- const decryptedDEK = decryptDEK(encryptedDEK, agent.secretKey);
181
- expect(encodeBase64(decryptedDEK)).toBe(encodeBase64(dek));
182
- });
183
-
184
- it('should produce different ciphertext for same DEK (due to ephemeral key)', () => {
185
- const agent = generateKeyPair();
186
- const dek = generateSessionDEK();
187
-
188
- const encrypted1 = encryptDEK(dek, agent.publicKey);
189
- const encrypted2 = encryptDEK(dek, agent.publicKey);
190
-
191
- expect(encrypted1).not.toBe(encrypted2);
192
- });
193
-
194
- it('should fail to decrypt DEK with wrong key', () => {
195
- const agent = generateKeyPair();
196
- const eve = generateKeyPair();
197
- const dek = generateSessionDEK();
198
-
199
- const encryptedDEK = encryptDEK(dek, agent.publicKey);
200
-
201
- expect(() => {
202
- decryptDEK(encryptedDEK, eve.secretKey);
203
- }).toThrow('DEK decryption failed');
204
- });
205
-
206
- it('should throw if DEK is not 32 bytes', () => {
207
- const agent = generateKeyPair();
208
- const invalidDEK = new Uint8Array(16); // Too short
209
-
210
- expect(() => {
211
- encryptDEK(invalidDEK, agent.publicKey);
212
- }).toThrow('DEK must be 32 bytes');
213
- });
214
-
215
- it('should work end-to-end: PWA generates DEK, Agent decrypts, both use for encryption', () => {
216
- // Simulate V2 key exchange
217
- const agentKeyPair = generateKeyPair();
218
-
219
- // PWA generates session DEK and encrypts it for Agent
220
- const sessionDEK = generateSessionDEK();
221
- const encryptedDEK = encryptDEK(sessionDEK, agentKeyPair.publicKey);
222
-
223
- // Agent decrypts the DEK
224
- const agentDEK = decryptDEK(encryptedDEK, agentKeyPair.secretKey);
225
-
226
- // Both should have the same DEK
227
- expect(encodeBase64(agentDEK)).toBe(encodeBase64(sessionDEK));
228
-
229
- // Both can now encrypt/decrypt messages using the DEK as shared secret
230
- const message = 'Hello from PWA!';
231
- const encrypted = encryptWithSharedSecret(message, sessionDEK);
232
- const decrypted = decryptWithSharedSecret(encrypted, agentDEK);
233
- expect(decrypted).toBe(message);
234
-
235
- // Agent can respond
236
- const response = 'Hello from Agent!';
237
- const encryptedResponse = encryptWithSharedSecret(response, agentDEK);
238
- const decryptedResponse = decryptWithSharedSecret(encryptedResponse, sessionDEK);
239
- expect(decryptedResponse).toBe(response);
240
- });
241
- });
242
-
243
- describe('Signing / Verification', () => {
244
- it('should sign and verify a message', () => {
245
- const keyPair = generateSigningKeyPair();
246
- const message = 'Sign this message';
247
-
248
- const signature = sign(message, keyPair.secretKey);
249
- expect(typeof signature).toBe('string');
250
-
251
- const isValid = verify(message, signature, keyPair.publicKey);
252
- expect(isValid).toBe(true);
253
- });
254
-
255
- it('should fail verification with wrong public key', () => {
256
- const alice = generateSigningKeyPair();
257
- const bob = generateSigningKeyPair();
258
- const message = 'Signed by Alice';
259
-
260
- const signature = sign(message, alice.secretKey);
261
- const isValid = verify(message, signature, bob.publicKey);
262
-
263
- expect(isValid).toBe(false);
264
- });
265
-
266
- it('should fail verification with modified message', () => {
267
- const keyPair = generateSigningKeyPair();
268
- const message = 'Original message';
269
-
270
- const signature = sign(message, keyPair.secretKey);
271
- const isValid = verify('Modified message', signature, keyPair.publicKey);
272
-
273
- expect(isValid).toBe(false);
274
- });
275
-
276
- it('should produce different signatures for different messages', () => {
277
- const keyPair = generateSigningKeyPair();
278
-
279
- const sig1 = sign('Message 1', keyPair.secretKey);
280
- const sig2 = sign('Message 2', keyPair.secretKey);
281
-
282
- expect(sig1).not.toBe(sig2);
283
- });
284
- });
285
-
286
- describe('Key Encoding / Decoding', () => {
287
- it('should encode and decode key pair correctly', () => {
288
- const original = generateKeyPair();
289
- const encoded = encodeKeyPair(original);
290
-
291
- expect(typeof encoded.publicKey).toBe('string');
292
- expect(typeof encoded.secretKey).toBe('string');
293
-
294
- const decoded = decodeKeyPair(encoded);
295
-
296
- expect(encodeBase64(decoded.publicKey)).toBe(encodeBase64(original.publicKey));
297
- expect(encodeBase64(decoded.secretKey)).toBe(encodeBase64(original.secretKey));
298
- });
299
-
300
- it('should produce valid base64 strings', () => {
301
- const keyPair = generateKeyPair();
302
- const encoded = encodeKeyPair(keyPair);
303
-
304
- // Check base64 format
305
- expect(encoded.publicKey).toMatch(/^[A-Za-z0-9+/]+=*$/);
306
- expect(encoded.secretKey).toMatch(/^[A-Za-z0-9+/]+=*$/);
307
- });
308
- });
309
-
310
- describe('Agent ID Generation', () => {
311
- it('should generate valid agent ID', () => {
312
- const agentId = generateAgentId();
313
-
314
- expect(typeof agentId).toBe('string');
315
- expect(agentId.length).toBeGreaterThan(0);
316
- // URL-safe base64 (no +, /, =)
317
- expect(agentId).toMatch(/^[A-Za-z0-9_-]+$/);
318
- });
319
-
320
- it('should generate unique agent IDs', () => {
321
- const ids = new Set<string>();
322
- for (let i = 0; i < 100; i++) {
323
- ids.add(generateAgentId());
324
- }
325
- expect(ids.size).toBe(100);
326
- });
327
- });
328
-
329
- describe('Base64 Encoding Utilities', () => {
330
- it('should encode and decode bytes correctly', () => {
331
- const original = new Uint8Array([1, 2, 3, 4, 5, 255, 0, 128]);
332
- const encoded = encodeBase64(original);
333
- const decoded = decodeBase64(encoded);
334
-
335
- expect(decoded).toEqual(original);
336
- });
337
- });
package/src/crypto.ts DELETED
@@ -1,335 +0,0 @@
1
- import nacl from 'tweetnacl';
2
- import naclUtil from 'tweetnacl-util';
3
- import type { License } from './types.js';
4
-
5
- const { encodeBase64, decodeBase64, encodeUTF8, decodeUTF8 } = naclUtil;
6
-
7
- // ============================================================================
8
- // Key Generation
9
- // ============================================================================
10
-
11
- export interface KeyPair {
12
- publicKey: Uint8Array;
13
- secretKey: Uint8Array;
14
- }
15
-
16
- /**
17
- * Generate a new X25519 key pair for encryption
18
- */
19
- export function generateKeyPair(): KeyPair {
20
- return nacl.box.keyPair();
21
- }
22
-
23
- /**
24
- * Generate a new Ed25519 key pair for signing
25
- */
26
- export function generateSigningKeyPair(): KeyPair {
27
- return nacl.sign.keyPair();
28
- }
29
-
30
- // ============================================================================
31
- // Encryption / Decryption
32
- // ============================================================================
33
-
34
- /**
35
- * Encrypt a message using X25519 + XSalsa20-Poly1305
36
- * @param message - The plaintext message
37
- * @param theirPublicKey - Recipient's public key
38
- * @param mySecretKey - Sender's secret key
39
- * @returns Base64 encoded encrypted message (nonce + ciphertext)
40
- */
41
- export function encrypt(
42
- message: string,
43
- theirPublicKey: Uint8Array,
44
- mySecretKey: Uint8Array
45
- ): string {
46
- const nonce = nacl.randomBytes(nacl.box.nonceLength);
47
- const messageBytes = decodeUTF8(message);
48
-
49
- const encrypted = nacl.box(messageBytes, nonce, theirPublicKey, mySecretKey);
50
-
51
- if (!encrypted) {
52
- throw new Error('Encryption failed');
53
- }
54
-
55
- // Combine nonce + ciphertext
56
- const combined = new Uint8Array(nonce.length + encrypted.length);
57
- combined.set(nonce);
58
- combined.set(encrypted, nonce.length);
59
-
60
- return encodeBase64(combined);
61
- }
62
-
63
- /**
64
- * Decrypt a message using X25519 + XSalsa20-Poly1305
65
- * @param encryptedMessage - Base64 encoded encrypted message (nonce + ciphertext)
66
- * @param theirPublicKey - Sender's public key
67
- * @param mySecretKey - Recipient's secret key
68
- * @returns Decrypted plaintext message
69
- */
70
- export function decrypt(
71
- encryptedMessage: string,
72
- theirPublicKey: Uint8Array,
73
- mySecretKey: Uint8Array
74
- ): string {
75
- const combined = decodeBase64(encryptedMessage);
76
-
77
- const nonce = combined.slice(0, nacl.box.nonceLength);
78
- const ciphertext = combined.slice(nacl.box.nonceLength);
79
-
80
- const decrypted = nacl.box.open(ciphertext, nonce, theirPublicKey, mySecretKey);
81
-
82
- if (!decrypted) {
83
- throw new Error('Decryption failed - invalid message or wrong key');
84
- }
85
-
86
- return encodeUTF8(decrypted);
87
- }
88
-
89
- // ============================================================================
90
- // Shared Secret (for symmetric encryption)
91
- // ============================================================================
92
-
93
- /**
94
- * Derive a shared secret from key pairs (X25519)
95
- */
96
- export function deriveSharedSecret(
97
- theirPublicKey: Uint8Array,
98
- mySecretKey: Uint8Array
99
- ): Uint8Array {
100
- return nacl.box.before(theirPublicKey, mySecretKey);
101
- }
102
-
103
- /**
104
- * Encrypt using a pre-computed shared secret (faster for multiple messages)
105
- */
106
- export function encryptWithSharedSecret(
107
- message: string,
108
- sharedSecret: Uint8Array
109
- ): string {
110
- const nonce = nacl.randomBytes(nacl.secretbox.nonceLength);
111
- const messageBytes = decodeUTF8(message);
112
-
113
- const encrypted = nacl.secretbox(messageBytes, nonce, sharedSecret);
114
-
115
- if (!encrypted) {
116
- throw new Error('Encryption failed');
117
- }
118
-
119
- const combined = new Uint8Array(nonce.length + encrypted.length);
120
- combined.set(nonce);
121
- combined.set(encrypted, nonce.length);
122
-
123
- return encodeBase64(combined);
124
- }
125
-
126
- /**
127
- * Decrypt using a pre-computed shared secret
128
- */
129
- export function decryptWithSharedSecret(
130
- encryptedMessage: string,
131
- sharedSecret: Uint8Array
132
- ): string {
133
- const combined = decodeBase64(encryptedMessage);
134
-
135
- const nonce = combined.slice(0, nacl.secretbox.nonceLength);
136
- const ciphertext = combined.slice(nacl.secretbox.nonceLength);
137
-
138
- const decrypted = nacl.secretbox.open(ciphertext, nonce, sharedSecret);
139
-
140
- if (!decrypted) {
141
- throw new Error('Decryption failed - invalid message or wrong key');
142
- }
143
-
144
- return encodeUTF8(decrypted);
145
- }
146
-
147
- // ============================================================================
148
- // Session DEK (Data Encryption Key) - V2 Protocol
149
- // ============================================================================
150
-
151
- /**
152
- * Generate a random 32-byte session DEK for symmetric encryption.
153
- * Used in V2 key exchange where PWA generates the DEK and sends it encrypted to Agent.
154
- */
155
- export function generateSessionDEK(): Uint8Array {
156
- return nacl.randomBytes(32);
157
- }
158
-
159
- /**
160
- * Encrypt a DEK for a specific recipient using sealed box pattern.
161
- * Uses an ephemeral keypair so the sender's identity is not revealed.
162
- *
163
- * Format: ephemeralPublicKey (32) + nonce (24) + ciphertext
164
- *
165
- * @param dek - The 32-byte DEK to encrypt
166
- * @param recipientPublicKey - Recipient's X25519 public key
167
- * @returns Base64 encoded encrypted DEK
168
- */
169
- export function encryptDEK(
170
- dek: Uint8Array,
171
- recipientPublicKey: Uint8Array
172
- ): string {
173
- if (dek.length !== 32) {
174
- throw new Error('DEK must be 32 bytes');
175
- }
176
-
177
- // Generate ephemeral keypair for this encryption
178
- const ephemeral = nacl.box.keyPair();
179
- const nonce = nacl.randomBytes(nacl.box.nonceLength);
180
-
181
- const encrypted = nacl.box(dek, nonce, recipientPublicKey, ephemeral.secretKey);
182
-
183
- if (!encrypted) {
184
- throw new Error('DEK encryption failed');
185
- }
186
-
187
- // Combine: ephemeralPublicKey + nonce + ciphertext
188
- const combined = new Uint8Array(
189
- ephemeral.publicKey.length + nonce.length + encrypted.length
190
- );
191
- combined.set(ephemeral.publicKey);
192
- combined.set(nonce, ephemeral.publicKey.length);
193
- combined.set(encrypted, ephemeral.publicKey.length + nonce.length);
194
-
195
- return encodeBase64(combined);
196
- }
197
-
198
- /**
199
- * Decrypt a DEK that was encrypted for us.
200
- *
201
- * @param encryptedDEK - Base64 encoded encrypted DEK (ephemeralPubKey + nonce + ciphertext)
202
- * @param mySecretKey - Our X25519 secret key
203
- * @returns The decrypted 32-byte DEK
204
- */
205
- export function decryptDEK(
206
- encryptedDEK: string,
207
- mySecretKey: Uint8Array
208
- ): Uint8Array {
209
- const combined = decodeBase64(encryptedDEK);
210
-
211
- // Extract components
212
- const ephemeralPublicKey = combined.slice(0, 32);
213
- const nonce = combined.slice(32, 32 + nacl.box.nonceLength);
214
- const ciphertext = combined.slice(32 + nacl.box.nonceLength);
215
-
216
- const decrypted = nacl.box.open(ciphertext, nonce, ephemeralPublicKey, mySecretKey);
217
-
218
- if (!decrypted) {
219
- throw new Error('DEK decryption failed - invalid message or wrong key');
220
- }
221
-
222
- if (decrypted.length !== 32) {
223
- throw new Error('Decrypted DEK has invalid length');
224
- }
225
-
226
- return decrypted;
227
- }
228
-
229
- // ============================================================================
230
- // Signing / Verification
231
- // ============================================================================
232
-
233
- /**
234
- * Sign a message using Ed25519
235
- */
236
- export function sign(message: string, secretKey: Uint8Array): string {
237
- const messageBytes = decodeUTF8(message);
238
- const signature = nacl.sign.detached(messageBytes, secretKey);
239
- return encodeBase64(signature);
240
- }
241
-
242
- /**
243
- * Verify an Ed25519 signature
244
- */
245
- export function verify(
246
- message: string,
247
- signature: string,
248
- publicKey: Uint8Array
249
- ): boolean {
250
- const messageBytes = decodeUTF8(message);
251
- const signatureBytes = decodeBase64(signature);
252
- return nacl.sign.detached.verify(messageBytes, signatureBytes, publicKey);
253
- }
254
-
255
- // ============================================================================
256
- // License Verification
257
- // ============================================================================
258
-
259
- // Quicksave's public key for license verification (Ed25519)
260
- // This would be generated once and hardcoded
261
- // For development, we'll generate a placeholder
262
- const QUICKSAVE_PUBLIC_KEY_BASE64 = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=';
263
-
264
- export function getQuicksavePublicKey(): Uint8Array {
265
- return decodeBase64(QUICKSAVE_PUBLIC_KEY_BASE64);
266
- }
267
-
268
- /**
269
- * Verify a license certificate
270
- */
271
- export function verifyLicense(license: License): boolean {
272
- const message = `${license.version}:${license.publicKey}:${license.issuedAt}:${license.type}`;
273
- return verify(message, license.signature, getQuicksavePublicKey());
274
- }
275
-
276
- /**
277
- * Create a license certificate (server-side only)
278
- */
279
- export function createLicense(
280
- userPublicKey: string,
281
- signingSecretKey: Uint8Array
282
- ): License {
283
- const license: Omit<License, 'signature'> = {
284
- version: 1,
285
- publicKey: userPublicKey,
286
- issuedAt: Date.now(),
287
- type: 'pro',
288
- };
289
-
290
- const message = `${license.version}:${license.publicKey}:${license.issuedAt}:${license.type}`;
291
- const signature = sign(message, signingSecretKey);
292
-
293
- return {
294
- ...license,
295
- signature,
296
- };
297
- }
298
-
299
- // ============================================================================
300
- // Utility Functions
301
- // ============================================================================
302
-
303
- /**
304
- * Encode a key pair to base64 strings for storage
305
- */
306
- export function encodeKeyPair(keyPair: KeyPair): { publicKey: string; secretKey: string } {
307
- return {
308
- publicKey: encodeBase64(keyPair.publicKey),
309
- secretKey: encodeBase64(keyPair.secretKey),
310
- };
311
- }
312
-
313
- /**
314
- * Decode base64 strings back to a key pair
315
- */
316
- export function decodeKeyPair(encoded: { publicKey: string; secretKey: string }): KeyPair {
317
- return {
318
- publicKey: decodeBase64(encoded.publicKey),
319
- secretKey: decodeBase64(encoded.secretKey),
320
- };
321
- }
322
-
323
- /**
324
- * Generate a random agent ID (used for signaling)
325
- */
326
- export function generateAgentId(): string {
327
- const bytes = nacl.randomBytes(16);
328
- return encodeBase64(bytes)
329
- .replace(/\+/g, '-')
330
- .replace(/\//g, '_')
331
- .replace(/=/g, '');
332
- }
333
-
334
- // Re-export encoding utilities
335
- export { encodeBase64, decodeBase64, encodeUTF8, decodeUTF8 };
package/src/index.ts DELETED
@@ -1,8 +0,0 @@
1
- // Types
2
- export * from './types.js';
3
-
4
- // Crypto utilities
5
- export * from './crypto.js';
6
-
7
- // Protocol utilities
8
- export * from './protocol.js';