upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorNsable-sh <nsable-sh@noreply.git.bitflash.network>2026-08-13 11:11:59 -0300
committerNsable-sh <nsable-sh@noreply.git.bitflash.network>2026-08-13 11:11:59 -0300
commitd2b86473a267c960a1f0c012a983176e5d962187 (patch)
tree002423e5987a3c544f469befae83519ccb29fffb /docs
parent851811b43be38bea48ba5d04d16987bd541dca53 (diff)
net: add signed direct onion peer endpoints
Diffstat (limited to 'docs')
-rw-r--r--docs/rendezvous.md70
-rw-r--r--docs/tor.md39
2 files changed, 93 insertions, 16 deletions
diff --git a/docs/rendezvous.md b/docs/rendezvous.md
index ac8e598..e1888b9 100644
--- a/docs/rendezvous.md
+++ b/docs/rendezvous.md
@@ -18,11 +18,16 @@ A connection to a `.btf` service has three layers:
181. **Discovery (Nostr).** The service publishes a signed descriptor as a Nostr 181. **Discovery (Nostr).** The service publishes a signed descriptor as a Nostr
19 event. A caller fetches it by the service public key and verifies the 19 event. A caller fetches it by the service public key and verifies the
20 signature. The descriptor says which rendezvous relay the service is waiting 20 signature. The descriptor says which rendezvous relay the service is waiting
21 at and which encryption key to use. 21 at, which encryption key to use, and optionally which Tor hidden service can
22 be dialed directly.
222. **Rendezvous (TCP).** Caller and service both connect out to the same relay 232. **Rendezvous (TCP).** Caller and service both connect out to the same relay
23 and are paired by public key. Neither needs an inbound port or a public IP. 24 and are paired by public key. Neither needs an inbound port or a public IP.
24 After pairing the relay is a blind byte pipe. 25 After pairing the relay is a blind byte pipe.
253. **Encrypted channel (X25519 + XChaCha20-Poly1305).** Over the paired pipe the 263. **Direct onion fallback bypass.** If the descriptor carries a valid signed
27 `.onion:port` endpoint and the caller is running with Tor mode, the caller
28 tries that endpoint before using rendezvous. This removes the rendezvous
29 relay from the data path for peers that choose to run hidden services.
304. **Encrypted channel (X25519 + XChaCha20-Poly1305).** Over the paired pipe the
26 caller and service run an ephemeral to static handshake and then exchange 31 caller and service run an ephemeral to static handshake and then exchange
27 authenticated frames. The relay sees only ciphertext. 32 authenticated frames. The relay sees only ciphertext.
28 33
@@ -107,6 +112,8 @@ The default rendezvous port is `8434`.
107The descriptor is a JSON object, signed with the identity key over a domain 112The descriptor is a JSON object, signed with the identity key over a domain
108separated digest of its own fields. 113separated digest of its own fields.
109 114
115Legacy descriptor:
116
110```json 117```json
111{ 118{
112 "v": 2, 119 "v": 2,
@@ -118,7 +125,22 @@ separated digest of its own fields.
118} 125}
119``` 126```
120 127
121The signed digest is: 128Onion-capable descriptor:
129
130```json
131{
132 "v": 3,
133 "pubkey": "<hex 32-byte x-only identity key>",
134 "enc": "<hex 32-byte X25519 public key>",
135 "meeting_node": "host:port",
136 "onion": "<56-char-v3-name>.onion:8433",
137 "created": <unix seconds>,
138 "sig": "<legacy v2 signature>",
139 "sig3": "<signature over the onion-capable digest>"
140}
141```
142
143The legacy signed digest is:
122 144
123``` 145```
124digest = SHA256( ".btf-descriptor-v2" 146digest = SHA256( ".btf-descriptor-v2"
@@ -128,17 +150,37 @@ digest = SHA256( ".btf-descriptor-v2"
128 || created (8 bytes, big endian) ) 150 || created (8 bytes, big endian) )
129``` 151```
130 152
131The signature is a deterministic BIP340 Schnorr signature (no auxiliary 153`sig` is kept on v3 descriptors so old nodes can still resolve and dial through
132randomness) over `digest` by the identity key. 154the rendezvous relay. The onion-capable digest is:
155
156```
157digest3 = SHA256( ".btf-descriptor-v3-onion"
158 || pubkey[32]
159 || enc (raw bytes of the string)
160 || meeting_node (raw bytes of the string)
161 || onion (raw bytes of the normalized string)
162 || created (8 bytes, big endian) )
163```
164
165`sig` and `sig3` are deterministic BIP340 Schnorr signatures (no auxiliary
166randomness) over their respective digests by the identity key.
133 167
134**Verification** (untrusted input, must never throw): parse the JSON, require all 168**Verification** (untrusted input, must never throw): parse the JSON, require all
135fields with the right types, confirm `pubkey` equals the address being resolved, 169fields with the right types, confirm `pubkey` equals the address being resolved,
136recompute the digest, and verify the Schnorr signature. Any failure rejects the 170recompute the digest, and verify the Schnorr signature. Any failure rejects the
137descriptor. 171descriptor.
138 172
173If `onion` is present, readers accept it only when it is a normalized v3 onion
174endpoint and `sig3` verifies. A bad or tampered onion field is ignored; the v2
175descriptor can still be used for rendezvous fallback if `sig` verifies.
176
139`created` lets a reader prefer the freshest descriptor when more than one is 177`created` lets a reader prefer the freshest descriptor when more than one is
140seen. A node only publishes a descriptor once it has actually registered at a 178seen. A node without a direct onion endpoint only publishes a descriptor once it
141`meeting_node`, so it never advertises a relay it cannot be reached at. 179has actually registered at a `meeting_node`, so it never advertises a relay it
180cannot be reached at. A node with a direct onion endpoint may publish before
181rendezvous registration using `meeting_node = "rendezvous-pending"`; Tor peers
182can still dial the signed onion endpoint, and rendezvous becomes fallback once
183registration succeeds.
142 184
143## 6. Rendezvous transport 185## 6. Rendezvous transport
144 186
@@ -243,8 +285,9 @@ tunnel.
243 not published anywhere. 285 not published anywhere.
244- **Forward secrecy.** The caller's per connection ephemeral key means a later 286- **Forward secrecy.** The caller's per connection ephemeral key means a later
245 compromise of the service encryption key does not decrypt past sessions. 287 compromise of the service encryption key does not decrypt past sessions.
246- **IP privacy.** Neither side needs a public IP or an inbound port. The observable 288- **IP privacy.** Neither side needs a public IP or an inbound port for
247 network fact is that each side has a TCP connection to a relay. 289 rendezvous. With a signed `.onion` endpoint, the reachable side exposes only a
290 Tor hidden service and the relay is not in the peer connection path.
248 291
249## 10. Threat model and limitations 292## 10. Threat model and limitations
250 293
@@ -265,6 +308,9 @@ tunnel.
265 unreachable, discovery stalls until one is reachable again. Relay TLS is 308 unreachable, discovery stalls until one is reachable again. Relay TLS is
266 verified, which closes a man in the middle path on discovery, but availability 309 verified, which closes a man in the middle path on discovery, but availability
267 still rests on the relay set. 310 still rests on the relay set.
311- **Direct onion is not automatic Tor configuration.** Bitflash signs and
312 advertises a hidden-service endpoint, and Tor-mode peers can dial it. The Tor
313 daemon still owns hidden-service creation, private keys, rotation and uptime.
268 314
269## 11. Wire reference 315## 11. Wire reference
270 316
@@ -273,9 +319,9 @@ tunnel.
273| `.btf` Base32 alphabet | `abcdefghijklmnopqrstuvwxyz234567`, no padding | 319| `.btf` Base32 alphabet | `abcdefghijklmnopqrstuvwxyz234567`, no padding |
274| Address payload | `pubkey[32] || checksum[2]`, 55 Base32 chars | 320| Address payload | `pubkey[32] || checksum[2]`, 55 Base32 chars |
275| Address checksum | `SHA256(".btf-checksum-v1" || pubkey)[0..2]` | 321| Address checksum | `SHA256(".btf-checksum-v1" || pubkey)[0..2]` |
276| Descriptor domain sep | `.btf-descriptor-v2` | 322| Descriptor domain sep | `.btf-descriptor-v2`; optional onion sep `.btf-descriptor-v3-onion` |
277| Descriptor version | `2` | 323| Descriptor version | `2`; `3` when a signed onion endpoint is present |
278| Descriptor signature | BIP340 Schnorr, deterministic (no aux rand) | 324| Descriptor signature | BIP340 Schnorr, deterministic (no aux rand), v3 keeps `sig` plus `sig3` |
279| Nostr descriptor event | kind `38501`, `d = btf-descriptor-2` | 325| Nostr descriptor event | kind `38501`, `d = btf-descriptor-2` |
280| Nostr relay event | kind `38502`, `d = btf-relay-2` | 326| Nostr relay event | kind `38502`, `d = btf-relay-2` |
281| Nostr pool event | kind `38503`, `d = btf-pool-2` | 327| Nostr pool event | kind `38503`, `d = btf-pool-2` |
diff --git a/docs/tor.md b/docs/tor.md
index 69b29f1..b4f88f9 100644
--- a/docs/tor.md
+++ b/docs/tor.md
@@ -40,6 +40,8 @@ When Tor mode is enabled:
40 40
41- outbound Nostr relay dials use Tor; 41- outbound Nostr relay dials use Tor;
42- outbound `.btf` rendezvous relay dials use Tor; 42- outbound `.btf` rendezvous relay dials use Tor;
43- outbound direct peer dials prefer signed `.onion` endpoints when a peer
44 advertises one;
43- destination names are sent to Tor as SOCKS5 domain-name CONNECT requests, so 45- destination names are sent to Tor as SOCKS5 domain-name CONNECT requests, so
44 the local DNS resolver does not see them; 46 the local DNS resolver does not see them;
45- direct `.onion` dials are refused unless a SOCKS5/Tor proxy is enabled; 47- direct `.onion` dials are refused unless a SOCKS5/Tor proxy is enabled;
@@ -98,7 +100,7 @@ bitflash -operator -tor \
98 -announcerelay=exampleexampleexampleexampleexampleexampleexampleexample.onion:8434 100 -announcerelay=exampleexampleexampleexampleexampleexampleexampleexample.onion:8434
99``` 101```
100 102
101## Full-node hidden service 103## Direct full-node hidden service
102 104
103The legacy P2P listener still binds to port `8433`. You can expose it through 105The legacy P2P listener still binds to port `8433`. You can expose it through
104Tor manually: 106Tor manually:
@@ -108,6 +110,35 @@ HiddenServiceDir /var/lib/tor/bitflash-node/
108HiddenServicePort 8433 127.0.0.1:8433 110HiddenServicePort 8433 127.0.0.1:8433
109``` 111```
110 112
111Current automatic peer discovery is `.btf`/rendezvous based, not onion-address 113After restarting Tor, read the generated onion name:
112gossip. Treat direct full-node onion access as an operator/admin tool unless a 114
113future release adds first-class onion peer advertisements. 115```bash
116sudo cat /var/lib/tor/bitflash-node/hostname
117```
118
119Then start Bitflash with Tor outbound enabled and advertise that hidden service:
120
121```bash
122bitflash -tor \
123 -onionservice=exampleexampleexampleexampleexampleexampleexampleexample.onion:8433
124```
125
126That onion endpoint is signed into this node's self-certifying `.btf`
127descriptor. New peers that resolve the descriptor and also run with `-tor` try
128the `.onion:8433` P2P connection first. If it fails, they fall back to the
129ordinary encrypted rendezvous path. Older nodes ignore the onion field and still
130use the rendezvous relay because the descriptor keeps the legacy signature too.
131
132If the node has `-onionservice` but has not registered at any rendezvous relay
133yet, it can still publish an onion-capable descriptor with
134`meeting_node = rendezvous-pending`. Tor-capable peers can dial the hidden
135service directly from that descriptor. Rendezvous becomes a fallback, not a
136precondition for being discoverable.
137
138This means rendezvous relays stop being the only way to reach a node that has
139published a hidden service. They remain useful bootstrap/fallback infrastructure,
140but an already-discovered onion-capable peer can be reached directly over Tor.
141
142The node does not create or rotate Tor hidden services itself. Tor owns the
143private key under `HiddenServiceDir`; back it up if you want the onion name to
144stay stable.