Files
n_signer/firmware/cyd_esp32_2432s028/README.md

8.3 KiB
Raw Blame History

n_signer CYD Firmware (ESP32-2432S028)

The Cheap Yellow Display (ESP32-2432S028) is a $15 ESP32-WROOM-32 board with a 2.8" 320×240 ILI9341 resistive-touch display, CH340 USB-UART bridge, and a Micro SD card slot. This firmware turns it into a hardware n_signer that speaks the same algorithm-based API as the host (README.md §4).

Firmware version: 0.0.2 (algorithm-based API)

Hardware summary

Concern Value
MCU ESP32-WROOM-32 (classic, dual-core Xtensa, 512 KB SRAM, no PSRAM)
USB-UART CH340 (1a86:7523) → /dev/ttyUSB0
Flash 4 MB
Display 2.8" 320×240 ILI9341 (HSPI: DC=IO2, CS=IO15, SCK=IO14, MOSI=IO13, MISO=IO12, BL=IO21)
Touch XPT2046 resistive (bit-banged SPI: CLK=IO25, MOSI=IO32, CS=IO33, MISO=IO39, IRQ=IO36)
SD card Micro SD, VSPI (CS=IO5, SCK=IO18, MISO=IO19, MOSI=IO23)
RGB LED R=IO4, G=IO16, B=IO17 (active LOW)
LDR IO34
Speaker IO26 (DAC)
BOOT button IO0
GUI LVGL 8.3

For the full pin map, connectors (P1/P3/CN1), and add-ons, see the upstream hardware docs copied to docs/ — especially docs/PINS.md and docs/SETUP.md.

SD card — size limits and OTP pad storage

The CYD's Micro SD slot is wired to VSPI (IO5/18/19/23). ESP-IDF drives it via the SDSPI host + FATFS filesystem. The proven bring-up example is 07_sd_card in the esp32_playground/cyb-esp32-2432s028/ workspace.

Size limits:

  • SDSC (≤ 2 GB): supported.
  • SDHC (2 GB 32 GB): supported — this is the recommended range. The Makerfabs CYD ships with a 16 GB card, which works.
  • SDXC (> 32 GB): not supported out of the box. SDXC cards ship formatted as exFAT, and ESP-IDF's FATFS does not include exFAT. An SDXC card reformatted to FAT32 will work up to 32 GB; beyond that, FAT32's 32 GB limit applies. For OTP pad storage, 32 GB is vastly more than enough (see below).

Recommendation: use any SDHC card from 432 GB formatted FAT32.

Using the SD card for the OTP pad

The current v0.0.2 firmware derives the OTP pad from the mnemonic seed via HKDF-SHA256 into a 1024-byte in-RAM pad (no SD card required). This keeps the wire contract identical to the host's encrypt/decrypt (algorithm:"otp") verbs but limits the pad to 1024 bytes per session.

To hold a large OTP pad (the original n_signer host design binds a pad file from --otp-pad-dir), the SD card is the right storage. The plan:

  1. Format the SD card as FAT32.
  2. Place a pad file (e.g. nsigner.pad) on it — any size up to the card's free space. A 1 GB pad gives ~1 billion one-time-pad bytes before exhaustion.
  3. The firmware mounts the SD card at boot via esp_vfs_fat_sdmmc_mount() on the SDSPI host, opens the pad file, and reads pad bytes on demand into a small ring buffer, advancing a persistent offset (stored in a small nsigner.offset file on the SD so the offset survives power cycles).
  4. The encrypt/decrypt verbs XOR against the SD-backed pad instead of the HKDF-derived in-RAM pad.

This is a planned enhancement (see plans/cyd_algorithm_api_upgrade.md §13 — the current implementation uses the mnemonic-derived pad as the embedded fallback). The SD card slot is confirmed working and the pin map is in docs/PINS.md.

Note on simultaneous display + touch + SD: The CYD's display (HSPI), touch (bit-banged), and SD (VSPI) use three different SPI buses. All three can run at the same time — the touch is bit-banged precisely so it doesn't contend with the other two hardware SPI buses (see docs/TROUBLESHOOTING.md).

Building and flashing

Requires ESP-IDF v5.x (tested with v5.4.2). The classic ESP32 target uses the xtensa-esp-elf unified toolchain.

source /home/user/esp/esp-idf/export.sh
cd firmware/cyd_esp32_2432s028
idf.py build
idf.py -p /dev/ttyUSB0 flash

If flashing fails with Wrong boot mode detected (0x13), see the serial-reset hardware note below.

Validation — Web Serial

The CYD has no native USB; the CH340 bridge exposes a serial port. The browser transport is Web Serial (navigator.serial), Chromium-only. A full test page covering every algorithm and verb lives at examples/cyd_webserial_demo.html:

  1. Open examples/cyd_webserial_demo.html in Chrome/Edge.
  2. Click Connect Web Serial, select the CH340 port (1a86:7523).
  3. On the CYD touchscreen, enter or generate a mnemonic to reach the "ready" state.
  4. Exercise each card: get_public_key (all 6 algorithms), sign/verify, encapsulate/decapsulate, derive_shared_secret, derive, nostr_get_public_key, nostr_sign_event, nostr_mine_event, nostr_nip04/nostr_nip44 encrypt+decrypt, and encrypt/decrypt (otp).

API

The CYD firmware speaks the same algorithm-based API as the host n_signer (README.md §4). Supported verbs:

Verb Algorithms
get_public_key secp256k1, ed25519, x25519, ml-dsa-65, slh-dsa-128s, ml-kem-768
sign / verify secp256k1 (schnorr/ecdsa), ed25519, ml-dsa-65, slh-dsa-128s
encapsulate / decapsulate ml-kem-768
derive_shared_secret x25519
derive secp256k1 (HMAC-SHA256)
encrypt / decrypt otp
nostr_get_public_key secp256k1 (NIP-06)
nostr_sign_event secp256k1 (NIP-06)
nostr_mine_event secp256k1 (NIP-06, single-threaded PoW)
nostr_nip04_encrypt / decrypt secp256k1 (NIP-06)
nostr_nip44_encrypt / decrypt secp256k1 (NIP-06)

All requests require an auth envelope (kind 27235). The key_id in every structured result is the first 16 hex characters of the public key, matching the host. Invalid (verb, algorithm) pairs return error 1010.

Embedded-specific notes

  • OTP pad: derived from the mnemonic seed (HKDF-SHA256, 1024 bytes) in v0.0.2. The offset advances monotonically and is reported in every encrypt/decrypt response. SD-card-backed pad is a planned enhancement (see above).
  • nostr_mine_event: single-threaded, hard 30 s default timeout, shows a "mining…" screen. Keep difficulty low (≤ 8) on ESP32.
  • SLH-DSA-128s: keygen and signing take 530 s. The UI shows a "deriving key…" / "signing…" indicator. ML-DSA-65 is much faster (~100 ms) and is the recommended PQ signature algorithm for interactive use.

Crypto backend

  • SHA-256 / SHA-512: mbedtls (ESP32 hardware accelerated).
  • SHA3 / SHAKE-128 / SHAKE-256: vendored Keccak-f[1600] (FIPS 202) in resources/pqclean/common/crypto_backend_mbedtls.c. No CONFIG_MBEDTLS_SHA3_C or SHAKE menuconfig dependency.
  • ed25519 / x25519: PSA Crypto API (psa_import_key, psa_sign_message, psa_raw_key_agreement, etc.) — ESP-IDF v5.x mbedtls removed the mbedtls_ed25519_* functions. Requires CONFIG_MBEDTLS_PSA_CRYPTO_C=y (set in sdkconfig.defaults).
  • secp256k1: the vendored secp256k1 component (schnorr + ECDSA).
  • PQ (ML-DSA-65, SLH-DSA-128s, ML-KEM-768): PQClean via the components/pqclean/ component.

Serial-reset hardware note (CH340 auto-reset)

Opening /dev/ttyUSB0 can reset the ESP32 because the CH340's DTR/RTS lines are wired into the ESP32 auto-reset circuit. Symptoms: the device returns to the startup menu when a host app opens the serial port.

Mitigation: add a 10 µF capacitor between EN and GND on the CYD board (negative leg to GND). Typical working range is 4.722 µF. This also fixes the Wrong boot mode detected (0x13) flashing error. See docs/TROUBLESHOOTING.md and the firmware/README.md CYD section for details.

Reference documentation