@hive-p2p/server 1.0.65 → 1.0.67

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.
@@ -105,7 +105,7 @@ export class CryptoCodex {
105
105
  async #generateAntiSybilIdentity(seed, asPublicNode) {
106
106
  const maxIterations = (2 ** IDENTITY.DIFFICULTY) * 100; // avoid infinite loop
107
107
  for (let i = 0; i < maxIterations; i++) { // avoid infinite loop
108
- const { secretKey, publicKey } = ed25519.keygen(seed);
108
+ const { secretKey, publicKey } = await ed25519.keygenAsync(seed);
109
109
  const id = this.#idFromPublicKey(publicKey);
110
110
  if (asPublicNode && !this.isPublicNode(id)) continue; // Check prefix
111
111
  if (!asPublicNode && this.isPublicNode(id)) continue; // Check prefix
@@ -120,13 +120,15 @@ export class CryptoCodex {
120
120
  }
121
121
 
122
122
  // MESSSAGE CREATION (SERIALIZATION AND SIGNATURE INCLUDED)
123
- signBufferViewAndAppendSignature(bufferView, privateKey, signaturePosition = bufferView.length - IDENTITY.SIGNATURE_LENGTH) {
123
+ /** @param {Uint8Array} bufferView @param {Uint8Array} privateKey @param {number} [signaturePosition] */
124
+ async signBufferViewAndAppendSignature(bufferView, privateKey, signaturePosition = bufferView.length - IDENTITY.SIGNATURE_LENGTH) {
124
125
  if (this.AVOID_CRYPTO) return;
125
126
  const dataToSign = bufferView.subarray(0, signaturePosition);
126
- bufferView.set(ed25519.sign(dataToSign, privateKey), signaturePosition);
127
+ const signature = await ed25519.signAsync(dataToSign, privateKey);
128
+ bufferView.set(signature, signaturePosition);
127
129
  }
128
130
  /** @param {string} topic @param {string | Uint8Array | Object} data @param {number} [HOPS] @param {string[]} route @param {string[]} [neighbors] */
129
- createGossipMessage(topic, data, HOPS = 3, neighbors = [], timestamp = CLOCK.time) {
131
+ async createGossipMessage(topic, data, HOPS = 3, neighbors = [], timestamp = CLOCK.time) {
130
132
  const MARKER = GOSSIP.MARKERS_BYTES[topic];
131
133
  if (MARKER === undefined) throw new Error(`Failed to create gossip message: unknown topic '${topic}'.`);
132
134
 
@@ -140,7 +142,7 @@ export class CryptoCodex {
140
142
  bufferView.set(neighborsBytes, 47); // X bytes for neighbors
141
143
  bufferView.set(dataBytes, 47 + neighborsBytes.length); // X bytes for data
142
144
  bufferView.set([Math.min(255, HOPS)], totalBytes - 1); // 1 byte for HOPS (Unsigned)
143
- this.signBufferViewAndAppendSignature(bufferView, this.privateKey, totalBytes - IDENTITY.SIGNATURE_LENGTH - 1);
145
+ await this.signBufferViewAndAppendSignature(bufferView, this.privateKey, totalBytes - IDENTITY.SIGNATURE_LENGTH - 1);
144
146
  return bufferView;
145
147
  }
146
148
  /** @param {Uint8Array} serializedMessage */
@@ -151,7 +153,7 @@ export class CryptoCodex {
151
153
  return clone;
152
154
  }
153
155
  /** @param {string} type @param {string | Uint8Array | Object} data @param {string[]} route @param {string[]} [neighbors] */
154
- createUnicastMessage(type, data, route, neighbors = [], timestamp = CLOCK.time) {
156
+ async createUnicastMessage(type, data, route, neighbors = [], timestamp = CLOCK.time) {
155
157
  const MARKER = UNICAST.MARKERS_BYTES[type];
156
158
  if (MARKER === undefined) throw new Error(`Failed to create unicast message: unknown type '${type}'.`);
157
159
  if (route.length < 2) throw new Error('Failed to create unicast message: route must have at least 2 nodes (next hop and target).');
@@ -171,11 +173,11 @@ export class CryptoCodex {
171
173
  bufferView.set([route.length], 47 + NDBL); // 1 byte for route length
172
174
  bufferView.set(routeBytes, 47 + 1 + NDBL); // X bytes for route
173
175
 
174
- this.signBufferViewAndAppendSignature(bufferView, this.privateKey, totalBytes - IDENTITY.SIGNATURE_LENGTH);
176
+ await this.signBufferViewAndAppendSignature(bufferView, this.privateKey, totalBytes - IDENTITY.SIGNATURE_LENGTH);
175
177
  return bufferView;
176
178
  }
177
179
  /** @param {Uint8Array} serialized @param {string[]} newRoute */
178
- createReroutedUnicastMessage(serialized, newRoute) {
180
+ async createReroutedUnicastMessage(serialized, newRoute) {
179
181
  if (newRoute.length < 2) throw new Error('Failed to create rerouted unicast message: route must have at least 2 nodes (next hop and target).');
180
182
  if (newRoute.length > UNICAST.MAX_HOPS) throw new Error(`Failed to create rerouted unicast message: route exceeds max hops (${UNICAST.MAX_HOPS}).`);
181
183
 
@@ -187,7 +189,7 @@ export class CryptoCodex {
187
189
  bufferView.set(this.publicKey, serialized.length); // 32 bytes for new public key
188
190
  for (let i = 0; i < routeBytesArray.length; i++) bufferView.set(routeBytesArray[i], serialized.length + 32 + (i * IDENTITY.ID_LENGTH)); // new route
189
191
 
190
- this.signBufferViewAndAppendSignature(bufferView, this.privateKey, totalBytes - IDENTITY.SIGNATURE_LENGTH);
192
+ await this.signBufferViewAndAppendSignature(bufferView, this.privateKey, totalBytes - IDENTITY.SIGNATURE_LENGTH);
191
193
  return bufferView;
192
194
  }
193
195
  /** @param {string[]} ids */
@@ -217,8 +219,6 @@ export class CryptoCodex {
217
219
  /** @param {Uint8Array} publicKey @param {Uint8Array} dataToVerify @param {Uint8Array} signature */
218
220
  async verifySignature(publicKey, dataToVerify, signature) {
219
221
  if (this.AVOID_CRYPTO) return true;
220
- //return ed25519.verifyAsync(signature, dataToVerify, publicKey);
221
- // new version with batching to optimize timings using ed25519 async.
222
222
  return this.verifier.verifySignature(publicKey, dataToVerify, signature);
223
223
  }
224
224
  /** @param {Uint8Array} bufferView */
package/core/gossip.mjs CHANGED
@@ -103,9 +103,9 @@ export class Gossip {
103
103
  }
104
104
  /** Gossip a message to all connected peers > will be forwarded to all peers
105
105
  * @param {string | Uint8Array | Object} data @param {string} topic default: 'gossip' @param {number} [HOPS] */
106
- broadcastToAll(data, topic = 'gossip', HOPS) {
106
+ async broadcastToAll(data, topic = 'gossip', HOPS) {
107
107
  const hops = HOPS || GOSSIP.HOPS[topic] || GOSSIP.HOPS.default;
108
- const serializedMessage = this.cryptoCodex.createGossipMessage(topic, data, hops, this.peerStore.neighborsList);
108
+ const serializedMessage = await this.cryptoCodex.createGossipMessage(topic, data, hops, this.peerStore.neighborsList);
109
109
  if (!this.bloomFilter.addMessage(serializedMessage)) return; // avoid sending duplicate messages
110
110
  if (this.verbose > 3) console.log(`(${this.id}) Gossip ${topic}, to ${JSON.stringify(this.peerStore.neighborsList)}: ${data}`);
111
111
  for (const peerId of this.peerStore.neighborsList) this.#broadcastToPeer(peerId, serializedMessage);
@@ -51,7 +51,7 @@ export class NodeServices {
51
51
  #startWebSocketServer(domain = 'localhost', port = SERVICE.PORT) {
52
52
  this.wsServer = new TRANSPORTS.WS_SERVER({ port, host: domain });
53
53
  this.wsServer.on('error', (error) => console.error(`WebSocket error on Node #${this.id}:`, error));
54
- this.wsServer.on('connection', (ws) => {
54
+ this.wsServer.on('connection', async (ws) => {
55
55
  ws.on('close', () => { if (remoteId) for (const cb of this.peerStore.callbacks.disconnect) cb(remoteId, 'in'); });
56
56
  ws.on('error', (error) => console.error(`WebSocket error on Node #${this.id} with peer ${remoteId}:`, error.stack));
57
57
 
@@ -78,7 +78,9 @@ export class NodeServices {
78
78
  for (const cb of this.peerStore.callbacks.connect) cb(remoteId, 'in');
79
79
  }
80
80
  });
81
- ws.send(this.cryptoCodex.createUnicastMessage('handshake', null, [this.id, this.id], this.peerStore.neighborsList));
81
+
82
+ const handshakeMsg = await this.cryptoCodex.createUnicastMessage('handshake', null, [this.id, this.id], this.peerStore.neighborsList);
83
+ ws.send(handshakeMsg);
82
84
  });
83
85
  }
84
86
  #startSTUNServer(host = 'localhost', port = SERVICE.PORT + 1) {
package/core/node.mjs CHANGED
@@ -162,10 +162,10 @@ export class Node {
162
162
  /** Broadcast a message to all connected peers or to a specified peer
163
163
  * @param {string | Uint8Array | Object} data @param {string} topic default: 'gossip' @param {string} [targetId] default: broadcast to all
164
164
  * @param {number} [timestamp] default: CLOCK.time @param {number} [HOPS] default: GOSSIP.HOPS[topic] || GOSSIP.HOPS.default */
165
- broadcast(data, topic, HOPS) { this.gossip.broadcastToAll(data, topic, HOPS); }
165
+ async broadcast(data, topic, HOPS) { return this.gossip.broadcastToAll(data, topic, HOPS); }
166
166
 
167
167
  /** @param {string} remoteId @param {string | Uint8Array | Object} data @param {string} type */
168
- sendMessage(remoteId, data, type, spread = 1) { this.messager.sendUnicast(remoteId, data, type, spread); }
168
+ async sendMessage(remoteId, data, type, spread = 1) { return this.messager.sendUnicast(remoteId, data, type, spread); }
169
169
 
170
170
  /** Send a connection request to a peer */
171
171
  async tryConnectToPeer(targetId = 'toto', retry = 10) {
@@ -169,7 +169,7 @@ export class Topologist {
169
169
  let remoteId = null;
170
170
  const ws = new TRANSPORTS.WS_CLIENT(this.#getFullWsUrl(publicUrl)); ws.binaryType = 'arraybuffer';
171
171
  ws.onerror = (error) => console.error(`WebSocket error:`, error.stack);
172
- ws.onopen = () => {
172
+ ws.onopen = async () => {
173
173
  this.bootstrapsConnectionState.set(publicUrl, true);
174
174
  ws.onclose = () => {
175
175
  this.bootstrapsConnectionState.set(publicUrl, false);
@@ -197,8 +197,9 @@ export class Topologist {
197
197
  for (const cb of this.peerStore.callbacks.connect) cb(remoteId, 'out');
198
198
  }
199
199
  };
200
- ws.send(this.cryptoCodex.createUnicastMessage('handshake', null, [this.id, this.id], this.peerStore.neighborsList));
201
- };
200
+ const handshakeMsg = await this.cryptoCodex.createUnicastMessage('handshake', null, [this.id, this.id], this.peerStore.neighborsList);
201
+ ws.send(handshakeMsg);
202
+ };
202
203
  }
203
204
  #tryToSpreadSDP(nonPublicNeighborsCount = 0, isHalfReached = false) { // LOOP TO SELECT ONE UNSEND READY OFFER AND BROADCAST IT
204
205
  if (!this.automation.spreadOffers) return;
package/core/unicast.mjs CHANGED
@@ -76,13 +76,14 @@ export class UnicastMessager {
76
76
  /** Send unicast message to a target
77
77
  * @param {string} remoteId @param {string | Uint8Array | Object} data @param {string} type
78
78
  * @param {number} [spread] Max neighbors used to relay the message, default: 1 */
79
- sendUnicast(remoteId, data, type = 'message', spread = 1) {
79
+ async sendUnicast(remoteId, data, type = 'message', spread = 1) {
80
80
  if (remoteId === this.id) return false;
81
81
 
82
82
  const builtResult = this.pathFinder.buildRoutes(remoteId, this.maxRoutes, this.maxHops, this.maxNodes, true);
83
83
  if (!builtResult.success) return false;
84
84
 
85
85
  // Caution: re-routing usage who can involve insane results
86
+ const createdMessagePromises = [];
86
87
  const finalSpread = builtResult.success === 'blind' ? 1 : spread; // Spread only if re-routing is false
87
88
  for (let i = 0; i < Math.min(finalSpread, builtResult.routes.length); i++) {
88
89
  const route = builtResult.routes[i].path;
@@ -90,9 +91,11 @@ export class UnicastMessager {
90
91
  if (this.verbose > 1) console.warn(`Cannot send unicast message to ${remoteId} as route exceeds maxHops (${UNICAST.MAX_HOPS}). BFS incurred.`);
91
92
  continue; // too long route
92
93
  }
93
- const message = this.cryptoCodex.createUnicastMessage(type, data, route, this.peerStore.neighborsList);
94
- this.#sendMessageToPeer(route[1], message); // send to next peer
94
+ createdMessagePromises.push(this.cryptoCodex.createUnicastMessage(type, data, route, this.peerStore.neighborsList));
95
95
  }
96
+
97
+ const createdMessages = await Promise.all(createdMessagePromises);
98
+ for (const message of createdMessages) this.#sendMessageToPeer(message.route[1], message);
96
99
  return true;
97
100
  }
98
101
  /** @param {string} targetId @param {Uint8Array} serialized */
@@ -148,7 +151,7 @@ export class UnicastMessager {
148
151
  return; // too long route
149
152
  }
150
153
 
151
- const patchedMessage = this.cryptoCodex.createReroutedUnicastMessage(serialized, newRoute);
154
+ const patchedMessage = await this.cryptoCodex.createReroutedUnicastMessage(serialized, newRoute);
152
155
  const nextPeerId = newRoute[selfPosition + 1];
153
156
  this.#sendMessageToPeer(nextPeerId, patchedMessage);
154
157
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hive-p2p/server",
3
- "version": "1.0.65",
3
+ "version": "1.0.67",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -2,14 +2,19 @@ import { Converter } from './converter.mjs';
2
2
  const IS_BROWSER = typeof window !== 'undefined';
3
3
 
4
4
  // ED25519 EXPOSURE NODEJS/BROWSER COMPATIBLE ---------------------------------
5
- const [ed_, {sha512}] = await Promise.all([
5
+ /*const [ed_, {sha512}] = await Promise.all([
6
6
  import(IS_BROWSER ? '../libs/ed25519-custom.min.js' : '@noble/ed25519'),
7
7
  import(IS_BROWSER ? '../libs/ed25519-custom.min.js' : '@noble/hashes/sha2.js')
8
- ]);
8
+ ]);*/
9
+
10
+ // Now we only use nodejs version without sha512
11
+ const ed_ = await import('@noble/ed25519');
12
+
9
13
  /** @type {import('@noble/ed25519')} */
10
14
  const ed25519 = ed_.default || ed_;
11
- ed25519.hashes.sha512 = sha512;
12
- export { ed25519, sha512 };
15
+ //ed25519.hashes.sha512 = sha512;
16
+ //export { ed25519, sha512 };
17
+ export { ed25519 };
13
18
 
14
19
  //-----------------------------------------------------------------------------
15
20