@hive-p2p/server 1.0.63 → 1.0.65
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/core/arbiter.mjs +1 -1
- package/core/crypto-codex.mjs +51 -2
- package/core/node-services.mjs +1 -1
- package/core/topologist.mjs +1 -1
- package/package.json +1 -1
- package/services/cryptos.mjs +3 -10
package/core/arbiter.mjs
CHANGED
|
@@ -115,7 +115,7 @@ export class Arbiter {
|
|
|
115
115
|
try {
|
|
116
116
|
const { pubkey, signature, signatureStart } = message;
|
|
117
117
|
const signedData = serialized.subarray(0, signatureStart);
|
|
118
|
-
const signatureValid = await this.cryptoCodex.verifySignature(pubkey,
|
|
118
|
+
const signatureValid = await this.cryptoCodex.verifySignature(pubkey, signedData, signature);
|
|
119
119
|
if (!signatureValid) throw new Error('Gossip signature invalid');
|
|
120
120
|
this.adjustTrust(from, TRUST_VALUES.VALID_SIGNATURE, 'Gossip signature valid');
|
|
121
121
|
return true;
|
package/core/crypto-codex.mjs
CHANGED
|
@@ -5,10 +5,54 @@ import { DirectMessage, ReroutedDirectMessage } from './unicast.mjs';
|
|
|
5
5
|
import { Converter } from '../services/converter.mjs';
|
|
6
6
|
import { ed25519, Argon2Unified } from '../services/cryptos.mjs'; // now exposed in full and browser builds
|
|
7
7
|
|
|
8
|
+
class Ed25519BatchVerifier {
|
|
9
|
+
#verifyQueue = [];
|
|
10
|
+
#verifyResolvers = new Map();
|
|
11
|
+
#batchTimer = null;
|
|
12
|
+
#nextId = 0;
|
|
13
|
+
#BATCH_SIZE = 10;
|
|
14
|
+
#BATCH_TIMEOUT = 5;
|
|
15
|
+
|
|
16
|
+
verifySignature(publicKey, dataToVerify, signature) {
|
|
17
|
+
return new Promise((resolve) => {
|
|
18
|
+
const id = this.#nextId++;
|
|
19
|
+
this.#verifyQueue.push({ id, publicKey, dataToVerify, signature });
|
|
20
|
+
this.#verifyResolvers.set(id, resolve);
|
|
21
|
+
|
|
22
|
+
// Flush immediately if batch full
|
|
23
|
+
if (this.#verifyQueue.length >= this.#BATCH_SIZE) {
|
|
24
|
+
this.#flushBatch();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Otherwise schedule flush
|
|
29
|
+
if (!this.#batchTimer)
|
|
30
|
+
this.#batchTimer = setTimeout(() => this.#flushBatch(), this.#BATCH_TIMEOUT);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async #flushBatch() {
|
|
35
|
+
if (this.#batchTimer) clearTimeout(this.#batchTimer), this.#batchTimer = null;
|
|
36
|
+
if (this.#verifyQueue.length === 0) return;
|
|
37
|
+
|
|
38
|
+
const batch = this.#verifyQueue.splice(0);
|
|
39
|
+
const results = await Promise.all(
|
|
40
|
+
batch.map(item => ed25519.verifyAsync(item.signature, item.dataToVerify, item.publicKey))
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
for (let i = 0; i < batch.length; i++) {
|
|
44
|
+
this.#verifyResolvers.get(batch[i].id)(results[i]);
|
|
45
|
+
this.#verifyResolvers.delete(batch[i].id);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
8
50
|
export class CryptoCodex {
|
|
9
51
|
argon2 = new Argon2Unified();
|
|
10
52
|
converter = new Converter();
|
|
11
53
|
AVOID_CRYPTO = false;
|
|
54
|
+
/** @type {Ed25519BatchVerifier} only if "AVOID_CRYPTO" is disabled*/
|
|
55
|
+
verifier;
|
|
12
56
|
verbose = NODE.DEFAULT_VERBOSE;
|
|
13
57
|
/** @type {string} */ id;
|
|
14
58
|
/** @type {Uint8Array} */ publicKey;
|
|
@@ -17,8 +61,9 @@ export class CryptoCodex {
|
|
|
17
61
|
/** @param {string} [nodeId] If provided: used to generate a fake keypair > disable crypto operations */
|
|
18
62
|
constructor(nodeId, verbose = NODE.DEFAULT_VERBOSE) {
|
|
19
63
|
this.verbose = verbose;
|
|
64
|
+
//this.AVOID_CRYPTO = IDENTITY.ARE_IDS_HEX ? false : true; // disable crypto if string ids are used
|
|
20
65
|
if (!nodeId) return; // IF NOT PROVIDED: generate() should be called.
|
|
21
|
-
|
|
66
|
+
|
|
22
67
|
this.id = nodeId.padEnd(IDENTITY.ID_LENGTH, ' ').slice(0, IDENTITY.ID_LENGTH);
|
|
23
68
|
this.privateKey = new Uint8Array(32).fill(0); this.publicKey = new Uint8Array(32).fill(0);
|
|
24
69
|
const idBytes = new TextEncoder().encode(this.id); // use nodeId to create a fake public key
|
|
@@ -42,6 +87,8 @@ export class CryptoCodex {
|
|
|
42
87
|
async generate(asPublicNode, seed) { // Generate Ed25519 keypair cross-platform | set id only for simulator
|
|
43
88
|
if (this.nodeId) return;
|
|
44
89
|
await this.#generateAntiSybilIdentity(seed, asPublicNode);
|
|
90
|
+
this.AVOID_CRYPTO = false; // enable crypto operations
|
|
91
|
+
this.verifier = new Ed25519BatchVerifier();
|
|
45
92
|
if (!this.id) throw new Error('Failed to generate identity');
|
|
46
93
|
}
|
|
47
94
|
/** Check if the pubKey meets the difficulty using Argon2 derivation @param {Uint8Array} publicKey */
|
|
@@ -170,7 +217,9 @@ export class CryptoCodex {
|
|
|
170
217
|
/** @param {Uint8Array} publicKey @param {Uint8Array} dataToVerify @param {Uint8Array} signature */
|
|
171
218
|
async verifySignature(publicKey, dataToVerify, signature) {
|
|
172
219
|
if (this.AVOID_CRYPTO) return true;
|
|
173
|
-
return ed25519.verifyAsync(
|
|
220
|
+
//return ed25519.verifyAsync(signature, dataToVerify, publicKey);
|
|
221
|
+
// new version with batching to optimize timings using ed25519 async.
|
|
222
|
+
return this.verifier.verifySignature(publicKey, dataToVerify, signature);
|
|
174
223
|
}
|
|
175
224
|
/** @param {Uint8Array} bufferView */
|
|
176
225
|
readBufferHeader(bufferView, readAssociatedId = true) {
|
package/core/node-services.mjs
CHANGED
|
@@ -68,7 +68,7 @@ export class NodeServices {
|
|
|
68
68
|
|
|
69
69
|
const { signatureStart, pubkey, signature } = message;
|
|
70
70
|
const signedData = d.subarray(0, signatureStart);
|
|
71
|
-
if (!await this.cryptoCodex.verifySignature(pubkey,
|
|
71
|
+
if (!await this.cryptoCodex.verifySignature(pubkey, signedData, signature)) return;
|
|
72
72
|
|
|
73
73
|
remoteId = route[0];
|
|
74
74
|
this.peerStore.digestPeerNeighbors(remoteId, neighborsList); // Update known store
|
package/core/topologist.mjs
CHANGED
|
@@ -187,7 +187,7 @@ export class Topologist {
|
|
|
187
187
|
|
|
188
188
|
const { signatureStart, pubkey, signature } = message;
|
|
189
189
|
const signedData = d.subarray(0, signatureStart);
|
|
190
|
-
if (!await this.cryptoCodex.verifySignature(pubkey,
|
|
190
|
+
if (!await this.cryptoCodex.verifySignature(pubkey, signedData, signature)) return;
|
|
191
191
|
|
|
192
192
|
remoteId = route[0];
|
|
193
193
|
this.peerStore.digestPeerNeighbors(remoteId, neighborsList); // Update known store
|
package/package.json
CHANGED
package/services/cryptos.mjs
CHANGED
|
@@ -2,21 +2,14 @@ import { Converter } from './converter.mjs';
|
|
|
2
2
|
const IS_BROWSER = typeof window !== 'undefined';
|
|
3
3
|
|
|
4
4
|
// ED25519 EXPOSURE NODEJS/BROWSER COMPATIBLE ---------------------------------
|
|
5
|
-
|
|
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
|
-
]);*/
|
|
9
|
-
/** @type {import('@noble/ed25519')} */
|
|
10
|
-
//const ed25519 = ed_.default || ed_;
|
|
11
|
-
//ed25519.hashes.sha512 = sha512;
|
|
12
|
-
//export { ed25519, sha512 };
|
|
13
|
-
|
|
14
|
-
const [ed_] = await Promise.all([
|
|
15
|
-
import(IS_BROWSER ? '../libs/ed25519-custom.min.js' : '@noble/ed25519'),
|
|
16
8
|
]);
|
|
17
9
|
/** @type {import('@noble/ed25519')} */
|
|
18
10
|
const ed25519 = ed_.default || ed_;
|
|
19
|
-
|
|
11
|
+
ed25519.hashes.sha512 = sha512;
|
|
12
|
+
export { ed25519, sha512 };
|
|
20
13
|
|
|
21
14
|
//-----------------------------------------------------------------------------
|
|
22
15
|
|