Skip to main content

GhostCloak

GhostCloak provides address unlinkability by routing transactions through a TLS relay server. Each transaction gets a fresh session, preventing network-level correlation.

How It Works

Mobile App → GhostCloakClient → WebSocket (TLS) → Relay Server → Midnight Node
  1. The GhostCloakClient opens a WebSocket connection to the relay server
  2. A session_start message creates a new session with a unique sessionId
  3. All Midnight node requests are proxied through the relay via proxy messages
  4. When done, a session_end message closes the session
  5. The relay discards all session data after cleanup

The relay server never logs transaction content — it only tracks session metadata (ID, start/end times) for billing via the SessionBilling contract.

Architecture

Relay Server

The relay server (packages/relay-server/) is a Node.js WebSocket server with TLS:

  • Listens on port 8443 (configurable)
  • Upstream connection to Midnight node via WebSocket
  • Session management with automatic cleanup (1-hour max age)
  • Health endpoint at /health
  • Memory and session monitoring every 60 seconds

Session Lifecycle

// Start a cloak session
const session = await ghostCloak.startSession();
// session = { sessionId, startedAt, isActive, relayUrl }

// Proxy a request through the relay
const response = await ghostCloak.proxyRequest(payload);

// End the session
await ghostCloak.stopSession();

Message Protocol

Message TypeDirectionFields
session_startClient → RelaysessionId
proxyClient → RelaysessionId, payload
proxy_responseRelay → ClientsessionId, payload
session_endClient → RelaysessionId

Timeouts

  • Connection timeout: 10 seconds
  • Proxy request timeout: 30 seconds
  • Session cleanup: 1 hour (server-side)

Mobile Integration

On mobile, the RelayClient service (packages/mobile/src/services/relay-client.ts) manages the WebSocket connection:

const client = new RelayClient('wss://relay.nightshield.app:8443');
const session = await client.connect();
// session = { sessionId, startedAt, relayUrl }

// ... use the session ...

await client.disconnect();

The GhostContext in the mobile app exposes startCloak() and stopCloak() methods that wrap the relay client.

Billing

Each relay session is tracked by the SessionBilling Compact contract:

  • startSession(userId, startTime) — records session start
  • endSession(userId, endTime, fee) — records session end and accumulated fee
  • Fee calculation: duration_seconds × fee_rate_per_second (computed off-chain)

See SessionBilling contract for details.

Security Considerations

  • The relay server sees the user's IP but not their Midnight address (encrypted in the ZK transaction)
  • TLS ensures the connection between client and relay is encrypted
  • Each session uses a fresh connection — no session cookies or persistent identifiers
  • The relay server should be self-hosted or operated by a trusted party