@massalabs/gossip-sdk 0.0.2-dev.20260130145448 → 0.0.2-dev.20260210150149

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.
@@ -19,7 +19,7 @@
19
19
  */
20
20
  import { type Contact, type GossipDatabase } from './db';
21
21
  import type { UpdateContactNameResult, DeleteContactResult } from './utils/contacts';
22
- import type { UserPublicKeys } from '#wasm';
22
+ import type { UserPublicKeys } from './wasm/bindings';
23
23
  import type { SessionModule } from './wasm/session';
24
24
  export type { UpdateContactNameResult, DeleteContactResult };
25
25
  /**
@@ -46,7 +46,7 @@ import { type MessageResult, type SendMessageResult } from './services/message';
46
46
  import { AuthService } from './services/auth';
47
47
  import type { DeleteContactResult, UpdateContactNameResult } from './utils/contacts';
48
48
  import { type ValidationResult } from './utils/validation';
49
- import type { UserPublicKeys } from '#wasm';
49
+ import type { UserPublicKeys } from './wasm/bindings';
50
50
  import { type SdkEventType, type SdkEventHandlers } from './core/SdkEventEmitter';
51
51
  export type { SdkEventType, SdkEventHandlers };
52
52
  export interface GossipSdkInitOptions {
package/dist/index.d.ts CHANGED
@@ -4,9 +4,9 @@
4
4
  * Main entry point for the Gossip SDK.
5
5
  * Works in both browser and Node.js environments.
6
6
  *
7
- * WASM is loaded via the #wasm subpath import which resolves conditionally:
8
- * - Browser: web target (uses import.meta.url)
9
- * - Node: nodejs target (uses fs, no import.meta.url)
7
+ * WASM is loaded via the web target build with runtime detection:
8
+ * - Browser: init() uses import.meta.url + fetch
9
+ * - Node.js / Jiti: init(bytes) reads the .wasm file from disk
10
10
  *
11
11
  * @example
12
12
  * ```typescript
@@ -56,4 +56,4 @@ export { MESSAGE_TYPE_KEEP_ALIVE, serializeKeepAliveMessage, serializeRegularMes
56
56
  export type { DeserializedMessage } from './utils/messageSerialization';
57
57
  export { generateMnemonic, validateMnemonic, mnemonicToSeed, accountFromMnemonic, PRIVATE_KEY_VERSION, } from './crypto/bip39';
58
58
  export { encrypt, decrypt, deriveKey } from './crypto/encryption';
59
- export { UserPublicKeys, UserSecretKeys, SessionStatus, SessionConfig, SessionManagerWrapper, SendMessageOutput, ReceiveMessageOutput, AnnouncementResult, generate_user_keys, } from '#wasm';
59
+ export { UserPublicKeys, UserSecretKeys, SessionStatus, SessionConfig, SessionManagerWrapper, SendMessageOutput, ReceiveMessageOutput, AnnouncementResult, generate_user_keys, } from './wasm/bindings';
package/dist/index.js CHANGED
@@ -4,9 +4,9 @@
4
4
  * Main entry point for the Gossip SDK.
5
5
  * Works in both browser and Node.js environments.
6
6
  *
7
- * WASM is loaded via the #wasm subpath import which resolves conditionally:
8
- * - Browser: web target (uses import.meta.url)
9
- * - Node: nodejs target (uses fs, no import.meta.url)
7
+ * WASM is loaded via the web target build with runtime detection:
8
+ * - Browser: init() uses import.meta.url + fetch
9
+ * - Node.js / Jiti: init(bytes) reads the .wasm file from disk
10
10
  *
11
11
  * @example
12
12
  * ```typescript
@@ -58,4 +58,4 @@ export { MESSAGE_TYPE_KEEP_ALIVE, serializeKeepAliveMessage, serializeRegularMes
58
58
  export { generateMnemonic, validateMnemonic, mnemonicToSeed, accountFromMnemonic, PRIVATE_KEY_VERSION, } from './crypto/bip39';
59
59
  export { encrypt, decrypt, deriveKey } from './crypto/encryption';
60
60
  // WASM types re-exported for convenience
61
- export { UserPublicKeys, UserSecretKeys, SessionStatus, SessionConfig, SessionManagerWrapper, SendMessageOutput, ReceiveMessageOutput, AnnouncementResult, generate_user_keys, } from '#wasm';
61
+ export { UserPublicKeys, UserSecretKeys, SessionStatus, SessionConfig, SessionManagerWrapper, SendMessageOutput, ReceiveMessageOutput, AnnouncementResult, generate_user_keys, } from './wasm/bindings';
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { type Discussion, type GossipDatabase } from '../db';
7
7
  import { IMessageProtocol } from '../api/messageProtocol';
8
- import { UserPublicKeys } from '#wasm';
8
+ import { UserPublicKeys } from '../wasm/bindings';
9
9
  import { SessionModule } from '../wasm/session';
10
10
  import { GossipSdkEvents } from '../types/events';
11
11
  import { SdkConfig } from '../config/sdk';
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { DiscussionStatus, DiscussionDirection, } from '../db';
7
7
  import { decodeUserId, encodeUserId } from '../utils/userId';
8
- import { SessionStatus } from '#wasm';
8
+ import { SessionStatus } from '../wasm/bindings';
9
9
  import { sessionStatusToString } from '../wasm/session';
10
10
  import { Logger } from '../utils/logs';
11
11
  import { defaultSdkConfig } from '../config/sdk';
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Handles storing and retrieving public keys by userId hash via the auth API.
5
5
  */
6
- import { UserPublicKeys } from '#wasm';
6
+ import { UserPublicKeys } from '../wasm/bindings';
7
7
  import { IMessageProtocol } from '../api/messageProtocol/types';
8
8
  import { type GossipDatabase } from '../db';
9
9
  export type PublicKeyResult = {
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Handles storing and retrieving public keys by userId hash via the auth API.
5
5
  */
6
- import { UserPublicKeys } from '#wasm';
6
+ import { UserPublicKeys } from '../wasm/bindings';
7
7
  import { decodeUserId } from '../utils/userId';
8
8
  import { encodeToBase64, decodeFromBase64 } from '../utils/base64';
9
9
  export class AuthService {
@@ -4,7 +4,7 @@
4
4
  * Class-based service for initializing, accepting, and managing discussions.
5
5
  */
6
6
  import { DiscussionStatus, MessageDirection, MessageStatus, DiscussionDirection, } from '../db';
7
- import { UserPublicKeys, SessionStatus } from '#wasm';
7
+ import { UserPublicKeys, SessionStatus } from '../wasm/bindings';
8
8
  import { EstablishSessionError } from './announcement';
9
9
  import { sessionStatusToString } from '../wasm/session';
10
10
  import { decodeUserId } from '../utils/userId';
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { DiscussionStatus, MessageDirection, MessageStatus, MessageType, } from '../db';
8
8
  import { decodeUserId, encodeUserId } from '../utils/userId';
9
- import { SessionStatus } from '#wasm';
9
+ import { SessionStatus } from '../wasm/bindings';
10
10
  import { serializeRegularMessage, serializeReplyMessage, serializeForwardMessage, serializeKeepAliveMessage, deserializeMessage, } from '../utils/messageSerialization';
11
11
  import { encodeToBase64 } from '../utils/base64';
12
12
  import { sessionStatusToString } from '../wasm/session';
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import { MessageDirection, MessageStatus, MessageType, } from '../db';
8
8
  import { sessionStatusToString } from '../wasm/session';
9
- import { SessionStatus } from '#wasm';
9
+ import { SessionStatus } from '../wasm/bindings';
10
10
  import { decodeUserId, encodeUserId } from '../utils/userId';
11
11
  import { Logger } from '../utils/logs';
12
12
  const logger = new Logger('RefreshService');
@@ -0,0 +1,9 @@
1
+ /**
2
+ * WASM Bindings Barrel
3
+ *
4
+ * Re-exports all WASM-generated types and functions from the web target.
5
+ * This centralizes the WASM import so the rest of the codebase uses
6
+ * a standard relative import instead of conditional #wasm subpath imports.
7
+ */
8
+ export { default as init } from '../assets/generated/wasm/gossip_wasm';
9
+ export * from '../assets/generated/wasm/gossip_wasm';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * WASM Bindings Barrel
3
+ *
4
+ * Re-exports all WASM-generated types and functions from the web target.
5
+ * This centralizes the WASM import so the rest of the codebase uses
6
+ * a standard relative import instead of conditional #wasm subpath imports.
7
+ */
8
+ export { default as init } from '../assets/generated/wasm/gossip_wasm';
9
+ export * from '../assets/generated/wasm/gossip_wasm';
@@ -5,7 +5,7 @@
5
5
  * and AEAD (Authenticated Encryption with Additional Data) operations,
6
6
  * ensuring proper initialization before calling any WASM functions.
7
7
  */
8
- import { EncryptionKey, Nonce } from '#wasm';
8
+ import { EncryptionKey, Nonce } from './bindings';
9
9
  export { EncryptionKey, Nonce };
10
10
  /**
11
11
  * Generate a new random encryption key (64 bytes)
@@ -6,7 +6,7 @@
6
6
  * ensuring proper initialization before calling any WASM functions.
7
7
  */
8
8
  import { ensureWasmInitialized } from './loader';
9
- import { EncryptionKey, Nonce, aead_encrypt as _aead_encrypt, aead_decrypt as _aead_decrypt, } from '#wasm';
9
+ import { EncryptionKey, Nonce, aead_encrypt as _aead_encrypt, aead_decrypt as _aead_decrypt, } from './bindings';
10
10
  // Re-export classes
11
11
  export { EncryptionKey, Nonce };
12
12
  /**
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * WASM Module Loader and Initialization Service
3
3
  *
4
- * This file handles WASM initialization. The actual wasm module is resolved
5
- * via the #wasm import which conditionally loads the correct target:
6
- * - Browser: web target (has init function, uses import.meta.url + fetch)
7
- * - Node: nodejs target (auto-initializes, no init function needed)
4
+ * This file handles WASM initialization. It uses a single web-target build
5
+ * and detects the runtime to load the WASM binary appropriately:
6
+ * - Browser: init() with no args (uses import.meta.url + fetch internally)
7
+ * - Node.js / Jiti: init(bytes) with WASM bytes read from the filesystem
8
8
  */
9
9
  /**
10
10
  * Initialize WASM modules if not already initialized
@@ -1,15 +1,12 @@
1
1
  /**
2
2
  * WASM Module Loader and Initialization Service
3
3
  *
4
- * This file handles WASM initialization. The actual wasm module is resolved
5
- * via the #wasm import which conditionally loads the correct target:
6
- * - Browser: web target (has init function, uses import.meta.url + fetch)
7
- * - Node: nodejs target (auto-initializes, no init function needed)
4
+ * This file handles WASM initialization. It uses a single web-target build
5
+ * and detects the runtime to load the WASM binary appropriately:
6
+ * - Browser: init() with no args (uses import.meta.url + fetch internally)
7
+ * - Node.js / Jiti: init(bytes) with WASM bytes read from the filesystem
8
8
  */
9
- import * as wasmModule from '#wasm';
10
- // The web target has a default export (init function), nodejs target doesn't
11
- const init = wasmModule
12
- .default;
9
+ import { init } from './bindings';
13
10
  /**
14
11
  * WASM Initialization State
15
12
  */
@@ -17,6 +14,14 @@ let isInitializing = false;
17
14
  let isInitialized = false;
18
15
  let initializationPromise = null;
19
16
  let initError = null;
17
+ /**
18
+ * Detect if running in a Node.js-like environment (Node, Bun, Jiti, etc.)
19
+ */
20
+ function isNodeRuntime() {
21
+ return (typeof process !== 'undefined' &&
22
+ process.versions != null &&
23
+ process.versions.node != null);
24
+ }
20
25
  /**
21
26
  * Initialize WASM modules if not already initialized
22
27
  * This function is idempotent - safe to call multiple times
@@ -35,13 +40,21 @@ export async function initializeWasm() {
35
40
  initError = null;
36
41
  initializationPromise = (async () => {
37
42
  try {
38
- // The #wasm import resolves to the correct target based on environment:
39
- // - Browser (web target): has init() function that needs to be called
40
- // - Node (nodejs target): auto-initializes on import, no init needed
41
- if (typeof init === 'function') {
43
+ if (isNodeRuntime()) {
44
+ // Node.js / Jiti: read WASM bytes from filesystem and pass to init()
45
+ // Dynamic imports ensure these Node.js modules are tree-shaken in browser builds
46
+ const fs = await import('node:fs');
47
+ const url = await import('node:url');
48
+ const path = await import('node:path');
49
+ const currentDir = path.dirname(url.fileURLToPath(import.meta.url));
50
+ const wasmPath = path.resolve(currentDir, '../assets/generated/wasm/gossip_wasm_bg.wasm');
51
+ const wasmBytes = fs.readFileSync(wasmPath);
52
+ await init(wasmBytes);
53
+ }
54
+ else {
55
+ // Browser: use default loading (import.meta.url + fetch internally)
42
56
  await init();
43
57
  }
44
- // For nodejs target, wasm is already initialized on import
45
58
  isInitialized = true;
46
59
  isInitializing = false;
47
60
  }
@@ -4,7 +4,7 @@
4
4
  * This file contains the real WASM implementation of the SessionModule
5
5
  * using SessionManagerWrapper and related WASM classes.
6
6
  */
7
- import { UserPublicKeys, UserSecretKeys, ReceiveMessageOutput, SendMessageOutput, SessionStatus, EncryptionKey, SessionConfig, AnnouncementResult, UserKeys } from '#wasm';
7
+ import { UserPublicKeys, UserSecretKeys, ReceiveMessageOutput, SendMessageOutput, SessionStatus, EncryptionKey, SessionConfig, AnnouncementResult, UserKeys } from './bindings';
8
8
  import { UserProfile } from '../db';
9
9
  export declare class SessionModule {
10
10
  private sessionManager;
@@ -4,7 +4,7 @@
4
4
  * This file contains the real WASM implementation of the SessionModule
5
5
  * using SessionManagerWrapper and related WASM classes.
6
6
  */
7
- import { SessionManagerWrapper, SessionStatus, SessionConfig, } from '#wasm';
7
+ import { SessionManagerWrapper, SessionStatus, SessionConfig, } from './bindings';
8
8
  import { encodeUserId } from '../utils/userId';
9
9
  export class SessionModule {
10
10
  constructor(userKeys, onPersist, config) {
@@ -4,7 +4,7 @@
4
4
  * This file provides proxy functions for user key generation,
5
5
  * ensuring proper initialization before calling any WASM functions.
6
6
  */
7
- import { UserKeys } from '#wasm';
7
+ import { UserKeys } from './bindings';
8
8
  export { UserKeys };
9
9
  /**
10
10
  * Generate user keys from a passphrase using password-based key derivation
@@ -5,7 +5,7 @@
5
5
  * ensuring proper initialization before calling any WASM functions.
6
6
  */
7
7
  import { ensureWasmInitialized } from './loader';
8
- import { generate_user_keys as _generate_user_keys, UserKeys } from '#wasm';
8
+ import { generate_user_keys as _generate_user_keys, UserKeys, } from './bindings';
9
9
  // Re-export classes
10
10
  export { UserKeys };
11
11
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massalabs/gossip-sdk",
3
- "version": "0.0.2-dev.20260130145448",
3
+ "version": "0.0.2-dev.20260210150149",
4
4
  "description": "Gossip SDK for automation, chatbot, and integration use cases",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -9,12 +9,6 @@
9
9
  "dist",
10
10
  "README.md"
11
11
  ],
12
- "imports": {
13
- "#wasm": {
14
- "browser": "./dist/assets/generated/wasm/gossip_wasm.js",
15
- "default": "./dist/assets/generated/wasm-node/gossip_wasm.js"
16
- }
17
- },
18
12
  "exports": {
19
13
  ".": {
20
14
  "types": "./dist/index.d.ts",
@@ -28,11 +22,13 @@
28
22
  "scripts": {
29
23
  "prebuild": "rimraf dist",
30
24
  "build": "tsc && npm run copy:wasm",
31
- "copy:wasm": "mkdir -p dist/assets/generated/wasm dist/assets/generated/wasm-node && cp -R src/assets/generated/wasm/* dist/assets/generated/wasm/ && cp -R src/assets/generated/wasm-node/* dist/assets/generated/wasm-node/",
25
+ "copy:wasm": "mkdir -p dist/assets/generated/wasm && cp -R src/assets/generated/wasm/* dist/assets/generated/wasm/",
32
26
  "test": "vitest",
33
27
  "test:run": "vitest run",
34
28
  "test:coverage": "vitest run --coverage",
35
- "test:e2e": "vitest run test/e2e/"
29
+ "test:e2e": "vitest run test/e2e/",
30
+ "lint": "eslint .",
31
+ "lint:fix": "eslint . --fix"
36
32
  },
37
33
  "keywords": [
38
34
  "gossip",
@@ -1,281 +0,0 @@
1
- # Gossip WASM - WebAssembly Bindings
2
-
3
- This crate provides WebAssembly bindings for the Gossip secure messaging system, exposing the SessionManager and Auth facilities to JavaScript/TypeScript applications.
4
-
5
- ## Features
6
-
7
- - **Session Management**: Create, persist, and manage encrypted messaging sessions
8
- - **Authentication**: Generate and manage cryptographic keys from passphrases
9
- - **Post-Quantum Security**: Uses ML-KEM and ML-DSA for quantum-resistant cryptography
10
- - **Encrypted State**: Secure serialization and deserialization of session state
11
- - **Seeker-based Addressing**: Messages use hashed Massa public keys for efficient lookups
12
-
13
- ## Building
14
-
15
- ### Prerequisites
16
-
17
- - Rust toolchain with `wasm32-unknown-unknown` target
18
- - wasm-pack (optional, for generating npm package)
19
-
20
- ### Build with Cargo
21
-
22
- ```bash
23
- cargo build --target wasm32-unknown-unknown --release
24
- ```
25
-
26
- The compiled WASM module will be at:
27
-
28
- ```
29
- ../target/wasm32-unknown-unknown/release/gossip_wasm.wasm
30
- ```
31
-
32
- ### Build with wasm-pack
33
-
34
- For a complete npm-ready package with TypeScript definitions:
35
-
36
- ```bash
37
- wasm-pack build --target web
38
- ```
39
-
40
- ## Usage
41
-
42
- ### JavaScript/TypeScript
43
-
44
- ```typescript
45
- import init, {
46
- SessionManagerWrapper,
47
- SessionConfig,
48
- generate_user_keys,
49
- EncryptionKey,
50
- } from './gossip_wasm';
51
-
52
- // Initialize WASM
53
- await init();
54
-
55
- // Generate user keys from passphrase
56
- const keys = generate_user_keys('my secure passphrase');
57
- const publicKeys = keys.public_keys();
58
- const secretKeys = keys.secret_keys();
59
- const userId = publicKeys.derive_id();
60
-
61
- // Create session manager with default configuration
62
- const config = SessionConfig.new_default();
63
- const manager = new SessionManagerWrapper(config);
64
-
65
- // Establish session with peer
66
- const peerKeys = generate_user_keys('peer passphrase');
67
- const userData = new TextEncoder().encode('contact_request'); // Optional user data
68
- const announcement = manager.establish_outgoing_session(
69
- peerKeys.public_keys(),
70
- publicKeys,
71
- secretKeys,
72
- userData
73
- );
74
- // Publish announcement to blockchain...
75
-
76
- // Feed incoming announcement from peer
77
- const result = manager.feed_incoming_announcement(
78
- announcementBytes,
79
- publicKeys,
80
- secretKeys
81
- );
82
- if (result) {
83
- console.log('Announcer public keys:', result.announcer_public_keys);
84
- console.log('Timestamp:', result.timestamp);
85
- console.log('User data:', new TextDecoder().decode(result.user_data));
86
- }
87
-
88
- // Send a message (raw bytes)
89
- const messageBytes = new TextEncoder().encode('Hello!');
90
- const peerId = peerKeys.public_keys().derive_id();
91
- const sendOutput = manager.send_message(peerId, messageBytes);
92
- if (sendOutput) {
93
- // Publish sendOutput.seeker and sendOutput.data to blockchain
94
- console.log('Seeker:', sendOutput.seeker);
95
- console.log('Data length:', sendOutput.data.length);
96
- }
97
-
98
- // Check for incoming messages
99
- const seekers = manager.get_message_board_read_keys();
100
- for (let i = 0; i < seekers.length; i++) {
101
- const seeker = seekers.get(i);
102
- // Read from blockchain using seeker...
103
- const received = manager.feed_incoming_message_board_read(
104
- seeker,
105
- data, // encrypted message data
106
- secretKeys
107
- );
108
- if (received) {
109
- console.log('Received:', new TextDecoder().decode(received.message));
110
- console.log('Timestamp:', received.timestamp);
111
- // Check acknowledged seekers
112
- const acks = received.acknowledged_seekers;
113
- for (let j = 0; j < acks.length; j++) {
114
- console.log('Acknowledged:', acks.get(j));
115
- }
116
- }
117
- }
118
-
119
- // Persist session state
120
- const encryptionKey = EncryptionKey.generate();
121
- const encrypted = manager.to_encrypted_blob(encryptionKey);
122
- // Save encrypted blob to storage...
123
-
124
- // Restore session state
125
- const restored = SessionManagerWrapper.from_encrypted_blob(
126
- encrypted,
127
- encryptionKey
128
- );
129
- ```
130
-
131
- ### Custom Configuration
132
-
133
- ```typescript
134
- const config = new SessionConfig(
135
- 604800000, // max_incoming_announcement_age_millis (1 week)
136
- 60000, // max_incoming_announcement_future_millis (1 minute)
137
- 604800000, // max_incoming_message_age_millis (1 week)
138
- 60000, // max_incoming_message_future_millis (1 minute)
139
- 604800000, // max_session_inactivity_millis (1 week)
140
- 86400000, // keep_alive_interval_millis (1 day)
141
- 10000 // max_session_lag_length
142
- );
143
- ```
144
-
145
- ## API Reference
146
-
147
- ### AEAD Encryption Functions
148
-
149
- Direct access to AES-256-SIV authenticated encryption:
150
-
151
- - `aead_encrypt(key: EncryptionKey, nonce: Nonce, plaintext: Uint8Array, aad: Uint8Array)`: Encrypt data
152
- - `aead_decrypt(key: EncryptionKey, nonce: Nonce, ciphertext: Uint8Array, aad: Uint8Array)`: Decrypt data
153
-
154
- #### AEAD Example
155
-
156
- ```typescript
157
- import {
158
- EncryptionKey,
159
- Nonce,
160
- aead_encrypt,
161
- aead_decrypt,
162
- } from './gossip_wasm';
163
-
164
- // Generate key and nonce
165
- const key = EncryptionKey.generate();
166
- const nonce = Nonce.generate();
167
-
168
- // Encrypt some data
169
- const plaintext = new TextEncoder().encode('Secret message');
170
- const aad = new TextEncoder().encode('context info'); // Additional authenticated data
171
- const ciphertext = aead_encrypt(key, nonce, plaintext, aad);
172
-
173
- // Decrypt
174
- const decrypted = aead_decrypt(key, nonce, ciphertext, aad);
175
- if (decrypted) {
176
- console.log('Success:', new TextDecoder().decode(decrypted));
177
- } else {
178
- console.error('Decryption failed - tampering detected!');
179
- }
180
- ```
181
-
182
- **Security Notes:**
183
-
184
- - Nonces should be unique per encryption (16 bytes)
185
- - AAD (Additional Authenticated Data) is authenticated but NOT encrypted
186
- - AES-SIV is nonce-misuse resistant - reusing nonces only leaks if plaintexts are identical
187
- - Keys are 64 bytes (512 bits) for AES-256-SIV
188
-
189
- ### SessionManagerWrapper
190
-
191
- Main class for managing messaging sessions.
192
-
193
- - `new(config: SessionConfig)`: Create new session manager
194
- - `from_encrypted_blob(blob: Uint8Array, key: EncryptionKey)`: Restore from encrypted state
195
- - `to_encrypted_blob(key: EncryptionKey)`: Serialize to encrypted blob
196
- - `establish_outgoing_session(peer_pk, our_pk, our_sk, user_data: Uint8Array)`: Initiate session with peer, including optional user data (returns announcement bytes)
197
- - `feed_incoming_announcement(bytes, our_pk, our_sk)`: Process incoming announcement (returns AnnouncementResult with announcer's public keys and user data, or undefined)
198
- - `send_message(peer_id: Uint8Array, message_contents: Uint8Array)`: Send raw message bytes to peer
199
- - `feed_incoming_message_board_read(seeker, data, our_sk)`: Process incoming messages
200
- - `get_message_board_read_keys()`: Get seekers to monitor for incoming messages
201
- - `peer_list()`: Get all peer IDs
202
- - `peer_session_status(peer_id: Uint8Array)`: Get session status
203
- - `peer_discard(peer_id: Uint8Array)`: Remove peer
204
- - `refresh()`: Refresh sessions and get keep-alive announcement list
205
-
206
- ### AnnouncementResult
207
-
208
- Result from processing an incoming announcement:
209
-
210
- - `announcer_public_keys(): UserPublicKeys`: The public keys of the peer who sent the announcement
211
- - `timestamp(): number`: Unix timestamp in milliseconds when the announcement was created
212
- - `user_data(): Uint8Array`: Arbitrary user data embedded in the announcement (can be empty)
213
-
214
- **Use Cases for User Data:**
215
-
216
- - Contact requests with metadata
217
- - Version information
218
- - Application-specific handshake data
219
- - Display names or profile information
220
- - Protocol negotiation parameters
221
-
222
- **⚠️ Security Warning:**
223
-
224
- The user_data in announcements has **reduced security compared to regular messages**:
225
-
226
- - ✅ **Plausible deniability preserved**: The user_data is not cryptographically signed, so the sender can deny specific content
227
- - ❌ **No post-compromise secrecy**: If long-term keys are compromised, past announcements can be decrypted
228
-
229
- **Recommendation**: Use user_data for non-highly-sensitive metadata. Send truly sensitive information through regular messages after the session is established.
230
-
231
- ### SendMessageOutput
232
-
233
- Output from sending a message:
234
-
235
- - `seeker(): Uint8Array`: Database key for message lookup on message board
236
- - `data(): Uint8Array`: Encrypted message data to publish
237
- - `timestamp(): number`: Message timestamp (milliseconds since Unix epoch)
238
-
239
- ### ReceiveMessageOutput
240
-
241
- Output from receiving a message:
242
-
243
- - `message(): Uint8Array`: Decrypted message contents
244
- - `timestamp(): number`: Message timestamp (milliseconds since Unix epoch)
245
- - `acknowledged_seekers()`: Array of seekers that were acknowledged
246
-
247
- ### Auth Functions
248
-
249
- - `generate_user_keys(passphrase: string)`: Generate keys from passphrase using password KDF
250
-
251
- ### Other Classes
252
-
253
- - `SessionConfig`: Session manager configuration
254
- - `EncryptionKey`: AES-256-SIV key (64 bytes)
255
- - `generate()`: Generate random key
256
- - `from_bytes(bytes: Uint8Array)`: Create from bytes
257
- - `to_bytes()`: Get raw bytes
258
- - `Nonce`: AES-256-SIV nonce (16 bytes)
259
- - `generate()`: Generate random nonce
260
- - `from_bytes(bytes: Uint8Array)`: Create from bytes
261
- - `to_bytes()`: Get raw bytes
262
- - `UserPublicKeys`: User's public keys
263
- - `derive_id()`: Get user ID (32 bytes)
264
- - `to_bytes()`: Serialize to bytes
265
- - `UserSecretKeys`: User's secret keys
266
- - `SessionStatus`: Enum for session states (Active, Inactive, etc.)
267
-
268
- ## Architecture
269
-
270
- The Gossip system uses a multi-layer architecture:
271
-
272
- 1. **Crypto Primitives**: ML-KEM (post-quantum KEM), ML-DSA (post-quantum signatures), AES-SIV (AEAD)
273
- 2. **Agraphon Protocol**: Double-ratchet encryption with forward secrecy and post-compromise security
274
- 3. **Session Layer**: Manages Agraphon sessions with seeker-based addressing using hashed Massa public keys
275
- 4. **Session Manager**: High-level API for multi-peer messaging with session lifecycle management
276
-
277
- Messages are identified by "seekers" - database keys derived from hashing ephemeral Massa public keys. This allows:
278
-
279
- - Efficient message lookup on public message boards
280
- - Privacy (seekers don't reveal sender/recipient identity)
281
- - Unlinkability (each message uses a fresh keypair)