Warp Signature Aggregation Protocol
P2P protocol for requesting and aggregating BLS signatures for Warp cross-chain messages
LP-0118: Warp Signature Aggregation Protocol
Abstract
This LP defines the P2P protocol for requesting and aggregating BLS signatures for Warp cross-chain messages. It specifies the message formats, handler interfaces, and aggregation process used by validators to collectively sign Warp messages.
Motivation
Warp messaging requires collecting signatures from multiple validators to achieve quorum. A standardized protocol ensures:
- Interoperability: All nodes use the same message format
- Efficiency: Binary format minimizes bandwidth
- Security: Proper verification before signing
- Consistency: Unified handler interface across VMs
Specification
P2P Handler ID
const SignatureHandlerID = 0x12345678
All Warp signature requests use this handler ID in the P2P protocol.
Message Formats
Signature Request
Binary format (length-prefixed fields):
+------------------+------------------+
| Message Length | Message Bytes |
| (4 bytes, BE) | (variable) |
+------------------+------------------+
| Justification Len| Justification |
| (4 bytes, BE) | (variable) |
+------------------+------------------+
Go representation:
type SignatureRequest struct {
Message []byte // Unsigned warp message bytes
Justification []byte // Optional proof/context
}
Signature Response
Binary format:
+------------------+
| Signature Bytes |
| (96 bytes) |
+------------------+
Go representation:
type SignatureResponse struct {
Signature []byte // BLS signature (96 bytes)
}
Interfaces
Verifier
Before signing, messages must be verified:
type Verifier interface {
Verify(ctx context.Context, msg *UnsignedMessage, justification []byte) error
}
SignatureHandler
Handles incoming signature requests:
type SignatureHandler interface {
Request(ctx context.Context, nodeID ids.NodeID, deadline time.Time, requestBytes []byte) ([]byte, error)
}
Signer
Signs verified messages:
type Signer interface {
Sign(msg *UnsignedMessage) ([]byte, error)
}
Protocol Flow
- Request: Node A sends
SignatureRequestto Node B - Verify: Node B's
Verifiervalidates the message and justification - Sign: If valid, Node B's
Signercreates a BLS signature - Cache: Signature is cached by message ID for future requests
- Respond: Node B returns
SignatureResponsewith the signature - Aggregate: Node A collects signatures until quorum is reached
Aggregation
The SignatureAggregator queries validators in parallel:
func (s *SignatureAggregator) AggregateSignatures(
ctx context.Context,
message *Message,
justification []byte,
validators []*Validator,
quorumNum, quorumDen uint64,
) (*Message, *big.Int, *big.Int, error)
Aggregation continues until:
- Quorum weight is achieved (success)
- All validators are exhausted without quorum (failure)
- Context is cancelled (failure)
Error Codes
| Code | Name | Description |
|---|---|---|
| 1 | ParseError | Failed to parse request |
| 2 | VerifyError | Message verification failed |
| 3 | SignError | Signing failed |
| 4 | NotFound | Message not found |
Rationale
Binary Message Format
Using a compact binary format (vs JSON) provides:
- Bandwidth Efficiency: 96-byte signatures are optimal for BLS
- Parsing Speed: Fixed-width fields enable zero-copy parsing
- Determinism: Binary serialization is unambiguous
- Cryptographic Safety: No string encoding edge cases
Handler ID Convention
Using 0x12345678 as the handler ID follows the p2p protocol convention where:
- IDs are allocated sequentially
- Application-specific handlers use high values
- Allows easy identification in network diagnostics
Parallel Aggregation
Collecting signatures in parallel (vs sequentially) reduces latency:
- Reduces worst-case latency from O(n) to O(1)
- Handles validator failures gracefully with timeouts
- Enables dynamic quorum adjustment based on available validators
Implementation
As of warp v1.18.0, this protocol is implemented in github.com/luxfi/warp:
signature_request.go- Request/response types and marshalingsignature_aggregator.go- Aggregator implementationverifier.go- Verifier interface
Migration from lp118 Package
The original implementation was in github.com/luxfi/p2p/lp118. As of warp v1.18.0, all types have been consolidated:
| Old (p2p/lp118) | New (warp) |
|---|---|
lp118.HandlerID | warp.SignatureHandlerID |
lp118.Verifier | warp.Verifier |
lp118.SignatureRequest | warp.SignatureRequest |
lp118.SignatureResponse | warp.SignatureResponse |
lp118.NewCachedHandler | warp.NewCachedSignatureHandler |
lp118.NewHandlerAdapter | warp.NewSignatureHandlerAdapter |
lp118.SignatureAggregator | warp.SignatureAggregator |
The github.com/luxfi/p2p/lp118 package has been deleted.
Security Considerations
- Verification Required: Always verify messages before signing
- Rate Limiting: Implement rate limiting to prevent DoS
- Justification Validation: Verify justification proofs when provided
- Quorum Security: Use 2/3+ quorum for BFT security guarantees
- Replay Protection: Network ID and chain ID prevent cross-chain replay
Backwards Compatibility
The binary format is backwards compatible. The package location change requires import updates but no protocol changes.
References
Copyright
Copyright and related rights waived via CC0.