feat: add fumi client implementation plan for Smol Mail 1.2

Add comprehensive plan for Rust client implementation including:
- TCP transport (v1.1) support
- RNS transport (v1.2) support via FFI with microReticulum
- Architecture with transport abstraction
- Module structure and dependencies
- CLI command design
- Testing strategy
- Implementation priority

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
randogoth 2026-09-28 11:21:58 +03:00
commit 1690aed3dc

399
README.md Normal file
View file

@ -0,0 +1,399 @@
# Fumi - Smol Mail Client (Rust)
A Rust implementation of the Smol Mail client protocol, compatible with version 1.2 (including RNS transport). Fumi is the client counterpart to [bunshin](../bunshin), the Smol Mail server implementation.
## Overview
Smol Mail is a minimalist, end-to-end encrypted mail protocol. This client implementation supports:
- **Full protocol v1.1**: All operations over TCP with Noise_NX_25519_ChaChaPoly_SHA256
- **Full protocol v1.2**: Reticulum Network Stack (RNS) transport for mesh networking
- **Shared codebase**: Single binary supports both transports (via feature flags)
- **Interoperability**: Works with reference Python implementations and bunshin server
## Protocol Compatibility
| Feature | v1.1 (TCP) | v1.2 (RNS) |
|---------|------------|------------|
| AUTH | ✅ | ✅ |
| RESOLVE | ✅ | ✅ |
| SEND | ✅ | ✅ |
| FETCH | ✅ | ✅ |
| DELETE | ✅ | ✅ |
| REGISTER | ✅ | ✅ |
| Accept Tokens | ✅ | ✅ |
| Key Rotation | ✅ | ✅ |
| Message Encryption | ✅ | ✅ |
## Address Formats
### TCP Transport (v1.1)
```
smol://alice@example.com[:1961]
smol://alice@example.com/abcdefghijklmnopqrstuvwxyz234567 # self-certifying
```
### RNS Transport (v1.2)
```
smol+rns://alice@8f2c1d0a7b6e5f4c3d2a1b0e9f8c7d6a
smol+rns://alice@8f2c1d0a7b6e5f4c3d2a1b0e9f8c7d6a/abcdefghijklmnopqrstuvwxyz234567
```
The RNS address uses the server's 32-character hex destination hash as the host.
---
## Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ fumi client │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ CLI (main.rs) │ │
│ │ keygen, import, trust, register, send, │ │
│ │ fetch, delete, resolve, show │ │
│ └──────────────────────────────┬──────────────────────────┘ │
│ │ │
│ ┌──────────────────────────────▼──────────────────────────┐ │
│ │ Client Core (client.rs) │ │
│ │ - Session management with servers │ │
│ │ - Message composition and parsing │ │
│ │ - Envelope sealing/unsealing │ │
│ └──────────────────────────────┬──────────────────────────┘ │
│ │ │
│ ┌──────────────────────────────▼──────────────────────────┐ │
│ │ Account (account.rs) │ │
│ │ - Master secret management │ │
│ │ - Identity derivation (rotation chains) │ │
│ │ - Token generation │ │
│ └──────────────────────────────┬──────────────────────────┘ │
│ │ │
│ ┌─────────────────┐ ┌─────────────────────────────┐ │ │
│ │ TCP Transport │ │ RNS Transport │ │ │
│ │ (tcp_transport) │ │ (rns_transport + FFI) │ │ │
│ └────────┬────────┘ └──────────┬───────────────────┘ │ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Transport Trait (transport.rs) │ │
│ │ - connect(address) : Establish session │ │
│ │ - request(op, body) : Send frame, get response │ │
│ │ - bind_values() : Get auth binding values │ │
│ │ - close() : Clean up connection │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Store (store.rs) │ │
│ │ - SQLite local mailbox │ │
│ │ - Accounts, identities, tokens, messages │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
---
## Implementation Plan
### Phase 1: Core Client (TCP Only)
#### Dependencies
```toml
[package]
name = "fumi"
version = "0.1.0"
edition = "2021"
description = "Smol Mail client"
[dependencies]
snow = "0.9" # Noise protocol
ed25519-dalek = "2" # Ed25519 signatures
x25519-dalek = "2" # X25519 key agreement
sha2 = "0.10" # SHA-256
rand_core = "0.6" # Randomness
hmac = "0.12" # HMAC-SHA256
clap = "4" # CLI parsing
log = "0.4" # Logging
env_logger = "0.11" # Logger setup
anyhow = "1" # Error handling
rusqlite = "0.32" # SQLite local store
hex = "0.4" # Hex encoding
data-encoding = "2" # Base32 encoding
```
#### Modules
1. **crypto.rs** - Cryptographic primitives
- Base32 encoding/decoding
- HKDF-SHA256
- HMAC-SHA256
- Identity derivation
- Accept token generation
- Message ID computation
2. **address.rs** - Address parsing
- Parse TCP addresses: `smol://user@host[:port][/identity]`
- Parse RNS addresses: `smol+rns://user@desthash[/identity]`
- Validate usernames
- Generate self-certifying URIs
3. **account.rs** - Account management
- Master secret storage
- Identity key derivation with rotation
- Current identity tracking
- Token generation for correspondents
4. **transport.rs** - Transport trait
- Define `Transport` trait with connect/request/close
- Define `TransportBindValues` for auth bindings
- Define operation and status constants
5. **tcp_transport.rs** - TCP transport
- Noise_NX handshake
- Frame reading/writing
- Server key pinning (optional)
6. **client.rs** - Core client logic
- Session management
- REGISTER operation
- AUTH operation
- RESOLVE operation
- SEND operation (envelope creation)
- FETCH operation
- DELETE operation
- Message sealing/unsealing
7. **store.rs** - Local SQLite store
- Account storage
- Trusted server keys
- Accept tokens
- Outbound message queue
- Inbound message storage
8. **main.rs** - CLI
- keygen: Generate new identity
- import: Import existing identity
- accounts: List accounts
- trust: Trust server key (TCP)
- register: Register username
- send: Send message
- fetch: Fetch messages
- delete: Delete messages
- resolve: Resolve username
- show: Display message info
---
### Phase 2: RNS Transport
Same approach as bunshin's RNS integration:
1. **FFI with microReticulum** (recommended for production)
- Use C++ microReticulum via FFI bindings
- Official implementation, full compliance
- Complex but most reliable
2. **Python IPC** (quick validation)
- Call `smolmail_rns.py` as subprocess
- Share data via files or pipes
- Fast to implement
3. **Native Rust** (future)
- Wait for mature Rust RNS crate
- Or implement minimal subset
---
## Key Differences from Server (bunshin)
| Aspect | bunshin (server) | fumi (client) |
|--------|------------------|---------------|
| Noise role | Responder (has static key) | Initiator (no static key) |
| Session | Accepts connections | Initiates connections |
| Trust | Server key pinned by client | Client pins server key |
| Auth | Verifies client signatures | Signs requests |
| Rate limiting | Enforces limits | Respects limits |
---
## CLI Commands
```bash
# Identity management
fumi keygen # Generate new identity
fumi keygen --name alice # Generate with name
fumi import --name alice -m ABCD... # Import master secret
fumi accounts # List accounts
# Server trust (TCP only)
fumi trust smol://alice@example.com ABCD... # Trust server key
# Account registration
fumi register smol://alice@example.com --username alice
fumi register smol://alice@example.com --username alice --invite TOK...
# Messaging
fumi send smol://bob@example.com --subject "Hello" --body "World"
fumi send smol://bob@example.com --file message.txt
fumi fetch smol://alice@example.com
fumi delete smol://alice@example.com --ids ABCD...
fumi resolve smol://alice@example.com --username bob
fumi show ABCD... # Show message details
```
---
## Project Structure
```
fumi/
├── Cargo.toml # Project configuration
├── Cargo.lock
├── src/
│ ├── main.rs # CLI entry point
│ ├── lib.rs # Library exports
│ ├── client.rs # Core client logic
│ ├── account.rs # Account/identity management
│ ├── address.rs # Address parsing
│ ├── store.rs # Local SQLite store
│ ├── crypto.rs # Cryptographic primitives
│ ├── transport.rs # Transport trait
│ ├── tcp_transport.rs # TCP transport implementation
│ └── error.rs # Error types
├── tests/
│ └── integration/ # Integration tests
├── flake.nix # Nix flake (optional)
└── README.md # This file
```
---
## Implementation Priority
### Phase 1: TCP Client (High Priority)
| # | Module | Description | Dependencies |
|---|--------|-------------|--------------|
| 1 | crypto.rs | Base32, HKDF, HMAC, identity derivation | sha2, hmac, data-encoding |
| 2 | address.rs | Address parsing and validation | regex, anyhow |
| 3 | account.rs | Account and identity management | ed25519-dalek, rand_core |
| 4 | transport.rs | Transport trait and types | None |
| 5 | tcp_transport.rs | TCP/Noise transport | snow, std::net |
| 6 | client.rs | Core operations (REGISTER, AUTH, etc.) | All above |
| 7 | store.rs | SQLite local storage | rusqlite |
| 8 | main.rs | CLI | clap, all above |
| 9 | Tests | Unit and integration tests | All above |
### Phase 2: RNS Support (Medium Priority)
| # | Module | Description | Dependencies |
|---|--------|-------------|--------------|
| 1 | rns/ffi.rs | FFI bindings to microReticulum | libffi |
| 2 | rns/transport.rs | RNS transport implementation | ffi.rs |
| 3 | rns/mod.rs | RNS module exports | transport.rs |
| 4 | Update transport.rs | Add RNS feature flag | None |
| 5 | Update client.rs | Handle RNS-specific logic | rns module |
| 6 | Update main.rs | Add RNS CLI commands | rns module |
| 7 | Tests | RNS integration tests | All above |
---
## Testing Strategy
### Unit Tests
- Address parsing (TCP and RNS)
- Identity generation and rotation
- Message sealing and unsealing
- Envelope format validation
- Token generation and verification
### Integration Tests
- Register with bunshin server (TCP)
- Send and receive messages (TCP)
- Key rotation interoperability
- Accept token usage
- Error response handling
### Interoperability Tests
- Against `smolmail.py` reference client
- Against `smolmaild.py` reference server
- Against `smolmail_rns.py` reference client
- Against `smolmaild_rns.py` reference server
---
## Compatibility Matrix
| Client \ Server | bunshin (TCP) | bunshin (RNS) | smolmaild.py | smolmaild_rns.py |
|------------------|---------------|---------------|---------------|------------------|
| fumi (TCP) | ✅ Full | ❌ No | ✅ Full | ❌ No |
| fumi (RNS) | ❌ No | ✅ Full | ❌ No | ✅ Full |
Both transports share the same account and store, so a user can use both transports with the same identity.
---
## Key Implementation Notes
### Message Sealing (SPEC.md S5)
1. Generate ephemeral X25519 keypair
2. Convert recipient Ed25519 public key to X25519 (per SPEC.md S2)
3. Perform X25519 key agreement
4. Derive two 32-byte keys using HKDF-SHA256:
- `k1 = HKDF(shared, "", "smolmail/1 msg", 64)[0:32]`
- `k2 = HKDF(shared, "", "smolmail/1 msg", 64)[32:64]`
5. Build payload with frontmatter (unencrypted): version, sender, timestamp
6. Build body with: version, timestamp, body_length, body (padded to 1024-byte boundary)
7. Encrypt body with ChaCha20-Poly1305 using k1
8. Build envelope: magic ("SMOL"), version, recipient, ephemeral_pub, payload
### Transport Differences
#### TCP (v1.1)
- Noise_NX handshake (client is initiator, server has static key)
- Frames: u32 length || u8 op || body (split across Noise messages)
- Binding values: Noise handshake hash and server static public key
- Server pinning: Client verifies server's Noise static key
#### RNS (v1.2)
- Reticulum link establishment
- Frames: u8 op || body (RNS delimits messages)
- Binding values: SHA-256("smolmail/1 bind" || dest_hash || link_id) and SHA-256("smolmail/1 bind" || dest_hash)
- Server pinning: Destination hash IS the server's identity (no separate pinning)
---
## Next Steps
1. **Implement Phase 1 (TCP Client)**
- Start with crypto, address, and account modules
- Then transport and tcp_transport
- Then client core operations
- Finally store and CLI
- Test against bunshin server
2. **Implement Phase 2 (RNS Support)**
- Research microReticulum C API
- Create FFI bindings
- Implement RNS transport
- Add tests with reference implementations
3. **Polish and Package**
- Documentation
- Nix flake integration (optional)
- Performance optimization
- Error handling improvements
---
## References
- [Smol Mail SPEC.md](https://code.randogoth.com/randogoth/smolmail/src/branch/main/SPEC.md)
- [Smol Mail RNS.md (v1.2)](https://code.randogoth.com/randogoth/smolmail/src/branch/main/RNS.md)
- [smolmail.py - Reference TCP client](https://code.randogoth.com/randogoth/smolmail/src/branch/main/smolmail.py)
- [smolmail_rns.py - Reference RNS client](https://code.randogoth.com/randogoth/smolmail/src/branch/main/smolmail_rns.py)
- [bunshin - Rust server implementation](../bunshin)
- [microReticulum - C++ RNS implementation](https://github.com/attermann/microReticulum)