Comparison: ML-KEM vs MLS vs Signal Protocol
Overview
Comprehensive security comparison between ML-KEM (TypeScript/JavaScript), MLS (TypeScript), and Signal Protocol (Rust/WASM) implementations, analyzing cryptography, protocol security, implementation quality, and risk profiles.
Analysis Date: January 2025
ML-KEM: TypeScript/JavaScript with Web Crypto API (838 lines)
MLS: TypeScript with ts-mls 1.3.1
Signal Protocol: Rust 1.70+ with WASM bindings (4,531 lines)
Purpose: Inform architecture decisions for secure messaging
Executive Summary
All three implementations have strong cryptographic foundations but differ significantly in security properties, use cases, and implementation quality.
High-Level Verdict:
- ML-KEM: Best for post-quantum security, long-term data protection, but needs production hardening
- MLS: Best for group messaging, RFC compliant, but weaker implementation security
- Signal Protocol: Best for 1:1 messaging, superior memory safety, but has protocol deviations
Key Differences:
- ML-KEM provides post-quantum security (quantum-resistant)
- Signal has better memory safety (Rust guarantees)
- MLS has better RFC compliance (95% for core protocol)
- ML-KEM has better test coverage (60% security tests)
- All need production hardening improvements
Cryptographic Primitives Comparison
Algorithm Selection
| Primitive | ML-KEM | MLS | Signal Protocol |
|---|---|---|---|
| Key Exchange | ML-KEM-768 (PQC) | X25519 ECDH | X25519 ECDH |
| Signatures | N/A (KEM only) | Ed25519 | Ed25519 |
| Symmetric Encryption | AES-256-GCM | AES-128-GCM | AES-256-GCM |
| Key Derivation | HKDF-SHA256 | HKDF-SHA256 | HKDF-SHA256 |
| Hash Function | SHA-256 | SHA-256 | SHA-256 |
| RNG | Web Crypto API | Platform CSRNG | OS CSPRNG |
Winner: ML-KEM for post-quantum security
- ML-KEM provides quantum-resistant key exchange
- Signal uses AES-256 (vs MLS AES-128) but both provide adequate security
- All use industry-standard algorithms
Security Levels
| Aspect | ML-KEM | MLS | Signal Protocol |
|---|---|---|---|
| Classical Security | 192-bit equivalent | 128-bit | 128-bit |
| Post-Quantum Security | ✅ Yes (NIST Level 3) | ❌ No | ❌ No |
| Quantum Resistance | ✅ Resistant | ❌ Vulnerable | ❌ Vulnerable |
| Forward Secrecy | ✅ Per-message | ✅ Per-epoch | ✅ Per-message |
| Post-Compromise Security | ⚠️ Limited | ✅ Yes | ✅ Yes |
Winner: ML-KEM for post-quantum security, MLS/Signal for forward secrecy
Library Quality Comparison
| Aspect | ML-KEM | MLS | Signal Protocol |
|---|---|---|---|
| Library | @hpke/ml-kem v0.2.1 | ts-mls v1.3.1 | curve25519-dalek, ed25519-dalek |
| Audits | ⚠️ Pre-1.0 | ✅ Cure53 (2024), Kudelski (2023) | ✅ Community audited |
| Standardization | ✅ NIST FIPS 203 | ✅ RFC 9420 | ⚠️ Signal spec (not RFC) |
| Maturity | ⚠️ Early (v0.2.1) | ✅ Mature (v1.3.1) | ✅ Mature |
| Maintenance | ⚠️ Active | ✅ Active | ✅ Active |
Winner: MLS for maturity and audits, ML-KEM for standardization
Implementation Quality Comparison
Code Quality
| Aspect | ML-KEM | MLS | Signal Protocol |
|---|---|---|---|
| Language | TypeScript/JavaScript | TypeScript | Rust |
| Memory Safety | ⚠️ Runtime only | ⚠️ Runtime only | ✅ Compiler-enforced |
| Type Safety | ✅ TypeScript | ✅ TypeScript | ✅ Rust |
| Lines of Code | 838 | ~2,000+ | 4,531 |
| Code Complexity | 🟡 Medium | 🟡 Medium | 🟢 Low |
Winner: Signal Protocol for memory safety (Rust guarantees)
Security Features
| Feature | ML-KEM | MLS | Signal Protocol |
|---|---|---|---|
| Zeroization | ✅ Implemented | ❌ Missing | ✅ Implemented |
| Constant-Time Ops | ⚠️ Best-effort | ❌ Missing | ✅ Implemented |
| Input Validation | ⚠️ Partial | ❌ Missing | ⚠️ Partial |
| Error Sanitization | ✅ Generic errors | ⚠️ Partial | ✅ Generic errors |
| IV Reuse Protection | ✅ Implemented | ✅ Implemented | ✅ Implemented |
| Rate Limiting | ❌ Missing | ❌ Missing | ❌ Missing |
Winner: ML-KEM for security features (zeroization, IV protection)
Test Coverage Comparison
| Category | ML-KEM | MLS | Signal Protocol |
|---|---|---|---|
| Functional Tests | 50+ (95%) | 52 (Good) | 120 (Good) |
| Security Tests | 30+ (60%) | 3 (5%) | 18 (15%) |
| Negative Tests | 25+ (80%) | 3 (6%) | ~20 (Medium) |
| Attack Scenario Tests | 15+ (40%) | 0 (0%) | ~10 (Low) |
| Timing Attack Tests | 5 (80%) | 0 (0%) | ~5 (Low) |
| Zeroization Tests | 8 (100%) | 0 (0%) | ~5 (Low) |
Overall Security Test Coverage:
- ML-KEM: 60% ✅
- MLS: 5% ❌
- Signal Protocol: 15% ⚠️
Winner: ML-KEM for comprehensive security test coverage
Vulnerability Comparison
Critical Vulnerabilities
| Issue | ML-KEM | MLS | Signal Protocol |
|---|---|---|---|
| Missing Input Validation | ⚠️ Partial (size limits) | ❌ None | ⚠️ Partial |
| Information Leakage | ✅ Secure | ❌ Extensive logging | ✅ Better |
| DoS Protection | ❌ Missing rate limiting | ❌ Missing | ❌ Missing |
| Protocol Deviations | ✅ None | ✅ None | ⚠️ AAD, signed prekey |
| Memory Safety | ⚠️ JavaScript | ⚠️ JavaScript | ✅ Rust |
Critical Vulnerabilities Count:
- ML-KEM: 3 Critical, 8 High
- MLS: 16 Critical, 15 High
- Signal Protocol: 2 Critical, 4 High
Winner: Signal Protocol for fewest critical vulnerabilities
Production Readiness Comparison
| Aspect | ML-KEM | MLS | Signal Protocol |
|---|---|---|---|
| Cryptographic Security | ✅ Secure | ✅ Secure | ✅ Secure |
| Input Validation | ⚠️ Partial | ❌ Missing | ⚠️ Partial |
| Error Handling | ✅ Good | ⚠️ Needs work | ✅ Good |
| Test Coverage | ✅ Good (60%) | ❌ Poor (5%) | ⚠️ Medium (15%) |
| Memory Safety |