# CLAUDE.md — fog Codebase Guide

This file provides context for AI assistants working on the fog repository.

---

## Project Overview

**fog** is a privacy-preserving anonymous SMTP relay network. It implements Sphinx mixnet routing with post-quantum cryptography (Kyber-768) to provide sender anonymity, forward secrecy, and resistance to traffic analysis. Messages are routed through 3–6 encrypted hops over Tor before being delivered.

- **Version**: 4.1.0
- **Language**: Go 1.21+
- **License**: MIT
- **Architecture**: Single binary, monolithic source file

---

## Repository Structure

```
fog/
├── fog.go            # Entire application (~2,355 lines) — single source file
├── fog-client.sh     # Interactive Bash SMTP client for end users
├── go.mod            # Go module: "fog", requires go 1.21
├── go.sum            # Dependency checksums
├── README.md         # User-facing documentation and quick start guide
└── LICENSE           # MIT License
```

There is **no Makefile, no CI/CD, no Docker configuration, and no test files** in this repository.

---

## Build & Run

### Build

```bash
go mod tidy
go build -tags="sqlite_omit_load_extension" -ldflags="-s -w" -trimpath -o fog fog.go
```

The `-tags="sqlite_omit_load_extension"` tag is required for the SQLite dependency. The `-ldflags="-s -w" -trimpath` flags strip debug info for smaller production binaries.

### Run (development)

```bash
./fog -name test.onion -short-name test -smtp 127.0.0.1:2525 -debug
```

### Tests

```bash
go test ./...
```

Note: There are currently no test files in the repository.

### Export node identity (first-time setup)

```bash
./fog -name your-onion-address.onion -short-name yourname -export-node-info
```

---

## Command-Line Flags

| Flag | Default | Description |
|------|---------|-------------|
| `-name` | `fog.onion` | Node hostname (.onion address) |
| `-short-name` | — | Short label for logs |
| `-smtp` | `127.0.0.1:2525` | SMTP listen address |
| `-node` | `127.0.0.1:9999` | Sphinx node listen address |
| `-sphinx` | `false` | Enable Sphinx mixnet routing |
| `-pki` | — | Path to bootstrap PKI file (`nodes.json`) |
| `-key` | — | Path to persistent node key file |
| `-debug` | `false` | Enable verbose debug logging |
| `-export-node-info` | — | Print node info JSON and exit |
| `-version` | — | Print version and feature list, then exit |

---

## Dependencies

Defined in `go.mod`:

| Package | Version | Purpose |
|---------|---------|---------|
| `github.com/mattn/go-sqlite3` | v1.14.18 | SQLite driver for persistent message queue |
| `golang.org/x/crypto` | v0.17.0 | HKDF key derivation |
| `golang.org/x/net` | v0.19.0 | SOCKS5 proxy support (Tor) |
| `github.com/symbolicsoft/kyber-k2so` | (indirect) | Kyber-768 post-quantum KEM |

The `kyber-k2so` package is imported directly in `fog.go:54` as `kyberk2so` but is not listed in `go.mod` — run `go mod tidy` to resolve this if needed.

---

## Source Code Architecture (`fog.go`)

The entire application lives in `fog.go`. It is organized into clearly delimited sections marked by banner comments:

```
// =============================================================================
// SECTION NAME
// =============================================================================
```

### Key Sections and Approximate Line Ranges

| Section | Approx. Lines | Description |
|---------|--------------|-------------|
| Constants & imports | 1–100 | Protocol constants, sizing, intervals |
| Global state | ~100–160 | Package-level vars (`pki`, `pool`, `queue`, `stats`, etc.) |
| PKI / Node types | ~160–400 | `Node`, `PKI`, gossip, health state |
| Sphinx cryptography | ~400–900 | Kyber-768 KEM, packet creation/processing, HMAC |
| Batch pool | ~900–1000 | Threshold mixing (`BatchPool`, `batchWorker`) |
| Cover traffic | ~1000–1100 | Dummy message generation (`CoverTraffic`, `coverWorker`) |
| SMTP server | ~1100–1350 | `startSMTP`, `handleSMTP`, ESMTP protocol |
| Node server | ~1350–1500 | `startNodeServer`, `handleNode`, Sphinx forwarding |
| Message relay | ~1500–1750 | `relayWorker`, `processMessage`, `deliverMessage` |
| Header sanitization | ~1750–1850 | `sanitizeHeaders` removes identifying metadata |
| DNS via Tor | ~1850–1950 | `lookupMXViaTor`, manual DNS MX query over SOCKS5 |
| Replay cache | ~1950–2050 | `ReplayCache`, TTL-based deduplication |
| Health checker | ~2050–2100 | `healthChecker`, `checkNode`, `checkAllNodes` |
| Statistics | ~2100–2120 | `statsMonitor`, periodic log output |
| Node init | ~2120–2165 | `initNode`, key generation/loading |
| `main()` | ~2170–2355 | Entry point, flag parsing, goroutine orchestration |

### Core Types

```go
// Node represents a fog network participant
type Node struct {
    ID        string    // hex-encoded SHA-256 of public key
    PublicKey []byte    // Kyber-768 public key (1184 bytes)
    Address   string    // host:port (.onion:9999)
    Name      string    // human-readable short name
    Version   string
    LastSeen  time.Time
    Healthy   bool
}

// Message is the internal relay unit
type Message struct {
    From    string
    To      []string
    Data    []byte    // raw SMTP DATA content
    IsRelay bool      // true = Sphinx packet, false = original message
    Payload []byte    // encoded Sphinx packet when IsRelay=true
}
```

### Critical Constants (`fog.go:59–99`)

```go
KyberPKSize = 1184    // Kyber-768 public key bytes
KyberCTSize = 1088    // Kyber-768 ciphertext bytes
HeaderSize  = 1232    // Sphinx header: CT(1088) + routing(128) + MAC(16)
PayloadMax  = 64*1024 // Fixed 64 KB packet size (prevents size correlation)
MinHops     = 3
MaxHops     = 6
BatchThresholdMin = 5
BatchThresholdMax = 15
```

### Goroutine Map

The `main()` function starts the following goroutines (when `-sphinx` is enabled):

| Goroutine | Function | Purpose |
|-----------|----------|---------|
| Node server | `startNodeServer` | Accepts Sphinx packets from peers |
| Health checker | `healthChecker` | Polls nodes every 3 minutes |
| Batch worker | `batchWorker` | Flushes pool when threshold reached |
| Gossip worker | `gossipWorker` | Exchanges PKI state every 5 minutes |
| Cover worker | `coverWorker` | Sends dummy traffic at random intervals |
| Relay workers (×3) | `relayWorker` | Processes message queue |
| Stats monitor | `statsMonitor` | Logs metrics every 60 seconds |
| Cache cleanup | `cacheCleanupWorker` | Evicts expired replay-cache entries |
| PKI state saver | (inline) | Persists gossip state every 10 minutes |

---

## Runtime Files

| File | Description |
|------|-------------|
| `nodes.json` | Bootstrap PKI — hand-crafted, **never overwritten** by fog |
| `nodes_state.json` | Dynamic gossip state, auto-generated alongside `nodes.json` |
| `<data-dir>/messages.db` | SQLite message queue, survives restarts |

---

## Protocol & Data Flow

```
Client
  │  SMTP (port 2525)
  ▼
Entry node
  │  Sphinx packet (Kyber-768, 3–6 hops, over Tor SOCKS5)
  ▼
Middle node(s)
  │  Each hop decrypts one layer, adds random delay, batches with others
  ▼
Exit node
  │  Final decryption → sanitize headers → MX lookup via Tor → deliver
  ▼
Destination SMTP server
```

**Key invariants:**
- All inter-node traffic goes through Tor (SOCKS5 at `127.0.0.1:9050`)
- All packets are padded to exactly 64 KB
- DNS MX lookups are performed manually over Tor (no system resolver used)
- The SMTP envelope (`MAIL FROM`, `RCPT TO`) is embedded in the Sphinx payload, not in headers

---

## Coding Conventions

- **Single-file architecture**: All code lives in `fog.go`. Do not create new `.go` files unless strictly necessary.
- **Package**: `package main` — this is a standalone binary, not a library.
- **Error handling**: Errors are logged with structured prefixes like `[SMTP]`, `[PKI]`, `[SPHINX]`, `[HEALTH]`, `[POOL]`, `[STATS]`, `[FOG]`. Use the same prefix conventions when adding log lines.
- **Concurrency**: Goroutines communicate via the `queue` channel (`chan *Message`, capacity 500). Shared state uses `sync.Mutex` or `sync/atomic`. Context cancellation (`ctx`) signals graceful shutdown.
- **No external frameworks**: Standard library + the four listed dependencies only. No HTTP frameworks, CLI libraries, or ORMs.
- **Security-sensitive code**: Cryptographic operations use constant-time comparisons (`hmac.Equal`) and `crypto/rand` exclusively. Never use `math/rand` for security purposes.

---

## Log Prefixes Reference

| Prefix | Component |
|--------|-----------|
| `[FOG]` | Main / startup |
| `[SMTP]` | SMTP server |
| `[NODE]` | Sphinx node server |
| `[PKI]` | PKI / gossip |
| `[SPHINX]` | Packet creation/processing |
| `[HEALTH]` | Node health checker |
| `[POOL]` | Batch pool |
| `[COVER]` | Cover traffic |
| `[RELAY]` | Message relay worker |
| `[DELIVER]` | Final delivery |
| `[SANITIZE]` | Header sanitization |
| `[DNS]` | Tor DNS lookup |
| `[STATS]` | Statistics |
| `[CACHE]` | Replay cache |
| `[TOR]` | Tor SOCKS5 dialer |

---

## Security Constraints

When modifying this codebase, preserve these invariants:

1. **No DNS leaks**: MX lookups must go through `lookupMXViaTor`, never `net.LookupMX`.
2. **No plaintext logs**: Never log message content, sender/recipient addresses in production paths.
3. **Fixed packet size**: Sphinx payloads must remain padded to `PayloadMax` (64 KB).
4. **Constant-time MAC verification**: Use `hmac.Equal`, not `==`, for HMAC comparisons.
5. **Ephemeral keys only**: Each Sphinx packet uses freshly generated Kyber keypairs — never reuse keys.
6. **Header sanitization**: The exit node must always call `sanitizeHeaders` before final delivery.

---

## Monitoring the Queue (SQLite)

```bash
# Total queued messages
sqlite3 /var/lib/fog/data/messages.db \
  "SELECT COUNT(*) FROM message_queue;"

# Messages ready to send
sqlite3 /var/lib/fog/data/messages.db \
  "SELECT COUNT(*) FROM message_queue WHERE send_after <= strftime('%s','now');"
```

---

## Stats Log Format

```
[STATS] Up:2h30m R:45 S:42 F:3 | Sphinx:40 Direct:2 | Mix R:120 F:115 | Q:23 D:156 | Healthy:4
```

| Field | Meaning |
|-------|---------|
| `R` | Messages received |
| `S` | Messages sent successfully |
| `F` | Failed deliveries |
| `Sphinx` / `Direct` | Routing method used |
| `Mix R` / `Mix F` | Sphinx packets received / forwarded |
| `Q` | Currently queued in delay pool |
| `D` | Total delayed messages delivered |
| `Healthy` | Healthy nodes in PKI |
