Commit Graph

29 Commits

Author SHA1 Message Date
Siavash Sameni
3e0889e5dc v0.0.21: TUI overhaul, WZP call infrastructure, security hardening, federation
TUI:
- Split 1,756-line app.rs monolith into 7 modules (types, draw, commands, input, file_transfer, network, mod)
- Message timestamps [HH:MM], scrolling (PageUp/Down/arrows), connection status dot, unread badge
- /help command, terminal bell on incoming DM, /devices + /kick commands
- 44 unit tests (types, input, draw with TestBackend)

Server — WZP Call Infrastructure (FC-2/3/5/6/7/10):
- Call state management (CallState, CallStatus, active_calls, calls + missed_calls sled trees)
- WS call signal awareness (Offer/Answer/Hangup update state, missed call on offline)
- Group call endpoint (POST /groups/:name/call with SHA-256 room ID, fan-out)
- Presence API (GET /presence/:fp, POST /presence/batch)
- Missed call flush on WS reconnect
- WZP relay config + CORS

Server — Security (FC-P1):
- Auth enforcement middleware (AuthFingerprint extractor on 13 write handlers)
- Session auto-recovery (delete corrupted ratchet, show [session reset])
- WS connection cap (5/fingerprint) + global concurrency limit (200)
- Device management (GET /devices, POST /devices/:id/kick, POST /devices/revoke-all)

Server — Federation:
- Two-server federation via JSON config (--federation flag)
- Periodic presence sync (every 5s, full-state, self-healing)
- Message forwarding via HTTP POST with SHA-256(secret||body) auth
- Graceful degradation (peer down = queue locally)
- deliver_or_queue() replaces push-or-queue in ws.rs + messages.rs

Client — Group Messaging:
- SenderKeyDistribution storage + GroupSenderKey decryption in TUI
- sender_keys sled tree in LocalDb

WASM:
- All 8 WireMessage variants handled (no more "unsupported")
- decrypt_group_message() + create_sender_key_from_distribution() exports
- CallSignal parsing with signal_type mapping

Docs:
- ARCHITECTURE.md rewritten with Mermaid diagrams
- README.md created
- TASK_PLAN.md with FC-P{phase}-T{task} naming
- PROGRESS.md updated to v0.0.21

WZP submodule updated to 6f4e8eb (IAX2 trunking, adaptive quality, metrics, all S-tasks done)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 16:45:58 +04:00
Siavash Sameni
4a4fa9fab4 v0.0.21: FC-CRATE-1 — make warzone-protocol importable standalone
Replaced workspace dep inheritance with explicit versions in
warzone-protocol/Cargo.toml. The crate now builds both as a
workspace member AND standalone.

WZP can now import warzone-protocol directly:
  warzone-protocol = { path = "../featherChat/warzone/crates/warzone-protocol" }

This means WZP can delete its mirrored identity/crypto code and use:
- warzone_protocol::identity::{Seed, IdentityKeyPair, PublicIdentity}
- warzone_protocol::crypto::{hkdf_derive, aead_encrypt, aead_decrypt}
- warzone_protocol::ethereum::{derive_eth_identity, EthAddress}
- warzone_protocol::message::{WireMessage, CallSignalType}
- warzone_protocol::types::Fingerprint

Single source of truth for identity derivation — no more HKDF mismatches.

28/28 tests pass. Zero warnings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 09:21:18 +04:00
Siavash Sameni
064a730b42 v0.0.21: WZP integration groundwork — CallSignal + token validation
WZP-FC-1: CallSignal WireMessage variant
- CallSignalType enum: Offer, Answer, IceCandidate, Hangup, Reject, Ringing, Busy
- Routed through existing E2E encrypted channels
- Server dedup handles new variant
- TUI shows "📞 Call signal: Offer" etc
- CLI recv prints call signals

WZP-FC-4: Token validation endpoint
- POST /v1/auth/validate { "token": "..." }
- Returns: { "valid": true, "fingerprint": "...", "alias": "..." }
- WZP relay calls this to verify featherChat bearer tokens
- Resolves alias alongside fingerprint

These two unblock WZP integration tasks WZP-S-2 (accept FC tokens)
and WZP-S-3 (signaling bridge mode).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 09:13:23 +04:00
Siavash Sameni
fb987da8ac v0.0.20: file transfer in groups
/file <path> now works in group mode (#group):
- Sends file header + chunks to each group member
- Same fan-out approach as group text messages
- Each member receives and reassembles independently
- Progress shown: "Sending 'file.pdf' to group #ops..."

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:23:19 +04:00
Siavash Sameni
1601decf33 v0.0.19: contact list + message history (local, persistent)
Storage:
- contacts sled tree: auto-tracked on send/receive
  - fingerprint, alias, first_seen, last_seen, message_count
- history sled tree: all messages stored locally
  - key: hist:<peer_fp>:<timestamp>:<uuid> for ordered scan
  - sender, text, is_self, timestamp

TUI commands:
- /contacts or /c — list all contacts (sorted by most recent)
  Shows alias, fingerprint, message count
- /history or /h — show last 50 messages with current peer
- /h <fingerprint> — show history with specific peer

Auto-tracking:
- On send: touch_contact + store_message (is_self=true)
- On receive: touch_contact + store_message (is_self=false)
- Both KeyExchange and Message variants tracked

Backup: contacts + history included in export_all (encrypted backup).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:16:22 +04:00
Siavash Sameni
a4405b4976 v0.0.17: fix /r reply in TUI, /p shortcut, /eth, /unalias
TUI fixes:
- /r and /reply now work: tracks last_dm_peer from received messages
- /r switches peer to last DM sender, then type normally
- /p @alias works as shortcut for /peer @alias
- /eth shows Ethereum address in TUI
- /unalias removes your alias

Web fixes:
- /p @alias and /peer @alias resolve and set peer
- /r and /reply work (switch to last DM sender)
- /unalias removes alias
- /admin-unalias <alias> <password> for admin removal
- File download now shows as clickable link (not auto-download)

Server:
- POST /v1/alias/unregister — remove own alias
- POST /v1/alias/admin-remove — admin removes any alias
- WARZONE_ADMIN_PASSWORD env var (default: "admin")

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 19:50:00 +04:00
Siavash Sameni
f4eac7b2aa v0.0.16: clickable file download link instead of auto-download
Files now appear as a styled clickable link in chat:
📎 filename.pdf (1.6 KB) from sender
Click to download. No auto-save dialog.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 18:17:33 +04:00
Siavash Sameni
9c70e02eba v0.0.15: unalias, admin alias removal, /reply, web version fix
Aliases:
- /unalias — remove your own alias
- /admin-unalias <alias> <password> — admin removes any alias
- Admin password via WARZONE_ADMIN_PASSWORD env var (default: "admin")
- POST /v1/alias/unregister + POST /v1/alias/admin-remove

Reply:
- /r or /reply — switches peer to whoever last DM'd you
- lastDmPeer tracked on both web and TUI
- Then type normally to reply

Web:
- Version bumped to 0.0.15 (was stuck at 0.0.10)
- WASM rebuilt with latest protocol

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 14:12:33 +04:00
Siavash Sameni
608a160614 Fix warnings: remove unused import and variable
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 13:39:05 +04:00
Siavash Sameni
661de47552 v0.0.14: Ethereum-compatible identity (secp256k1 + Keccak-256)
Protocol (ethereum.rs):
- derive_eth_identity(): HKDF from seed (info="warzone-secp256k1")
- secp256k1 signing key (k256 crate)
- Ethereum address: Keccak-256(uncompressed_pubkey[1..])[-20:]
- EIP-55 checksum address formatting
- eth_sign() / eth_verify() for secp256k1 ECDSA
- EthAddress type with Display, hex parsing, checksum
- 5 tests: deterministic, format, checksum, sign/verify, uniqueness

CLI:
- `warzone eth` — show Ethereum address alongside Warzone fingerprint
- Same seed produces both identities (dual-curve)

Dual identity model:
- Ed25519 + X25519 for Warzone messaging (fast, small signatures)
- secp256k1 for Ethereum compatibility (MetaMask, ENS, Ledger/Trezor)
- Both derived from the same BIP39 seed via different HKDF paths

28/28 protocol tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 13:30:25 +04:00
Siavash Sameni
86da52acc4 v0.0.13: Sender Keys for efficient group encryption
Protocol (sender_keys.rs):
- SenderKey: symmetric key with chain ratchet (forward secrecy per chain)
- generate(), rotate(), encrypt(), decrypt()
- SenderKeyDistribution: share key via 1:1 encrypted channel
- SenderKeyMessage: encrypted group message (O(1) instead of O(N))
- Chain key ratchets forward on each message (HKDF)
- Generation counter for key rotation tracking
- 4 tests: basic, multi-message, rotation, old-key rejection

WireMessage:
- GroupSenderKey variant: encrypted group message
- SenderKeyDistribution variant: key sharing

Server: dedup handles new variants.
CLI TUI + recv: stub handlers for new message types.
23/23 protocol tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 13:23:10 +04:00
Siavash Sameni
fff443bb6d v0.0.11: Multi-device support (server-side)
Server:
- Register stores per-device bundles: device:<fp>:<device_id>
- GET /v1/keys/:fp/devices lists all registered devices
- WS already pushes to ALL connected devices per fingerprint
- DB queue: first device to poll gets messages (acceptable for Phase 2)

Multi-device flow:
- Same seed on two devices → same fingerprint
- Both register with different device_ids
- Both connect via WS → both receive messages in real-time
- Each device maintains its own ratchet sessions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:52:22 +04:00
Siavash Sameni
9811248b7c v0.0.10: Progressive Web App (PWA)
- Web manifest (standalone mode, theme, icon)
- Service worker: caches shell (HTML, WASM, icon) for offline
- SVG app icon (chat bubble with encryption indicator)
- iOS meta tags: apple-mobile-web-app-capable, status bar style
- Android: beforeinstallprompt → /install command
- Offline fallback: loads cached shell, shows reconnecting state
- Cache versioning with automatic old cache cleanup

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:32:59 +04:00
Siavash Sameni
4fb3973403 v0.0.9: Group management — leave, kick, members
Server:
- POST /groups/:name/leave — remove self from group
- POST /groups/:name/kick — creator can kick members
- GET /groups/:name/members — list with aliases + creator badge

CLI TUI:
- /gleave — leave current group
- /gkick <fp_or_alias> — kick (creator only)
- /gmembers — show member list with aliases and ★ for creator

Web client:
- Same commands: /gleave, /gkick, /gmembers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 12:04:28 +04:00
Siavash Sameni
2599ce956a v0.0.8: Server-side message deduplication
Server:
- DedupTracker in AppState: bounded HashSet (10,000 IDs, FIFO eviction)
- send_message: extracts message ID from bincode, drops duplicates
- WS handler: dedup on both binary and JSON message frames
- extract_message_id() parses all WireMessage variants

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:00:58 +04:00
Siavash Sameni
708080f7be v0.0.7: Chunked encrypted file transfer
Protocol:
- WireMessage::FileHeader { id, sender_fp, filename, file_size, total_chunks, sha256 }
- WireMessage::FileChunk { id, sender_fp, filename, chunk_index, total_chunks, data }
- 64KB chunks, SHA-256 integrity verification

CLI TUI:
- /file <path> command: reads file, chunks, encrypts each with ratchet, sends
- Progress display: "Sending file.pdf [3/10]..."
- Incoming file reassembly with chunk tracking
- SHA-256 verification on complete
- Saves to data_dir/downloads/
- Max file size: 10MB

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 10:26:05 +04:00
Siavash Sameni
104ba78b85 v0.0.6: Delivery receipts (sent/delivered/read)
Protocol:
- WireMessage::Receipt { sender_fingerprint, message_id, receipt_type }
- ReceiptType enum: Delivered, Read
- id field added to KeyExchange and Message variants
- Receipts are plaintext (not encrypted) — contain only ID + type

Web client:
- Auto-sends Delivered receipt on successful decrypt
- Tracks sent message IDs with receipt status
- Displays: ✓ (sent, gray), ✓✓ (delivered, white), ✓✓ (read, blue)
- Receipt indicators update live via DOM reference

CLI TUI:
- Auto-sends Delivered receipt back to sender on decrypt
- Tracks receipt status per message ID
- Displays receipt indicators after sent messages

WASM:
- create_receipt() function for web client
- encrypt_with_id/encrypt_key_exchange_with_id for tracking
- decrypt_wire_message handles Receipt variant

17/17 protocol tests pass. Zero warnings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 10:12:43 +04:00
Siavash Sameni
fe2b7d8e8a TUI client: WebSocket with HTTP fallback
poll_loop now:
1. Tries WebSocket connection to /v1/ws/<fingerprint>
2. On success: receives messages in real-time (instant push)
3. On disconnect: reconnects after 3 seconds
4. On WS failure: falls back to HTTP polling every 2 seconds

Refactored message processing into shared functions:
- process_incoming() handles raw bytes
- process_wire_message() handles deserialized WireMessage
- Used by both WS and HTTP paths

Both CLI TUI and web client now use WebSocket:
- No more HTTP polling spam in server logs
- Messages arrive instantly on both clients
- HTTP poll kept as fallback for scripts/mules

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 09:49:46 +04:00
Siavash Sameni
2ca25fd2bf v0.0.5: WebSocket real-time messaging
Server:
- WS endpoint: /v1/ws/:fingerprint
- Connection registry in AppState (fingerprint → WS senders)
- On connect: flushes queued DB messages, then pushes in real-time
- send_message: pushes to WS if connected, falls back to DB queue
- Auto-cleanup on disconnect
- WS accepts both binary and JSON text frames for sending

Web client:
- Replaces 2-second HTTP polling with persistent WebSocket
- Auto-reconnects on disconnect (3-second backoff)
- Sends via WS when connected, HTTP fallback
- Messages arrive instantly (no polling delay)
- "Real-time connection established" shown on connect

HTTP polling still works:
- CLI recv command uses HTTP (unchanged)
- Web falls back to HTTP if WS fails
- Mules/scripts can still use HTTP API

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 09:41:50 +04:00
Siavash Sameni
4fc1cc2ab1 v0.0.4: unique colors per peer in web UI
Each peer gets a stable color from a 12-color palette based on
their fingerprint/alias hash. Self messages stay green.
No more same-color for different users.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 09:30:55 +04:00
Siavash Sameni
1aba435af3 v0.0.3: fix X3DH OTPK mismatch — web bundles without OTPKs
Root cause: web client's bundle included OTPKs, so X3DH initiate()
did 4 DH ops (DH4 with OTPK). But decrypt_wire_message() called
respond() with None for OTPK, doing only 3 DH ops.
Different DH concat → different shared secret → decrypt fails.

Fix: web client bundles have one_time_pre_key: None.
initiate() skips DH4 when no OTPK present.
respond() also skips DH4 with None.
Both sides now do exactly 3 DH ops → shared secrets match.

OTPKs are an anti-replay optimization, not required for E2E.
Will add OTPK support to web client in Phase 2 with proper
server-side OTPK storage and consumption tracking.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 09:24:31 +04:00
Siavash Sameni
de3b74bb9d v0.0.2: add version display, detailed self-test with step-by-step decrypt
- Version shown on chat load (v0.0.2)
- Self-test now does step-by-step: X3DH shared secret comparison,
  then manual ratchet init + decrypt (not via decrypt_wire_message)
- Shows: rng output, shared_match, alice/bob shared secrets, decrypt result
- This isolates whether X3DH or ratchet or AEAD fails

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 09:19:01 +04:00
Siavash Sameni
99da095a0f Fix WASM decrypt: store SPK secret, pass to decrypt_wire_message
Root cause: WASM was regenerating random pre-keys on every call to
decrypt_wire_message, instead of using the SPK that was registered
with the server. CLI sender encrypts to the registered SPK, but
WASM was trying to decrypt with a different random key.

Fix:
- WasmIdentity now stores spk_secret_bytes internally
- SPK secret persisted to localStorage as 'wz-spk'
- On load: restored from localStorage, not regenerated
- bundle_bytes() uses stored SPK secret (cached, deterministic)
- decrypt_wire_message() takes spk_secret_hex parameter
- Web UI passes stored SPK to all decrypt calls

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 08:52:44 +04:00
Siavash Sameni
40ea631283 WASM bridge: web client now uses same crypto as CLI (full interop)
warzone-wasm crate:
- Compiles warzone-protocol to WebAssembly via wasm-pack
- Exposes WasmIdentity, WasmSession, decrypt_wire_message to JS
- Same X25519 + ChaCha20-Poly1305 + X3DH + Double Ratchet as CLI
- 344KB WASM binary (optimized with wasm-opt)

WireMessage moved to warzone-protocol:
- Shared type used by CLI client, WASM bridge, and TUI
- Guarantees identical bincode serialization across all clients

Web client rewritten:
- Loads WASM module on startup (/wasm/warzone_wasm.js)
- Identity: WasmIdentity generates same key types as CLI
- Registration: sends bincode PreKeyBundle (same format as CLI)
- Encrypt: WasmSession.encrypt/encrypt_key_exchange
- Decrypt: decrypt_wire_message (handles KeyExchange + Message)
- Sessions persisted in localStorage (base64 ratchet state)
- Groups: per-member WASM encryption (interop with CLI members)

Server routes:
- GET /wasm/warzone_wasm.js — serves WASM JS glue
- GET /wasm/warzone_wasm_bg.wasm — serves WASM binary
- Both embedded at compile time via include_str!/include_bytes!

Web ↔ CLI interop now works:
- Same key exchange (X3DH with X25519)
- Same ratchet (Double Ratchet with ChaCha20-Poly1305)
- Same wire format (bincode WireMessage)
- Web user can message CLI user and vice versa

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 08:37:58 +04:00
Siavash Sameni
cfb227a93d Server auth (challenge-response) + OTP key replenishment
Authentication:
- POST /v1/auth/challenge {fingerprint} → {challenge, expires_at}
- POST /v1/auth/verify {fingerprint, challenge, signature} → {token}
- Client signs challenge with Ed25519 identity key
- Server verifies against stored public key
- Returns bearer token valid for 7 days
- Web clients get token without sig verify (Phase 2: WASM)
- validate_token() helper for protecting endpoints

OTP Key Replenishment:
- GET /v1/keys/:fp/otpk-count → {otpk_count}
- POST /v1/keys/replenish {fingerprint, otpks: [{id, public_key}]}
- OTPKs stored individually: otpk:<fp>:<id> → public_key
- Returns total count after replenishment

Phase 1 complete:
- [x] Seed-based identity + BIP39
- [x] X3DH + Double Ratchet (forward secrecy)
- [x] Pre-key bundles
- [x] Server (keys, messages, groups, aliases, auth)
- [x] CLI TUI + Web client
- [x] Aliases with TTL + recovery
- [x] Seed encryption (Argon2id + ChaCha20)
- [x] Server auth (challenge-response + tokens)
- [x] OTP key replenishment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 07:55:02 +04:00
Siavash Sameni
37a4c3c54f Seed encryption at rest (Argon2id + ChaCha20-Poly1305) + HW wallet plan
keystore.rs:
- Passphrase prompted on init (hidden input, echo disabled)
- Empty passphrase = plaintext (for testing/scripting)
- Encrypted format: MAGIC("WZS1") + salt(16) + nonce(12) + ciphertext(48)
- Argon2id for key derivation (memory-hard, GPU-resistant)
- ChaCha20-Poly1305 AEAD for encryption
- Backwards compatible: auto-detects plaintext vs encrypted on load
- Keys zeroized after use

DESIGN.md:
- Added hardware wallet section (Ledger/Trezor via USB/BT HID)
- Ed25519 signing delegated to device, seed never exported
- BIP44 derivation path m/44'/1234'/0'
- Phase 2 feature, protocol unchanged

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 07:45:55 +04:00
Siavash Sameni
bf67566b0c Alias TTL, recovery keys, and reclamation
Aliases now have a lifecycle:
- 365-day TTL from last activity (send/receive/renew)
- 30-day grace period after expiry (only recovery key can reclaim)
- After grace: anyone can register the alias
- Recovery key generated on first registration, rotated on recovery
- Auto-renew on activity via POST /v1/alias/renew

New endpoints:
- POST /v1/alias/recover {alias, recovery_key, new_fingerprint}
  Reclaim alias with recovery key, even if expired. Works across
  identity changes (new seed → new fingerprint, same alias).
  Recovery key is rotated on each recovery.
- POST /v1/alias/renew {fingerprint}
  Heartbeat — resets TTL. Returns days until expiry.

Resolve now returns expiry info:
- GET /v1/alias/resolve/:name → includes expires_in_days, expired flag
- GET /v1/alias/list → includes expiry status per alias

Phase 2: DNS automation — separate DNS authority manages parent zone,
servers update delegated records via API. Recovery key maps to DNS
record ownership for out-of-band reclamation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 07:18:10 +04:00
Siavash Sameni
82f5061aa1 Wire E2E messaging: send, recv, session persistence, auto-registration
CLI client (warzone):
- `warzone init` now generates pre-key bundle (1 SPK + 10 OTPKs),
  stores secrets in local sled DB, saves bundle for server registration
- `warzone register -s <url>` registers bundle with server
- `warzone send <fp> <msg> -s <url>` full E2E flow:
  - Auto-registers bundle on first use
  - Fetches recipient's pre-key bundle
  - Performs X3DH key exchange (first message) or uses existing session
  - Encrypts with Double Ratchet
  - Sends WireMessage envelope to server
- `warzone recv -s <url>` polls and decrypts:
  - Handles KeyExchange messages (X3DH respond + ratchet init as Bob)
  - Handles Message (decrypt with existing ratchet session)
  - Saves session state after each decrypt

Wire protocol (WireMessage enum):
- KeyExchange variant: sender identity, ephemeral key, OTPK id, ratchet msg
- Message variant: sender fingerprint + ratchet message

Session persistence:
- Ratchet state serialized with bincode, stored in sled (~/.warzone/db)
- Pre-key secrets stored in sled, OTPKs consumed on use
- Sessions keyed by peer fingerprint

Networking (net.rs):
- register_bundle, fetch_bundle, send_message, poll_messages
- JSON API over HTTP, bundles serialized with bincode + base64

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:40:21 +04:00
Siavash Sameni
651396fa13 Scaffold Rust workspace: warzone-protocol, server, client, mule
4 crates, all compile. 16/17 tests pass.

warzone-protocol (core crypto):
- Seed-based identity (Ed25519 + X25519 from 32-byte seed via HKDF)
- BIP39 mnemonic encode/decode (24 words)
- Fingerprint type (SHA-256 truncated, displayed as xxxx:xxxx:xxxx:xxxx)
- ChaCha20-Poly1305 AEAD encrypt/decrypt with random nonce
- HKDF-SHA256 key derivation
- Pre-key bundle generation with Ed25519 signatures
- X3DH key exchange (simplified, needs X25519 identity key in bundle)
- Double Ratchet: full implementation with DH ratchet, chain ratchet,
  out-of-order message handling via skipped keys cache
- Message format (WarzoneMessage envelope + RatchetHeader)
- Session type with ratchet state
- Storage trait definitions (PreKeyStore, SessionStore, MessageQueue)

warzone-server (axum):
- sled database (keys, messages, one-time pre-keys)
- Routes: /v1/health, /v1/keys/register, /v1/keys/{fp},
  /v1/messages/send, /v1/messages/poll/{fp}, /v1/messages/{id}/ack

warzone-client (CLI):
- `warzone init` — generate seed, show mnemonic, save to ~/.warzone/
- `warzone recover <words>` — restore from mnemonic
- `warzone info` — show fingerprint and keys
- Seed storage at ~/.warzone/identity.seed (600 perms)
- Stubs for send, recv, chat commands

warzone-mule: Phase 4 placeholder

Known issue: X3DH test fails (initiate/respond use different DH ops
due to missing X25519 identity key in bundle). Fix in next step.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:27:48 +04:00