149 lines
5.3 KiB
ReStructuredText
149 lines
5.3 KiB
ReStructuredText
================================================================================
|
||
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
|