Skip to content

Add ESP32 support with secureLSL encryption#1

Merged
neuromechanist merged 4 commits intomainfrom
feature/esp32-support
Mar 18, 2026
Merged

Add ESP32 support with secureLSL encryption#1
neuromechanist merged 4 commits intomainfrom
feature/esp32-support

Conversation

@neuromechanist
Copy link
Member

Summary

Adds liblsl-ESP32: a clean-room C reimplementation of the LSL wire protocol for ESP32 microcontrollers with full secureLSL encryption support.

What's included

Core library (liblsl-ESP32/components/liblsl_esp32/, ~4100 lines C)

  • LSL protocol v1.10: UDP multicast discovery + TCP data streaming
  • Bidirectional: outlet (push) and inlet (pull)
  • secureLSL encryption: ChaCha20-Poly1305, Ed25519, wire-compatible with desktop
  • Pre-allocated memory architecture (~200KB SRAM, 300KB+ free for application)

Examples (4 projects)

  • basic_outlet, basic_inlet (unencrypted)
  • secure_outlet, secure_inlet (encrypted, with key provisioning via menuconfig)

Benchmarks (firmware + desktop Python scripts)

  • Throughput benchmark: configurable channels, rate, security
  • Desktop collection scripts for jitter/throughput/loss measurement

Documentation (integrated into mkdocs)

  • docs/esp32/overview.md -- scope, quick start, API, performance, compatibility
  • liblsl-ESP32/docs/ -- architecture, security guide, benchmarks

Key design decisions

  • Clean reimplementation (not a port): desktop liblsl's Boost/C++ stack is impractical on 520KB SRAM
  • Communication layer only: designed to pair with dedicated ADC ICs for biosignal acquisition
  • Transport-agnostic: WiFi current, extensible to Ethernet/Bluetooth/ESP-NOW
  • Low-latency local network scope (consistent with LSL design)

Hardware-verified performance

Config Rate Loss Encryption overhead
8ch float32 250 Hz 0% Not measurable (async)
8ch float32 1000 Hz 0.02% Not measurable (async)
64ch float32 250 Hz 0% Not measurable (async)

Bidirectional encrypted interop verified with desktop secureLSL (cpp_secure_inlet/outlet).

Protocol compatibility

Feature Desktop liblsl liblsl-ESP32
Protocol 1.00 + 1.10 1.10 only
IP IPv4 + IPv6 IPv4 only
Formats All float32, double64, int32, int16, int8
secureLSL Yes Yes (wire-compatible)
Max connections Unlimited 3
Max channels Unlimited 128

Add liblsl-ESP32: clean-room C reimplementation of the LSL wire
protocol for ESP32 microcontrollers with full secureLSL encryption.

Components:
- Core library (~4100 lines C, ESP-IDF component)
- 4 examples: basic_outlet, basic_inlet, secure_outlet, secure_inlet
- Benchmark suite: throughput firmware + desktop Python scripts
- Documentation: architecture, security guide, benchmarks

Key features:
- Protocol v1.10, wire-compatible with desktop liblsl/secureLSL
- ChaCha20-Poly1305 encryption, Ed25519 key exchange via libsodium
- Sustains up to 1000 Hz with near-zero packet loss
- Zero measurable encryption overhead (async on dual-core)
- ~200KB SRAM footprint, 300KB+ free for application

Documentation integrated into mkdocs site under ESP32 section.
- Fix key exchange terminology: X25519 (not Ed25519)
- Add passphrase caveat (ESP32 uses raw keys, not encrypted_private_key)
- Add key distribution workflow (import desktop keys recommended)
- Fix broken links: use GitHub URLs instead of relative paths
- Add MkDocs admonitions (warning, note) matching secureLSL style
- Add section separators (---) for consistency
- Show export_pubkey and has_keypair in API overview
- Replace "Not measurable" with "2 KB heap (push async)" in perf table
- Cross-reference secureLSL Installation instead of inline build commands
- Remove duplicated key extraction snippet (link to security guide)
- Consistent line count (~4,000)
- Add copyright headers to all remaining source files
- Add nonce policy documentation (strict vs windowed)
@neuromechanist
Copy link
Member Author

PR Review Complete - All findings addressed

Code reviewer (5 findings)

# Finding Fix
1 Missing copyright on 21 files Added to all wifi_helpers, crypto_bench, build_test
2 sodium_init doc inconsistency Updated: "initializes internally if needed"
3 export_pubkey loads secret key Noted for future optimization (not blocking)
4 Nonce policy difference vs desktop Documented with comment in security_decrypt
5 Stack allocation in resolve_streams Verified safe for current MAX_RESULTS

Doc reviewer (13 findings)

# Finding Fix
1 "Ed25519 key exchange" incorrect Changed to "X25519 key exchange (from Ed25519 identity)"
2 private_key vs encrypted_private_key Added !!! note caveat about ESP32 raw key storage
3 Missing key distribution step Reordered: import desktop keys as recommended workflow
4 Key extraction snippet fragile Removed from overview, linked to security guide
5 "Not measurable" misleading Changed to "2 KB heap (push async)"
6 Missing MkDocs admonitions/separators Added !!! warning, !!! note, --- separators
7 Inconsistent product name Standardized within page
8 Missing API functions in overview Added export_pubkey, has_keypair
9 Broken relative links Changed to GitHub URLs
10 Documentation links broken on mkdocs Changed to GitHub URLs
11 Missing Installation cross-reference Added link to getting-started/installation
12 Inconsistent line count Standardized to ~4,000
13 Duplicated key extraction snippet Removed, linked to security guide

Positive findings

  • Scope section well-written and scientifically grounded
  • Protocol compatibility table honest about limitations
  • Wire format verified correct against desktop secureLSL
  • No hardcoded credentials in codebase
  • Memory safety thorough with bounds checking throughout

ESP32 support is a significant feature addition warranting
a minor version bump from 1.0.0 to 1.1.0.

Updated: mkdocs.yml, liblsl/CMakeLists.txt, CHANGELOG.md
@neuromechanist neuromechanist merged commit a7bfbbc into main Mar 18, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant