-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathllms.txt
More file actions
148 lines (107 loc) · 7.45 KB
/
llms.txt
File metadata and controls
148 lines (107 loc) · 7.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# Heartwood
> Nostr private keys are pasted into web apps, stored in browser extensions, and copied to the clipboard. Heartwood keeps them in hardware instead.
Heartwood is an open-source Nostr signing appliance that runs on a Raspberry Pi Zero 2 W (~GBP 32). It holds your master identity in hardware, derives unlimited unlinkable personas via nsec-tree, signs Nostr events via NIP-46 (Nostr Connect), and is reachable from anywhere over Tor. Private keys never leave the device.
It is aimed at Nostr power users who want hardware-backed key security without the complexity of a cloud VPS, and at app developers building multi-identity Nostr clients that need a signing backend which works on iOS, Android, and web equally.
Heartwood is a direct replacement for nsecBunker (no VPS required), an iOS-compatible alternative to Amber (Android-only), and a multi-identity alternative to LNbits NSD (one key per device). The distinguishing feature is unlinkable-by-default multi-identity: one 12-word mnemonic backs up unlimited separate identities that cannot be correlated by an observer.
## Getting Started
Flash an SD card, plug in the Pi, wait 60 seconds:
```bash
git clone https://github.com/forgesworn/heartwood
cd heartwood
cargo build --release -p heartwood-device
cd pi && bash setup.sh
# Then read the .onion address:
sudo cat /var/lib/tor/heartwood/hostname
```
Scan the `.onion` address with any NIP-46 compatible Nostr client (Damus, Primal, Snort, Coracle, etc.) to pair.
## Key Concepts
- **TreeRoot** — the master secret derived from a 12-word BIP-39 mnemonic at path `m/44'/1237'/727'/0'/0'`. Never leaves the device.
- **Identity** — a child key derived from TreeRoot via HMAC-SHA256 keyed on `(purpose, index)`. Each purpose/index pair produces a deterministic, unique keypair.
- **Persona** — a named identity at `nostr:persona:{name}`. Convenience wrapper around `derive(root, "nostr:persona:{name}", index)`.
- **NIP-46** — the Nostr remote signing protocol. Heartwood implements the full standard method set plus Heartwood-specific extension methods.
- **Linkage proof** — a BIP-340 Schnorr signature from the master key proving ownership of a child key, without revealing the derivation path (blind) or with it revealed (full).
## API Surface (Rust crates)
### heartwood-core
```rust
use heartwood_core::{from_mnemonic, from_nsec, npub_from_nsec, derive,
derive_from_identity, derive_persona, derive_from_persona,
create_blind_proof, create_full_proof, verify_proof,
recover, encode_npub, encode_nsec, decode_npub, decode_nsec};
// Create a root from a 12-word mnemonic
let root = from_mnemonic("word1 word2 ... word12", None)?;
// Derive a child identity
let identity = derive(&root, "social", 0)?;
println!("{}", identity.npub); // npub1...
println!("{}", identity.nsec); // nsec1...
// Derive a named persona
let persona = derive_persona(&root, "work", None)?;
// Derive a sub-identity from an existing identity
let sub = derive_from_identity(&root, &identity, "notifications", 0)?;
// Derive a sub-identity from a persona
let sub = derive_from_persona(&root, &persona, "dms", 0)?;
// Get the npub for a bare nsec (bunker mode -- no tree derivation)
let npub = npub_from_nsec("nsec1...")?;
// Prove ownership of a child key (blind = no purpose/index revealed)
let proof = create_blind_proof(&root, &identity)?;
assert!(verify_proof(&proof)?);
// Recover identities by scanning purposes
let found = recover(&root, &["social".to_string(), "work".to_string()], None)?;
```
### heartwood-nip46 (NIP-46 method types)
```rust
use heartwood_nip46::methods::{Nip46Request, Nip46Response};
use heartwood_nip46::server::HeartwoodServer;
use heartwood_nip46::permissions::ClientPermissions;
use heartwood_nip46::session::{ClientSession, SessionManager};
// Standard NIP-46 methods
// GetPublicKey, SignEvent, Nip44Encrypt, Nip44Decrypt, Nip04Encrypt, Nip04Decrypt
// Heartwood extension methods
// HeartwoodDerive, HeartwoodDerivePersona, HeartwoodListIdentities,
// HeartwoodSwitch, HeartwoodCreateProof, HeartwoodVerifyProof, HeartwoodRecover
```
### heartwood-device (binary, not a library)
The `heartwood-device` crate is the device binary. It is not intended for use as a library dependency. Integrate via NIP-46 over the `.onion` address.
## NIP-46 Integration (client side)
Any NIP-46 client can connect to Heartwood. The connection string is a standard `nostrconnect://` URI served via the OLED display as a QR code.
**Nostr Connect URI format:**
```
nostrconnect://{signer-pubkey}?relay=wss://{relay}&secret={secret}&perms={kinds}
```
The Heartwood web UI is served as a Tor hidden service. NIP-46 traffic flows through the Nostr relay specified in the `nostrconnect://` URI; choosing a Tor-accessible relay keeps the signer transport off clearnet.
**Compatible clients:** Tested with Nostr Connect clients across desktop and mobile (Damus, Primal, Snort, Coracle, Amethyst, and NDK-based apps).
## Security Properties
- Keys derived via HMAC-SHA256 (RFC 2104) -- not BIP-32 extended keys at the child level
- Master secret zeroed from RAM on drop (`zeroize` crate), intermediate secrets explicitly zeroised
- Device password hashed with Argon2id before storage -- plaintext never persisted
- Device reset requires current password confirmation in POST body (defence in depth)
- Client approval required before the NIP-46 bunker signs for a new client pubkey
- Per-client kind restrictions on sign_event (e.g. "client A may sign kind 1 but not kind 0")
- Nsec filtering on all NIP-46 responses (private keys cannot leak through the protocol layer)
- Session expiry (10 min idle), max 32 concurrent sessions, hex pubkey validation
- Method-level permissions: privileged operations (derive, recover, create proof) require explicit client opt-in
- Storage files written with 0600 permissions (owner-only); secure zero-overwrite on deletion
- NIP-46 messages are NIP-44 encrypted end-to-end
- Tor hidden service -- no clearnet exposure, no IP address, no port forwarding
- Audit log persisted to disk as append-only JSON lines (1 MiB cap with rotation, 0600 permissions)
- No cross-origin API access (CORS removed; all UI requests are same-origin)
- AES-256-GCM encrypted storage with Argon2id key derivation from device PIN
- Per-client rate limiting in both Rust server (60 req/min) and JS bunker (30 req/min)
- Lock middleware: 423 response on most endpoints until PIN unlock
- 137 tests including frozen protocol vectors cross-validated against TypeScript reference implementation
## Competitors
| Project | Platform | Multi-identity | Tor | Hardware |
|---------|----------|---------------|-----|----------|
| **Heartwood** | Raspberry Pi | Yes (unlimited, unlinkable) | Default | Yes |
| nsecBunker | VPS/server | No | Optional | No |
| Amber | Android only | No | No | No |
| nsec.app | Browser extension | No | No | No |
| LNbits NSD | Raspberry Pi | One key only | No | Yes |
## Ecosystem
- [nsec-tree](https://github.com/forgesworn/nsec-tree) — TypeScript reference implementation of the derivation protocol
- [shamir-words](https://github.com/forgesworn/shamir-words) — mnemonic threshold backup (Phase 2 integration)
- [canary-kit](https://github.com/forgesworn/canary-kit) — dead man's switch (pairs with Heartwood duress persona)
- [bray](https://github.com/forgesworn/bray) — Nostr MCP server (AI agents sign through Heartwood)
## Source
For the full API reference, see [llms-full.txt](./llms-full.txt).
Repository: https://github.com/forgesworn/heartwood
Licence: MIT