2026 is being called the Year of Quantum Security. The Global Risk Institute estimates a 44% probability of a cryptographically-relevant quantum computer by 2030. NIST just released Hamming Quasi-Cyclic (HQC) as the fifth post-quantum algorithm.
And I decided to integrate ML-KEM-768 (formerly Kyber 768) into a production mesh network.
Here's what broke, what worked, and what I'd do differently.
Why Post-Quantum for a Mesh Network?
GhostWire is built for crisis communication. When disasters strike, infrastructure fails, or communities are remote — people need to talk securely.
The threat model includes "Harvest Now, Decrypt Later":
- Adversary records your encrypted traffic today
- Waits 5-10 years for a quantum computer
- Decrypts everything retroactively
For activists, journalists, and security teams, this isn't theoretical. If you're communicating about sensitive topics today, your messages could be decrypted tomorrow.
Post-quantum cryptography solves this. Even with a quantum computer, ML-KEM-768 remains secure.
The Integration
Step 1: Adding the Dependency
# Cargo.toml
pqcrypto-mlkem = { version = "0.1.1" }
pqcrypto-traits = { version = "0.3" }
pqcrypto-mlkem is a Rust wrapper around the C reference implementation of ML-KEM (Module-Lattice-Based Key Encapsulation Mechanism).
Step 2: Key Generation
use pqcrypto_mlkem::kem768;
use pqcrypto_traits::kem::{PublicKey, SecretKey, Ciphertext, SharedSecret};
// Generate ML-KEM-768 keypair
let (pk, sk) = kem768::keypair();
// Public key: 1,184 bytes (vs 32 bytes for X25519)
// Secret key: 2,400 bytes (vs 32 bytes for X25519)
println!("Public key size: {} bytes", pk.as_bytes().len());
println!("Secret key size: {} bytes", sk.as_bytes().len());
First thing that broke: Key sizes.
| Algorithm | Public Key | Secret Key |
|---|---|---|
| X25519 | 32 bytes | 32 bytes |
| ML-KEM-768 | 1,184 bytes | 2,400 bytes |
ML-KEM-768 keys are 37x larger than X25519. In a mesh network where every byte counts, this matters.
Step 3: Key Encapsulation
// Encapsulate: create shared secret using recipient's public key
let (ct, ss_sender) = kem768::encapsulate(&pk);
// Decapsulate: recover shared secret using recipient's secret key
let ss_receiver = kem768::decapsulate(&ct, &sk);
// Both sides now have the same shared secret
assert_eq!(ss_sender.as_bytes(), ss_receiver.as_bytes());
What broke: Performance.
| Operation | X25519 | ML-KEM-768 | Slowdown |
|---|---|---|---|
| Key generation | 12μs | 89μs | 7.4x |
| Encapsulation | N/A | 134μs | — |
| Decapsulation | N/A | 178μs | — |
| Total handshake | 24μs | 401μs | 16.7x |
For a mesh network with hundreds of peer connections, a 16.7x slowdown in key exchange is significant. But it's still under 1ms — acceptable for most use cases.
Step 4: Hybrid Key Exchange
We didn't replace X25519. We combined it with ML-KEM-768:
// Hybrid key exchange: X25519 + ML-KEM-768
// Security = max(classical, post-quantum)
// If either is secure, the combined key is secure
// Step 1: X25519 key exchange (fast, well-studied)
let x25519_shared = x25519_dalek::diffie_hellman(&my_x25519_secret, &their_x25519_public);
// Step 2: ML-KEM-768 key encapsulation (post-quantum)
let (ciphertext, mlkem_shared) = kem768::encapsulate(&their_mlkem_public);
// Step 3: Combine both shared secrets via HKDF
let mut combined = Vec::with_capacity(
x25519_shared.as_bytes().len() + mlkem_shared.as_bytes().len()
);
combined.extend_from_slice(x25519_shared.as_bytes());
combined.extend_from_slice(mlkem_shared.as_bytes());
let final_key = hkdf::Hkdf::<Sha256>::new(None, &combined);
let mut output = [0u8; 32];
final_key.expand(b"ghostwire-hybrid-key", &mut output).unwrap();
Why hybrid?
- If ML-KEM-768 has a hidden flaw, X25519 still protects you
- If X25519 is broken by quantum computers, ML-KEM-768 still protects you
- You get the best of both worlds
What Broke
1. Message Size Explosion
ML-KEM-768 ciphertexts are 1,088 bytes (vs 32 bytes for X25519). Every key exchange message grew by 1KB.
Impact: On BLE (Bluetooth Low Energy) with 27-byte MTU, a single ML-KEM ciphertext requires 40 BLE packets. On LoRa with 250-byte packets, it requires 5 packets.
Fix: We batch key exchanges. Instead of rotating keys every message, we rotate every 1,000 messages. This amortizes the overhead.
2. Memory Pressure on Raspberry Pi
ML-KEM-768 operations allocate temporary buffers. On a Raspberry Pi with 1GB RAM running 100+ peer connections, this caused memory pressure.
Fix: We implemented a key exchange pool — pre-allocate buffers and reuse them. This reduced memory allocation overhead by 80%.
// Pre-allocated key exchange pool
pub struct KeyExchangePool {
buffers: Vec<Mutex<Vec<u8>>>,
}
impl KeyExchangePool {
pub fn new(size: usize) -> Self {
Self {
buffers: (0..size)
.map(|_| Mutex::new(vec![0u8; 4096]))
.collect(),
}
}
pub fn acquire(&self) -> KeyExchangeGuard<'_> {
// Find available buffer
for buffer in &self.buffers {
if let Ok(mut buf) = buffer.try_lock() {
return KeyExchangeGuard { buffer: buf };
}
}
// Allocate new if pool exhausted
KeyExchangeGuard {
buffer: Mutex::new(vec![0u8; 4096]).lock().unwrap(),
}
}
}
3. Compilation Time
Adding pqcrypto-mlkem pulled in the C reference implementation, which requires a C compiler and adds ~30 seconds to build time.
Fix: We pre-compile the C library and cache it in CI. Local builds use the cached version.
4. Cross-Compilation Nightmares
pqcrypto-mlkem uses C bindings. Cross-compiling for ARM (Raspberry Pi) and Android required setting up the C toolchain for each target.
Fix: We use cross (Docker-based cross-compilation) with pre-configured toolchains:
# Cross-compile for ARM64
cross build --target aarch64-unknown-linux-gnu --release
# Cross-compile for Android
cross build --target aarch64-linux-android --release
Performance Results
After optimization:
| Metric | X25519 Only | Hybrid (X25519 + ML-KEM) | Overhead |
|---|---|---|---|
| Key exchange time | 24μs | 401μs | 16.7x |
| Message size overhead | 0 bytes | 1,088 bytes per exchange | +1KB |
| Memory per connection | 64 bytes | 3,648 bytes | 57x |
| Throughput impact | Baseline | -2.3% | Negligible |
| Security level | Classical | Classical + Post-Quantum | Future-proof |
The 2.3% throughput impact is acceptable for the security benefit.
The NIST Context
In March 2025, NIST released HQC (Hamming Quasi-Cyclic) as the fifth post-quantum algorithm, serving as a backup to ML-KEM-768. This means:
- ML-KEM-768 (Kyber) — Primary KEM standard
- ML-DSA (Dilithium) — Primary signature standard
- SLH-DSA (SPHINCS+) — Stateless hash-based signatures
- HQC — Backup KEM (lattice alternative)
- FN-DS — Backup signature
GhostWire uses ML-KEM-768 for key encapsulation. We're planning to add ML-DSA for signatures in the next release.
Quantum Timeline
| Year | Event |
|---|---|
| 2025 | NIST releases HQC as 5th PQC algorithm |
| 2026 | "Year of Quantum Security" — 44% probability of CRQC by 2030 |
| 2030 | Estimated 50% probability of cryptographically-relevant quantum computer |
| 2035 | Estimated 90% probability |
If you're building security-critical systems today, post-quantum isn't optional anymore. It's table stakes.
What I'd Do Differently
1. Start with Hybrid from Day One
Don't add post-quantum as an afterthought. Design your protocol for hybrid key exchange from the start. It's easier to disable it later than to add it later.
2. Use a Rust-Native Implementation
pqcrypto-mlkem uses C bindings. A pure Rust implementation would be easier to cross-compile and audit. We're watching the pqcrypto ecosystem for native Rust alternatives.
3. Benchmark Earlier
We didn't benchmark ML-KEM-768 performance until after integration. We should have tested on Raspberry Pi from day one. The 16.7x slowdown would have influenced our protocol design.
4. Plan for Key Size
1KB ciphertexts matter on BLE and LoRa. Design your protocol to handle large key exchange messages from the start.
Try It Yourself
git clone https://github.com/Phantomojo/GhostWire-secure-mesh-communication.git
cd GhostWire-secure-mesh-communication
cargo run --features security
The hybrid key exchange is enabled by default in the security feature flag.
"The AI has to be faster than the crisis. The crypto has to be stronger than the quantum computer."
Built in Nairobi, for the world. 🇰🇪
About the Author: Michael (Phantomojo) is a Cybersecurity student at Open University of Kenya and Team Lead of Team GhostWire, competing in GCD4F 2026. He builds encrypted mesh networks, bio-adaptive honeypots, and offline AI assistants from Nairobi, Kenya.
Top comments (0)