@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,259 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// MeshWhisper SDK — Double Ratchet Module
|
|
3
|
+
// Per-message forward secrecy using the Signal Double Ratchet algorithm.
|
|
4
|
+
// ============================================================
|
|
5
|
+
import { x25519 } from '@noble/curves/ed25519';
|
|
6
|
+
import { blake3 } from '@noble/hashes/blake3';
|
|
7
|
+
import { concatBytes } from '@noble/hashes/utils';
|
|
8
|
+
import { gcm } from '@noble/ciphers/aes';
|
|
9
|
+
// ---- Constants ----
|
|
10
|
+
const MAX_SKIP = 1000;
|
|
11
|
+
const KEY_LENGTH = 32;
|
|
12
|
+
const GCM_NONCE_LENGTH = 12;
|
|
13
|
+
// ---- Key helpers ----
|
|
14
|
+
/** Generate a fresh X25519 keypair for the DH ratchet. */
|
|
15
|
+
function generateDHKeyPair() {
|
|
16
|
+
const secretKey = x25519.utils.randomSecretKey();
|
|
17
|
+
const publicKey = x25519.getPublicKey(secretKey);
|
|
18
|
+
return { privateKey: secretKey, publicKey };
|
|
19
|
+
}
|
|
20
|
+
/** Compute an X25519 shared secret. */
|
|
21
|
+
function dh(keyPair, publicKey) {
|
|
22
|
+
return x25519.getSharedSecret(keyPair.privateKey, publicKey);
|
|
23
|
+
}
|
|
24
|
+
// ---- KDF operations ----
|
|
25
|
+
/**
|
|
26
|
+
* KDF root step: derive a new root key and chain key from a root key and DH output.
|
|
27
|
+
* output = BLAKE3(rootKey || dhOutput, dkLen=64), split into two 32-byte halves.
|
|
28
|
+
*/
|
|
29
|
+
export function kdfRootStep(rootKey, dhOutput) {
|
|
30
|
+
const input = concatBytes(rootKey, dhOutput);
|
|
31
|
+
const output = blake3(input, { dkLen: 64, key: rootKey });
|
|
32
|
+
return {
|
|
33
|
+
newRootKey: output.slice(0, KEY_LENGTH),
|
|
34
|
+
chainKey: output.slice(KEY_LENGTH, KEY_LENGTH * 2),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* KDF chain step: derive a message key and the next chain key from the current chain key.
|
|
39
|
+
* messageKey = BLAKE3(chainKey || 0x01)
|
|
40
|
+
* newChainKey = BLAKE3(chainKey || 0x02)
|
|
41
|
+
*/
|
|
42
|
+
export function kdfChainStep(chainKey) {
|
|
43
|
+
const messageKey = blake3(concatBytes(chainKey, new Uint8Array([0x01])));
|
|
44
|
+
const newChainKey = blake3(concatBytes(chainKey, new Uint8Array([0x02])));
|
|
45
|
+
return { newChainKey, messageKey };
|
|
46
|
+
}
|
|
47
|
+
// ---- Skipped-key bookkeeping ----
|
|
48
|
+
/** Build a map key for a skipped message from the sender's DH public key and the message number. */
|
|
49
|
+
function skippedKeyId(dhPublicKey, messageNumber) {
|
|
50
|
+
// Encode as hex(dhPub) + ":" + messageNumber for uniqueness.
|
|
51
|
+
let hex = '';
|
|
52
|
+
for (let i = 0; i < dhPublicKey.length; i++) {
|
|
53
|
+
hex += dhPublicKey[i].toString(16).padStart(2, '0');
|
|
54
|
+
}
|
|
55
|
+
return hex + ':' + messageNumber;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Skip ahead in the receiving chain, storing message keys for out-of-order messages.
|
|
59
|
+
* Throws if too many messages would be skipped (DoS protection).
|
|
60
|
+
*/
|
|
61
|
+
function skipMessageKeys(state, until) {
|
|
62
|
+
if (state.receivingChainKey === null) {
|
|
63
|
+
return state;
|
|
64
|
+
}
|
|
65
|
+
if (until - state.receiveMessageNumber > MAX_SKIP) {
|
|
66
|
+
throw new Error(`Cannot skip more than ${MAX_SKIP} messages (requested skip of ${until - state.receiveMessageNumber})`);
|
|
67
|
+
}
|
|
68
|
+
const skippedMessageKeys = new Map(state.skippedMessageKeys);
|
|
69
|
+
let chainKey = state.receivingChainKey;
|
|
70
|
+
let n = state.receiveMessageNumber;
|
|
71
|
+
while (n < until) {
|
|
72
|
+
const { newChainKey, messageKey } = kdfChainStep(chainKey);
|
|
73
|
+
const id = skippedKeyId(state.dhReceiving, n);
|
|
74
|
+
skippedMessageKeys.set(id, messageKey);
|
|
75
|
+
chainKey = newChainKey;
|
|
76
|
+
n++;
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
...state,
|
|
80
|
+
receivingChainKey: chainKey,
|
|
81
|
+
receiveMessageNumber: n,
|
|
82
|
+
skippedMessageKeys,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
// ---- DH ratchet step ----
|
|
86
|
+
/**
|
|
87
|
+
* Perform a DH ratchet step: compute new root key / receiving chain key from the
|
|
88
|
+
* remote's new public key, then generate a new sending keypair and compute the
|
|
89
|
+
* sending chain key.
|
|
90
|
+
*/
|
|
91
|
+
export function dhRatchetStep(state, remotePublicKey) {
|
|
92
|
+
const previousSendingChainLength = state.sendMessageNumber;
|
|
93
|
+
// Receiving side: DH with our current sending keypair and their new public key.
|
|
94
|
+
const dhReceiveOutput = dh(state.dhSending, remotePublicKey);
|
|
95
|
+
const { newRootKey: rootKey1, chainKey: receivingChainKey } = kdfRootStep(state.rootKey, dhReceiveOutput);
|
|
96
|
+
// Sending side: generate new DH keypair, compute DH with new keypair and their public key.
|
|
97
|
+
const dhSending = generateDHKeyPair();
|
|
98
|
+
const dhSendOutput = dh(dhSending, remotePublicKey);
|
|
99
|
+
const { newRootKey: rootKey2, chainKey: sendingChainKey } = kdfRootStep(rootKey1, dhSendOutput);
|
|
100
|
+
return {
|
|
101
|
+
...state,
|
|
102
|
+
dhSending,
|
|
103
|
+
dhReceiving: remotePublicKey,
|
|
104
|
+
rootKey: rootKey2,
|
|
105
|
+
sendingChainKey,
|
|
106
|
+
receivingChainKey,
|
|
107
|
+
sendMessageNumber: 0,
|
|
108
|
+
receiveMessageNumber: 0,
|
|
109
|
+
previousSendingChainLength,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// ---- Encrypt / Decrypt helpers ----
|
|
113
|
+
/** Encrypt plaintext with AES-256-GCM using a message key. Nonce is derived deterministically. */
|
|
114
|
+
function aesEncrypt(messageKey, plaintext) {
|
|
115
|
+
// Derive a nonce from the message key via BLAKE3 to avoid needing random state.
|
|
116
|
+
const nonce = blake3(messageKey, { dkLen: GCM_NONCE_LENGTH });
|
|
117
|
+
const cipher = gcm(messageKey, nonce);
|
|
118
|
+
const ciphertext = cipher.encrypt(plaintext);
|
|
119
|
+
// Prepend nonce so the receiver can decrypt.
|
|
120
|
+
return concatBytes(nonce, ciphertext);
|
|
121
|
+
}
|
|
122
|
+
/** Decrypt ciphertext produced by aesEncrypt. */
|
|
123
|
+
function aesDecrypt(messageKey, nonceAndCiphertext) {
|
|
124
|
+
const nonce = nonceAndCiphertext.slice(0, GCM_NONCE_LENGTH);
|
|
125
|
+
const ciphertext = nonceAndCiphertext.slice(GCM_NONCE_LENGTH);
|
|
126
|
+
const cipher = gcm(messageKey, nonce);
|
|
127
|
+
return cipher.decrypt(ciphertext);
|
|
128
|
+
}
|
|
129
|
+
// ---- Initialization ----
|
|
130
|
+
/**
|
|
131
|
+
* Initialize the ratchet state as the sender (initiator) after X3DH.
|
|
132
|
+
*
|
|
133
|
+
* The sender knows the shared secret and the remote's signed pre-key (or ratchet public key).
|
|
134
|
+
* It performs the first DH ratchet step immediately so it can begin sending.
|
|
135
|
+
*/
|
|
136
|
+
export function initSender(sharedSecret, remotePublicKey) {
|
|
137
|
+
const dhSending = generateDHKeyPair();
|
|
138
|
+
const dhOutput = dh(dhSending, remotePublicKey);
|
|
139
|
+
const { newRootKey, chainKey } = kdfRootStep(sharedSecret, dhOutput);
|
|
140
|
+
return {
|
|
141
|
+
dhSending,
|
|
142
|
+
dhReceiving: remotePublicKey,
|
|
143
|
+
rootKey: newRootKey,
|
|
144
|
+
sendingChainKey: chainKey,
|
|
145
|
+
receivingChainKey: null,
|
|
146
|
+
sendMessageNumber: 0,
|
|
147
|
+
receiveMessageNumber: 0,
|
|
148
|
+
previousSendingChainLength: 0,
|
|
149
|
+
skippedMessageKeys: new Map(),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Initialize the ratchet state as the receiver (responder) after X3DH.
|
|
154
|
+
*
|
|
155
|
+
* The receiver provides its own keypair (the signed pre-key used in X3DH) and
|
|
156
|
+
* the shared secret. It waits for the first message to complete the DH ratchet.
|
|
157
|
+
*/
|
|
158
|
+
export function initReceiver(sharedSecret, localKeyPair) {
|
|
159
|
+
return {
|
|
160
|
+
dhSending: localKeyPair,
|
|
161
|
+
dhReceiving: null,
|
|
162
|
+
rootKey: sharedSecret,
|
|
163
|
+
sendingChainKey: null,
|
|
164
|
+
receivingChainKey: null,
|
|
165
|
+
sendMessageNumber: 0,
|
|
166
|
+
receiveMessageNumber: 0,
|
|
167
|
+
previousSendingChainLength: 0,
|
|
168
|
+
skippedMessageKeys: new Map(),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
// ---- Encrypt ----
|
|
172
|
+
/**
|
|
173
|
+
* Encrypt a plaintext message, advancing the sending chain.
|
|
174
|
+
*
|
|
175
|
+
* Returns the updated state, a header (to be sent alongside the ciphertext), and
|
|
176
|
+
* the AES-256-GCM ciphertext.
|
|
177
|
+
*/
|
|
178
|
+
export function ratchetEncrypt(state, plaintext) {
|
|
179
|
+
if (state.sendingChainKey === null) {
|
|
180
|
+
throw new Error('Sending chain not initialized — cannot encrypt before the first DH ratchet step');
|
|
181
|
+
}
|
|
182
|
+
const { newChainKey, messageKey } = kdfChainStep(state.sendingChainKey);
|
|
183
|
+
const header = {
|
|
184
|
+
dhPublicKey: state.dhSending.publicKey,
|
|
185
|
+
previousChainLength: state.previousSendingChainLength,
|
|
186
|
+
messageNumber: state.sendMessageNumber,
|
|
187
|
+
};
|
|
188
|
+
const ciphertext = aesEncrypt(messageKey, plaintext);
|
|
189
|
+
const newState = {
|
|
190
|
+
...state,
|
|
191
|
+
sendingChainKey: newChainKey,
|
|
192
|
+
sendMessageNumber: state.sendMessageNumber + 1,
|
|
193
|
+
};
|
|
194
|
+
return { state: newState, header, ciphertext };
|
|
195
|
+
}
|
|
196
|
+
// ---- Decrypt ----
|
|
197
|
+
/**
|
|
198
|
+
* Decrypt a received message, handling DH ratchet steps and out-of-order delivery.
|
|
199
|
+
*
|
|
200
|
+
* 1. Try skipped message keys first (for out-of-order messages).
|
|
201
|
+
* 2. If the header's DH public key differs from our stored remote key, perform
|
|
202
|
+
* a DH ratchet step (advancing the root chain).
|
|
203
|
+
* 3. Advance the receiving chain to the header's message number, storing any
|
|
204
|
+
* skipped message keys along the way.
|
|
205
|
+
* 4. Decrypt with the derived message key.
|
|
206
|
+
*/
|
|
207
|
+
export function ratchetDecrypt(state, header, ciphertext) {
|
|
208
|
+
// 1. Check skipped message keys.
|
|
209
|
+
const skippedId = skippedKeyId(header.dhPublicKey, header.messageNumber);
|
|
210
|
+
const skippedKey = state.skippedMessageKeys.get(skippedId);
|
|
211
|
+
if (skippedKey !== undefined) {
|
|
212
|
+
const skippedMessageKeys = new Map(state.skippedMessageKeys);
|
|
213
|
+
skippedMessageKeys.delete(skippedId);
|
|
214
|
+
const plaintext = aesDecrypt(skippedKey, ciphertext);
|
|
215
|
+
return {
|
|
216
|
+
state: { ...state, skippedMessageKeys },
|
|
217
|
+
plaintext,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
let currentState = state;
|
|
221
|
+
// 2. DH ratchet step if the remote key has changed.
|
|
222
|
+
const remoteKeyChanged = currentState.dhReceiving === null ||
|
|
223
|
+
!bytesEqual(header.dhPublicKey, currentState.dhReceiving);
|
|
224
|
+
if (remoteKeyChanged) {
|
|
225
|
+
// Skip any remaining messages on the old receiving chain.
|
|
226
|
+
if (currentState.dhReceiving !== null && currentState.receivingChainKey !== null) {
|
|
227
|
+
currentState = skipMessageKeys(currentState, header.previousChainLength);
|
|
228
|
+
}
|
|
229
|
+
currentState = dhRatchetStep(currentState, header.dhPublicKey);
|
|
230
|
+
}
|
|
231
|
+
// 3. Skip messages on the current receiving chain up to this message number.
|
|
232
|
+
currentState = skipMessageKeys(currentState, header.messageNumber);
|
|
233
|
+
// 4. Derive the message key.
|
|
234
|
+
if (currentState.receivingChainKey === null) {
|
|
235
|
+
throw new Error('Receiving chain key is null — protocol state error');
|
|
236
|
+
}
|
|
237
|
+
const { newChainKey, messageKey } = kdfChainStep(currentState.receivingChainKey);
|
|
238
|
+
const plaintext = aesDecrypt(messageKey, ciphertext);
|
|
239
|
+
return {
|
|
240
|
+
state: {
|
|
241
|
+
...currentState,
|
|
242
|
+
receivingChainKey: newChainKey,
|
|
243
|
+
receiveMessageNumber: currentState.receiveMessageNumber + 1,
|
|
244
|
+
},
|
|
245
|
+
plaintext,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
// ---- Utility ----
|
|
249
|
+
/** Constant-time(ish) byte array comparison. */
|
|
250
|
+
function bytesEqual(a, b) {
|
|
251
|
+
if (a.length !== b.length)
|
|
252
|
+
return false;
|
|
253
|
+
let diff = 0;
|
|
254
|
+
for (let i = 0; i < a.length; i++) {
|
|
255
|
+
diff |= a[i] ^ b[i];
|
|
256
|
+
}
|
|
257
|
+
return diff === 0;
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ratchet/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { RelayLedgerEntry, ReciprocityTier } from '../types.js';
|
|
2
|
+
export interface RelayLedgerOptions {
|
|
3
|
+
/** Duration of the new-device grace period, in hours. Defaults to 48. */
|
|
4
|
+
gracePeriodHours?: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Tracks bytes relayed for and by each peer, computes reciprocity scores,
|
|
8
|
+
* and makes relay-priority decisions. Purely local and approximate — there
|
|
9
|
+
* is no global accounting.
|
|
10
|
+
*/
|
|
11
|
+
export declare class RelayLedger {
|
|
12
|
+
private readonly gracePeriodMs;
|
|
13
|
+
private entries;
|
|
14
|
+
private deviceId;
|
|
15
|
+
private deviceRegisteredAt;
|
|
16
|
+
constructor(options?: RelayLedgerOptions);
|
|
17
|
+
/**
|
|
18
|
+
* Record that we relayed `bytes` of data on behalf of `peerId`.
|
|
19
|
+
*/
|
|
20
|
+
recordRelayedForPeer(peerId: string, bytes: number): void;
|
|
21
|
+
/**
|
|
22
|
+
* Record that `peerId` relayed `bytes` of data for us.
|
|
23
|
+
*/
|
|
24
|
+
recordPeerRelayedForUs(peerId: string, bytes: number): void;
|
|
25
|
+
/**
|
|
26
|
+
* Return the ledger entry for a given peer, or `null` if none exists.
|
|
27
|
+
*/
|
|
28
|
+
getEntry(peerId: string): RelayLedgerEntry | null;
|
|
29
|
+
/**
|
|
30
|
+
* Return a snapshot of all ledger entries.
|
|
31
|
+
*/
|
|
32
|
+
getAllEntries(): RelayLedgerEntry[];
|
|
33
|
+
/**
|
|
34
|
+
* Compute the reciprocity score for a specific peer.
|
|
35
|
+
*
|
|
36
|
+
* Score = bytes_relayed_for_them / bytes_they_relayed_for_us
|
|
37
|
+
*
|
|
38
|
+
* - If neither party has relayed anything, returns 1.0 (neutral).
|
|
39
|
+
* - If we have relayed for them but they haven't for us, returns Infinity
|
|
40
|
+
* (we are a pure contributor to this peer).
|
|
41
|
+
* - If they have relayed for us but we haven't for them, returns 0.0
|
|
42
|
+
* (we are a pure consumer from this peer).
|
|
43
|
+
*/
|
|
44
|
+
getScore(peerId: string): number;
|
|
45
|
+
/**
|
|
46
|
+
* Compute the aggregate reciprocity score across all peers.
|
|
47
|
+
*
|
|
48
|
+
* Uses total bytes relayed for all peers vs total bytes all peers
|
|
49
|
+
* relayed for us.
|
|
50
|
+
*/
|
|
51
|
+
getGlobalScore(): number;
|
|
52
|
+
/**
|
|
53
|
+
* Determine the reciprocity tier for a given peer.
|
|
54
|
+
*/
|
|
55
|
+
getTier(peerId: string): ReciprocityTier;
|
|
56
|
+
/**
|
|
57
|
+
* Determine whether we should relay traffic for this peer.
|
|
58
|
+
*
|
|
59
|
+
* Free-riders are refused unless we are still in our grace period.
|
|
60
|
+
*/
|
|
61
|
+
shouldRelay(peerId: string): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Return a relay-queue priority between 0.0 and 1.0 for this peer.
|
|
64
|
+
*
|
|
65
|
+
* Higher values mean packets for/from this peer should be relayed sooner.
|
|
66
|
+
*/
|
|
67
|
+
getRelayPriority(peerId: string): number;
|
|
68
|
+
/**
|
|
69
|
+
* Register this device, recording the current time as the creation
|
|
70
|
+
* timestamp for grace-period purposes.
|
|
71
|
+
*/
|
|
72
|
+
registerDevice(deviceId: string): void;
|
|
73
|
+
/**
|
|
74
|
+
* Returns `true` if this device was registered within the configured
|
|
75
|
+
* grace period (default 48 hours).
|
|
76
|
+
*/
|
|
77
|
+
isInGracePeriod(): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Apply exponential decay to every entry in the ledger.
|
|
80
|
+
*
|
|
81
|
+
* Multiplies both byte counters by `factor` (should be between 0 and 1).
|
|
82
|
+
* This prevents ancient history from permanently dominating the score.
|
|
83
|
+
*/
|
|
84
|
+
decayLedger(factor: number): void;
|
|
85
|
+
/**
|
|
86
|
+
* Remove entries for peers whose `lastUpdated` timestamp is older
|
|
87
|
+
* than `maxAgeMs` milliseconds ago.
|
|
88
|
+
*/
|
|
89
|
+
pruneInactive(maxAgeMs: number): void;
|
|
90
|
+
/**
|
|
91
|
+
* Clear all ledger entries. Device registration is preserved.
|
|
92
|
+
*/
|
|
93
|
+
reset(): void;
|
|
94
|
+
/**
|
|
95
|
+
* Serialize the entire ledger state to a `Uint8Array` for persistence.
|
|
96
|
+
*/
|
|
97
|
+
serialize(): Uint8Array;
|
|
98
|
+
/**
|
|
99
|
+
* Restore a `RelayLedger` from previously serialized data.
|
|
100
|
+
*/
|
|
101
|
+
static deserialize(data: Uint8Array): RelayLedger;
|
|
102
|
+
/**
|
|
103
|
+
* Map a numeric reciprocity score to a tier label.
|
|
104
|
+
*/
|
|
105
|
+
static tierFromScore(score: number): ReciprocityTier;
|
|
106
|
+
private getOrCreateEntry;
|
|
107
|
+
private computeScore;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reciprocity/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AA2BhE,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAkBD;;;;GAIG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,OAAO,CAA4C;IAC3D,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,kBAAkB,CAAuB;gBAErC,OAAO,CAAC,EAAE,kBAAkB;IAYxC;;OAEG;IACH,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IASzD;;OAEG;IACH,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAS3D;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAKjD;;OAEG;IACH,aAAa,IAAI,gBAAgB,EAAE;IAQnC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAQhC;;;;;OAKG;IACH,cAAc,IAAI,MAAM;IAUxB;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe;IAYxC;;;;OAIG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAOpC;;;;OAIG;IACH,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAkBxC;;;OAGG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQtC;;;OAGG;IACH,eAAe,IAAI,OAAO;IAW1B;;;;;OAKG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAUjC;;;OAGG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAYrC;;OAEG;IACH,KAAK,IAAI,IAAI;IAQb;;OAEG;IACH,SAAS,IAAI,UAAU;IAYvB;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW;IAwCjD;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe;IAWpD,OAAO,CAAC,gBAAgB;IAcxB,OAAO,CAAC,YAAY;CASrB"}
|