v0.1.0 - CYD firmware v0.0.2: algorithm-based API upgrade (all verbs, all algorithms), vendored Keccak/SHAKE + PSA ed25519/x25519 for IDF v5.4, Web Serial test page, CYD docs, Teensy 4.1 port plan (1TB SDXC OTP pad), brainstorming READMEs for BLE/IR/NFC/FPGA signer concepts

This commit is contained in:
Laan Tungir
2026-07-21 13:16:04 -04:00
parent ca18e1e42d
commit 64fbd5c874
23 changed files with 4271 additions and 488 deletions

View File

@@ -0,0 +1,175 @@
# 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`](../../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/`](docs/) — especially
[`docs/PINS.md`](docs/PINS.md) and [`docs/SETUP.md`](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`](../../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`](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`](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.
```bash
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`](../../examples/cyd_webserial_demo.html):
1. Open [`examples/cyd_webserial_demo.html`](../../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`](../../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`](../../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`](sdkconfig.defaults)).
- **secp256k1:** the vendored secp256k1 component (schnorr + ECDSA).
- **PQ (ML-DSA-65, SLH-DSA-128s, ML-KEM-768):** PQClean via the
[`components/pqclean/`](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`](docs/TROUBLESHOOTING.md) and the
[`firmware/README.md`](../README.md) CYD section for details.
## Reference documentation
- [`docs/`](docs/) — upstream CYD hardware docs (PINS, SETUP, TROUBLESHOOTING, ADDONS, etc.)
- [`plans/cyd_signer_port.md`](../../plans/cyd_signer_port.md) — original port plan (hardware comparison, architecture, UI flow)
- [`plans/cyd_algorithm_api_upgrade.md`](../../plans/cyd_algorithm_api_upgrade.md) — v0.0.2 API upgrade plan
- [`firmware/README.md`](../README.md) — shared firmware README (PQ crypto, mbedtls backend, feather target)
- [`README.md`](../../README.md) §4 — the authoritative n_signer API reference