Grove is a two-file system:
grove.py โ Core library: crypto, chunking, manifests, networking, placement, syncweb.py โ Web dashboard + REST API server (Flask + SocketIO)Both run on every cell. web.py imports from grove.py.
1. Master key: 256-bit random key stored in ~/.grove/.key
2. Per-file key: derived via HKDF-SHA256 from master key + file hash
3. Chunk encryption: ChaCha20-Poly1305 (authenticated encryption)
4. Why ChaCha20: 5x faster than AES on ARM devices without AES-NI (tested: 279 vs 55 MB/s on Pi)
1. Key exchange: X25519 Diffie-Hellman
2. Message encryption: ChaCha20-Poly1305
3. Each message has a unique nonce
4. Forward secrecy per-message (random nonce)
File (any size)
โ split into 4MB chunks
โ each chunk encrypted (ChaCha20-Poly1305)
โ chunk hash = SHA-256(encrypted_bytes)
โ stored as ~/.grove/chunks/{hash[:2]}/{hash}
Content-addressed storage (like git): identical chunks deduplicate automatically.
SQLite database (~/.grove/placement.db) tracking:
1. Desired factor โ target copies (default: 2)
2. Speed-ranked peers โ fastest peers get chunks first
3. Preferred peers โ favorites always get copies (up to desired factor)
4. Strict cap โ never exceed desired factor (no over-replication)
5. Self-healing โ if a peer goes offline, opp sync re-replicates to maintain factor
best_route() scores routes by: effective_score = latency - (throughput_MB/s ร 0.1)
A route with higher throughput gets a bonus. Benchmarked every 6 hours with real 256KB transfers.
Runs every ~5 minutes:
1. Resolve peers (group routes by identity)
2. Benchmark routes (every 6h)
3. Probe each peer (best_route, record latency, health check)
4. For each reachable peer:
a. Get their chunk inventory
b. Pull chunks they have that we need
c. Push chunks they need (speed-ranked placement)
d. Sync manifests and grants
5. Check for updates (auto-update if newer build found)
6. Identify at-risk chunks and heal
Sharer:
1. User selects file + recipients in UI
2. For each recipient:
a. Create ShareGrant(manifest_hash, encrypted_file_key, recipient_pubkey)
b. Sign grant with Ed25519
c. Push grant to recipient's cell via /api/receive-grant
3. Push manifest + chunks to recipient
Recipient:
1. Receives grant via API
2. Verifies Ed25519 signature
3. File appears in Feed tab
4. On view/download: decrypt file key from grant, decrypt chunks
WebSocket relay for NAT-traversed cells:
Cell A โโ Relay Server โโ Cell B
(WebSocket)
ws://host:5680 (direct) or wss://domain/relay (nginx proxy)wss://grove.nook.website/relaySingle HTML page rendered by Flask render_template_string. Features:
Separate process (watchdog.py) for reliability:
--auto-restart: restarts Grove if it crashes--no-redirect: for systemd mode (avoids port 5678 conflict)Cells can update each other:
1. During opp sync, cells compare build hashes
2. If a peer has a newer build (different hash + newer build_time), flag update
3. User can accept via dashboard notification
4. Update downloads grove.py and web.py from peer, restarts
Build time is deterministic (derived from content hash, not file mtime) so identical code always has identical build_time across cells.
| File | Purpose | Permissions |
|---|---|---|
~/.grove/node.key |
Ed25519 private key (identity) | 600 |
~/.grove/node_x25519.key |
X25519 private key (chat) | 600 |
~/.grove/.key |
Master encryption key | 600 |
~/.grove/peer_secret |
API auth secret | 600 |
~/.grove/dashboard_auth |
Password hash (PBKDF2) | 600 |
~/.grove/config.json |
Cell configuration | 644 |
~/.grove/placement.db |
Chunk placement (SQLite) | 644 |
~/.grove/peer_speeds.json |
Route speed records | 644 |
~/.grove/peer_health.json |
Peer uptime records | 644 |
FileManifestDescribes a chunked file: filename, source_path, chunks (list of hashes), total_size, encryption metadata, version, synced_at.
ShareGrantCryptographic sharing permission: manifest_hash, encrypted_file_key, creator_pubkey, recipient_pubkey, signature, granted_at, filename, file_type, total_size.
ChunkInfoMetadata for a single chunk: hash, size, index.
DeleteRequestSigned request to delete a file from peers (currently disabled for safety).
FileWatcherMonitors watched directories for new/changed files, auto-chunks and syncs them.
GroveServiceListenermDNS/Zeroconf listener for discovering peers on local network.