Nostr Event Signer
Hardware NIP-07 signer
Your nsec sealed to the device. The browser stays the Nostr client; Passport only returns a signature after you approve on-screen.
Last updated Jul 2026

Approve a signature
Overview
A hardware Nostr signer that runs natively on Passport Prime. Your nsec is sealed to the device and never leaves it: the browser remains the Nostr client, and Passport only returns a signature (or a decrypted payload) after you approve on the device screen, unless the request matches a narrow auto-sign rule you configured on Passport.
It ships as two halves in one repo. The KeyOS app holds the keys, derives identities deterministically via NIP-06, and shows the approval screen; a Chromium MV3 extension implements the standard window.nostr (NIP-07) surface and relays requests over WebUSB (or WebSocket against the simulator). All Nostr crypto lives in a host-testable nostr-core crate built from first principles on k256.
What it does
- Full NIP-07 surface: getPublicKey, signEvent (BIP-340 Schnorr), nip04 and nip44 encrypt/decrypt.
- Identities derived deterministically via NIP-06 (m/44’/1237’/account’/0/0) from the device seed, or import an nsec.
- Identity records sealed with AES-GCM under a key derived from the hardware app seed.
- Narrow auto-sign rules: exact key + origin + event kind, with expiry and an hourly cap; HMAC-authenticated at rest.
- On-device approval shows origin, key label, peer pubkey (DMs), event kind/tags, and a content preview.
- Extension gates by origin: a site must be explicitly allowed before any window.nostr call succeeds.
- Audit log of the last 100 auto-signed events. getRelays() is intentionally empty in v1.
Technical breakdown
How the proof-of-concept is built, for developers evaluating the platform.
Two halves, one wire protocol
The device app (src/) and the Chromium extension (extension/) are two halves of one mechanism: the device is inert without the host-side NIP-07 provider, and both speak the same envelope (the protocol crate, mirrored in the extension’s JS). The extension runs an inpage shim, an isolated content script, and an MV3 service worker that holds the transport and enforces origin permissions.
Key sealing & policy
New identities derive from the device seed via NIP-06; records are sealed with AES-GCM under a key from KeyOS GetAppSeed. Auto-sign policies are HMAC-SHA256 authenticated as a whole. A failed MAC disables auto-sign for the session and forces manual approval. nostr-core (k256, chacha20, aes, hmac) implements NIP-01/04/44 v2/06/19 and is fully host-testable.
Transport
On hardware the device advertises a vendor-class USB interface (0xFF/0xFF/0xFF, two 64-byte interrupt endpoints) and exchanges newline-delimited JSON, chunked across 64-byte transfers, capped at 16 KiB. The simulator swaps in a WebSocket on ws://127.0.0.1:9876 with one JSON per frame; the extension flips transports via a setting.
Dig into the source
README, architecture notes, and the wire protocol live in the repo.
