315 lines
9.3 KiB
JavaScript
315 lines
9.3 KiB
JavaScript
/**
|
|
* P2P Swarm V2 WASM Integration
|
|
*
|
|
* Provides WASM-accelerated components for P2P Swarm:
|
|
* - Ed25519 identity (faster key generation)
|
|
* - HNSW indexing (fast member/capability search)
|
|
* - Semantic matching (intelligent task routing)
|
|
*/
|
|
import { initRuVectorWasm, isWasmInitialized, generateIdentity, signData, verifySignature, RuVectorHnswIndex, RuVectorSemanticMatcher, } from '../wasm/ruvector-edge.js';
|
|
import { logger } from '../utils/logger.js';
|
|
//=============================================================================
|
|
// WASM-Enhanced Identity Manager
|
|
//=============================================================================
|
|
/**
|
|
* WASM-accelerated identity manager for P2P Swarm
|
|
* Falls back to Node.js crypto when WASM unavailable
|
|
*/
|
|
export class WasmIdentityManager {
|
|
publicKey = null;
|
|
secretKey = null;
|
|
publicKeyHex = '';
|
|
initialized = false;
|
|
sendCounter = 0;
|
|
recvCounters = new Map();
|
|
seenNonces = new Map();
|
|
maxNonceAge = 300000; // 5 minutes
|
|
async initialize() {
|
|
if (this.initialized)
|
|
return;
|
|
// Try to initialize WASM
|
|
await initRuVectorWasm();
|
|
// Generate identity (uses WASM if available)
|
|
const identity = await generateIdentity();
|
|
this.publicKey = identity.publicKey;
|
|
this.secretKey = identity.secretKey;
|
|
this.publicKeyHex = identity.publicKeyHex;
|
|
this.initialized = true;
|
|
logger.info('WASM identity manager initialized', {
|
|
wasmAccelerated: isWasmInitialized(),
|
|
publicKeyPrefix: this.publicKeyHex.slice(0, 16),
|
|
});
|
|
}
|
|
/**
|
|
* Get public key as hex string
|
|
*/
|
|
getPublicKeyHex() {
|
|
return this.publicKeyHex;
|
|
}
|
|
/**
|
|
* Get public key as Uint8Array
|
|
*/
|
|
getPublicKey() {
|
|
if (!this.publicKey)
|
|
throw new Error('Identity not initialized');
|
|
return this.publicKey;
|
|
}
|
|
/**
|
|
* Sign data and return base64 signature
|
|
*/
|
|
async sign(data) {
|
|
if (!this.secretKey)
|
|
throw new Error('Identity not initialized');
|
|
const signature = await signData(new Uint8Array(Buffer.from(data)), this.secretKey);
|
|
return Buffer.from(signature).toString('base64');
|
|
}
|
|
/**
|
|
* Verify signature from peer
|
|
*/
|
|
async verify(data, signature, peerPublicKeyHex) {
|
|
try {
|
|
const pubKey = new Uint8Array(Buffer.from(peerPublicKeyHex, 'hex'));
|
|
const sig = new Uint8Array(Buffer.from(signature, 'base64'));
|
|
const dataBytes = new Uint8Array(Buffer.from(data));
|
|
return await verifySignature(dataBytes, sig, pubKey);
|
|
}
|
|
catch (error) {
|
|
logger.warn('Signature verification failed', { error });
|
|
return false;
|
|
}
|
|
}
|
|
/**
|
|
* Get next send counter (monotonic)
|
|
*/
|
|
getNextCounter() {
|
|
return ++this.sendCounter;
|
|
}
|
|
/**
|
|
* Validate counter from peer (must be strictly increasing)
|
|
*/
|
|
validateCounter(peerId, counter) {
|
|
const lastSeen = this.recvCounters.get(peerId) || 0;
|
|
if (counter <= lastSeen) {
|
|
return false;
|
|
}
|
|
this.recvCounters.set(peerId, counter);
|
|
return true;
|
|
}
|
|
/**
|
|
* Generate and track nonce
|
|
*/
|
|
generateNonce() {
|
|
const crypto = require('crypto');
|
|
return crypto.randomBytes(16).toString('hex');
|
|
}
|
|
/**
|
|
* Validate nonce (replay protection)
|
|
*/
|
|
validateNonce(senderId, nonce, timestamp) {
|
|
// Reject old messages
|
|
if (Date.now() - timestamp > this.maxNonceAge) {
|
|
return false;
|
|
}
|
|
// Get or create nonce set for sender
|
|
if (!this.seenNonces.has(senderId)) {
|
|
this.seenNonces.set(senderId, new Map());
|
|
}
|
|
const senderNonces = this.seenNonces.get(senderId);
|
|
// Reject replayed nonces
|
|
if (senderNonces.has(nonce)) {
|
|
return false;
|
|
}
|
|
senderNonces.set(nonce, timestamp);
|
|
return true;
|
|
}
|
|
/**
|
|
* Check if WASM acceleration is active
|
|
*/
|
|
isWasmAccelerated() {
|
|
return isWasmInitialized();
|
|
}
|
|
}
|
|
/**
|
|
* WASM-accelerated member index for fast capability search
|
|
*/
|
|
export class WasmMemberIndex {
|
|
hnswIndex;
|
|
members = new Map();
|
|
indexToAgentId = new Map();
|
|
dimensions;
|
|
constructor(dimensions = 128) {
|
|
this.dimensions = dimensions;
|
|
this.hnswIndex = new RuVectorHnswIndex(dimensions, 16, 200);
|
|
}
|
|
/**
|
|
* Add or update member
|
|
*/
|
|
addMember(member) {
|
|
this.members.set(member.agentId, member);
|
|
// If member has embedding, add to HNSW index
|
|
if (member.embedding) {
|
|
const idx = this.hnswIndex.add(member.embedding);
|
|
this.indexToAgentId.set(idx, member.agentId);
|
|
}
|
|
}
|
|
/**
|
|
* Remove member
|
|
*/
|
|
removeMember(agentId) {
|
|
this.members.delete(agentId);
|
|
// Note: HNSW doesn't support removal, but member won't be returned in searches
|
|
}
|
|
/**
|
|
* Get member by ID
|
|
*/
|
|
getMember(agentId) {
|
|
return this.members.get(agentId);
|
|
}
|
|
/**
|
|
* Find members with specific capabilities
|
|
*/
|
|
findByCapabilities(capabilities) {
|
|
const results = [];
|
|
for (const member of this.members.values()) {
|
|
const hasAll = capabilities.every(cap => member.capabilities.includes(cap));
|
|
if (hasAll) {
|
|
results.push(member);
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
/**
|
|
* Find k nearest members by embedding similarity
|
|
*/
|
|
findSimilar(queryEmbedding, k = 5) {
|
|
const searchResults = this.hnswIndex.search(queryEmbedding, k);
|
|
const members = [];
|
|
for (const result of searchResults) {
|
|
const agentId = this.indexToAgentId.get(result.index);
|
|
if (agentId) {
|
|
const member = this.members.get(agentId);
|
|
if (member) {
|
|
members.push(member);
|
|
}
|
|
}
|
|
}
|
|
return members;
|
|
}
|
|
/**
|
|
* Get all live members (last seen within threshold)
|
|
*/
|
|
getLiveMembers(maxAge = 30000) {
|
|
const now = Date.now();
|
|
const live = [];
|
|
for (const member of this.members.values()) {
|
|
if (now - member.lastSeen < maxAge) {
|
|
live.push(member);
|
|
}
|
|
}
|
|
return live;
|
|
}
|
|
/**
|
|
* Get total member count
|
|
*/
|
|
size() {
|
|
return this.members.size;
|
|
}
|
|
/**
|
|
* Check if WASM acceleration is active
|
|
*/
|
|
isWasmAccelerated() {
|
|
return this.hnswIndex.isWasmAccelerated();
|
|
}
|
|
}
|
|
//=============================================================================
|
|
// WASM-Enhanced Task Router
|
|
//=============================================================================
|
|
/**
|
|
* WASM-accelerated task router for intelligent agent selection
|
|
*/
|
|
export class WasmTaskRouter {
|
|
semanticMatcher;
|
|
dimensions;
|
|
constructor(dimensions = 128) {
|
|
this.dimensions = dimensions;
|
|
this.semanticMatcher = new RuVectorSemanticMatcher();
|
|
}
|
|
/**
|
|
* Register agent for task routing
|
|
*/
|
|
registerAgent(agentId, embedding, capabilities) {
|
|
this.semanticMatcher.registerAgent(agentId, embedding, capabilities);
|
|
}
|
|
/**
|
|
* Route task to best matching agents
|
|
*/
|
|
routeTask(taskEmbedding, requiredCapabilities, topK = 3) {
|
|
const matches = this.semanticMatcher.matchTask(taskEmbedding, topK * 2);
|
|
// Filter by required capabilities if specified
|
|
if (requiredCapabilities && requiredCapabilities.length > 0) {
|
|
return matches
|
|
.filter(m => requiredCapabilities.every(cap => m.capabilities.includes(cap)))
|
|
.slice(0, topK)
|
|
.map(m => ({
|
|
agentId: m.agent,
|
|
score: m.score,
|
|
capabilities: m.capabilities,
|
|
}));
|
|
}
|
|
return matches.slice(0, topK).map(m => ({
|
|
agentId: m.agent,
|
|
score: m.score,
|
|
capabilities: m.capabilities,
|
|
}));
|
|
}
|
|
/**
|
|
* Check if WASM acceleration is active
|
|
*/
|
|
isWasmAccelerated() {
|
|
return this.semanticMatcher.isWasmAccelerated();
|
|
}
|
|
}
|
|
//=============================================================================
|
|
// Factory Functions
|
|
//=============================================================================
|
|
/**
|
|
* Create WASM-enhanced identity manager
|
|
*/
|
|
export async function createWasmIdentityManager() {
|
|
const manager = new WasmIdentityManager();
|
|
await manager.initialize();
|
|
return manager;
|
|
}
|
|
/**
|
|
* Create WASM-enhanced member index
|
|
*/
|
|
export function createWasmMemberIndex(dimensions = 128) {
|
|
return new WasmMemberIndex(dimensions);
|
|
}
|
|
/**
|
|
* Create WASM-enhanced task router
|
|
*/
|
|
export function createWasmTaskRouter(dimensions = 128) {
|
|
return new WasmTaskRouter(dimensions);
|
|
}
|
|
/**
|
|
* Get WASM acceleration status
|
|
*/
|
|
export function getWasmStatus() {
|
|
return {
|
|
initialized: isWasmInitialized(),
|
|
features: isWasmInitialized()
|
|
? ['WasmIdentity', 'WasmHnswIndex', 'WasmSemanticMatcher']
|
|
: ['JS Fallback'],
|
|
};
|
|
}
|
|
export default {
|
|
WasmIdentityManager,
|
|
WasmMemberIndex,
|
|
WasmTaskRouter,
|
|
createWasmIdentityManager,
|
|
createWasmMemberIndex,
|
|
createWasmTaskRouter,
|
|
getWasmStatus,
|
|
};
|
|
//# sourceMappingURL=p2p-swarm-wasm.js.map
|