dVPN cover traffic

In dVPN mode many wallet clients spread across several entry gateways all exit through one shared exit gateway to lightwalletd. Each sends a GetBlockHeight(height=…) gRPC call — the height varies per entry gateway — so lightwalletd sees a mix of requests from a single exit IP and cannot map any to a client. The more wallets share the exit, the larger the anonymity set — this is why coordinating on shared exit-gateway sets matters. Below: the WireGuard packet framing (two nested headers + the remaining payload, up to a 1500-byte MTU).

Anonymity set ≈ 10
5 entry gateways → 1 exit gateway → lightwalletdEach client sends GetBlockHeight(height=…); the height varies per entry gatewaylightwalletd sees every request from one exit IP — can't map it to a client
10 clientsEntry 1h=2650431Entry 2h=2650388Entry 3h=2650502Entry 4h=2650417Entry 5h=2650369Exit GW · 198.51.100.42lightwalletd

What lightwalletd sees

GetBlockHeight(height = 2650431)src=198.51.100.42 (exit GW) · client=?
GetBlockHeight(height = 2650388)src=198.51.100.42 (exit GW) · client=?
GetBlockHeight(height = 2650502)src=198.51.100.42 (exit GW) · client=?
GetBlockHeight(height = 2650417)src=198.51.100.42 (exit GW) · client=?
GetBlockHeight(height = 2650369)src=198.51.100.42 (exit GW) · client=?
GetBlockHeight(height = 2650431)src=198.51.100.42 (exit GW) · client=?
GetBlockHeight(height = 2650388)src=198.51.100.42 (exit GW) · client=?
GetBlockHeight(height = 2650502)src=198.51.100.42 (exit GW) · client=?
GetBlockHeight(height = 2650417)src=198.51.100.42 (exit GW) · client=?
GetBlockHeight(height = 2650369)src=198.51.100.42 (exit GW) · client=?

Requests arrive from a single exit-gateway IP. The height parameter varies per entry gateway, and clients sharing an entry gateway send the same height — so lightwalletd sees a mix of heights it cannot bind to any client. With 10 wallets across 5 gateways the cover set is large. (dVPN hides the IP but not timing; pair with mixnet broadcast for timing safety.)

dVPN packet framing

A few KB — the ideal mixnet broadcast workload.

2.1 KB chunked into 2 WireGuard packets
packet #1 · 1.5 KB
1380
packet #2 · 940 B
820
Goodput ≈ 90%2 packetson-wire 2.4 KBVariable packet size — WireGuard preserves size & timing (leaks)
WireGuard hdr — entry hop ~60 BWireGuard hdr — exit hop ~60 Bremaining payload (≤1380 B)