================================================================================ Ultra Mode – ASCII Diagrams (Hydra Apocalypse Ratchet) ================================================================================ These diagrams illustrate the core flows in Ultra Secret Mode. All flows assume: - CCCData is fully configured and shared at channel creation. - No ratchet_public is ever sent on wire (pre-defined symmetric ratchet + rekey inside payload). - Relay is stateless RAM forwarder. - Everything except absolute minimum routing info is inside the encrypted `data` field. 1. Message Lifecycle (Full End-to-End Flow) =========================================== .. code-block:: text Sender Device (Ultra Mode enabled) | User types message + current timestamp | Load CCCData → build cascade pool (48-64 entries from enabled providers) | Advance inner Double Ratchet (symmetric every msg) → base_message_key | Derive seq_seed = KMAC256(base_message_key + "seq-seed" + counter) | Generate secret cascade sequence (16-24 layers) via CSPRNG(seed) | Pad plaintext: to block_size + random min_padding_bytes from KDF | Inner AEAD round-robin (user-chosen aeadConfigs) → inner_ct | Cascade encrypt (strongest first) → cascade_ct | If cascadeReKeyAfter: new_inner_root = KMAC256(cascade_ct + old_root) | Outer AEAD (fast fixed) on cascade_ct → final_data | Build RelayMessage: from_rly_user_id | to_rly_chan_id | options | data (final_data) | server_seq | Send via gRPC to relay | v Ephemeral Relay (RAM only – no disk, no keys) | +------------------> Recipient Device A | | | Store raw RelayMessage to Hive immediately | | +------------------> Recipient Device B | | | Store raw RelayMessage to Hive immediately | v Relay discards blob after forwarding 2. Rekey Flow (Post-Compromise Security – Inside Payload) ========================================================= .. code-block:: text Sender decides to rekey (manual button / auto interval) | Generate fresh hybrid KEM keypair(s) using ccc.kemConfigs | Encapsulate new group_master_seed (or root secret) → shared_secret | Create RekeyPayload (JSON inside encrypted data): { "type": "rekey", "new_root_secret": encapsulated_shared_secret, "rekey_counter": current_sender_counter, "timestamp": now } | Proceed with normal message encryption: - Use CURRENT base_message_key + cascade to encrypt the RekeyPayload + real message | Send as normal RelayMessage (recipient sees it as regular message) | Recipient decrypts normal flow: | Detects "type": "rekey" inside decrypted payload | Extracts and decapsulates new_root_secret | Updates group_master_seed / root keys / chain keys | All future messages use the new root → PCS achieved 3. Message Over the Wire (Minimal gRPC Payload – Zero Metadata) =============================================================== .. code-block:: text +-------------------------------- RelayMessage (gRPC over TLS/Noise) -------------------------------+ | from_rly_user_id (4 B) | to_rly_chan_id (4 B) | options (4 B) | server_seq (8 B) | | | data_length (4 B) | data (variable) | | | | data contents (E2EE – never visible to relay): | | timestamp (8 B) + message JSON + padding + RekeyPayload (if rekey) + inner ciphertext layers | +-----------------------------------------------------------------------------------------------------+ → Relay sees only routing IDs + opaque encrypted data → No public keys, no timestamps, no sequence beyond sender_counter (derived inside) 4. Loading Messages from Local Storage (Hive → UI) ================================================== .. code-block:: text User opens channel → app queries Hive 'messages' box | For each row (key = groupId + fromRlyUserId + senderCounter): | Load StoredMessage.rawRelayMessage (full protobuf bytes) | Extract RelayMessage.data from protobuf | Load CCCData for groupId | Advance receiving inner ratchet using fromRlyUserId + senderCounter | Derive base_message_key + seq_seed + cascade_sequence (deterministic) | Decrypt outer AEAD → cascade_ct | Cascade decrypt (reverse order, using same provider/algorithm selections) | Inner AEAD round-robin decrypt → padded_plaintext | Remove padding → extract timestamp + message content + (if present) RekeyPayload | If RekeyPayload → apply new root secrets | Display timestamp + content in UI | (Optional) Cache plaintext in StoredMessage.plaintext for faster reload