@meshwhisper/sdk 0.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.
- package/README.md +138 -0
- package/dist/browser/index.d.ts +4 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +19 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/chaff/index.d.ts +91 -0
- package/dist/chaff/index.d.ts.map +1 -0
- package/dist/chaff/index.js +268 -0
- package/dist/chaff/index.js.map +1 -0
- package/dist/cluster/index.d.ts +159 -0
- package/dist/cluster/index.d.ts.map +1 -0
- package/dist/cluster/index.js +393 -0
- package/dist/cluster/index.js.map +1 -0
- package/dist/compliance/index.d.ts +129 -0
- package/dist/compliance/index.d.ts.map +1 -0
- package/dist/compliance/index.js +315 -0
- package/dist/compliance/index.js.map +1 -0
- package/dist/crypto/index.d.ts +65 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +146 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/group/index.d.ts +155 -0
- package/dist/group/index.d.ts.map +1 -0
- package/dist/group/index.js +560 -0
- package/dist/group/index.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/namespace/index.d.ts +155 -0
- package/dist/namespace/index.d.ts.map +1 -0
- package/dist/namespace/index.js +278 -0
- package/dist/namespace/index.js.map +1 -0
- package/dist/node/index.d.ts +4 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +19 -0
- package/dist/node/index.js.map +1 -0
- package/dist/packet/index.d.ts +63 -0
- package/dist/packet/index.d.ts.map +1 -0
- package/dist/packet/index.js +244 -0
- package/dist/packet/index.js.map +1 -0
- package/dist/permissions/index.d.ts +107 -0
- package/dist/permissions/index.d.ts.map +1 -0
- package/dist/permissions/index.js +282 -0
- package/dist/permissions/index.js.map +1 -0
- package/dist/persistence/idb-storage.d.ts +27 -0
- package/dist/persistence/idb-storage.d.ts.map +1 -0
- package/dist/persistence/idb-storage.js +75 -0
- package/dist/persistence/idb-storage.js.map +1 -0
- package/dist/persistence/index.d.ts +4 -0
- package/dist/persistence/index.d.ts.map +1 -0
- package/dist/persistence/index.js +3 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/persistence/node-storage.d.ts +33 -0
- package/dist/persistence/node-storage.d.ts.map +1 -0
- package/dist/persistence/node-storage.js +90 -0
- package/dist/persistence/node-storage.js.map +1 -0
- package/dist/persistence/serialization.d.ts +4 -0
- package/dist/persistence/serialization.d.ts.map +1 -0
- package/dist/persistence/serialization.js +49 -0
- package/dist/persistence/serialization.js.map +1 -0
- package/dist/persistence/types.d.ts +29 -0
- package/dist/persistence/types.d.ts.map +1 -0
- package/dist/persistence/types.js +5 -0
- package/dist/persistence/types.js.map +1 -0
- package/dist/ratchet/index.d.ts +80 -0
- package/dist/ratchet/index.d.ts.map +1 -0
- package/dist/ratchet/index.js +259 -0
- package/dist/ratchet/index.js.map +1 -0
- package/dist/reciprocity/index.d.ts +109 -0
- package/dist/reciprocity/index.d.ts.map +1 -0
- package/dist/reciprocity/index.js +311 -0
- package/dist/reciprocity/index.js.map +1 -0
- package/dist/relay/index.d.ts +87 -0
- package/dist/relay/index.d.ts.map +1 -0
- package/dist/relay/index.js +286 -0
- package/dist/relay/index.js.map +1 -0
- package/dist/routing/index.d.ts +136 -0
- package/dist/routing/index.d.ts.map +1 -0
- package/dist/routing/index.js +478 -0
- package/dist/routing/index.js.map +1 -0
- package/dist/sdk/index.d.ts +322 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +1530 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sybil/index.d.ts +123 -0
- package/dist/sybil/index.d.ts.map +1 -0
- package/dist/sybil/index.js +491 -0
- package/dist/sybil/index.js.map +1 -0
- package/dist/transport/browser/index.d.ts +34 -0
- package/dist/transport/browser/index.d.ts.map +1 -0
- package/dist/transport/browser/index.js +176 -0
- package/dist/transport/browser/index.js.map +1 -0
- package/dist/transport/local/index.d.ts +57 -0
- package/dist/transport/local/index.d.ts.map +1 -0
- package/dist/transport/local/index.js +442 -0
- package/dist/transport/local/index.js.map +1 -0
- package/dist/transport/negotiator/index.d.ts +79 -0
- package/dist/transport/negotiator/index.d.ts.map +1 -0
- package/dist/transport/negotiator/index.js +289 -0
- package/dist/transport/negotiator/index.js.map +1 -0
- package/dist/transport/node/index.d.ts +56 -0
- package/dist/transport/node/index.d.ts.map +1 -0
- package/dist/transport/node/index.js +209 -0
- package/dist/transport/node/index.js.map +1 -0
- package/dist/transport/noop/index.d.ts +11 -0
- package/dist/transport/noop/index.d.ts.map +1 -0
- package/dist/transport/noop/index.js +20 -0
- package/dist/transport/noop/index.js.map +1 -0
- package/dist/transport/p2p/index.d.ts +109 -0
- package/dist/transport/p2p/index.d.ts.map +1 -0
- package/dist/transport/p2p/index.js +237 -0
- package/dist/transport/p2p/index.js.map +1 -0
- package/dist/transport/websocket/index.d.ts +89 -0
- package/dist/transport/websocket/index.d.ts.map +1 -0
- package/dist/transport/websocket/index.js +498 -0
- package/dist/transport/websocket/index.js.map +1 -0
- package/dist/transport/websocket/serialize.d.ts +5 -0
- package/dist/transport/websocket/serialize.d.ts.map +1 -0
- package/dist/transport/websocket/serialize.js +55 -0
- package/dist/transport/websocket/serialize.js.map +1 -0
- package/dist/types.d.ts +215 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -0
- package/dist/x3dh/index.d.ts +120 -0
- package/dist/x3dh/index.d.ts.map +1 -0
- package/dist/x3dh/index.js +290 -0
- package/dist/x3dh/index.js.map +1 -0
- package/package.json +59 -0
- package/src/browser/index.ts +19 -0
- package/src/chaff/index.ts +340 -0
- package/src/cluster/index.ts +482 -0
- package/src/compliance/index.ts +407 -0
- package/src/crypto/index.ts +193 -0
- package/src/group/index.ts +719 -0
- package/src/index.ts +87 -0
- package/src/lz4js.d.ts +58 -0
- package/src/namespace/index.ts +336 -0
- package/src/node/index.ts +19 -0
- package/src/packet/index.ts +326 -0
- package/src/permissions/index.ts +405 -0
- package/src/persistence/idb-storage.ts +83 -0
- package/src/persistence/index.ts +3 -0
- package/src/persistence/node-storage.ts +96 -0
- package/src/persistence/serialization.ts +75 -0
- package/src/persistence/types.ts +33 -0
- package/src/ratchet/index.ts +363 -0
- package/src/reciprocity/index.ts +371 -0
- package/src/relay/index.ts +382 -0
- package/src/routing/index.ts +577 -0
- package/src/sdk/index.ts +1994 -0
- package/src/sybil/index.ts +661 -0
- package/src/transport/browser/index.ts +201 -0
- package/src/transport/local/index.ts +540 -0
- package/src/transport/negotiator/index.ts +397 -0
- package/src/transport/node/index.ts +234 -0
- package/src/transport/noop/index.ts +22 -0
- package/src/transport/p2p/index.ts +345 -0
- package/src/transport/websocket/index.ts +660 -0
- package/src/transport/websocket/serialize.ts +68 -0
- package/src/types.ts +275 -0
- package/src/x3dh/index.ts +388 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// MeshWhisper SDK — X3DH Key Exchange Module
|
|
3
|
+
// Extended Triple Diffie-Hellman adapted for serverless P2P
|
|
4
|
+
// ============================================================
|
|
5
|
+
import { x25519, ed25519 } from '@noble/curves/ed25519';
|
|
6
|
+
import { blake3 } from '@noble/hashes/blake3';
|
|
7
|
+
// --- Constants ---
|
|
8
|
+
/** Protocol version for serialized pre-key bundles. */
|
|
9
|
+
const BUNDLE_VERSION = 0x01;
|
|
10
|
+
/** Length of an X25519/Ed25519 public key in bytes. */
|
|
11
|
+
const KEY_LENGTH = 32;
|
|
12
|
+
/** Length of an Ed25519 signature in bytes. */
|
|
13
|
+
const SIGNATURE_LENGTH = 64;
|
|
14
|
+
/**
|
|
15
|
+
* Generates a full PreKeyBundle for distribution to peers.
|
|
16
|
+
*
|
|
17
|
+
* The bundle contains:
|
|
18
|
+
* - Identity key (Ed25519 public key from the provided key pair)
|
|
19
|
+
* - Signed pre-key (X25519, signed by the identity key)
|
|
20
|
+
* - One-time pre-key (X25519, single-use)
|
|
21
|
+
*
|
|
22
|
+
* The returned `signedPreKeyPair` and `oneTimePreKeyPair` private keys
|
|
23
|
+
* must be stored by the caller — they are required to complete X3DH on
|
|
24
|
+
* the responder side when a handshake arrives.
|
|
25
|
+
*
|
|
26
|
+
* @param identityKeyPair - Ed25519 identity key pair
|
|
27
|
+
* @returns Bundle (public) plus the key pairs (private keys must be stored)
|
|
28
|
+
*/
|
|
29
|
+
export function generatePreKeyBundle(identityKeyPair) {
|
|
30
|
+
// Generate signed pre-key (X25519)
|
|
31
|
+
const signedPreKeyPrivate = x25519.utils.randomSecretKey();
|
|
32
|
+
const signedPreKeyPublic = x25519.getPublicKey(signedPreKeyPrivate);
|
|
33
|
+
// Sign the signed pre-key's public key with the Ed25519 identity key
|
|
34
|
+
const signature = ed25519.sign(signedPreKeyPublic, identityKeyPair.privateKey);
|
|
35
|
+
// Generate one-time pre-key (X25519)
|
|
36
|
+
const oneTimePreKeyPrivate = x25519.utils.randomSecretKey();
|
|
37
|
+
const oneTimePreKeyPublic = x25519.getPublicKey(oneTimePreKeyPrivate);
|
|
38
|
+
return {
|
|
39
|
+
bundle: {
|
|
40
|
+
identityKey: identityKeyPair.publicKey,
|
|
41
|
+
signedPreKey: signedPreKeyPublic,
|
|
42
|
+
signedPreKeySignature: signature,
|
|
43
|
+
oneTimePreKey: oneTimePreKeyPublic,
|
|
44
|
+
},
|
|
45
|
+
signedPreKeyPair: {
|
|
46
|
+
publicKey: signedPreKeyPublic,
|
|
47
|
+
privateKey: signedPreKeyPrivate,
|
|
48
|
+
},
|
|
49
|
+
oneTimePreKeyPair: {
|
|
50
|
+
publicKey: oneTimePreKeyPublic,
|
|
51
|
+
privateKey: oneTimePreKeyPrivate,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Generates a batch of one-time pre-keys for replenishment.
|
|
57
|
+
*
|
|
58
|
+
* Returns full KeyPairs — the caller must store the private keys.
|
|
59
|
+
* Only public keys are distributed in the prekey bundle; private keys
|
|
60
|
+
* are required locally to complete X3DH when a matching handshake arrives.
|
|
61
|
+
*
|
|
62
|
+
* @param _identityKeyPair - Unused; kept for API consistency
|
|
63
|
+
* @param count - Number of one-time pre-keys to generate
|
|
64
|
+
* @returns Array of X25519 key pairs
|
|
65
|
+
*/
|
|
66
|
+
export function generateOneTimePreKeys(_identityKeyPair, count) {
|
|
67
|
+
if (count < 0 || !Number.isInteger(count)) {
|
|
68
|
+
throw new Error('count must be a non-negative integer');
|
|
69
|
+
}
|
|
70
|
+
const keys = [];
|
|
71
|
+
for (let i = 0; i < count; i++) {
|
|
72
|
+
const privateKey = x25519.utils.randomSecretKey();
|
|
73
|
+
keys.push({ privateKey, publicKey: x25519.getPublicKey(privateKey) });
|
|
74
|
+
}
|
|
75
|
+
return keys;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Performs the initiator side (Alice) of the X3DH key exchange.
|
|
79
|
+
*
|
|
80
|
+
* Executes 3 or 4 DH operations:
|
|
81
|
+
* DH1 = DH(IK_A, SPK_B) — Alice's identity key with Bob's signed pre-key
|
|
82
|
+
* DH2 = DH(EK_A, IK_B) — Alice's ephemeral key with Bob's identity key
|
|
83
|
+
* DH3 = DH(EK_A, SPK_B) — Alice's ephemeral key with Bob's signed pre-key
|
|
84
|
+
* DH4 = DH(EK_A, OPK_B) — Alice's ephemeral key with Bob's one-time pre-key (optional)
|
|
85
|
+
*
|
|
86
|
+
* The shared secret is derived as BLAKE3(DH1 || DH2 || DH3 [|| DH4]).
|
|
87
|
+
*
|
|
88
|
+
* @param aliceIdentity - Alice's Ed25519 identity key pair
|
|
89
|
+
* @param bobPreKeyBundle - Bob's published PreKeyBundle
|
|
90
|
+
* @returns The derived shared secret, ephemeral public key, and OPK usage flag
|
|
91
|
+
* @throws If the pre-key bundle signature is invalid
|
|
92
|
+
*/
|
|
93
|
+
export function initiateKeyExchange(aliceIdentity, bobPreKeyBundle) {
|
|
94
|
+
// Verify Bob's signed pre-key before proceeding
|
|
95
|
+
if (!verifyPreKeyBundle(bobPreKeyBundle)) {
|
|
96
|
+
throw new Error('Invalid pre-key bundle: signed pre-key signature verification failed');
|
|
97
|
+
}
|
|
98
|
+
// Convert Alice's Ed25519 identity key to X25519 for DH operations
|
|
99
|
+
const aliceIdentityX25519Private = ed25519.utils.toMontgomerySecret(aliceIdentity.privateKey);
|
|
100
|
+
// Convert Bob's Ed25519 identity public key to X25519
|
|
101
|
+
const bobIdentityX25519Public = ed25519.utils.toMontgomery(bobPreKeyBundle.identityKey);
|
|
102
|
+
// Generate Alice's ephemeral X25519 key pair
|
|
103
|
+
const ephemeralPrivate = x25519.utils.randomSecretKey();
|
|
104
|
+
const ephemeralPublic = x25519.getPublicKey(ephemeralPrivate);
|
|
105
|
+
// DH1: DH(IK_A, SPK_B)
|
|
106
|
+
const dh1 = x25519.getSharedSecret(aliceIdentityX25519Private, bobPreKeyBundle.signedPreKey);
|
|
107
|
+
// DH2: DH(EK_A, IK_B)
|
|
108
|
+
const dh2 = x25519.getSharedSecret(ephemeralPrivate, bobIdentityX25519Public);
|
|
109
|
+
// DH3: DH(EK_A, SPK_B)
|
|
110
|
+
const dh3 = x25519.getSharedSecret(ephemeralPrivate, bobPreKeyBundle.signedPreKey);
|
|
111
|
+
// DH4: DH(EK_A, OPK_B) — optional
|
|
112
|
+
const usedOneTimePreKey = bobPreKeyBundle.oneTimePreKey != null;
|
|
113
|
+
let dhConcat;
|
|
114
|
+
if (usedOneTimePreKey) {
|
|
115
|
+
const dh4 = x25519.getSharedSecret(ephemeralPrivate, bobPreKeyBundle.oneTimePreKey);
|
|
116
|
+
dhConcat = concatBytes(dh1, dh2, dh3, dh4);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
dhConcat = concatBytes(dh1, dh2, dh3);
|
|
120
|
+
}
|
|
121
|
+
// Derive shared secret via BLAKE3
|
|
122
|
+
const sharedSecret = blake3(dhConcat);
|
|
123
|
+
return {
|
|
124
|
+
sharedSecret,
|
|
125
|
+
ephemeralPublicKey: ephemeralPublic,
|
|
126
|
+
usedOneTimePreKey,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
// --- Key Exchange: Responder (Bob) ---
|
|
130
|
+
/**
|
|
131
|
+
* Performs the responder side (Bob) of the X3DH key exchange.
|
|
132
|
+
*
|
|
133
|
+
* Mirrors the initiator's DH operations to derive the same shared secret:
|
|
134
|
+
* DH1 = DH(SPK_B, IK_A) — Bob's signed pre-key with Alice's identity key
|
|
135
|
+
* DH2 = DH(IK_B, EK_A) — Bob's identity key with Alice's ephemeral key
|
|
136
|
+
* DH3 = DH(SPK_B, EK_A) — Bob's signed pre-key with Alice's ephemeral key
|
|
137
|
+
* DH4 = DH(OPK_B, EK_A) — Bob's one-time pre-key with Alice's ephemeral key (optional)
|
|
138
|
+
*
|
|
139
|
+
* @param bobIdentity - Bob's Ed25519 identity key pair
|
|
140
|
+
* @param bobSignedPreKey - Bob's X25519 signed pre-key pair
|
|
141
|
+
* @param bobOneTimePreKey - Bob's X25519 one-time pre-key pair (null if not used)
|
|
142
|
+
* @param aliceIdentityKey - Alice's Ed25519 identity public key
|
|
143
|
+
* @param aliceEphemeralKey - Alice's X25519 ephemeral public key
|
|
144
|
+
* @returns The derived shared secret (same as Alice's if inputs are correct)
|
|
145
|
+
*/
|
|
146
|
+
export function completeKeyExchange(bobIdentity, bobSignedPreKey, bobOneTimePreKey, aliceIdentityKey, aliceEphemeralKey) {
|
|
147
|
+
// Convert Alice's Ed25519 identity public key to X25519
|
|
148
|
+
const aliceIdentityX25519Public = ed25519.utils.toMontgomery(aliceIdentityKey);
|
|
149
|
+
// Convert Bob's Ed25519 identity key to X25519
|
|
150
|
+
const bobIdentityX25519Private = ed25519.utils.toMontgomerySecret(bobIdentity.privateKey);
|
|
151
|
+
// DH1: DH(SPK_B, IK_A) — mirrors Alice's DH(IK_A, SPK_B)
|
|
152
|
+
const dh1 = x25519.getSharedSecret(bobSignedPreKey.privateKey, aliceIdentityX25519Public);
|
|
153
|
+
// DH2: DH(IK_B, EK_A) — mirrors Alice's DH(EK_A, IK_B)
|
|
154
|
+
const dh2 = x25519.getSharedSecret(bobIdentityX25519Private, aliceEphemeralKey);
|
|
155
|
+
// DH3: DH(SPK_B, EK_A) — mirrors Alice's DH(EK_A, SPK_B)
|
|
156
|
+
const dh3 = x25519.getSharedSecret(bobSignedPreKey.privateKey, aliceEphemeralKey);
|
|
157
|
+
// DH4: DH(OPK_B, EK_A) — optional
|
|
158
|
+
let dhConcat;
|
|
159
|
+
if (bobOneTimePreKey != null) {
|
|
160
|
+
const dh4 = x25519.getSharedSecret(bobOneTimePreKey.privateKey, aliceEphemeralKey);
|
|
161
|
+
dhConcat = concatBytes(dh1, dh2, dh3, dh4);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
dhConcat = concatBytes(dh1, dh2, dh3);
|
|
165
|
+
}
|
|
166
|
+
// Derive shared secret via BLAKE3
|
|
167
|
+
return blake3(dhConcat);
|
|
168
|
+
}
|
|
169
|
+
// --- PreKey Bundle Verification ---
|
|
170
|
+
/**
|
|
171
|
+
* Verifies the signed pre-key signature in a PreKeyBundle.
|
|
172
|
+
*
|
|
173
|
+
* Checks that the signedPreKey was signed by the holder of the identityKey
|
|
174
|
+
* using Ed25519.
|
|
175
|
+
*
|
|
176
|
+
* @param bundle - The PreKeyBundle to verify
|
|
177
|
+
* @returns true if the signature is valid, false otherwise
|
|
178
|
+
*/
|
|
179
|
+
export function verifyPreKeyBundle(bundle) {
|
|
180
|
+
try {
|
|
181
|
+
return ed25519.verify(bundle.signedPreKeySignature, bundle.signedPreKey, bundle.identityKey);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// --- Serialization ---
|
|
188
|
+
/**
|
|
189
|
+
* Serializes a PreKeyBundle to a compact binary format for gossip distribution.
|
|
190
|
+
*
|
|
191
|
+
* Wire format:
|
|
192
|
+
* [version: 1 byte]
|
|
193
|
+
* [flags: 1 byte] — bit 0: hasOneTimePreKey
|
|
194
|
+
* [identityKey: 32 bytes]
|
|
195
|
+
* [signedPreKey: 32 bytes]
|
|
196
|
+
* [signedPreKeySignature: 64 bytes]
|
|
197
|
+
* [oneTimePreKey: 32 bytes] — optional, present if flags bit 0 is set
|
|
198
|
+
*
|
|
199
|
+
* Total: 130 bytes without OPK, 162 bytes with OPK.
|
|
200
|
+
*
|
|
201
|
+
* @param bundle - The PreKeyBundle to serialize
|
|
202
|
+
* @returns Serialized binary representation
|
|
203
|
+
*/
|
|
204
|
+
export function serializePreKeyBundle(bundle) {
|
|
205
|
+
const hasOPK = bundle.oneTimePreKey != null;
|
|
206
|
+
const flags = hasOPK ? 0x01 : 0x00;
|
|
207
|
+
const totalLength = 1 + 1 + KEY_LENGTH + KEY_LENGTH + SIGNATURE_LENGTH + (hasOPK ? KEY_LENGTH : 0);
|
|
208
|
+
const data = new Uint8Array(totalLength);
|
|
209
|
+
let offset = 0;
|
|
210
|
+
// Version
|
|
211
|
+
data[offset++] = BUNDLE_VERSION;
|
|
212
|
+
// Flags
|
|
213
|
+
data[offset++] = flags;
|
|
214
|
+
// Identity key
|
|
215
|
+
data.set(bundle.identityKey, offset);
|
|
216
|
+
offset += KEY_LENGTH;
|
|
217
|
+
// Signed pre-key
|
|
218
|
+
data.set(bundle.signedPreKey, offset);
|
|
219
|
+
offset += KEY_LENGTH;
|
|
220
|
+
// Signed pre-key signature
|
|
221
|
+
data.set(bundle.signedPreKeySignature, offset);
|
|
222
|
+
offset += SIGNATURE_LENGTH;
|
|
223
|
+
// One-time pre-key (optional)
|
|
224
|
+
if (hasOPK) {
|
|
225
|
+
data.set(bundle.oneTimePreKey, offset);
|
|
226
|
+
}
|
|
227
|
+
return data;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Deserializes a PreKeyBundle from its binary representation.
|
|
231
|
+
*
|
|
232
|
+
* @param data - Serialized PreKeyBundle bytes
|
|
233
|
+
* @returns The deserialized PreKeyBundle
|
|
234
|
+
* @throws If the data is malformed or has an unsupported version
|
|
235
|
+
*/
|
|
236
|
+
export function deserializePreKeyBundle(data) {
|
|
237
|
+
if (data.length < 2) {
|
|
238
|
+
throw new Error('PreKeyBundle data too short: missing header');
|
|
239
|
+
}
|
|
240
|
+
let offset = 0;
|
|
241
|
+
// Version
|
|
242
|
+
const version = data[offset++];
|
|
243
|
+
if (version !== BUNDLE_VERSION) {
|
|
244
|
+
throw new Error(`Unsupported PreKeyBundle version: ${version}`);
|
|
245
|
+
}
|
|
246
|
+
// Flags
|
|
247
|
+
const flags = data[offset++];
|
|
248
|
+
const hasOPK = (flags & 0x01) !== 0;
|
|
249
|
+
const expectedLength = 1 + 1 + KEY_LENGTH + KEY_LENGTH + SIGNATURE_LENGTH + (hasOPK ? KEY_LENGTH : 0);
|
|
250
|
+
if (data.length < expectedLength) {
|
|
251
|
+
throw new Error(`PreKeyBundle data too short: expected ${expectedLength} bytes, got ${data.length}`);
|
|
252
|
+
}
|
|
253
|
+
// Identity key
|
|
254
|
+
const identityKey = data.slice(offset, offset + KEY_LENGTH);
|
|
255
|
+
offset += KEY_LENGTH;
|
|
256
|
+
// Signed pre-key
|
|
257
|
+
const signedPreKey = data.slice(offset, offset + KEY_LENGTH);
|
|
258
|
+
offset += KEY_LENGTH;
|
|
259
|
+
// Signed pre-key signature
|
|
260
|
+
const signedPreKeySignature = data.slice(offset, offset + SIGNATURE_LENGTH);
|
|
261
|
+
offset += SIGNATURE_LENGTH;
|
|
262
|
+
// One-time pre-key (optional)
|
|
263
|
+
const oneTimePreKey = hasOPK
|
|
264
|
+
? data.slice(offset, offset + KEY_LENGTH)
|
|
265
|
+
: undefined;
|
|
266
|
+
return {
|
|
267
|
+
identityKey,
|
|
268
|
+
signedPreKey,
|
|
269
|
+
signedPreKeySignature,
|
|
270
|
+
oneTimePreKey,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
// --- Utility ---
|
|
274
|
+
/**
|
|
275
|
+
* Concatenates multiple Uint8Arrays into a single Uint8Array.
|
|
276
|
+
*/
|
|
277
|
+
function concatBytes(...arrays) {
|
|
278
|
+
let totalLength = 0;
|
|
279
|
+
for (const arr of arrays) {
|
|
280
|
+
totalLength += arr.length;
|
|
281
|
+
}
|
|
282
|
+
const result = new Uint8Array(totalLength);
|
|
283
|
+
let offset = 0;
|
|
284
|
+
for (const arr of arrays) {
|
|
285
|
+
result.set(arr, offset);
|
|
286
|
+
offset += arr.length;
|
|
287
|
+
}
|
|
288
|
+
return result;
|
|
289
|
+
}
|
|
290
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/x3dh/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@meshwhisper/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Serverless P2P E2EE Messaging SDK",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./browser": {
|
|
14
|
+
"types": "./dist/browser/index.d.ts",
|
|
15
|
+
"default": "./dist/browser/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./node": {
|
|
18
|
+
"types": "./dist/node/index.d.ts",
|
|
19
|
+
"default": "./dist/node/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./persistence/idb": {
|
|
22
|
+
"types": "./dist/persistence/idb-storage.d.ts",
|
|
23
|
+
"default": "./dist/persistence/idb-storage.js"
|
|
24
|
+
},
|
|
25
|
+
"./persistence/node": {
|
|
26
|
+
"types": "./dist/persistence/node-storage.d.ts",
|
|
27
|
+
"default": "./dist/persistence/node-storage.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": ["dist", "src"],
|
|
31
|
+
"publishConfig": { "access": "public" },
|
|
32
|
+
"scripts": {
|
|
33
|
+
"prepublishOnly": "npm run build",
|
|
34
|
+
"build": "tsc",
|
|
35
|
+
"test": "vitest run",
|
|
36
|
+
"test:watch": "vitest",
|
|
37
|
+
"lint": "eslint src/",
|
|
38
|
+
"demo": "npx tsx demo/server.ts",
|
|
39
|
+
"demo:alice": "npx tsx demo/server.ts 3001 Alice",
|
|
40
|
+
"demo:bob": "npx tsx demo/server.ts 3002 Bob"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@noble/ciphers": "^1.2.0",
|
|
44
|
+
"@noble/curves": "^1.8.0",
|
|
45
|
+
"@noble/hashes": "^1.7.0",
|
|
46
|
+
"lz4js": "^0.2.0"
|
|
47
|
+
},
|
|
48
|
+
"optionalDependencies": {
|
|
49
|
+
"ws": "^8.18.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/node": "^22.0.0",
|
|
53
|
+
"@types/ws": "^8.5.0",
|
|
54
|
+
"tsx": "^4.21.0",
|
|
55
|
+
"typescript": "^5.7.0",
|
|
56
|
+
"vitest": "^3.0.0"
|
|
57
|
+
},
|
|
58
|
+
"license": "MIT"
|
|
59
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// MeshWhisper SDK — Browser / PWA entry point
|
|
3
|
+
// @meshwhisper/sdk/browser
|
|
4
|
+
//
|
|
5
|
+
// Re-exports everything from the main SDK plus browser-specific
|
|
6
|
+
// storage and transport implementations.
|
|
7
|
+
//
|
|
8
|
+
// Usage:
|
|
9
|
+
// import { MeshWhisper, IDBStorage, BrowserTransport } from '@meshwhisper/sdk/browser';
|
|
10
|
+
//
|
|
11
|
+
// When you call MeshWhisper.init() in a browser environment, the SDK
|
|
12
|
+
// detects window/indexedDB and auto-selects IDBStorage + BrowserTransport.
|
|
13
|
+
// You only need to import from this path if you want to reference the
|
|
14
|
+
// classes explicitly (e.g. to construct IDBStorage with a custom namespace).
|
|
15
|
+
// ============================================================
|
|
16
|
+
|
|
17
|
+
export * from '../index.js';
|
|
18
|
+
export { IDBStorage } from '../persistence/idb-storage.js';
|
|
19
|
+
export { BrowserTransport } from '../transport/browser/index.js';
|