upleb.uk

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

summaryrefslogtreecommitdiff
path: root/docs/rendezvous.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/rendezvous.md')
-rw-r--r--docs/rendezvous.md72
1 files changed, 60 insertions, 12 deletions
diff --git a/docs/rendezvous.md b/docs/rendezvous.md
index ac8e598..68b5df3 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,11 @@ 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 needs Tor.** With `-managedtor`, Bitflash starts a Tor process,
312 writes a local hidden-service config, and advertises the generated onion
313 endpoint. With `-onionservice`, an operator can still run Tor manually and
314 provide the endpoint. In both cases Tor owns the hidden-service private key and
315 uptime.
268 316
269## 11. Wire reference 317## 11. Wire reference
270 318
@@ -273,9 +321,9 @@ tunnel.
273| `.btf` Base32 alphabet | `abcdefghijklmnopqrstuvwxyz234567`, no padding | 321| `.btf` Base32 alphabet | `abcdefghijklmnopqrstuvwxyz234567`, no padding |
274| Address payload | `pubkey[32] || checksum[2]`, 55 Base32 chars | 322| Address payload | `pubkey[32] || checksum[2]`, 55 Base32 chars |
275| Address checksum | `SHA256(".btf-checksum-v1" || pubkey)[0..2]` | 323| Address checksum | `SHA256(".btf-checksum-v1" || pubkey)[0..2]` |
276| Descriptor domain sep | `.btf-descriptor-v2` | 324| Descriptor domain sep | `.btf-descriptor-v2`; optional onion sep `.btf-descriptor-v3-onion` |
277| Descriptor version | `2` | 325| Descriptor version | `2`; `3` when a signed onion endpoint is present |
278| Descriptor signature | BIP340 Schnorr, deterministic (no aux rand) | 326| Descriptor signature | BIP340 Schnorr, deterministic (no aux rand), v3 keeps `sig` plus `sig3` |
279| Nostr descriptor event | kind `38501`, `d = btf-descriptor-2` | 327| Nostr descriptor event | kind `38501`, `d = btf-descriptor-2` |
280| Nostr relay event | kind `38502`, `d = btf-relay-2` | 328| Nostr relay event | kind `38502`, `d = btf-relay-2` |
281| Nostr pool event | kind `38503`, `d = btf-pool-2` | 329| Nostr pool event | kind `38503`, `d = btf-pool-2` |