A high-performance cryptographic pipeline implementing ML-KEM (Kyber-768) and AES-256 on the ESP32 platform. This project demonstrates a secure, untethered wireless tunnel capable of resisting quantum-scale attacks.
To optimize for resource-constrained IoT environments, I implemented a Sender-Only Provisioning Model:
- Server keys are generated off-device (on the server/laptop).
- The Server Public Key (
server_pk.bin) is embedded into the ESP32 firmware via CMake linker symbols. - The ESP32 skips the heavy CPU tax of KeyGen and Decap, focusing strictly on Kyber Encapsulation and hardware-accelerated AES-256.
- The node never stores a private PQC key, reducing the attack surface if the hardware is physically compromised.
- Device: LOLIN32 (ESP32-WROOM-32)
- Processor: Dual-core 32-bit Xtensa LX6 (240MHz)
- SRAM: 520 KB (Optimized via 32KB dedicated PQC task stack)
- TRNG: Integrated hardware True Random Number Generator.
- Security Logic: Hybrid System (Kyber-768 KEM + AES-256 CBC)
Verified on device over 10-iteration wireless trials.
| Operation | Component | Execution Time (Avg) |
|---|---|---|
| PQC Encapsulation | Kyber768 (PQClean) | 17.07 ms |
| Wireless Burst | UDP (BSD Sockets) | 4.38 ms |
| Symmetric Encryption | AES-256 (Hardware) | < 0.1 ms |
| Server Recovery | Python (Quantcrypt) | 5.04ms |
Total Device Cycle Time: ~22.37 ms
** Network Stability: Jitter ±150ms over standard 802.11n Wi-Fi.
We conducted isolated trials to see how Kyber-768 stacks up against a classical Curve25519 (ECC) baseline. The results challenged the assumption that PQC is always "heavier" for IoT.
- The Performance Paradox:
Surprisingly, Kyber-768 is nearly
10xfaster than the classical baseline. This is because the ESP32 does not have dedicated hardware for Montgomery curves like Curve25519. This forces the chip to use software-based big-integer math, which is incredibly slow. In contrast, Kyber’s structured lattice operations are much more efficient on the Xtensa architecture.
- The RAM Tax:
Efficiency in time comes at a cost in space. We tracked the peak stack high-water mark for both suites. Kyber requires roughly
6xmore RAM than ECC. While ECC is slow, it is "thin," fitting into less than 3 KB. Kyber’s reliance on large coefficient arrays makes the 32 KB stack allocation a hard requirement.
- Run
server/keygenerator.pyto generateserver_pk.bin. - Copy
.bintomain/. ESP-IDF will automatically link the binary viatarget_add_binary_data. - Flash the ESP32. It will connect to the AP defined in
wifi_credentials.h(formatted as below, found inmain/) and start a 10s telemetry loop.
#ifndef WIFI_CREDENTIALS_H
#define WIFI_CREDENTIALS_H
#define WIFI_SSID "YOUR_SSID"
#define WIFI_PASS "YOUR_PASSWORD"
#define SERVER_IP "YOUR_IP"
#define SERVER_PORT 4444 //Can be another open port number
#endif- Run
server/server.pyon your laptop to receive and auto-decrypt the incoming quantum-secure stream.
To switch between cryptographic modes and generate comparison data:
-
Open
main/benchmark_config.hand uncomment the desired suite (MODE_PQCorMODE_ECC). -
Rebuild/Flash the device, then run the automated logger:
python tools/serial_logger.py-
The logger will capture 10 clean readings and save them to mode-specific CSVs.
-
Once both suites are collected, generate the charts:
python tools/report.py- Memory Management: Resolved stack overflows by isolating the Kyber task with a dedicated 32KB partition.
- Binary Embedding: Implemented custom CMake logic to handle raw PQC keys without manual hex-pasting.
- Network Tax: Verified that moving to UDP reduced wireless latency by 85% compared to initial TCP concepts.

