UNPKG

lotus-sdk

Version:

Central repository for several classes of tools for integrating with, and building for, the Lotusia ecosystem

161 lines (160 loc) 7.02 kB
import { MuSig2MessageType, } from './types.js'; import { EventEmitter } from 'events'; import { validateMessageStructure, validateSessionJoinPayload, validateSessionJoinAckPayload, validateNonceSharePayload, validatePartialSigSharePayload, validateSessionAbortPayload, validateSessionCompletePayload, } from './validation.js'; import { ValidationError, DeserializationError, SerializationError, ErrorCode, } from './errors.js'; export class MuSig2ProtocolHandler extends EventEmitter { protocolName = 'musig2'; protocolId = '/lotus/musig2/1.0.0'; securityValidator; setSecurityValidator(validator) { this.securityValidator = validator; } async handleMessage(message, from) { try { if (message.protocol !== this.protocolName) { console.warn(`[MuSig2Protocol] Ignoring message with wrong protocol: ${message.protocol}`); return; } if (this.securityValidator) { const isSecure = await this.securityValidator.validateMessage(message, from); if (!isSecure) { console.warn(`[MuSig2Protocol] Security validation failed for ${message.type} from ${from.peerId}`); this.emit('security:rejected', { message, from, reason: 'security_validation_failed', }); return; } } validateMessageStructure(message); const validatedPayload = this._validateAndRouteMessage(message); this._emitValidatedMessage(message.type, validatedPayload, from); } catch (error) { this._handleMessageError(error, message, from); } } _validateAndRouteMessage(message) { switch (message.type) { case MuSig2MessageType.SESSION_JOIN: validateSessionJoinPayload(message.payload); return message.payload; case MuSig2MessageType.SESSION_JOIN_ACK: validateSessionJoinAckPayload(message.payload); return message.payload; case MuSig2MessageType.NONCE_SHARE: validateNonceSharePayload(message.payload); return message.payload; case MuSig2MessageType.PARTIAL_SIG_SHARE: validatePartialSigSharePayload(message.payload); return message.payload; case MuSig2MessageType.SESSION_ABORT: validateSessionAbortPayload(message.payload); return message.payload; case MuSig2MessageType.SESSION_COMPLETE: validateSessionCompletePayload(message.payload); return message.payload; default: throw new ValidationError(ErrorCode.INVALID_PAYLOAD, `Unknown message type: ${message.type}`); } } _emitValidatedMessage(type, payload, from) { switch (type) { case MuSig2MessageType.SESSION_JOIN: this.emit('session:join', payload, from); break; case MuSig2MessageType.SESSION_JOIN_ACK: this.emit('session:join-ack', payload, from); break; case MuSig2MessageType.NONCE_SHARE: this.emit('nonce:share', payload, from); break; case MuSig2MessageType.PARTIAL_SIG_SHARE: this.emit('partial-sig:share', payload, from); break; case MuSig2MessageType.SESSION_ABORT: this.emit('session:abort', payload, from); break; case MuSig2MessageType.SESSION_COMPLETE: this.emit('session:complete', payload, from); break; } } _handleMessageError(error, message, from) { if (error instanceof ValidationError) { console.warn(`[MuSig2Protocol] Validation failed for ${message.type} from ${from.peerId}: ${error.message}`); this.emit('validation:error', { error, message, from }); return; } if (error instanceof DeserializationError) { console.warn(`[MuSig2Protocol] Deserialization failed for ${message.type} from ${from.peerId}: ${error.message}`); this.emit('deserialization:error', { error, message, from }); return; } if (error instanceof SerializationError) { console.warn(`[MuSig2Protocol] Serialization error for ${message.type} from ${from.peerId}: ${error.message}`); this.emit('serialization:error', { error, message, from }); return; } console.error(`[MuSig2Protocol] Unexpected error processing ${message.type} from ${from.peerId}:`, error); this.emit('unexpected:error', { error, message, from }); } async onPeerConnected(peerId) { console.log(`[MuSig2Protocol] Peer connected: ${peerId}`); this.emit('peer:connected', peerId); } async onPeerDisconnected(peerId) { console.log(`[MuSig2Protocol] Peer disconnected: ${peerId}`); this.emit('peer:disconnected', peerId); } async onPeerDiscovered(peerInfo) { console.log(`[MuSig2Protocol] Peer discovered: ${peerInfo.peerId}`); this.emit('peer:discovered', peerInfo); } validateMessagePayload(type, payload) { try { switch (type) { case MuSig2MessageType.SESSION_JOIN: validateSessionJoinPayload(payload); break; case MuSig2MessageType.SESSION_JOIN_ACK: validateSessionJoinAckPayload(payload); break; case MuSig2MessageType.NONCE_SHARE: validateNonceSharePayload(payload); break; case MuSig2MessageType.PARTIAL_SIG_SHARE: validatePartialSigSharePayload(payload); break; case MuSig2MessageType.SESSION_ABORT: validateSessionAbortPayload(payload); break; case MuSig2MessageType.SESSION_COMPLETE: validateSessionCompletePayload(payload); break; default: return false; } return true; } catch (error) { return false; } } getValidationInfo() { return { supportedMessageTypes: [ MuSig2MessageType.SESSION_JOIN, MuSig2MessageType.SESSION_JOIN_ACK, MuSig2MessageType.NONCE_SHARE, MuSig2MessageType.PARTIAL_SIG_SHARE, MuSig2MessageType.SESSION_ABORT, MuSig2MessageType.SESSION_COMPLETE, ], validationEnabled: true, errorHandlingEnabled: true, securityChecksEnabled: true, }; } }