An Android NIP‑55 signer for Heartwood
The signer that
holds no keys.
Cambium registers as a signer on your phone, but it is not one. Fresh cryptographic requests travel over Nostr relays to your Heartwood hardware signer and are answered there; safe, exact repeats can use bounded caches. Compromise the phone and you hold the ability to ask; the answer still comes from hardware, behind its own policy and a physical button.
The gap it fills
Amethyst, Primal, Voyage and most other Amber-compatible Android clients cannot log in to a remote NIP‑46 bunker directly. All of them can sign in with any installed NIP‑55 external signer.
Cambium sits between the two: it registers as a signer, translates each NIP‑55 intent into a NIP‑46 request against your Heartwood, and hands the response straight back. The name follows the tree: cambium is the living layer between bark and wood.
Security model
- Nothing to steal
- No user secrets ever touch the phone. Cambium stores the pairing (Heartwood's public key, its relay list, the connection secret) and its own ephemeral NIP‑46 client keypair. The identity key is not here to find.
- Encrypted at rest
- What little it does store lives in Android Keystore-backed encrypted preferences, never in plain files.
- Hardware is the authority
- Per-app approval on the phone is a convenience filter. Heartwood's own policy engine and physical confirmation button decide what actually gets signed. Cambium can refuse on its behalf, never grant.
- Sealed in transit
- Every NIP‑46 payload is NIP‑44-encrypted end to end. Relays route envelopes; they read nothing.
What's inside
-
Several identities, no guessing
Pair more than one Heartwood. NIP‑55's
current_userselects the identity per request; a request naming an identity Cambium does not hold is refused, never silently substituted. -
Genuinely invisible
Once an app is approved, its requests run with no flash, no dimmed overlay, no popup. A silent provider path does the work, plus a truly transparent window for the rest.
-
Websites, one request at a time
A website can open a NIP‑55
nostrsigner:link. Each request gets an explicit one-shot approval, then returns through a validated HTTPS callback or the clipboard. Browser approval is never remembered. -
Remembers what cannot change
Repeat decrypts are answered from a per-identity cache instead of costing a hardware round trip each time you scroll past the same message.
-
Burst-contained
Each identity gets its own bounded queue and user work keeps a reserved slot. Relay AUTH admits one distinct challenge at a time, never retries it, and backs off for 60 seconds after a transport failure. A burst against one identity cannot shed another.
-
An honest activity log
What was asked, by which app, answered how, by which identity. Metadata only, never an event body, plaintext or ciphertext. Yours to clear, or switch off.
-
App lock that knows its place
An optional biometric or device-unlock gate on the management and activity-log screens and on approval decisions. Background signing for already-approved apps keeps working with the phone locked, because that is the point of a proxy.
-
Keeps the line warm
An optional foreground service holds the relay session between requests, so silent signing skips the reconnect penalty. Off by default; survives reboots when on.
-
Private zaps, honestly scoped
Zaps sent privately to you decrypt (DIP‑03, recipient path). Viewing your own sent private zaps needs the raw key hashed directly, which is impossible over NIP‑46, so Cambium does not pretend otherwise.
-
De-Googled by default
No Play services, no Firebase, no analytics, no push servers. Built for GrapheneOS; runs on any 64‑bit Android 8.1 or later.
Pairing takes a minute
-
i
Install Cambium on your phone.
-
ii
In Sapwood, choose Connect an app and name it. It shows a
bunker://URI as a QR code. -
iii
In Cambium, scan it; a successful scan pairs immediately. No camera? Paste the URI text instead; the camera is never required.
-
iv
In any Amber-compatible client, log in with an external signer and pick Cambium. Approve the app once; every signature still comes from your hardware.
Honest numbers: on a healthy kept-warm session, a fresh signature is one relay round trip, commonly roughly half a second to a couple of seconds. Cold reconnects, contention, or an unhealthy relay can take longer. Repeat deterministic decrypts skip the trip entirely.
Install, then verify
Download the signed APK from GitHub Releases, or point Obtainium at the repository for automatic update tracking. A Zapstore listing carries v0.4.3, signed with the same key as the GitHub release. An F-Droid listing is under review. Before installing, check the signing certificate with AppVerifier:
dev.forgesworn.cambium
9E:A1:88:EF:A9:01:5F:7E:7F:90:E1:88:8F:58:6F:52:
7B:2A:0E:8A:6D:CD:B3:99:1E:41:FB:4F:14:EE:EF:C6
Releases before 0.2.0 were never published; the 0.2.0 key is the trust root.
The whole tree
Heartwood
The hardware signer. Wi‑Fi-standalone, policy engine, physical button. Keys live here, and only here.
Sapwood
Flashing and management. Provisions your Heartwood and issues the
bunker:// pairings.
Cambium
The living layer on your phone. Signs nothing; fresh cryptographic work comes from hardware. You are here.
Bark
The protective outer layer. NIP‑07 in your browser; the keys are nowhere near it.
Bray
The pack animal alongside the tree. Nostr for AI assistants and the terminal; happiest signing through a Heartwood.