HEARTWOOD

An open hardware signer for Nostr

Keys on a chip.
Approval on a button.

Heartwood generates your Nostr identity from hardware entropy on an ESP32 dev board and never lets it leave. Every signature is produced on the device: a policy you installed decides what signs unattended, and a physical button decides everything else. The computer it plugs into only ever sees ciphertext.

Rust firmware  ·  four boards  ·  NIP‑46 / NIP‑44  ·  MIT  ·  v0.13.7

Heartwood's OLED boot sequence: a pixel cat walks along a scrolling ground, meets a ghost of itself at centre screen, then HEARTWOOD decrypts letter by letter in rainbow colours with the firmware version beneath
Fig. 1. The boot sequence, frame for frame from the firmware: the cat walks, suffers a moment of déjà vu, and HEARTWOOD decrypts.
01

Why the key belongs on a chip

A Nostr key has no password reset. Yet most of them live inside the most attacked software their owners run: a browser profile, a phone app, a server's home directory. One phishing page, one malicious update, one bad backup, and the identity is someone else's forever.

Heartwood moves the key to a device whose only job is to hold it. NIP‑44 decryption, policy evaluation and the BIP‑340 signature itself all happen on the chip; the seed never crosses the USB port, the relay connection, or any backup path. Whatever the request, the answer is the same: the device signs, or nobody does.

02

The hardware

One Rust firmware and four boards, from a bare OLED module to a colour display with two buttons. The board is chosen at compile time and every signed update is tied to a board id, so the device refuses an update built for the wrong board.

Heltec WiFi LoRa 32 V3
ESP32‑S3 with a 128×64 OLED. The workhorse: cheap, everywhere, and everything Heartwood needs.
Heltec WiFi LoRa 32 V4
ESP32‑S3, native USB, same OLED. The default build target.
LilyGO T‑Display
Classic ESP32 with a colour TFT and a second button, which makes typing a recovery phrase far less of a chore.
Waveshare ESP32‑C6
RISC‑V core with a 1.47″ colour LCD, for the smallest desk footprint.

When a request needs you, the display shows which identity, what kind of event, and a preview of the content, with a countdown. Hold the button two seconds to approve; a short press denies; thirty seconds of silence denies for you.

03

Security model

Born on the device
The seed is drawn from the chip's hardware entropy source, shown once on the display at creation, and never leaves by any code path: not USB, not relay, not backup. Up to eight master identities per device.
Policies that fail closed
Each client gets an exact allowlist of methods and event kinds. Inside the ceiling, signing is unattended; outside it, the request is denied, and no button press can escalate it after the fact.
A bounded operator
Management commands are accepted only from your operator key, and every mutation must answer a fresh one-time challenge. The operator can shape policies and connectivity; it cannot read or replace a seed, change the PIN, or start a firmware update.
Updates you can trust
Every release is signed in CI; the device verifies the signature twice and ties it to its own board id. Flashing happens over USB with a two-second button hold. Remote update is deliberately not implemented.
Sealed at rest
Set a PIN and each seed is stored encrypted, with no PIN hash kept on the device. Every guess pays the full key-derivation cost, and five wrong attempts wipe the device clean.

Honest limits: the default build leaves ESP32 flash encryption and secure boot off, because burning eFuses is irreversible and that stays your call. Without a PIN, someone holding the board can read flash. Set the PIN, and treat physical custody as part of the model: Heartwood is a signer you own, not a bank vault. The full write-up is in SECURITY‑MODEL.md.

04

No hardware yet? Run it soft.

heartwoodd is the same signer as a daemon for a Pi or any Linux box, and it has two modes. In soft mode it signs locally: keys live in a keyfile sealed under Argon2id and XChaCha20‑Poly1305, decrypted only into memory and zeroised on lock, behind the same policy engine and approval queue the hardware uses. You unlock it from Sapwood in your browser.

Plug an ESP32 in and it becomes hard mode: the daemon stops holding anything at all and turns into zero-trust plumbing between your relays and the chip. Start soft tonight and move to hardware whenever. It stays your own bunker, no third party, and your apps keep the same connection either way.

Just need the plumbing? A standalone keyless bridge, heartwood‑bridge, ships from its own repo with a one-line installer, Docker images, and prebuilt binaries for aarch64, x86_64, armv7 and riscv64.

05

A signature's journey

YOUR APPS Bark · Cambium · any client RELAYS kind 24133 · NIP-44 PI / SERVER heartwoodd · keyless USB HEARTWOOD policy → button → sign keys never leave the signature returns by the same path
Fig. 2. Nothing left of the device ever holds a key. Compromise the browser, the phone, the Pi, or the relay, and you hold the ability to ask.
06

Get started

  1. i

    Pick a board, any of the four above, from the usual suspects for a few pounds. No soldering.

  2. ii

    Flash and provision from your browser with Sapwood (Web Serial, so a Chromium browser), or fully offline with the provision CLI for an air-gapped setup.

  3. iii

    Pair your apps: Bark in the browser, Cambium on Android, or paste the bunker:// URI into any NIP‑46 client.

# or build it yourself and check our work
git clone https://github.com/forgesworn/heartwood-esp32.git
cd heartwood-esp32
./scripts/build-firmware.sh v4 --release   # v3 | v4 | tdisplay | c6
espflash flash target/heartwood-v4.elf

Prebuilt per-board images, with checksums and release signatures, are on GitHub Releases.

§

The whole tree