Skip to content

nSealr/esp32

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

201 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

nSealr ESP32

Firmware for ESP32-based nSealr signer targets.

This repository groups the ESP32 firmware family instead of splitting every board into a separate repository.

Planned Targets

  • ESP32 USB/NIP-46 signer with ESP32-S3 as the primary display/button target. The no-camera LILYGO T-Display S3 is tracked as an integrated display-board candidate for this line.
  • ESP32 stateless QR vault with T-Display S3 Pro OV5640 as the primary camera/display target.
  • Classic ESP32/TTGO compatibility target under the USB/NIP-46 family.
  • Future ESP32-S3 plus TROPIC01 prototype only under the custom persistent-secret hardware-wallet research family.

The shared identity/policy route split is explicit: esp32_qr_vault remains a stateless, manual-only QR route with persistent_grants: false, while esp32_usb_nip46 is the future persistent daily-use route described by nsealr-account-descriptor-v0. The ESP32 QR route is pinned by esp32-qr-nip06-account-0, policy-manual-only-qr-vault, and esp32-qr-sign-event-account-0; the USB route is pinned by esp32-usb-device-slot-0, policy-manual-only-persistent-device, and esp32-usb-sign-event-slot-0. The scoped automation profile policy-scoped-automation-daily-use and test grant grant-esp32-usb-kind-1-session are reachable only through the device-reviewed esp32-usb-enable-kind-1-automation policy-change proposal. The USB route does not clear any production signing gate yet; signing remains disabled until provisioning, storage, review, hardening, and signed-output verification are accepted.

The final account/custody split is also explicit. esp32_qr_vault should match the Raspberry QR vault behavior for shared features: RAM-only session keyring, manual approval for every signature, SeedSigner SeedQR/CompactSeedQR-compatible BIP-39 import, plain mnemonic QR, nsec QR, local generation, no persistent policy, no persistent secret, and no TROPIC01. esp32_usb_nip46 should become a persistent encrypted device vault with seed profiles, passphrase namespaces, NIP-06 accounts, standalone key slots, and per-public-key policy state after production gates pass. The current policy vectors are conformance scaffolds, not the final policy UX.

Feature targets and current status are tracked in nSealr/specs vectors/features/signer-feature-matrix-v0.json. ESP32 may implement both QR vault and USB/NIP-46 features, but each shared feature must keep the same behavior as other implementations by using the shared contract_id. The ESP32 stateless QR vault is a parity target with the Raspberry QR vault; current hardware readiness can differ, final vault behavior must converge.

Current Capabilities

  • Host-buildable C++ firmware core foundation.
  • ESP-IDF scaffold for the ESP32-S3 USB signer target.
  • Host-side ESP32-S3 detection gate for native USB/JTAG serial boards.
  • Local ESP-IDF v5.5.4 build, flash, and capability/public-key/signing-disabled smoke test on an attached ESP32-S3.
  • nsealr1f: serial frame encode/decode compatible with the companion serial framing draft. The decoder mirrors the shared v0 max_serial_frame_bytes limit, accepts common serial line endings, and rejects shared invalid serial-frame vectors for unsupported frame types, oversized frames, checksum mismatch, and malformed base64url payloads.
  • nsealr1: static QR envelope decode boundary plus nsealr1a: animated QR frame reconstruction compatible with the shared transport vectors. The host core rejects malformed, padded, invalid UTF-8, oversized, missing-frame, and checksum-mismatched QR inputs before any future camera/display adapter can review them; camera capture, animated scan timing, and signing remain future work.
  • QR sign_event request metadata parsing for decoded envelopes. It extracts version, request_id, method, params presence, and the raw params.event_template object boundary. The minimal field parser is described below; signing remains disabled.
  • QR event-template safety gate rejecting host-supplied id, pubkey, or sig fields before any future review/signing path. The parser tolerates normal JSON string escapes while keeping full event semantics pending.
  • Minimal QR event-template field parsing for created_at, kind, tags, and content. This prepares trusted review generation without enabling tag semantics, key storage, or signing.
  • Host-core NIP-19 nsec decoder checked against the shared nSealr/specs vector. This is a RAM-only key-source parser for the future ESP32 QR vault; it does not add persistent key slots, storage, policies, or a signing backend.
  • Host-core SeedSigner Standard SeedQR and CompactSeedQR decoders checked against the shared nSealr/specs vector. They validate BIP-39 word indexes and checksum bits for future RAM-only QR-vault session loading.
  • Host-core BIP-39 English mnemonic parser and word-index renderer checked against the shared NIP-06 mnemonic and SeedQR vectors. This enables one canonical RAM-only representation for manual words, plain mnemonic QR, and SeedQR-derived indexes; it does not derive NIP-06 keys, persist material, or sign.
  • Host-core decoded session-source QR parser for future camera adapters. It accepts canonical NIP-19 nsec, plain BIP-39 English mnemonic QR text, SeedSigner Standard SeedQR digit streams, and CompactSeedQR entropy bytes, then routes each source into the same RAM-only key-source type used by import review. It does not derive NIP-06 keys, persist material, or sign.
  • Host-core decoded QR session-source import flow. It composes the decoded QR parser with the local import-review button flow, so nsec, mnemonic, Standard SeedQR, and CompactSeedQR inputs load into the RAM-only keyring only after the final import decision page is approved. Rejection and invalid QR inputs leave the keyring empty; this still does not add camera capture, NIP-06 derivation, persistence, response QR display, or signing.
  • Host-core QR session-account selection. It binds a RAM-only source to secretless account metadata only when route, recovery type, path, public key shape, and reviewed source fingerprint match, then uses that selected public key for Event review and approval-digest binding. The selected account explicitly reports source_public_key_proof_verified: false, so this metadata binding cannot satisfy the real-signing source proof gate. It still does not derive NIP-06 keys, persist material, or sign.
  • Host-core stateless session keyring model for already parsed nsec and BIP-39 key sources. It is a bounded RAM-only container for future import UX tests. The source value type and keyring wipe active nsec and BIP-39 word index material on clear, destruction, assignment replacement, and moves; this is still best-effort process hygiene, not a hardware anti-extraction claim. The model does not derive NIP-06 keys, persist material, expose policy state, or connect a signing backend.
  • Host-core secret-hidden session import review summaries for parsed nsec and BIP-39 sources. The review shows source type, label, word count when applicable, and a deterministic fingerprint, and is checked against shared nSealr/specs session-import-review vectors, but never raw nsec bytes or mnemonic words. It is not a signing approval gate.
  • Host-core session import flow requiring local traversal of the import review before a parsed source can be loaded into the stateless session keyring. Rejection and incomplete button streams leave the keyring empty, and approval only loads RAM-only source material; it still does not sign, derive NIP-06 keys, persist material, or create policy state.
  • Host-core local session-source generation for the future ESP32 QR vault. Explicit entropy inputs can become generated BIP-39 or standalone nsec-equivalent sources in the same RAM-only import/review/keyring boundary. Host-core now also models the separate danger-zone backup review that can reveal BIP-39 words/SeedQR or NIP-19 nsec recovery payloads only after final-page local approval. A host-core backup/output harness displays bounded danger-zone frames before local button reads and emits the recovery payload to an injected output sink only after final-page approval. Hardware RNG wiring, physical backup display/output acceptance, and physical acceptance remain pending.
  • Host-core QR response-envelope encoding for already-produced response JSON. Static nsealr1: and animated nsealr1a: output match the shared signed response vector. A host-core response-display harness now chooses static versus animated frame output only after the response JSON passes a v0 top-level response-shape gate, then cycles animated frames for future display adapters. Firmware signing, QR matrix/display hardware, camera scan-back, and physical acceptance remain pending.
  • Shared nSealr v0 implementation limits for constrained firmware parsing, with host-core rejection of applicable invalid QR-envelope and signing-request hardening vectors before review or signing can be reached.
  • QR trusted-review page generation from parsed event templates, checked against shared nSealr/specs review-screen vectors. QR-derived approval_digest now matches shared basic/tagged vectors, while camera input, display/GPIO drivers, key storage, and signing remain disabled.
  • T-Display S3 sized QR review detail pages checked against shared nSealr/specs review-detail-page vectors. These pin complete Event/Content/Tags/Decision pages, scroll windows, compact line styles, long value continuations, visible JSON-style escapes for decoded control characters, and explicit U+XXXX fallback for unsupported display glyphs without changing the approval_digest contract. Supported printable ASCII punctuation remains literal in review text.
  • QR-derived trusted-review session creation that drives the existing bounded display-frame and approval-gate state machines. It is still host-core only and has no signing backend.
  • QrReviewFlow host-core boundary from raw scanned static nsealr1: QR envelope or complete animated nsealr1a: request frame set to trusted review frames and physical approval state. It rejects unsafe QR requests before a future camera/display adapter can display them.
  • QrReviewIo host-core adapter harness for future scanner, display, and physical-button drivers. It scans one static or complete animated QR request, shows each trusted frame before reading a button, bounds non-terminal button streams, and returns the terminal approval state plus the exact displayed frame/button transcript; it still has no signing backend.
  • Serial/USB sign_event trusted-review boundary for decoded request JSON. It builds the same review pages and approval_digest as the QR path before the runtime dispatcher returns signing_disabled.
  • SerialReviewIo host-core adapter harness for future USB signer display and physical-button drivers. It reads one decoded serial request, shows each trusted frame before reading a button, and returns a frame/button transcript; it still has no signing backend.
  • Deterministic QR review transcripts for display/button adapter tests. A transcript records each displayed frame, input button, decision, and approval state without exposing any signing output, and the host-core tests consume the shared nSealr/specs review-transcript vectors.
  • ESP32-S3 scaffold capability response over the same nsealr1f: frame contract used by the companion.
  • ESP32-S3 scaffold get_public_key response using the shared deterministic development-only fixture key.
  • Host-core signer identity context that binds get_public_key, Event review author display, and approval digest generation to the same public key. The default scaffold context still uses the deterministic development fixture key; production account/provisioning work must replace that context before any signing backend is connected.
  • ESP32-S3 scaffold request dispatcher that parses valid serial-frame request payloads and echoes dynamic request_id values for get_capabilities, get_signing_status, get_public_key, and disabled sign_event responses.
  • Primary ESP-IDF console configured on native USB Serial/JTAG so the scaffold can receive hardware smoke-test requests over the attached USB-C cable.
  • Portable SHA-256 checksum helper for frame corruption detection.
  • Approval gate state machine requiring request-id and approval-digest matched approval before a request can be signed.
  • Host-buildable review controls, display frames, and trusted review session that model the future display/button approval loop without enabling signing.
  • Host-buildable signing-readiness policy that keeps runtime signing disabled until parser limits, trusted display, physical controls, approval-digest binding, Unicode review rendering acceptance, key provisioning, source public-key proof, secure boot, flash encryption, debug lock, companion verification, and an explicit runtime feature flag are all present.
  • Shared identity/policy descriptors are tracked without enabling signing: esp32_usb_nip46 starts from policy-manual-only-persistent-device and can reach future scoped automation only through a device-reviewed policy-change proposal, while esp32_qr_vault remains manual-only/stateless with persistent_grants: false and no TROPIC01 dependency.
  • Host-core policy-change review for the future ESP32 USB/NIP-46 persistent route. The firmware can build the shared device-review pages and approval_digest for esp32-usb-enable-kind-1-automation, requires local page traversal plus physical-style approval, rejects companion-authoritative or secret-bearing proposals, and still does not persist grants, provision storage, or enable signing.
  • Machine-readable ESP32-S3 USB signer security profile that records the current development-only hardening state and production blockers before any persistent-secret or real-signing path can be claimed.
  • The security profile now also records manual development acceptance evidence for T-Display S3 trusted display and physical approve/reject controls, while keeping those gates as production blockers. Display-review protocol smoke reports are tracked separately for review-rendering traceability and do not replace production trusted-display acceptance.
  • Unicode review rendering is tracked as its own blocker: the development display path uses explicit U+XXXX fallback for unsupported non-ASCII glyphs, renders decoded control characters as visible JSON-style escapes, and this does not count as full production Unicode review acceptance.
  • Companion transport evidence is tracked separately from companion signed-output verification. Direct serial-line smokes prove request-bound USB host/device exchange and the expected signing_disabled refusal; they do not clear the signed-output production blocker.
  • Firmware protocol evidence is tracked separately from display/control acceptance and signed-output verification. Current T-Display S3 hardware smokes prove the flashed firmware still answers valid protocol requests, rejects invalid protocol input deterministically, exposes the Unicode review rendering gate, normalizes duplicate signing-status development gates, and refuses valid sign_event requests with signing_disabled; they do not clear real-signing blockers.
  • Read-only ESP32-S3 security eFuse audit support through make idf-audit-security-fuses. The audit reports secure boot, flash encryption, download-mode, and debug-lock fuse state without burning or modifying eFuses; it measures the M9 hardening gap and does not clear any production signing blocker. The security profile tracks these reports in a separate security_fuse_audit_evidence field.
  • Generic bounded display frames wrap and truncate frame text to configured display limits, giving small ESP32 screens and display adapters a deterministic rendering oracle for one-frame status/review previews. The sign-event detail review path is separate: Event/Content/Tags/Decision pages use scroll windows and must not abbreviate event content or tag values with ellipses.
  • Generated host test fixtures from shared serial, review-screen, review-display-frame, review-detail-page, review-transcript, limits, and invalid hardening vectors in nSealr/specs.
  • Board profile for the no-camera LILYGO T-Display S3 as an ESP32-S3 USB/display signer candidate. The profile documents integrated ST7789 display constraints, GPIO0/GPIO14 onboard button mapping, touch-not-approval, wireless policy, debug-lock policy, and disabled production signing.
  • Initial T-Display S3 ST7789/i80 ESP-IDF display bring-up for the USB/display signer scaffold. It pins the display dimensions, bus pins, GPIO38 backlight, GPIO15 display-power line, no-camera status, and touch-not-approval rule, then draws a Ready/No request frame while keeping storage and signing disabled.
  • Host-buildable T-Display S3 raster tests cover the same boot and review-frame pixel-color function used by the ESP-IDF ST7789/i80 draw path, including border, boot pattern, title, page indicator, body, footer samples, and representative printable ASCII punctuation glyphs. Value/continuation lines use a dedicated yellow display color so long pubkeys, content chunks, and tag items remain visually grouped after wrapping.
  • T-Display S3 onboard button polling for manual review navigation after a live sign_event request. Short GPIO14 cycles the stable Event, Content, Tags, and Decision pages; short GPIO0 scrolls within Content or Tags when that page has more display windows; long GPIO14 maps Approve on the Decision page; and long GPIO0 maps Reject from any page. The runtime still returns signing_disabled, shows a terminal non-signing review screen after approve/reject, expires stale active review sessions into a terminal non-signing timeout frame, and never signs.
  • Host-buildable T-Display S3 button logic tests cover debounce filtering, short-press classification, long-press classification, and the GPIO0/GPIO14 review-button mapping used by the ESP-IDF GPIO polling adapter.
  • Host-buildable T-Display S3 status-frame tests cover the non-signing Ready, approve/reject-closed, timeout, and request-error frames shown by the runtime display loop, keeping user-visible safety copy out of untested main.cpp branches.
  • Host-buildable T-Display S3 serial-input tests cover overlong-frame refusal and drain-until-newline behavior so a rejected transport frame cannot leave tail bytes to contaminate the next request line.
  • Board profile for the LILYGO T-Display S3 Pro with OV5640 camera as the primary ESP32 stateless QR vault candidate. The profile documents display, camera, touch, physical-approval, wireless-disabled, and debug-lock constraints; it does not add real camera/display/GPIO drivers.

The current firmware is still a scaffold. It logs startup, answers get_capabilities, returns the deterministic development public key for get_public_key, returns explicit signing-readiness diagnostics through get_signing_status, returns an explicit signing_disabled protocol response for valid sign_event requests, initializes the T-Display S3 display only far enough to draw a Ready/No request frame and live trusted-review pages, polls the two onboard physical buttons for local review navigation, shows closed review decisions as Not signed, clears active review state on rejected serial requests, drains overlong serial input until the next newline, and keeps real signing disabled until storage, production hardening, and signing tests are implemented. An active T-Display S3 review session is RAM-only and expires after five minutes of inactivity; expiry clears the session and shows Review Timeout / Expired / Not signed rather than leaving stale event content on screen.

The ESP32 stateless QR vault target belongs in this repository as ESP32 firmware. It must reuse the shared QR envelope, review model, review-screen vectors, approval_digest, and signing vectors from nSealr/specs; it should not depend on Raspberry implementation code. It has no persistent secret and no TROPIC01 dependency.

Initial Layout

  • firmware/: ESP-IDF firmware projects and shared modules.
  • boards/: board profiles, pinouts, displays, buttons, and hardware configs.
  • docs/: build, flash, provisioning, and security notes.

Quality Baseline

Run the repository verification loop with:

make ci

Build/flash prerequisites and commands are documented in docs/flash.md. Physical board detection can be checked with:

make detect-board
make idf-smoke-capabilities
make idf-audit-security-fuses
make IDF_ACCEPTANCE_MANUAL=passed IDF_FIRMWARE_REVISION=<flashed-revision> idf-acceptance-report

The hardware smoke sends the shared fixture requests and additional dynamic request_id variants for capabilities, signing status, development public-key, and disabled sign_event handling. It also sends invalid dynamic metadata requests from shared specs vectors plus serial-wrapped invalid signing-request vectors, including unknown top-level request fields, and expects deterministic unsupported_request rejections. It also exercises shared malformed serial transport vectors for checksum mismatch, malformed base64url payload, unsupported frame type, and overlong frame handling, expecting deterministic malformed_frame or overlong_frame errors, then sends a fresh valid capability request to prove the runtime drained the overlong line and recovered before the next request. The default smoke output summarizes expected rejections instead of printing raw protocol error frames; use scripts/smoke_capabilities.py --verbose-frames when raw frames are needed. Real signing is still expected to return signing_disabled. The security-fuse audit is read-only. It calls espefuse.py summary and prints JSON describing current secure boot, flash encryption, download-mode, and debug-lock state. The acceptance-report target runs the capability smoke, review-scenario smoke, read-only fuse audit, post-audit hard reset, and a post-reset protocol recovery smoke, then writes a development JSON report under build/acceptance/ with the detected serial ports, USB identity, and ESP-IDF/esptool availability. Set IDF_ACCEPTANCE_MANUAL=passed only after a human has completed the display/button checklist for the flashed firmware revision.

For manual T-Display S3 display inspection after flashing, use:

python3 scripts/manual_review_display.py show-review --port /dev/cu.<device>
python3 scripts/manual_review_display.py show-dense-tags --port /dev/cu.<device>
python3 scripts/manual_review_display.py show-request-error --port /dev/cu.<device>
python3 scripts/manual_review_display.py button-approve --port /dev/cu.<device>
python3 scripts/manual_review_display.py button-reject --port /dev/cu.<device>

show-review leaves a valid disabled sign_event review on the physical display. show-dense-tags stresses a valid event with enough structured tags to require Tags scroll windows without interpreting tag meaning or abbreviating values. show-request-error first shows that review and then sends an invalid request so the firmware should clear the active review and display the non-signing request-error state. button-approve and button-reject send the same valid review request and print the physical-control checklist for manual approval/rejection acceptance. Terminal request-error, approve, and reject screens include the final Send new request prompt. All modes still expect signing to remain disabled.

License

Firmware and tooling are released under the MIT License unless a file says otherwise. Third-party SDK and component licenses must be preserved.

About

ESP32 firmware and host-core for nSealr USB/display and stateless QR signer targets; production signing remains disabled.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages